diff --git a/openbas-api/src/main/java/io/openbas/App.java b/openbas-api/src/main/java/io/openbas/App.java index 0c2aa134c9..b15244996f 100644 --- a/openbas-api/src/main/java/io/openbas/App.java +++ b/openbas-api/src/main/java/io/openbas/App.java @@ -6,7 +6,7 @@ @SpringBootApplication public class App { - public static void main(String[] args) { - SpringApplication.run(App.class, args); - } + public static void main(String[] args) { + SpringApplication.run(App.class, args); + } } diff --git a/openbas-api/src/main/java/io/openbas/aop/LogExecutionTime.java b/openbas-api/src/main/java/io/openbas/aop/LogExecutionTime.java index 6b852d1e6d..bddf19eb51 100644 --- a/openbas-api/src/main/java/io/openbas/aop/LogExecutionTime.java +++ b/openbas-api/src/main/java/io/openbas/aop/LogExecutionTime.java @@ -5,11 +5,7 @@ import java.lang.annotation.RetentionPolicy; import java.lang.annotation.Target; -/** - * Custom annotation used for logging execution time of any method - */ +/** Custom annotation used for logging execution time of any method */ @Retention(RetentionPolicy.RUNTIME) @Target(ElementType.METHOD) -public @interface LogExecutionTime { - -} +public @interface LogExecutionTime {} diff --git a/openbas-api/src/main/java/io/openbas/aop/LoggingAspect.java b/openbas-api/src/main/java/io/openbas/aop/LoggingAspect.java index 8a1ef6c2df..78bc4a0ba5 100644 --- a/openbas-api/src/main/java/io/openbas/aop/LoggingAspect.java +++ b/openbas-api/src/main/java/io/openbas/aop/LoggingAspect.java @@ -18,9 +18,9 @@ public class LoggingAspect { private static final long EXECUTION_TIME_THRESHOLD = 500; /** - * This method uses Around advice which ensures that an advice can run before and after the method execution, to and - * log the execution time of the method This advice will be applied to all the method which are annotate with the - * annotation @LogExecutionTime + * This method uses Around advice which ensures that an advice can run before and after the method + * execution, to and log the execution time of the method This advice will be applied to all the + * method which are annotate with the annotation @LogExecutionTime */ @Around("@annotation(io.openbas.aop.LogExecutionTime)") public Object methodTimeLogger(ProceedingJoinPoint proceedingJoinPoint) throws Throwable { @@ -44,8 +44,12 @@ public Object methodTimeLogger(ProceedingJoinPoint proceedingJoinPoint) throws T } if (executionTime > EXECUTION_TIME_THRESHOLD) { - logger.warn("Execution of {}.{} took {} ms, which exceeds the threshold of {} ms", - className, methodName, executionTime, EXECUTION_TIME_THRESHOLD); + logger.warn( + "Execution of {}.{} took {} ms, which exceeds the threshold of {} ms", + className, + methodName, + executionTime, + EXECUTION_TIME_THRESHOLD); } return result; diff --git a/openbas-api/src/main/java/io/openbas/collectors/expectations_expiration_manager/ExpectationsExpirationManagerCollector.java b/openbas-api/src/main/java/io/openbas/collectors/expectations_expiration_manager/ExpectationsExpirationManagerCollector.java index b9b40e04e4..923ad12a87 100644 --- a/openbas-api/src/main/java/io/openbas/collectors/expectations_expiration_manager/ExpectationsExpirationManagerCollector.java +++ b/openbas-api/src/main/java/io/openbas/collectors/expectations_expiration_manager/ExpectationsExpirationManagerCollector.java @@ -4,12 +4,11 @@ import io.openbas.collectors.expectations_expiration_manager.service.ExpectationsExpirationManagerService; import io.openbas.integrations.CollectorService; import jakarta.annotation.PostConstruct; +import java.time.Duration; import lombok.RequiredArgsConstructor; import org.springframework.scheduling.concurrent.ThreadPoolTaskScheduler; import org.springframework.stereotype.Service; -import java.time.Duration; - @RequiredArgsConstructor @Service public class ExpectationsExpirationManagerCollector { @@ -22,9 +21,10 @@ public class ExpectationsExpirationManagerCollector { @PostConstruct public void init() { if (this.config.isEnable()) { - ExpectationsExpirationManagerJob job = new ExpectationsExpirationManagerJob(this.collectorService, this.config, this.fakeDetectorService); + ExpectationsExpirationManagerJob job = + new ExpectationsExpirationManagerJob( + this.collectorService, this.config, this.fakeDetectorService); this.taskScheduler.scheduleAtFixedRate(job, Duration.ofSeconds(this.config.getInterval())); } } - } diff --git a/openbas-api/src/main/java/io/openbas/collectors/expectations_expiration_manager/ExpectationsExpirationManagerJob.java b/openbas-api/src/main/java/io/openbas/collectors/expectations_expiration_manager/ExpectationsExpirationManagerJob.java index bb76f1ee7f..24e3c347a0 100644 --- a/openbas-api/src/main/java/io/openbas/collectors/expectations_expiration_manager/ExpectationsExpirationManagerJob.java +++ b/openbas-api/src/main/java/io/openbas/collectors/expectations_expiration_manager/ExpectationsExpirationManagerJob.java @@ -3,12 +3,11 @@ import io.openbas.collectors.expectations_expiration_manager.config.ExpectationsExpirationManagerConfig; import io.openbas.collectors.expectations_expiration_manager.service.ExpectationsExpirationManagerService; import io.openbas.integrations.CollectorService; +import java.util.logging.Level; import lombok.extern.java.Log; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Service; -import java.util.logging.Level; - @Service @Log public class ExpectationsExpirationManagerJob implements Runnable { @@ -17,10 +16,17 @@ public class ExpectationsExpirationManagerJob implements Runnable { private final ExpectationsExpirationManagerService fakeDetectorService; @Autowired - public ExpectationsExpirationManagerJob(CollectorService collectorService, ExpectationsExpirationManagerConfig config, ExpectationsExpirationManagerService fakeDetectorService) { + public ExpectationsExpirationManagerJob( + CollectorService collectorService, + ExpectationsExpirationManagerConfig config, + ExpectationsExpirationManagerService fakeDetectorService) { this.fakeDetectorService = fakeDetectorService; try { - collectorService.register(config.getId(), FAKE_DETECTOR_COLLECTOR_TYPE, FAKE_DETECTOR_COLLECTOR_NAME, getClass().getResourceAsStream("/img/icon-fake-detector.png")); + collectorService.register( + config.getId(), + FAKE_DETECTOR_COLLECTOR_TYPE, + FAKE_DETECTOR_COLLECTOR_NAME, + getClass().getResourceAsStream("/img/icon-fake-detector.png")); } catch (Exception e) { log.log(Level.SEVERE, "Error creating expectations expiration manager "); } @@ -35,5 +41,4 @@ public void run() { log.log(Level.SEVERE, "Error running expectations expiration manager service", e); } } - } diff --git a/openbas-api/src/main/java/io/openbas/collectors/expectations_expiration_manager/config/ExpectationsExpirationManagerConfig.java b/openbas-api/src/main/java/io/openbas/collectors/expectations_expiration_manager/config/ExpectationsExpirationManagerConfig.java index 948c51dfbb..d6d004d865 100644 --- a/openbas-api/src/main/java/io/openbas/collectors/expectations_expiration_manager/config/ExpectationsExpirationManagerConfig.java +++ b/openbas-api/src/main/java/io/openbas/collectors/expectations_expiration_manager/config/ExpectationsExpirationManagerConfig.java @@ -27,4 +27,3 @@ public int getExpirationTimeInMinute() { return this.expirationTime / 60; } } - diff --git a/openbas-api/src/main/java/io/openbas/collectors/expectations_expiration_manager/service/ExpectationsExpirationManagerService.java b/openbas-api/src/main/java/io/openbas/collectors/expectations_expiration_manager/service/ExpectationsExpirationManagerService.java index 8ca361a582..816be26911 100644 --- a/openbas-api/src/main/java/io/openbas/collectors/expectations_expiration_manager/service/ExpectationsExpirationManagerService.java +++ b/openbas-api/src/main/java/io/openbas/collectors/expectations_expiration_manager/service/ExpectationsExpirationManagerService.java @@ -1,20 +1,19 @@ package io.openbas.collectors.expectations_expiration_manager.service; +import static io.openbas.collectors.expectations_expiration_manager.config.ExpectationsExpirationManagerConfig.PRODUCT_NAME; +import static io.openbas.collectors.expectations_expiration_manager.utils.ExpectationUtils.computeFailedMessage; +import static io.openbas.collectors.expectations_expiration_manager.utils.ExpectationUtils.isExpired; + import io.openbas.collectors.expectations_expiration_manager.config.ExpectationsExpirationManagerConfig; import io.openbas.database.model.InjectExpectation; import io.openbas.inject_expectation.InjectExpectationService; import jakarta.validation.constraints.NotNull; +import java.util.List; import lombok.RequiredArgsConstructor; import lombok.extern.java.Log; import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; -import java.util.List; - -import static io.openbas.collectors.expectations_expiration_manager.config.ExpectationsExpirationManagerConfig.PRODUCT_NAME; -import static io.openbas.collectors.expectations_expiration_manager.utils.ExpectationUtils.computeFailedMessage; -import static io.openbas.collectors.expectations_expiration_manager.utils.ExpectationUtils.isExpired; - @RequiredArgsConstructor @Service @Log @@ -23,7 +22,6 @@ public class ExpectationsExpirationManagerService { private final InjectExpectationService injectExpectationService; private final ExpectationsExpirationManagerConfig config; - @Transactional(rollbackFor = Exception.class) public void computeExpectations() { List expectations = this.injectExpectationService.expectationsNotFill(); @@ -38,57 +36,49 @@ public void computeExpectations() { private void computeExpectations(@NotNull final List expectations) { List expectationAssets = expectations.stream().toList(); - expectationAssets.forEach((expectation) -> { - if (isExpired(expectation)) { - String result = computeFailedMessage(expectation.getType()); - this.injectExpectationService.computeExpectation( - expectation, - this.config.getId(), - "collector", - PRODUCT_NAME, - result, - false - ); - } - - }); + expectationAssets.forEach( + (expectation) -> { + if (isExpired(expectation)) { + String result = computeFailedMessage(expectation.getType()); + this.injectExpectationService.computeExpectation( + expectation, this.config.getId(), "collector", PRODUCT_NAME, result, false); + } + }); } private void computeExpectationsForAssets(@NotNull final List expectations) { - List expectationAssets = expectations.stream().filter(e -> e.getAsset() != null).toList(); - expectationAssets.forEach((expectation) -> { - if (isExpired(expectation)) { - String result = computeFailedMessage(expectation.getType()); - this.injectExpectationService.computeExpectation( - expectation, - this.config.getId(), - "collector", - PRODUCT_NAME, - result, - false - ); - } - - }); + List expectationAssets = + expectations.stream().filter(e -> e.getAsset() != null).toList(); + expectationAssets.forEach( + (expectation) -> { + if (isExpired(expectation)) { + String result = computeFailedMessage(expectation.getType()); + this.injectExpectationService.computeExpectation( + expectation, this.config.getId(), "collector", PRODUCT_NAME, result, false); + } + }); } - private void computeExpectationsForAssetGroups(@NotNull final List expectations) { - List expectationAssetGroups = expectations.stream().filter(e -> e.getAssetGroup() != null) - .toList(); - expectationAssetGroups.forEach((expectationAssetGroup -> { - List expectationAssets = this.injectExpectationService.expectationsForAssets( - expectationAssetGroup.getInject(), expectationAssetGroup.getAssetGroup(), expectationAssetGroup.getType() - ); - // Every expectation assets are filled - if (expectationAssets.stream().noneMatch(e -> e.getResults().isEmpty())) { - this.injectExpectationService.computeExpectationGroup( - expectationAssetGroup, - expectationAssets, - this.config.getId(), - "collector", - PRODUCT_NAME - ); - } - })); + private void computeExpectationsForAssetGroups( + @NotNull final List expectations) { + List expectationAssetGroups = + expectations.stream().filter(e -> e.getAssetGroup() != null).toList(); + expectationAssetGroups.forEach( + (expectationAssetGroup -> { + List expectationAssets = + this.injectExpectationService.expectationsForAssets( + expectationAssetGroup.getInject(), + expectationAssetGroup.getAssetGroup(), + expectationAssetGroup.getType()); + // Every expectation assets are filled + if (expectationAssets.stream().noneMatch(e -> e.getResults().isEmpty())) { + this.injectExpectationService.computeExpectationGroup( + expectationAssetGroup, + expectationAssets, + this.config.getId(), + "collector", + PRODUCT_NAME); + } + })); } } diff --git a/openbas-api/src/main/java/io/openbas/collectors/expectations_expiration_manager/utils/ExpectationUtils.java b/openbas-api/src/main/java/io/openbas/collectors/expectations_expiration_manager/utils/ExpectationUtils.java index 701f68f7e4..ab963377a4 100644 --- a/openbas-api/src/main/java/io/openbas/collectors/expectations_expiration_manager/utils/ExpectationUtils.java +++ b/openbas-api/src/main/java/io/openbas/collectors/expectations_expiration_manager/utils/ExpectationUtils.java @@ -1,32 +1,27 @@ package io.openbas.collectors.expectations_expiration_manager.utils; +import static io.openbas.database.model.InjectExpectation.EXPECTATION_TYPE.DETECTION; +import static io.openbas.database.model.InjectExpectation.EXPECTATION_TYPE.PREVENTION; + import io.openbas.database.model.InjectExpectation; import io.openbas.database.model.InjectExpectation.EXPECTATION_TYPE; import jakarta.validation.constraints.NotNull; - import java.time.Instant; import java.time.temporal.ChronoUnit; -import static io.openbas.database.model.InjectExpectation.EXPECTATION_TYPE.DETECTION; -import static io.openbas.database.model.InjectExpectation.EXPECTATION_TYPE.PREVENTION; - public class ExpectationUtils { - private ExpectationUtils() { - - } + private ExpectationUtils() {} public static boolean isExpired(@NotNull final InjectExpectation expectation) { - Instant expirationTime = Instant.now().minus(expectation.getExpirationTime() / 60, ChronoUnit.MINUTES); + Instant expirationTime = + Instant.now().minus(expectation.getExpirationTime() / 60, ChronoUnit.MINUTES); return expectation.getCreatedAt().isBefore(expirationTime); } public static String computeFailedMessage(@NotNull final EXPECTATION_TYPE expectationType) { return DETECTION.equals(expectationType) ? "Not Detected" - : PREVENTION.equals(expectationType) - ? "Not Prevented" - : "FAILED"; + : PREVENTION.equals(expectationType) ? "Not Prevented" : "FAILED"; } - } diff --git a/openbas-api/src/main/java/io/openbas/config/AppConfig.java b/openbas-api/src/main/java/io/openbas/config/AppConfig.java index 4dab0e7953..fddb0fcf0e 100644 --- a/openbas-api/src/main/java/io/openbas/config/AppConfig.java +++ b/openbas-api/src/main/java/io/openbas/config/AppConfig.java @@ -20,14 +20,14 @@ public class AppConfig { // Validations - public final static String EMPTY_MESSAGE = "This list cannot be empty."; - public final static String MANDATORY_MESSAGE = "This value should not be blank."; - public final static String NOW_FUTURE_MESSAGE = "This date must be now or in the future."; - public final static String EMAIL_FORMAT = "This field must be a valid email."; - public final static String PHONE_FORMAT = "This field must start with '+' character and country identifier."; + public static final String EMPTY_MESSAGE = "This list cannot be empty."; + public static final String MANDATORY_MESSAGE = "This value should not be blank."; + public static final String NOW_FUTURE_MESSAGE = "This date must be now or in the future."; + public static final String EMAIL_FORMAT = "This field must be a valid email."; + public static final String PHONE_FORMAT = + "This field must start with '+' character and country identifier."; - @Resource - private OpenBASConfig openBASConfig; + @Resource private OpenBASConfig openBASConfig; @Bean ObjectMapper openBASJsonMapper() { @@ -37,12 +37,16 @@ ObjectMapper openBASJsonMapper() { @Bean public OpenAPI openBASOpenAPI() { return new OpenAPI() - .info(new Info().title("OpenBAS API") - .description("Software under open source licence designed to plan and conduct exercises") - .version(this.openBASConfig.getVersion()) - .license(new License().name("Apache 2.0").url("https://filigran.io//"))) - .externalDocs(new ExternalDocumentation() - .description("OpenBAS documentation") - .url("https://docs.openbas.io/")); + .info( + new Info() + .title("OpenBAS API") + .description( + "Software under open source licence designed to plan and conduct exercises") + .version(this.openBASConfig.getVersion()) + .license(new License().name("Apache 2.0").url("https://filigran.io//"))) + .externalDocs( + new ExternalDocumentation() + .description("OpenBAS documentation") + .url("https://docs.openbas.io/")); } } diff --git a/openbas-api/src/main/java/io/openbas/config/AppSecurityConfig.java b/openbas-api/src/main/java/io/openbas/config/AppSecurityConfig.java index 3ecdcb00a6..04c90dfdd1 100644 --- a/openbas-api/src/main/java/io/openbas/config/AppSecurityConfig.java +++ b/openbas-api/src/main/java/io/openbas/config/AppSecurityConfig.java @@ -1,5 +1,11 @@ package io.openbas.config; +import static io.openbas.database.model.User.ROLE_ADMIN; +import static io.openbas.database.model.User.ROLE_USER; +import static java.util.Optional.ofNullable; +import static org.apache.commons.lang3.StringUtils.isBlank; +import static org.springframework.util.StringUtils.hasLength; + import com.fasterxml.jackson.core.type.TypeReference; import com.fasterxml.jackson.databind.JsonNode; import com.fasterxml.jackson.databind.ObjectMapper; @@ -12,6 +18,14 @@ import io.openbas.security.TokenAuthenticationFilter; import io.openbas.service.UserService; import jakarta.annotation.Resource; +import java.io.IOException; +import java.util.ArrayList; +import java.util.Base64; +import java.util.List; +import java.util.Optional; +import java.util.logging.Level; +import java.util.logging.Logger; +import java.util.stream.Stream; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; @@ -48,21 +62,6 @@ import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter; import org.springframework.security.web.savedrequest.HttpSessionRequestCache; -import java.io.IOException; -import java.util.ArrayList; -import java.util.Base64; -import java.util.List; -import java.util.Optional; -import java.util.logging.Level; -import java.util.logging.Logger; -import java.util.stream.Stream; - -import static io.openbas.database.model.User.ROLE_ADMIN; -import static io.openbas.database.model.User.ROLE_USER; -import static java.util.Optional.ofNullable; -import static org.apache.commons.lang3.StringUtils.isBlank; -import static org.springframework.util.StringUtils.hasLength; - @Configuration @EnableWebSecurity public class AppSecurityConfig { @@ -74,8 +73,7 @@ public class AppSecurityConfig { private OpenBASConfig openBASConfig; private Environment env; - @Resource - protected ObjectMapper mapper; + @Resource protected ObjectMapper mapper; @Autowired public void setEnv(Environment env) { @@ -104,56 +102,68 @@ public void setUserRepository(UserRepository userRepository) { public SecurityFilterChain filterChain(HttpSecurity http) throws Exception { http.addFilterBefore(tokenAuthenticationFilter(), UsernamePasswordAuthenticationFilter.class) .requestCache(Customizer.withDefaults()) - /**/.requestCache((cache) -> cache.requestCache(new HttpSessionRequestCache())) + /**/ .requestCache((cache) -> cache.requestCache(new HttpSessionRequestCache())) .csrf(AbstractHttpConfigurer::disable) .formLogin(AbstractHttpConfigurer::disable) .securityContext((securityContext) -> securityContext.requireExplicitSave(false)) .authorizeHttpRequests( - rq -> rq.requestMatchers("/api/comcheck/**").permitAll() - .requestMatchers("/api/player/**").permitAll() - .requestMatchers("/api/settings").permitAll() - .requestMatchers("/api/agent/**").permitAll() - .requestMatchers("/api/implant/**").permitAll() - .requestMatchers("/api/login").permitAll() - .requestMatchers("/api/reset/**").permitAll() - .requestMatchers("/api/**").authenticated() - .anyRequest().permitAll() - ) + rq -> + rq.requestMatchers("/api/comcheck/**") + .permitAll() + .requestMatchers("/api/player/**") + .permitAll() + .requestMatchers("/api/settings") + .permitAll() + .requestMatchers("/api/agent/**") + .permitAll() + .requestMatchers("/api/implant/**") + .permitAll() + .requestMatchers("/api/login") + .permitAll() + .requestMatchers("/api/reset/**") + .permitAll() + .requestMatchers("/api/**") + .authenticated() + .anyRequest() + .permitAll()) .logout( - logout -> logout.invalidateHttpSession(true) - .deleteCookies("JSESSIONID", openBASConfig.getCookieName()) - .logoutSuccessUrl(env.getProperty("openbas.logout-success-url", String.class, "/")) - ); + logout -> + logout + .invalidateHttpSession(true) + .deleteCookies("JSESSIONID", openBASConfig.getCookieName()) + .logoutSuccessUrl( + env.getProperty("openbas.logout-success-url", String.class, "/"))); if (openBASConfig.isAuthOpenidEnable()) { http.oauth2Login( - login -> login.successHandler(new SsoRefererAuthenticationSuccessHandler()) - .failureHandler(new SsoRefererAuthenticationFailureHandler()) - ); + login -> + login + .successHandler(new SsoRefererAuthenticationSuccessHandler()) + .failureHandler(new SsoRefererAuthenticationFailureHandler())); } if (openBASConfig.isAuthSaml2Enable()) { - DefaultRelyingPartyRegistrationResolver relyingPartyRegistrationResolver = new DefaultRelyingPartyRegistrationResolver( - this.relyingPartyRegistrationRepository); - Saml2MetadataFilter filter = new Saml2MetadataFilter( - relyingPartyRegistrationResolver, - new OpenSamlMetadataResolver()); + DefaultRelyingPartyRegistrationResolver relyingPartyRegistrationResolver = + new DefaultRelyingPartyRegistrationResolver(this.relyingPartyRegistrationRepository); + Saml2MetadataFilter filter = + new Saml2MetadataFilter(relyingPartyRegistrationResolver, new OpenSamlMetadataResolver()); OpenSaml4AuthenticationProvider authenticationProvider = getOpenSaml4AuthenticationProvider(); http.addFilterBefore(filter, Saml2WebSsoAuthenticationFilter.class) .saml2Login( - saml2Login -> saml2Login - .authenticationManager(new ProviderManager(authenticationProvider)) - .successHandler(new SsoRefererAuthenticationSuccessHandler()) - ); + saml2Login -> + saml2Login + .authenticationManager(new ProviderManager(authenticationProvider)) + .successHandler(new SsoRefererAuthenticationSuccessHandler())); } // Rewrite 403 code to 401 http.exceptionHandling( - exceptionHandling -> exceptionHandling.authenticationEntryPoint( - (request, response, authException) -> response.setStatus(HttpStatus.UNAUTHORIZED.value())) - ); + exceptionHandling -> + exceptionHandling.authenticationEntryPoint( + (request, response, authException) -> + response.setStatus(HttpStatus.UNAUTHORIZED.value()))); return http.build(); } @@ -164,27 +174,30 @@ public TokenAuthenticationFilter tokenAuthenticationFilter() { } private List extractRolesFromToken(OAuth2AccessToken accessToken, String registrationId) { - ObjectReader listReader = mapper.readerFor(new TypeReference>() { - }); + ObjectReader listReader = mapper.readerFor(new TypeReference>() {}); if (accessToken != null) { String rolesPathConfig = "openbas.provider." + registrationId + ".roles_path"; //noinspection unchecked - List rolesPath = env.getProperty(rolesPathConfig, List.class, new ArrayList()); + List rolesPath = + env.getProperty(rolesPathConfig, List.class, new ArrayList()); try { String[] chunks = accessToken.getTokenValue().split("\\."); Base64.Decoder decoder = Base64.getUrlDecoder(); String payload = new String(decoder.decode(chunks[1])); JsonNode jsonNode = mapper.readTree(payload); - return rolesPath.stream().map(path -> "/" + path.replaceAll("\\.", "/")) - .flatMap(path -> { - JsonNode arrayRoles = jsonNode.at(path); - try { - List roles = listReader.readValue(arrayRoles); - return roles.stream(); - } catch (IOException e) { - return Stream.empty(); - } - }).toList(); + return rolesPath.stream() + .map(path -> "/" + path.replaceAll("\\.", "/")) + .flatMap( + path -> { + JsonNode arrayRoles = jsonNode.at(path); + try { + List roles = listReader.readValue(arrayRoles); + return roles.stream(); + } catch (IOException e) { + return Stream.empty(); + } + }) + .toList(); } catch (Exception e) { LOGGER.log(Level.SEVERE, e.getMessage(), e); } @@ -192,21 +205,24 @@ private List extractRolesFromToken(OAuth2AccessToken accessToken, String return new ArrayList<>(); } - private List extractRolesFromUser(Saml2AuthenticatedPrincipal user, String registrationId) { + private List extractRolesFromUser( + Saml2AuthenticatedPrincipal user, String registrationId) { String rolesPathConfig = "openbas.provider." + registrationId + ".roles_path"; //noinspection unchecked List rolesPath = env.getProperty(rolesPathConfig, List.class, new ArrayList()); try { return rolesPath.stream() - .flatMap(path -> { - try { - List roles = user.getAttribute(path); - assert roles != null; - return roles.stream(); - } catch (NullPointerException e) { - return Stream.empty(); - } - }).toList(); + .flatMap( + path -> { + try { + List roles = user.getAttribute(path); + assert roles != null; + return roles.stream(); + } catch (NullPointerException e) { + return Stream.empty(); + } + }) + .toList(); } catch (Exception e) { LOGGER.log(Level.SEVERE, e.getMessage(), e); } @@ -223,7 +239,8 @@ public User userManagement( String rolesAdminConfig = "openbas.provider." + registrationId + ".roles_admin"; String allAdminConfig = "openbas.provider." + registrationId + ".all_admin"; //noinspection unchecked - List rolesAdmin = this.env.getProperty(rolesAdminConfig, List.class, new ArrayList()); + List rolesAdmin = + this.env.getProperty(rolesAdminConfig, List.class, new ArrayList()); boolean allAdmin = this.env.getProperty(allAdminConfig, Boolean.class, false); boolean isAdmin = allAdmin || rolesAdmin.stream().anyMatch(rolesFromToken::contains); if (hasLength(email)) { @@ -253,19 +270,25 @@ public User userManagement( } public User userOauth2Management( - OAuth2AccessToken accessToken, - ClientRegistration clientRegistration, - OAuth2User user) { + OAuth2AccessToken accessToken, ClientRegistration clientRegistration, OAuth2User user) { String emailAttribute = user.getAttribute("email"); String registrationId = clientRegistration.getRegistrationId(); List rolesFromToken = extractRolesFromToken(accessToken, registrationId); if (isBlank(emailAttribute)) { - OAuth2Error authError = new OAuth2Error("invalid_configuration", "You probably need a public email in your " + - registrationId + " account", ""); + OAuth2Error authError = + new OAuth2Error( + "invalid_configuration", + "You probably need a public email in your " + registrationId + " account", + ""); throw new OAuth2AuthenticationException(authError); } - User userLogin = userManagement(emailAttribute, registrationId, rolesFromToken, user.getAttribute("given_name"), - user.getAttribute("family_name")); + User userLogin = + userManagement( + emailAttribute, + registrationId, + rolesFromToken, + user.getAttribute("given_name"), + user.getAttribute("family_name")); if (userLogin != null) { return userLogin; @@ -281,11 +304,21 @@ public User userSaml2Management(Saml2AuthenticatedPrincipal user) { List rolesFromUser = extractRolesFromUser(user, registrationId); User userLogin = null; try { - userLogin = userManagement(emailAttribute, registrationId, rolesFromUser, - user.getFirstAttribute( - env.getProperty("openbas.provider." + registrationId + ".firstname_attribute_key", String.class, "")), - user.getFirstAttribute( - env.getProperty("openbas.provider." + registrationId + ".lastname_attribute_key", String.class, ""))); + userLogin = + userManagement( + emailAttribute, + registrationId, + rolesFromUser, + user.getFirstAttribute( + env.getProperty( + "openbas.provider." + registrationId + ".firstname_attribute_key", + String.class, + "")), + user.getFirstAttribute( + env.getProperty( + "openbas.provider." + registrationId + ".lastname_attribute_key", + String.class, + ""))); } catch (Exception e) { LOGGER.log(Level.SEVERE, e.getMessage(), e); } @@ -298,20 +331,19 @@ public User userSaml2Management(Saml2AuthenticatedPrincipal user) { throw new Saml2AuthenticationException(authError); } - public OidcUser oidcUserManagement(OAuth2AccessToken accessToken, ClientRegistration clientRegistration, - OAuth2User user) { + public OidcUser oidcUserManagement( + OAuth2AccessToken accessToken, ClientRegistration clientRegistration, OAuth2User user) { User loginUser = userOauth2Management(accessToken, clientRegistration, user); return new OpenBASOidcUser(loginUser); } - public OAuth2User oAuth2UserManagement(OAuth2AccessToken accessToken, ClientRegistration clientRegistration, - OAuth2User user) { + public OAuth2User oAuth2UserManagement( + OAuth2AccessToken accessToken, ClientRegistration clientRegistration, OAuth2User user) { User loginUser = userOauth2Management(accessToken, clientRegistration, user); return new OpenBASOAuth2User(loginUser); } - public Saml2Authentication saml2UserManagement( - Saml2Authentication authentication) { + public Saml2Authentication saml2UserManagement(Saml2Authentication authentication) { Saml2AuthenticatedPrincipal user = (Saml2AuthenticatedPrincipal) authentication.getPrincipal(); User loginUser = userSaml2Management(user); @@ -321,32 +353,36 @@ public Saml2Authentication saml2UserManagement( roles.add(new SimpleGrantedAuthority(ROLE_ADMIN)); } - return new Saml2Authentication(new OpenBASSaml2User(loginUser, roles), authentication.getSaml2Response(), roles); + return new Saml2Authentication( + new OpenBASSaml2User(loginUser, roles), authentication.getSaml2Response(), roles); } @Bean public OAuth2UserService oidcUserService() { OidcUserService delegate = new OidcUserService(); - return request -> oidcUserManagement(request.getAccessToken(), request.getClientRegistration(), - delegate.loadUser(request)); + return request -> + oidcUserManagement( + request.getAccessToken(), request.getClientRegistration(), delegate.loadUser(request)); } @Bean public OAuth2UserService oauth2UserService() { DefaultOAuth2UserService delegate = new DefaultOAuth2UserService(); - return request -> oAuth2UserManagement(request.getAccessToken(), request.getClientRegistration(), - delegate.loadUser(request)); + return request -> + oAuth2UserManagement( + request.getAccessToken(), request.getClientRegistration(), delegate.loadUser(request)); } private OpenSaml4AuthenticationProvider getOpenSaml4AuthenticationProvider() { OpenSaml4AuthenticationProvider authenticationProvider = new OpenSaml4AuthenticationProvider(); - authenticationProvider.setResponseAuthenticationConverter(responseToken -> { - Saml2Authentication authentication = OpenSaml4AuthenticationProvider - .createDefaultResponseAuthenticationConverter() - .convert(responseToken); - assert authentication != null; - return saml2UserManagement(authentication); - }); + authenticationProvider.setResponseAuthenticationConverter( + responseToken -> { + Saml2Authentication authentication = + OpenSaml4AuthenticationProvider.createDefaultResponseAuthenticationConverter() + .convert(responseToken); + assert authentication != null; + return saml2UserManagement(authentication); + }); return authenticationProvider; } } diff --git a/openbas-api/src/main/java/io/openbas/config/MvcConfig.java b/openbas-api/src/main/java/io/openbas/config/MvcConfig.java index dd11ca349b..d314217cbb 100644 --- a/openbas-api/src/main/java/io/openbas/config/MvcConfig.java +++ b/openbas-api/src/main/java/io/openbas/config/MvcConfig.java @@ -2,6 +2,8 @@ import com.fasterxml.jackson.databind.ObjectMapper; import jakarta.annotation.Resource; +import java.util.List; +import java.util.concurrent.Executors; import org.jetbrains.annotations.NotNull; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; @@ -17,17 +19,13 @@ import org.springframework.web.servlet.resource.EncodedResourceResolver; import org.springframework.web.servlet.resource.PathResourceResolver; -import java.util.List; -import java.util.concurrent.Executors; - @Configuration @EnableWebMvc public class MvcConfig implements WebMvcConfigurer { - private final static int CACHE_PERIOD = 3600; + private static final int CACHE_PERIOD = 3600; - @Resource - private ObjectMapper objectMapper; + @Resource private ObjectMapper objectMapper; @Bean public MappingJackson2HttpMessageConverter customJackson2HttpMessageConverter() { @@ -38,7 +36,7 @@ public MappingJackson2HttpMessageConverter customJackson2HttpMessageConverter() @Override public void configureMessageConverters(List> messageConverters) { - //https://springdoc.org/#why-am-i-getting-an-error-swagger-ui-unable-to-render-definition-when-overriding-the-default-spring-registered-httpmessageconverter + // https://springdoc.org/#why-am-i-getting-an-error-swagger-ui-unable-to-render-definition-when-overriding-the-default-spring-registered-httpmessageconverter messageConverters.add(new ByteArrayHttpMessageConverter()); messageConverters.add(new StringHttpMessageConverter()); messageConverters.add(customJackson2HttpMessageConverter()); @@ -54,7 +52,8 @@ protected ConcurrentTaskExecutor getTaskExecutor() { return new ConcurrentTaskExecutor(Executors.newFixedThreadPool(20)); } - private void addPathStaticResolver(ResourceHandlerRegistry registry, String pattern, String location) { + private void addPathStaticResolver( + ResourceHandlerRegistry registry, String pattern, String location) { registry .addResourceHandler(pattern) .addResourceLocations(location) diff --git a/openbas-api/src/main/java/io/openbas/config/OpenBASAnonymous.java b/openbas-api/src/main/java/io/openbas/config/OpenBASAnonymous.java index d147ed3306..a3b7a2c68f 100644 --- a/openbas-api/src/main/java/io/openbas/config/OpenBASAnonymous.java +++ b/openbas-api/src/main/java/io/openbas/config/OpenBASAnonymous.java @@ -1,13 +1,11 @@ package io.openbas.config; -import org.springframework.security.core.GrantedAuthority; - import java.util.Collection; - +import org.springframework.security.core.GrantedAuthority; public class OpenBASAnonymous implements OpenBASPrincipal { - public final static String ANONYMOUS = "anonymous"; + public static final String ANONYMOUS = "anonymous"; public static final String LANG_AUTO = "auto"; @Override diff --git a/openbas-api/src/main/java/io/openbas/config/OpenBASOAuth2User.java b/openbas-api/src/main/java/io/openbas/config/OpenBASOAuth2User.java index 33c6c69367..c6e5f13540 100644 --- a/openbas-api/src/main/java/io/openbas/config/OpenBASOAuth2User.java +++ b/openbas-api/src/main/java/io/openbas/config/OpenBASOAuth2User.java @@ -1,16 +1,15 @@ package io.openbas.config; +import static io.openbas.database.model.User.ROLE_ADMIN; +import static io.openbas.database.model.User.ROLE_USER; + import io.openbas.database.model.User; +import java.util.*; import org.jetbrains.annotations.NotNull; import org.springframework.security.core.GrantedAuthority; import org.springframework.security.core.authority.SimpleGrantedAuthority; import org.springframework.security.oauth2.core.user.OAuth2User; -import java.util.*; - -import static io.openbas.database.model.User.ROLE_ADMIN; -import static io.openbas.database.model.User.ROLE_USER; - public class OpenBASOAuth2User implements OpenBASPrincipal, OAuth2User { private final User user; @@ -52,9 +51,9 @@ public boolean isAdmin() { public String getLang() { return this.user.getLang(); } + @Override public String getName() { return this.user.getFirstname() + " " + this.user.getLastname(); } - } diff --git a/openbas-api/src/main/java/io/openbas/config/OpenBASOidcUser.java b/openbas-api/src/main/java/io/openbas/config/OpenBASOidcUser.java index b62cbc17c0..811171ec8c 100644 --- a/openbas-api/src/main/java/io/openbas/config/OpenBASOidcUser.java +++ b/openbas-api/src/main/java/io/openbas/config/OpenBASOidcUser.java @@ -1,6 +1,10 @@ package io.openbas.config; +import static io.openbas.database.model.User.ROLE_ADMIN; +import static io.openbas.database.model.User.ROLE_USER; + import io.openbas.database.model.User; +import java.util.*; import org.jetbrains.annotations.NotNull; import org.springframework.security.core.GrantedAuthority; import org.springframework.security.core.authority.SimpleGrantedAuthority; @@ -8,11 +12,6 @@ import org.springframework.security.oauth2.core.oidc.OidcUserInfo; import org.springframework.security.oauth2.core.oidc.user.OidcUser; -import java.util.*; - -import static io.openbas.database.model.User.ROLE_ADMIN; -import static io.openbas.database.model.User.ROLE_USER; - public class OpenBASOidcUser implements OpenBASPrincipal, OidcUser { private final User user; @@ -74,5 +73,4 @@ public Collection getAuthorities() { public String getName() { return user.getFirstname() + " " + user.getLastname(); } - } diff --git a/openbas-api/src/main/java/io/openbas/config/OpenBASPrincipal.java b/openbas-api/src/main/java/io/openbas/config/OpenBASPrincipal.java index fe0c4675cd..bcf6f20498 100644 --- a/openbas-api/src/main/java/io/openbas/config/OpenBASPrincipal.java +++ b/openbas-api/src/main/java/io/openbas/config/OpenBASPrincipal.java @@ -1,8 +1,7 @@ package io.openbas.config; -import org.springframework.security.core.GrantedAuthority; - import java.util.Collection; +import org.springframework.security.core.GrantedAuthority; public interface OpenBASPrincipal { diff --git a/openbas-api/src/main/java/io/openbas/config/OpenBASSaml2AuthenticationRequestRepository.java b/openbas-api/src/main/java/io/openbas/config/OpenBASSaml2AuthenticationRequestRepository.java index c65e552ecf..ba183f70f9 100644 --- a/openbas-api/src/main/java/io/openbas/config/OpenBASSaml2AuthenticationRequestRepository.java +++ b/openbas-api/src/main/java/io/openbas/config/OpenBASSaml2AuthenticationRequestRepository.java @@ -3,79 +3,82 @@ import jakarta.servlet.http.HttpServletRequest; import jakarta.servlet.http.HttpServletResponse; import jakarta.servlet.http.HttpSession; +import java.util.HashMap; +import java.util.Iterator; +import java.util.Map; import org.springframework.security.saml2.provider.service.authentication.AbstractSaml2AuthenticationRequest; import org.springframework.security.saml2.provider.service.web.HttpSessionSaml2AuthenticationRequestRepository; import org.springframework.security.saml2.provider.service.web.Saml2AuthenticationRequestRepository; import org.springframework.stereotype.Component; import org.springframework.stereotype.Repository; -import java.util.HashMap; -import java.util.Iterator; -import java.util.Map; - /** - * This class is heavily based on - * HttpSessionSaml2AuthenticationRequestRepository.java - * The only difference is in saveAuthenticationRequest where we recreate an HttpSession and copy the attributes - * from the previous one. This is to prevent an issue where the session would be recreated during the callback - * after the authentication. To fix this issue, we recreate a new session during the save of the request and copy - * the attributes to the new session. - * FIXME : Check if we can remove this custom class when we switch to a more modern saml library - * + * This class is heavily based on HttpSessionSaml2AuthenticationRequestRepository.java + * The only difference is in saveAuthenticationRequest where we recreate an HttpSession and copy the + * attributes from the previous one. This is to prevent an issue where the session would be + * recreated during the callback after the authentication. To fix this issue, we recreate a new + * session during the save of the request and copy the attributes to the new session. FIXME : Check + * if we can remove this custom class when we switch to a more modern saml library */ @Component @Repository -public class OpenBASSaml2AuthenticationRequestRepository implements Saml2AuthenticationRequestRepository { +public class OpenBASSaml2AuthenticationRequestRepository + implements Saml2AuthenticationRequestRepository { - private static final String DEFAULT_SAML2_AUTHN_REQUEST_ATTR_NAME = HttpSessionSaml2AuthenticationRequestRepository.class - .getName() - .concat(".SAML2_AUTHN_REQUEST"); + private static final String DEFAULT_SAML2_AUTHN_REQUEST_ATTR_NAME = + HttpSessionSaml2AuthenticationRequestRepository.class + .getName() + .concat(".SAML2_AUTHN_REQUEST"); - private final String saml2AuthnRequestAttributeName = DEFAULT_SAML2_AUTHN_REQUEST_ATTR_NAME; + private final String saml2AuthnRequestAttributeName = DEFAULT_SAML2_AUTHN_REQUEST_ATTR_NAME; - @Override - public AbstractSaml2AuthenticationRequest loadAuthenticationRequest(HttpServletRequest request) { - HttpSession httpSession = request.getSession(false); - if (httpSession == null) { - return null; - } - return (AbstractSaml2AuthenticationRequest) httpSession.getAttribute(this.saml2AuthnRequestAttributeName); + @Override + public AbstractSaml2AuthenticationRequest loadAuthenticationRequest(HttpServletRequest request) { + HttpSession httpSession = request.getSession(false); + if (httpSession == null) { + return null; } + return (AbstractSaml2AuthenticationRequest) + httpSession.getAttribute(this.saml2AuthnRequestAttributeName); + } - @Override - public void saveAuthenticationRequest(AbstractSaml2AuthenticationRequest authenticationRequest, - HttpServletRequest request, HttpServletResponse response) { - if (authenticationRequest == null) { - removeAuthenticationRequest(request, response); - return; - } - // Get the session - HttpSession httpSession = request.getSession(); - Map attributes = new HashMap<>(); - Iterator attributeIterator = httpSession.getAttributeNames().asIterator(); - // Copy the attributes to a new list - while (attributeIterator.hasNext()) { - String param = attributeIterator.next(); - attributes.put(param, httpSession.getAttribute(param)); - } - // Invalidate the previous session to have a fresh one for the login - httpSession.invalidate(); - HttpSession newSession = request.getSession(true); - // Set the former attributes into the new session - attributes.forEach(newSession::setAttribute); - // Save the request into the new session for ulterior validation - newSession.setAttribute(this.saml2AuthnRequestAttributeName, authenticationRequest); + @Override + public void saveAuthenticationRequest( + AbstractSaml2AuthenticationRequest authenticationRequest, + HttpServletRequest request, + HttpServletResponse response) { + if (authenticationRequest == null) { + removeAuthenticationRequest(request, response); + return; + } + // Get the session + HttpSession httpSession = request.getSession(); + Map attributes = new HashMap<>(); + Iterator attributeIterator = httpSession.getAttributeNames().asIterator(); + // Copy the attributes to a new list + while (attributeIterator.hasNext()) { + String param = attributeIterator.next(); + attributes.put(param, httpSession.getAttribute(param)); } + // Invalidate the previous session to have a fresh one for the login + httpSession.invalidate(); + HttpSession newSession = request.getSession(true); + // Set the former attributes into the new session + attributes.forEach(newSession::setAttribute); + // Save the request into the new session for ulterior validation + newSession.setAttribute(this.saml2AuthnRequestAttributeName, authenticationRequest); + } - @Override - public AbstractSaml2AuthenticationRequest removeAuthenticationRequest(HttpServletRequest request, - HttpServletResponse response) { - AbstractSaml2AuthenticationRequest authenticationRequest = loadAuthenticationRequest(request); - if (authenticationRequest == null) { - return null; - } - HttpSession httpSession = request.getSession(); - httpSession.removeAttribute(this.saml2AuthnRequestAttributeName); - return authenticationRequest; + @Override + public AbstractSaml2AuthenticationRequest removeAuthenticationRequest( + HttpServletRequest request, HttpServletResponse response) { + AbstractSaml2AuthenticationRequest authenticationRequest = loadAuthenticationRequest(request); + if (authenticationRequest == null) { + return null; } + HttpSession httpSession = request.getSession(); + httpSession.removeAttribute(this.saml2AuthnRequestAttributeName); + return authenticationRequest; + } } diff --git a/openbas-api/src/main/java/io/openbas/config/OpenBASSaml2User.java b/openbas-api/src/main/java/io/openbas/config/OpenBASSaml2User.java index d014cf3d8e..f54de79295 100644 --- a/openbas-api/src/main/java/io/openbas/config/OpenBASSaml2User.java +++ b/openbas-api/src/main/java/io/openbas/config/OpenBASSaml2User.java @@ -1,22 +1,20 @@ package io.openbas.config; import io.openbas.database.model.User; +import java.util.Collection; +import java.util.List; import org.jetbrains.annotations.NotNull; import org.springframework.security.core.GrantedAuthority; import org.springframework.security.core.authority.SimpleGrantedAuthority; import org.springframework.security.saml2.provider.service.authentication.Saml2AuthenticatedPrincipal; -import java.util.Collection; -import java.util.List; - public class OpenBASSaml2User implements OpenBASPrincipal, Saml2AuthenticatedPrincipal { private final User user; private final List roles; public OpenBASSaml2User( - @NotNull final User user, - @NotNull final List roles) { + @NotNull final User user, @NotNull final List roles) { this.user = user; this.roles = roles; } @@ -45,5 +43,4 @@ public boolean isAdmin() { public String getLang() { return user.getLang(); } - } diff --git a/openbas-api/src/main/java/io/openbas/config/SessionHelper.java b/openbas-api/src/main/java/io/openbas/config/SessionHelper.java index ad67292753..81a11943f5 100644 --- a/openbas-api/src/main/java/io/openbas/config/SessionHelper.java +++ b/openbas-api/src/main/java/io/openbas/config/SessionHelper.java @@ -4,7 +4,7 @@ public class SessionHelper { - public final static String ANONYMOUS_USER = "anonymousUser"; + public static final String ANONYMOUS_USER = "anonymousUser"; public static OpenBASPrincipal currentUser() { Object principal = SecurityContextHolder.getContext().getAuthentication().getPrincipal(); diff --git a/openbas-api/src/main/java/io/openbas/config/SessionManager.java b/openbas-api/src/main/java/io/openbas/config/SessionManager.java index ed2d5ce96c..fe799cbc49 100644 --- a/openbas-api/src/main/java/io/openbas/config/SessionManager.java +++ b/openbas-api/src/main/java/io/openbas/config/SessionManager.java @@ -67,36 +67,45 @@ private Optional extractPrincipal(HttpSession httpSession) { } private Stream getUserSessions(String userId) { - return sessions.values().stream().filter(httpSession -> { - try { - Optional extractPrincipal = extractPrincipal(httpSession); - return extractPrincipal.map(user -> user.getId().equals(userId)).orElse(false); - } catch (IllegalStateException e) { - return false; - } - }); + return sessions.values().stream() + .filter( + httpSession -> { + try { + Optional extractPrincipal = extractPrincipal(httpSession); + return extractPrincipal.map(user -> user.getId().equals(userId)).orElse(false); + } catch (IllegalStateException e) { + return false; + } + }); } public void refreshUserSessions(User databaseUser) { - getUserSessions(databaseUser.getId()).forEach(httpSession -> { - Optional context = extractSecurityContext(httpSession); - Optional auth = extractAuthentication(httpSession); - OpenBASPrincipal user = extractPrincipal(httpSession).orElseThrow(); - if (context.isPresent() && auth.isPresent()) { - Authentication authentication = auth.get(); - SecurityContext securityContext = context.get(); - if (authentication instanceof OAuth2AuthenticationToken oauth) { - OAuth2User oAuth2User = (OAuth2User) user; - Authentication newAuth = new OAuth2AuthenticationToken( - oAuth2User, oAuth2User.getAuthorities(), oauth.getAuthorizedClientRegistrationId()); - securityContext.setAuthentication(newAuth); - } else if (authentication instanceof PreAuthenticatedAuthenticationToken) { - Authentication newAuth = new PreAuthenticatedAuthenticationToken(user, databaseUser.getPassword(), user.getAuthorities()); - securityContext.setAuthentication(newAuth); - } - // TODO ADD SAML2 - } - }); + getUserSessions(databaseUser.getId()) + .forEach( + httpSession -> { + Optional context = extractSecurityContext(httpSession); + Optional auth = extractAuthentication(httpSession); + OpenBASPrincipal user = extractPrincipal(httpSession).orElseThrow(); + if (context.isPresent() && auth.isPresent()) { + Authentication authentication = auth.get(); + SecurityContext securityContext = context.get(); + if (authentication instanceof OAuth2AuthenticationToken oauth) { + OAuth2User oAuth2User = (OAuth2User) user; + Authentication newAuth = + new OAuth2AuthenticationToken( + oAuth2User, + oAuth2User.getAuthorities(), + oauth.getAuthorizedClientRegistrationId()); + securityContext.setAuthentication(newAuth); + } else if (authentication instanceof PreAuthenticatedAuthenticationToken) { + Authentication newAuth = + new PreAuthenticatedAuthenticationToken( + user, databaseUser.getPassword(), user.getAuthorities()); + securityContext.setAuthentication(newAuth); + } + // TODO ADD SAML2 + } + }); } public void invalidateUserSession(String userId) { diff --git a/openbas-api/src/main/java/io/openbas/config/ThreadPoolTaskSchedulerConfig.java b/openbas-api/src/main/java/io/openbas/config/ThreadPoolTaskSchedulerConfig.java index 638c38a47e..e09a795058 100644 --- a/openbas-api/src/main/java/io/openbas/config/ThreadPoolTaskSchedulerConfig.java +++ b/openbas-api/src/main/java/io/openbas/config/ThreadPoolTaskSchedulerConfig.java @@ -7,13 +7,11 @@ @Configuration public class ThreadPoolTaskSchedulerConfig { - @Bean - public ThreadPoolTaskScheduler threadPoolTaskScheduler(){ - ThreadPoolTaskScheduler threadPoolTaskScheduler - = new ThreadPoolTaskScheduler(); - threadPoolTaskScheduler.setPoolSize(20); - threadPoolTaskScheduler.setThreadNamePrefix( - "ThreadPoolTaskScheduler"); - return threadPoolTaskScheduler; - } + @Bean + public ThreadPoolTaskScheduler threadPoolTaskScheduler() { + ThreadPoolTaskScheduler threadPoolTaskScheduler = new ThreadPoolTaskScheduler(); + threadPoolTaskScheduler.setPoolSize(20); + threadPoolTaskScheduler.setThreadNamePrefix("ThreadPoolTaskScheduler"); + return threadPoolTaskScheduler; + } } diff --git a/openbas-api/src/main/java/io/openbas/executors/caldera/CalderaExecutor.java b/openbas-api/src/main/java/io/openbas/executors/caldera/CalderaExecutor.java index a119e5c113..296536ac72 100644 --- a/openbas-api/src/main/java/io/openbas/executors/caldera/CalderaExecutor.java +++ b/openbas-api/src/main/java/io/openbas/executors/caldera/CalderaExecutor.java @@ -9,33 +9,37 @@ import io.openbas.integrations.InjectorService; import io.openbas.service.PlatformSettingsService; import jakarta.annotation.PostConstruct; +import java.time.Duration; import lombok.RequiredArgsConstructor; import org.springframework.scheduling.concurrent.ThreadPoolTaskScheduler; import org.springframework.stereotype.Service; -import java.time.Duration; - @RequiredArgsConstructor @Service public class CalderaExecutor { - private final CalderaExecutorConfig config; - private final ThreadPoolTaskScheduler taskScheduler; - private final CalderaExecutorClient client; - private final EndpointService endpointService; - private final CalderaExecutorContextService calderaExecutorContextService; - private final ExecutorService executorService; - private final InjectorService injectorService; - private final PlatformSettingsService platformSettingsService; + private final CalderaExecutorConfig config; + private final ThreadPoolTaskScheduler taskScheduler; + private final CalderaExecutorClient client; + private final EndpointService endpointService; + private final CalderaExecutorContextService calderaExecutorContextService; + private final ExecutorService executorService; + private final InjectorService injectorService; + private final PlatformSettingsService platformSettingsService; - @PostConstruct - public void init() { - CalderaExecutorService service = new CalderaExecutorService( - this.executorService, this.client, this.config, this.calderaExecutorContextService, - this.endpointService, this.injectorService, this.platformSettingsService - ); - if (this.config.isEnable()) { - this.taskScheduler.scheduleAtFixedRate(service, Duration.ofSeconds(60)); - } + @PostConstruct + public void init() { + CalderaExecutorService service = + new CalderaExecutorService( + this.executorService, + this.client, + this.config, + this.calderaExecutorContextService, + this.endpointService, + this.injectorService, + this.platformSettingsService); + if (this.config.isEnable()) { + this.taskScheduler.scheduleAtFixedRate(service, Duration.ofSeconds(60)); } + } } diff --git a/openbas-api/src/main/java/io/openbas/executors/caldera/service/CalderaExecutorService.java b/openbas-api/src/main/java/io/openbas/executors/caldera/service/CalderaExecutorService.java index abcc4b881c..24dcd57374 100644 --- a/openbas-api/src/main/java/io/openbas/executors/caldera/service/CalderaExecutorService.java +++ b/openbas-api/src/main/java/io/openbas/executors/caldera/service/CalderaExecutorService.java @@ -1,5 +1,8 @@ package io.openbas.executors.caldera.service; +import static java.time.Instant.now; +import static java.time.ZoneOffset.UTC; + import io.openbas.asset.EndpointService; import io.openbas.database.model.*; import io.openbas.executors.caldera.client.CalderaExecutorClient; @@ -10,11 +13,6 @@ import io.openbas.service.PlatformSettingsService; import jakarta.validation.constraints.NotBlank; import jakarta.validation.constraints.NotNull; -import lombok.extern.java.Log; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty; -import org.springframework.stereotype.Service; - import java.time.Instant; import java.time.LocalDateTime; import java.time.ZonedDateTime; @@ -24,169 +22,203 @@ import java.util.Locale; import java.util.Optional; import java.util.logging.Level; - -import static java.time.Instant.now; -import static java.time.ZoneOffset.UTC; +import lombok.extern.java.Log; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Service; @Log @Service public class CalderaExecutorService implements Runnable { - private static final int CLEAR_TTL = 1800000; // 30 minutes - private static final int DELETE_TTL = 86400000; // 24 hours - private static final String CALDERA_EXECUTOR_TYPE = "openbas_caldera"; - private static final String CALDERA_EXECUTOR_NAME = "Caldera"; - - private final CalderaExecutorClient client; - - private final EndpointService endpointService; - - private final CalderaExecutorContextService calderaExecutorContextService; - - private final InjectorService injectorService; - private final PlatformSettingsService platformSettingsService; - - private Executor executor = null; - - public static Endpoint.PLATFORM_TYPE toPlatform(@NotBlank final String platform) { - return switch (platform) { - case "linux" -> Endpoint.PLATFORM_TYPE.Linux; - case "windows" -> Endpoint.PLATFORM_TYPE.Windows; - case "darwin" -> Endpoint.PLATFORM_TYPE.MacOS; - default -> throw new IllegalArgumentException("This platform is not supported : " + platform); - }; - } - - public static Endpoint.PLATFORM_ARCH toArch(@NotBlank final String arch) { - return switch (arch) { - case "amd64" -> Endpoint.PLATFORM_ARCH.x86_64; - case "arm64" -> Endpoint.PLATFORM_ARCH.arm64; - default -> throw new IllegalArgumentException("This arch is not supported : " + arch); - }; + private static final int CLEAR_TTL = 1800000; // 30 minutes + private static final int DELETE_TTL = 86400000; // 24 hours + private static final String CALDERA_EXECUTOR_TYPE = "openbas_caldera"; + private static final String CALDERA_EXECUTOR_NAME = "Caldera"; + + private final CalderaExecutorClient client; + + private final EndpointService endpointService; + + private final CalderaExecutorContextService calderaExecutorContextService; + + private final InjectorService injectorService; + private final PlatformSettingsService platformSettingsService; + + private Executor executor = null; + + public static Endpoint.PLATFORM_TYPE toPlatform(@NotBlank final String platform) { + return switch (platform) { + case "linux" -> Endpoint.PLATFORM_TYPE.Linux; + case "windows" -> Endpoint.PLATFORM_TYPE.Windows; + case "darwin" -> Endpoint.PLATFORM_TYPE.MacOS; + default -> throw new IllegalArgumentException("This platform is not supported : " + platform); + }; + } + + public static Endpoint.PLATFORM_ARCH toArch(@NotBlank final String arch) { + return switch (arch) { + case "amd64" -> Endpoint.PLATFORM_ARCH.x86_64; + case "arm64" -> Endpoint.PLATFORM_ARCH.arm64; + default -> throw new IllegalArgumentException("This arch is not supported : " + arch); + }; + } + + @Autowired + public CalderaExecutorService( + ExecutorService executorService, + CalderaExecutorClient client, + CalderaExecutorConfig config, + CalderaExecutorContextService calderaExecutorContextService, + EndpointService endpointService, + InjectorService injectorService, + PlatformSettingsService platformSettingsService) { + this.client = client; + this.endpointService = endpointService; + this.calderaExecutorContextService = calderaExecutorContextService; + this.injectorService = injectorService; + this.platformSettingsService = platformSettingsService; + try { + if (config.isEnable()) { + this.executor = + executorService.register( + config.getId(), + CALDERA_EXECUTOR_TYPE, + CALDERA_EXECUTOR_NAME, + getClass().getResourceAsStream("/img/icon-caldera.png"), + new String[] { + Endpoint.PLATFORM_TYPE.Windows.name(), + Endpoint.PLATFORM_TYPE.Linux.name(), + Endpoint.PLATFORM_TYPE.MacOS.name() + }); + this.calderaExecutorContextService.registerAbilities(); + } else { + this.platformSettingsService.cleanMessage(BannerMessage.BANNER_KEYS.CALDERA_UNAVAILABLE); + executorService.removeFromType(CALDERA_EXECUTOR_TYPE); + } + } catch (Exception e) { + log.log(Level.SEVERE, "Error creating caldera executor: " + e); } - - @Autowired - public CalderaExecutorService( - ExecutorService executorService, - CalderaExecutorClient client, - CalderaExecutorConfig config, - CalderaExecutorContextService calderaExecutorContextService, - EndpointService endpointService, - InjectorService injectorService, - PlatformSettingsService platformSettingsService) { - this.client = client; - this.endpointService = endpointService; - this.calderaExecutorContextService = calderaExecutorContextService; - this.injectorService = injectorService; - this.platformSettingsService = platformSettingsService; - try { - if (config.isEnable()) { - this.executor = executorService.register(config.getId(), CALDERA_EXECUTOR_TYPE, CALDERA_EXECUTOR_NAME, getClass().getResourceAsStream("/img/icon-caldera.png"), new String[]{Endpoint.PLATFORM_TYPE.Windows.name(), Endpoint.PLATFORM_TYPE.Linux.name(), Endpoint.PLATFORM_TYPE.MacOS.name()}); - this.calderaExecutorContextService.registerAbilities(); + } + + @Override + public void run() { + try { + log.info("Running Caldera executor endpoints gathering..."); + // The executor only retrieve "main" agents (without the keyword "executor") + // This is NOT a standard behaviour, this is because we are using Caldera as an executor and + // we should not + // Will be replaced by the XTM agent + List agents = + this.client.agents().stream() + .filter(agent -> !agent.getExe_name().contains("implant")) + .toList(); + List endpoints = toEndpoint(agents).stream().filter(Asset::getActive).toList(); + log.info("Caldera executor provisioning based on " + endpoints.size() + " assets"); + endpoints.forEach( + endpoint -> { + List existingEndpoints = + this.endpointService + .findAssetsForInjectionByHostname(endpoint.getHostname()) + .stream() + .filter( + endpoint1 -> + Arrays.stream(endpoint1.getIps()) + .anyMatch( + s -> Arrays.stream(endpoint.getIps()).toList().contains(s))) + .toList(); + if (existingEndpoints.isEmpty()) { + Optional endpointByExternalReference = + endpointService.findByExternalReference(endpoint.getExternalReference()); + if (endpointByExternalReference.isPresent()) { + this.updateEndpoint(endpoint, List.of(endpointByExternalReference.get())); + } else { + this.endpointService.createEndpoint(endpoint); + } } else { - this.platformSettingsService.cleanMessage(BannerMessage.BANNER_KEYS.CALDERA_UNAVAILABLE); - executorService.removeFromType(CALDERA_EXECUTOR_TYPE); + this.updateEndpoint(endpoint, existingEndpoints); } - } catch (Exception e) { - log.log(Level.SEVERE, "Error creating caldera executor: " + e); - } - } - - @Override - public void run() { - try { - log.info("Running Caldera executor endpoints gathering..."); - // The executor only retrieve "main" agents (without the keyword "executor") - // This is NOT a standard behaviour, this is because we are using Caldera as an executor and we should not - // Will be replaced by the XTM agent - List agents = this.client.agents().stream().filter(agent -> !agent.getExe_name().contains("implant")).toList(); - List endpoints = toEndpoint(agents).stream().filter(Asset::getActive).toList(); - log.info("Caldera executor provisioning based on " + endpoints.size() + " assets"); - endpoints.forEach(endpoint -> { - List existingEndpoints = this.endpointService.findAssetsForInjectionByHostname(endpoint.getHostname()).stream().filter(endpoint1 -> Arrays.stream(endpoint1.getIps()).anyMatch(s -> Arrays.stream(endpoint.getIps()).toList().contains(s))).toList(); - if (existingEndpoints.isEmpty()) { - Optional endpointByExternalReference = endpointService.findByExternalReference(endpoint.getExternalReference()); - if (endpointByExternalReference.isPresent()) { - this.updateEndpoint(endpoint, List.of(endpointByExternalReference.get())); - } else { - this.endpointService.createEndpoint(endpoint); - } - } else { - this.updateEndpoint(endpoint, existingEndpoints); - } - }); - List inactiveEndpoints = toEndpoint(agents).stream().filter(endpoint -> !endpoint.getActive()).toList(); - inactiveEndpoints.forEach(endpoint -> { - Optional optionalExistingEndpoint = this.endpointService.findByExternalReference(endpoint.getExternalReference()); - if (optionalExistingEndpoint.isPresent()) { - Endpoint existingEndpoint = optionalExistingEndpoint.get(); - if ((now().toEpochMilli() - existingEndpoint.getClearedAt().toEpochMilli()) > DELETE_TTL) { - log.info("Found stale agent " + existingEndpoint.getName() + ", deleting it..."); - this.client.deleteAgent(existingEndpoint); - this.endpointService.deleteEndpoint(existingEndpoint.getId()); - } - } - }); - this.platformSettingsService.cleanMessage(BannerMessage.BANNER_KEYS.CALDERA_UNAVAILABLE); - } catch (Exception e) { - this.platformSettingsService.errorMessage(BannerMessage.BANNER_KEYS.CALDERA_UNAVAILABLE); - } - } - - // -- PRIVATE -- - - private List toEndpoint(@NotNull final List agents) { - return agents.stream() - .map((agent) -> { - Endpoint endpoint = new Endpoint(); - endpoint.setExecutor(this.executor); - endpoint.setExternalReference(agent.getPaw()); - endpoint.setName(agent.getHost()); - endpoint.setDescription("Asset collected by Caldera executor context."); - endpoint.setIps(agent.getHost_ip_addrs()); - endpoint.setHostname(agent.getHost()); - endpoint.setPlatform(toPlatform(agent.getPlatform())); - endpoint.setArch(toArch(agent.getArchitecture())); - endpoint.setProcessName(agent.getExe_name()); - endpoint.setLastSeen(toInstant(agent.getLast_seen())); - return endpoint; - }) - .toList(); - } - - private void updateEndpoint(@NotNull final Endpoint external, @NotNull final List existingList) { - Endpoint matchingExistingEndpoint = existingList.getFirst(); - matchingExistingEndpoint.setLastSeen(external.getLastSeen()); - matchingExistingEndpoint.setExternalReference(external.getExternalReference()); - matchingExistingEndpoint.setName(external.getName()); - matchingExistingEndpoint.setIps(external.getIps()); - matchingExistingEndpoint.setHostname(external.getHostname()); - matchingExistingEndpoint.setProcessName(external.getProcessName()); - matchingExistingEndpoint.setPlatform(external.getPlatform()); - matchingExistingEndpoint.setArch(external.getArch()); - matchingExistingEndpoint.setExecutor(this.executor); - if ((now().toEpochMilli() - matchingExistingEndpoint.getClearedAt().toEpochMilli()) > CLEAR_TTL) { - try { - log.info("Clearing endpoint " + matchingExistingEndpoint.getHostname()); - Iterable injectors = injectorService.injectors(); - injectors.forEach(injector -> { - if (injector.getExecutorClearCommands() != null) { - this.calderaExecutorContextService.launchExecutorClear(injector, matchingExistingEndpoint); - } - }); - matchingExistingEndpoint.setClearedAt(now()); - } catch (RuntimeException e) { - log.info("Failed clear agents"); + }); + List inactiveEndpoints = + toEndpoint(agents).stream().filter(endpoint -> !endpoint.getActive()).toList(); + inactiveEndpoints.forEach( + endpoint -> { + Optional optionalExistingEndpoint = + this.endpointService.findByExternalReference(endpoint.getExternalReference()); + if (optionalExistingEndpoint.isPresent()) { + Endpoint existingEndpoint = optionalExistingEndpoint.get(); + if ((now().toEpochMilli() - existingEndpoint.getClearedAt().toEpochMilli()) + > DELETE_TTL) { + log.info("Found stale agent " + existingEndpoint.getName() + ", deleting it..."); + this.client.deleteAgent(existingEndpoint); + this.endpointService.deleteEndpoint(existingEndpoint.getId()); + } } - } - this.endpointService.updateEndpoint(matchingExistingEndpoint); + }); + this.platformSettingsService.cleanMessage(BannerMessage.BANNER_KEYS.CALDERA_UNAVAILABLE); + } catch (Exception e) { + this.platformSettingsService.errorMessage(BannerMessage.BANNER_KEYS.CALDERA_UNAVAILABLE); } - - private Instant toInstant(@NotNull final String lastSeen) { - String pattern = "yyyy-MM-dd'T'HH:mm:ss'Z'"; - DateTimeFormatter dateTimeFormatter = DateTimeFormatter.ofPattern(pattern, Locale.getDefault()); - LocalDateTime localDateTime = LocalDateTime.parse(lastSeen, dateTimeFormatter); - ZonedDateTime zonedDateTime = localDateTime.atZone(UTC); - return zonedDateTime.toInstant(); + } + + // -- PRIVATE -- + + private List toEndpoint(@NotNull final List agents) { + return agents.stream() + .map( + (agent) -> { + Endpoint endpoint = new Endpoint(); + endpoint.setExecutor(this.executor); + endpoint.setExternalReference(agent.getPaw()); + endpoint.setName(agent.getHost()); + endpoint.setDescription("Asset collected by Caldera executor context."); + endpoint.setIps(agent.getHost_ip_addrs()); + endpoint.setHostname(agent.getHost()); + endpoint.setPlatform(toPlatform(agent.getPlatform())); + endpoint.setArch(toArch(agent.getArchitecture())); + endpoint.setProcessName(agent.getExe_name()); + endpoint.setLastSeen(toInstant(agent.getLast_seen())); + return endpoint; + }) + .toList(); + } + + private void updateEndpoint( + @NotNull final Endpoint external, @NotNull final List existingList) { + Endpoint matchingExistingEndpoint = existingList.getFirst(); + matchingExistingEndpoint.setLastSeen(external.getLastSeen()); + matchingExistingEndpoint.setExternalReference(external.getExternalReference()); + matchingExistingEndpoint.setName(external.getName()); + matchingExistingEndpoint.setIps(external.getIps()); + matchingExistingEndpoint.setHostname(external.getHostname()); + matchingExistingEndpoint.setProcessName(external.getProcessName()); + matchingExistingEndpoint.setPlatform(external.getPlatform()); + matchingExistingEndpoint.setArch(external.getArch()); + matchingExistingEndpoint.setExecutor(this.executor); + if ((now().toEpochMilli() - matchingExistingEndpoint.getClearedAt().toEpochMilli()) + > CLEAR_TTL) { + try { + log.info("Clearing endpoint " + matchingExistingEndpoint.getHostname()); + Iterable injectors = injectorService.injectors(); + injectors.forEach( + injector -> { + if (injector.getExecutorClearCommands() != null) { + this.calderaExecutorContextService.launchExecutorClear( + injector, matchingExistingEndpoint); + } + }); + matchingExistingEndpoint.setClearedAt(now()); + } catch (RuntimeException e) { + log.info("Failed clear agents"); + } } + this.endpointService.updateEndpoint(matchingExistingEndpoint); + } + + private Instant toInstant(@NotNull final String lastSeen) { + String pattern = "yyyy-MM-dd'T'HH:mm:ss'Z'"; + DateTimeFormatter dateTimeFormatter = DateTimeFormatter.ofPattern(pattern, Locale.getDefault()); + LocalDateTime localDateTime = LocalDateTime.parse(lastSeen, dateTimeFormatter); + ZonedDateTime zonedDateTime = localDateTime.atZone(UTC); + return zonedDateTime.toInstant(); + } } diff --git a/openbas-api/src/main/java/io/openbas/expectation/ExpectationStatus.java b/openbas-api/src/main/java/io/openbas/expectation/ExpectationStatus.java index 808e458a81..1c460a6bfa 100644 --- a/openbas-api/src/main/java/io/openbas/expectation/ExpectationStatus.java +++ b/openbas-api/src/main/java/io/openbas/expectation/ExpectationStatus.java @@ -1,3 +1 @@ package io.openbas.expectation; - - diff --git a/openbas-api/src/main/java/io/openbas/expectation/ExpectationType.java b/openbas-api/src/main/java/io/openbas/expectation/ExpectationType.java index 727afe11b4..51cd247efc 100644 --- a/openbas-api/src/main/java/io/openbas/expectation/ExpectationType.java +++ b/openbas-api/src/main/java/io/openbas/expectation/ExpectationType.java @@ -15,7 +15,8 @@ public enum ExpectationType { public static final String PARTIAL_ID = "PARTIAL"; public static final String FAILED_ID = "FAILED"; - ExpectationType(String successLabel, String pendingLabel, String partialLabel, String failureLabel) { + ExpectationType( + String successLabel, String pendingLabel, String partialLabel, String failureLabel) { this.successLabel = successLabel; this.pendingLabel = pendingLabel; this.partialLabel = partialLabel; @@ -32,5 +33,4 @@ public static ExpectationType of(String value) { return valueOf(value); } } - } diff --git a/openbas-api/src/main/java/io/openbas/helper/DatabaseHelper.java b/openbas-api/src/main/java/io/openbas/helper/DatabaseHelper.java index 503a45ab28..0f46006f53 100644 --- a/openbas-api/src/main/java/io/openbas/helper/DatabaseHelper.java +++ b/openbas-api/src/main/java/io/openbas/helper/DatabaseHelper.java @@ -1,38 +1,40 @@ package io.openbas.helper; +import static java.util.Optional.ofNullable; +import static org.springframework.util.StringUtils.hasLength; + import io.openbas.database.model.Base; import io.openbas.rest.exception.ElementNotFoundException; -import org.springframework.data.repository.CrudRepository; - import java.util.Optional; - -import static java.util.Optional.ofNullable; -import static org.springframework.util.StringUtils.hasLength; +import org.springframework.data.repository.CrudRepository; public class DatabaseHelper { - public static T updateRelation(String inputRelationId, Base current, CrudRepository repository) { - if (hasLength(inputRelationId)) { - String currentGroupId = ofNullable(current).map(Base::getId).orElse(null); - if (!inputRelationId.equals(currentGroupId)) { - Optional existingEntity = repository.findById(inputRelationId); - return existingEntity.orElse(null); - } - // noinspection unchecked - return (T) current; - } - return null; + public static T updateRelation( + String inputRelationId, Base current, CrudRepository repository) { + if (hasLength(inputRelationId)) { + String currentGroupId = ofNullable(current).map(Base::getId).orElse(null); + if (!inputRelationId.equals(currentGroupId)) { + Optional existingEntity = repository.findById(inputRelationId); + return existingEntity.orElse(null); + } + // noinspection unchecked + return (T) current; } + return null; + } - public static T resolveOptionalRelation(String inputRelationId, CrudRepository repository) { - if (hasLength(inputRelationId)) { - Optional existingEntity = repository.findById(inputRelationId); - return existingEntity.orElse(null); - } - return null; + public static T resolveOptionalRelation( + String inputRelationId, CrudRepository repository) { + if (hasLength(inputRelationId)) { + Optional existingEntity = repository.findById(inputRelationId); + return existingEntity.orElse(null); } + return null; + } - public static T resolveRelation(String inputRelationId, CrudRepository repository) { - return repository.findById(inputRelationId).orElseThrow(ElementNotFoundException::new); - } + public static T resolveRelation( + String inputRelationId, CrudRepository repository) { + return repository.findById(inputRelationId).orElseThrow(ElementNotFoundException::new); + } } diff --git a/openbas-api/src/main/java/io/openbas/helper/InjectHelper.java b/openbas-api/src/main/java/io/openbas/helper/InjectHelper.java index eb6e8679df..8ab96e2408 100644 --- a/openbas-api/src/main/java/io/openbas/helper/InjectHelper.java +++ b/openbas-api/src/main/java/io/openbas/helper/InjectHelper.java @@ -1,5 +1,8 @@ package io.openbas.helper; +import static java.util.stream.Collectors.groupingBy; +import static java.util.stream.Stream.concat; + import com.fasterxml.jackson.databind.ObjectMapper; import io.openbas.database.model.*; import io.openbas.database.repository.DryInjectRepository; @@ -11,6 +14,10 @@ import io.openbas.execution.ExecutionContextService; import jakarta.annotation.Resource; import jakarta.validation.constraints.NotNull; +import java.time.Instant; +import java.util.List; +import java.util.stream.Collectors; +import java.util.stream.Stream; import lombok.RequiredArgsConstructor; import org.hibernate.Hibernate; import org.springframework.stereotype.Component; @@ -18,20 +25,11 @@ import reactor.util.function.Tuple2; import reactor.util.function.Tuples; -import java.time.Instant; -import java.util.List; -import java.util.stream.Collectors; -import java.util.stream.Stream; - -import static java.util.stream.Collectors.groupingBy; -import static java.util.stream.Stream.concat; - @Component @RequiredArgsConstructor public class InjectHelper { - @Resource - protected ObjectMapper mapper; + @Resource protected ObjectMapper mapper; private final InjectRepository injectRepository; private final DryInjectRepository dryInjectRepository; @@ -41,7 +39,9 @@ public class InjectHelper { private List getInjectTeams(@NotNull final Inject inject) { Exercise exercise = inject.getExercise(); - if(inject.isAllTeams()) { // In order to process expectations from players, we also need to load players into teams + if (inject + .isAllTeams()) { // In order to process expectations from players, we also need to load + // players into teams exercise.getTeams().forEach(team -> Hibernate.initialize(team.getUsers())); return exercise.getTeams(); } else { @@ -54,31 +54,41 @@ private List getInjectTeams(@NotNull final Inject inject) { private Stream> getUsersFromInjection(Injection injection) { if (injection instanceof DryInject dryInject) { - return dryInject.getRun().getUsers().stream() - .map(user -> Tuples.of(user, "Dryrun")); + return dryInject.getRun().getUsers().stream().map(user -> Tuples.of(user, "Dryrun")); } else if (injection instanceof Inject inject) { List teams = getInjectTeams(inject); // We get all the teams for this inject // But those team can be used in other exercises with different players enabled // So we need to focus on team players only enabled in the context of the current exercise - if( inject.getInject().isAtomicTesting() ) { - return teams.stream().flatMap(team -> team.getUsers().stream().map(user -> Tuples.of(user, team.getName()))); + if (inject.getInject().isAtomicTesting()) { + return teams.stream() + .flatMap(team -> team.getUsers().stream().map(user -> Tuples.of(user, team.getName()))); } - return teams.stream().flatMap(team -> - team.getExerciseTeamUsers() - .stream() - .filter(exerciseTeamUser -> exerciseTeamUser.getExercise().getId().equals(injection.getExercise().getId())) - .map(exerciseTeamUser -> Tuples.of(exerciseTeamUser.getUser(), team.getName())) - ); + return teams.stream() + .flatMap( + team -> + team.getExerciseTeamUsers().stream() + .filter( + exerciseTeamUser -> + exerciseTeamUser + .getExercise() + .getId() + .equals(injection.getExercise().getId())) + .map( + exerciseTeamUser -> + Tuples.of(exerciseTeamUser.getUser(), team.getName()))); } throw new UnsupportedOperationException("Unsupported type of Injection"); } private List usersFromInjection(Injection injection) { - return getUsersFromInjection(injection) - .collect(groupingBy(Tuple2::getT1)).entrySet().stream() - .map(entry -> this.executionContextService.executionContext(entry.getKey(), injection, - entry.getValue().stream().flatMap(ua -> Stream.of(ua.getT2())).toList())) + return getUsersFromInjection(injection).collect(groupingBy(Tuple2::getT1)).entrySet().stream() + .map( + entry -> + this.executionContextService.executionContext( + entry.getKey(), + injection, + entry.getValue().stream().flatMap(ua -> Stream.of(ua.getT2())).toList())) .toList(); } @@ -94,31 +104,62 @@ private boolean isBeforeOrEqualsNow(Injection injection) { public List getInjectsToRun() { // Get injects List injects = this.injectRepository.findAll(InjectSpecification.executable()); - Stream executableInjects = injects.stream() - .filter(this::isBeforeOrEqualsNow) - .sorted(Inject.executionComparator) - .map(inject -> { - Hibernate.initialize(inject.getTags()); - Hibernate.initialize(inject.getUser()); - return new ExecutableInject(true, false, inject, getInjectTeams(inject), inject.getAssets(), inject.getAssetGroups(), usersFromInjection(inject)); - }); + Stream executableInjects = + injects.stream() + .filter(this::isBeforeOrEqualsNow) + .sorted(Inject.executionComparator) + .map( + inject -> { + Hibernate.initialize(inject.getTags()); + Hibernate.initialize(inject.getUser()); + return new ExecutableInject( + true, + false, + inject, + getInjectTeams(inject), + inject.getAssets(), + inject.getAssetGroups(), + usersFromInjection(inject)); + }); // Get dry injects - List dryInjects = this.dryInjectRepository.findAll(DryInjectSpecification.executable()); - Stream executableDryInjects = dryInjects.stream() - .filter(this::isBeforeOrEqualsNow) - .sorted(DryInject.executionComparator) - .map(dry -> new ExecutableInject(false, false, dry, List.of(), dry.getInject().getAssets(), dry.getInject().getAssetGroups(), usersFromInjection(dry))); + List dryInjects = + this.dryInjectRepository.findAll(DryInjectSpecification.executable()); + Stream executableDryInjects = + dryInjects.stream() + .filter(this::isBeforeOrEqualsNow) + .sorted(DryInject.executionComparator) + .map( + dry -> + new ExecutableInject( + false, + false, + dry, + List.of(), + dry.getInject().getAssets(), + dry.getInject().getAssetGroups(), + usersFromInjection(dry))); // Get atomic testing injects - List atomicTests = this.injectRepository.findAll(InjectSpecification.forAtomicTesting()); - Stream executableAtomicTests = atomicTests.stream() + List atomicTests = + this.injectRepository.findAll(InjectSpecification.forAtomicTesting()); + Stream executableAtomicTests = + atomicTests.stream() .filter(this::isBeforeOrEqualsNow) .sorted(Inject.executionComparator) - .map(inject -> { - Hibernate.initialize(inject.getTags()); - Hibernate.initialize(inject.getUser()); - return new ExecutableInject(true, false, inject, getInjectTeams(inject), inject.getAssets(), inject.getAssetGroups(), usersFromInjection(inject)); - }); + .map( + inject -> { + Hibernate.initialize(inject.getTags()); + Hibernate.initialize(inject.getUser()); + return new ExecutableInject( + true, + false, + inject, + getInjectTeams(inject), + inject.getAssets(), + inject.getAssetGroups(), + usersFromInjection(inject)); + }); // Combine injects and dry - return concat(concat(executableInjects, executableDryInjects), executableAtomicTests).collect(Collectors.toList()); + return concat(concat(executableInjects, executableDryInjects), executableAtomicTests) + .collect(Collectors.toList()); } } diff --git a/openbas-api/src/main/java/io/openbas/helper/ObjectMapperHelper.java b/openbas-api/src/main/java/io/openbas/helper/ObjectMapperHelper.java index 05bbb9e980..2fc413b781 100644 --- a/openbas-api/src/main/java/io/openbas/helper/ObjectMapperHelper.java +++ b/openbas-api/src/main/java/io/openbas/helper/ObjectMapperHelper.java @@ -18,5 +18,4 @@ public static ObjectMapper openBASJsonMapper() { mapper.registerModule(new JavaTimeModule()); return mapper; } - } diff --git a/openbas-api/src/main/java/io/openbas/helper/RabbitMQHelper.java b/openbas-api/src/main/java/io/openbas/helper/RabbitMQHelper.java index 903f179699..4aa87e7841 100644 --- a/openbas-api/src/main/java/io/openbas/helper/RabbitMQHelper.java +++ b/openbas-api/src/main/java/io/openbas/helper/RabbitMQHelper.java @@ -1,6 +1,16 @@ package io.openbas.helper; import io.openbas.config.RabbitmqConfig; +import java.io.IOException; +import java.security.KeyManagementException; +import java.security.KeyStoreException; +import java.security.NoSuchAlgorithmException; +import java.security.cert.CertificateException; +import java.time.Duration; +import java.util.Collections; +import java.util.logging.Level; +import java.util.logging.Logger; +import javax.net.ssl.SSLContext; import org.apache.hc.client5.http.impl.classic.CloseableHttpClient; import org.apache.hc.client5.http.impl.classic.HttpClients; import org.apache.hc.client5.http.impl.io.BasicHttpClientConnectionManager; @@ -23,106 +33,115 @@ import org.springframework.web.client.RestClientException; import org.springframework.web.client.RestTemplate; -import javax.net.ssl.SSLContext; -import java.io.IOException; -import java.security.KeyManagementException; -import java.security.KeyStoreException; -import java.security.NoSuchAlgorithmException; -import java.security.cert.CertificateException; -import java.time.Duration; -import java.util.Collections; -import java.util.logging.Level; -import java.util.logging.Logger; - public class RabbitMQHelper { - private static final Logger LOGGER = Logger.getLogger(RabbitMQHelper.class.getName()); - - private static String rabbitMQVersion; - - /** - * Return the version of Rabbit MQ we're using - * - * @return the rabbit MQ version - */ - public static String getRabbitMQVersion(RabbitmqConfig rabbitmqConfig) { - // If we already have the version, we don't need to get it again - if (rabbitMQVersion == null) { - // Init the rabbit MQ management api overview url - String uri = "http://" - + rabbitmqConfig.getHostname() + ":" + rabbitmqConfig.getManagementPort() - + "/api/overview"; - - RestTemplate restTemplate; - try { - restTemplate = restTemplate(rabbitmqConfig); - } catch (KeyStoreException | NoSuchAlgorithmException | KeyManagementException | CertificateException | IOException e) { - LOGGER.severe(e.getMessage()); - return null; - } - - // Init the headers - HttpHeaders headers = new HttpHeaders(); - headers.setAccept(Collections.singletonList(MediaType.APPLICATION_JSON)); - headers.setBasicAuth(rabbitmqConfig.getUser(), rabbitmqConfig.getPass()); - HttpEntity entity = new HttpEntity<>("parameters", headers); - - // Make the call - ResponseEntity result; - try { - result = restTemplate.exchange(uri, HttpMethod.GET, entity, String.class); - } catch (RestClientException e) { - LOGGER.log(Level.SEVERE, e.getMessage(), e); - return null; - } - - // Init the parser to get the rabbit_mq version - BasicJsonParser jsonParser = new BasicJsonParser(); - rabbitMQVersion = (String) jsonParser.parseMap((String) result.getBody()).get("rabbitmq_version"); - } - - return rabbitMQVersion; + private static final Logger LOGGER = Logger.getLogger(RabbitMQHelper.class.getName()); + + private static String rabbitMQVersion; + + /** + * Return the version of Rabbit MQ we're using + * + * @return the rabbit MQ version + */ + public static String getRabbitMQVersion(RabbitmqConfig rabbitmqConfig) { + // If we already have the version, we don't need to get it again + if (rabbitMQVersion == null) { + // Init the rabbit MQ management api overview url + String uri = + "http://" + + rabbitmqConfig.getHostname() + + ":" + + rabbitmqConfig.getManagementPort() + + "/api/overview"; + + RestTemplate restTemplate; + try { + restTemplate = restTemplate(rabbitmqConfig); + } catch (KeyStoreException + | NoSuchAlgorithmException + | KeyManagementException + | CertificateException + | IOException e) { + LOGGER.severe(e.getMessage()); + return null; + } + + // Init the headers + HttpHeaders headers = new HttpHeaders(); + headers.setAccept(Collections.singletonList(MediaType.APPLICATION_JSON)); + headers.setBasicAuth(rabbitmqConfig.getUser(), rabbitmqConfig.getPass()); + HttpEntity entity = new HttpEntity<>("parameters", headers); + + // Make the call + ResponseEntity result; + try { + result = restTemplate.exchange(uri, HttpMethod.GET, entity, String.class); + } catch (RestClientException e) { + LOGGER.log(Level.SEVERE, e.getMessage(), e); + return null; + } + + // Init the parser to get the rabbit_mq version + BasicJsonParser jsonParser = new BasicJsonParser(); + rabbitMQVersion = + (String) jsonParser.parseMap((String) result.getBody()).get("rabbitmq_version"); } - private static RestTemplate restTemplate(RabbitmqConfig rabbitmqConfig) - throws KeyStoreException, NoSuchAlgorithmException, KeyManagementException, IOException, CertificateException { - RestTemplate restTemplate = new RestTemplateBuilder() - .setConnectTimeout(Duration.ofSeconds(2)) - .setReadTimeout(Duration.ofSeconds(2)) - .build(); - - if(rabbitmqConfig.isSsl() && rabbitmqConfig.isManagementInsecure()) { - HttpComponentsClientHttpRequestFactory requestFactoryHttp = new HttpComponentsClientHttpRequestFactory(); - - TrustStrategy acceptingTrustStrategy = (cert, authType) -> true; - SSLContext sslContext = SSLContexts.custom() - .loadTrustMaterial(null, acceptingTrustStrategy) - .build(); - SSLConnectionSocketFactory sslsf = new SSLConnectionSocketFactory(sslContext, NoopHostnameVerifier.INSTANCE); - Registry socketFactoryRegistry = RegistryBuilder. create() - .register("https", sslsf) - .register("http", new PlainConnectionSocketFactory()) - .build(); - - BasicHttpClientConnectionManager connectionManager = - new BasicHttpClientConnectionManager(socketFactoryRegistry); - CloseableHttpClient httpClient = HttpClients.custom() - .setConnectionManager(connectionManager) - .build(); - requestFactoryHttp.setHttpClient(httpClient); - restTemplate = new RestTemplate(requestFactoryHttp); - } else if (rabbitmqConfig.isSsl()) { - SSLContext sslContext = new SSLContextBuilder() - .loadTrustMaterial(rabbitmqConfig.getTrustStore().getURL(), rabbitmqConfig.getTrustStorePassword().toCharArray()).build(); - SSLConnectionSocketFactory sslConFactory = new SSLConnectionSocketFactory(sslContext); - HttpClientConnectionManager cm = PoolingHttpClientConnectionManagerBuilder.create() - .setSSLSocketFactory(sslConFactory) - .build(); - CloseableHttpClient httpClient = HttpClients.custom().setConnectionManager(cm).build(); - ClientHttpRequestFactory requestFactory = new HttpComponentsClientHttpRequestFactory(httpClient); - restTemplate = new RestTemplate(requestFactory); - } - - return restTemplate; + return rabbitMQVersion; + } + + private static RestTemplate restTemplate(RabbitmqConfig rabbitmqConfig) + throws KeyStoreException, + NoSuchAlgorithmException, + KeyManagementException, + IOException, + CertificateException { + RestTemplate restTemplate = + new RestTemplateBuilder() + .setConnectTimeout(Duration.ofSeconds(2)) + .setReadTimeout(Duration.ofSeconds(2)) + .build(); + + if (rabbitmqConfig.isSsl() && rabbitmqConfig.isManagementInsecure()) { + HttpComponentsClientHttpRequestFactory requestFactoryHttp = + new HttpComponentsClientHttpRequestFactory(); + + TrustStrategy acceptingTrustStrategy = (cert, authType) -> true; + SSLContext sslContext = + SSLContexts.custom().loadTrustMaterial(null, acceptingTrustStrategy).build(); + SSLConnectionSocketFactory sslsf = + new SSLConnectionSocketFactory(sslContext, NoopHostnameVerifier.INSTANCE); + Registry socketFactoryRegistry = + RegistryBuilder.create() + .register("https", sslsf) + .register("http", new PlainConnectionSocketFactory()) + .build(); + + BasicHttpClientConnectionManager connectionManager = + new BasicHttpClientConnectionManager(socketFactoryRegistry); + CloseableHttpClient httpClient = + HttpClients.custom().setConnectionManager(connectionManager).build(); + requestFactoryHttp.setHttpClient(httpClient); + restTemplate = new RestTemplate(requestFactoryHttp); + } else if (rabbitmqConfig.isSsl()) { + SSLContext sslContext = + new SSLContextBuilder() + .loadTrustMaterial( + rabbitmqConfig.getTrustStore().getURL(), + rabbitmqConfig.getTrustStorePassword().toCharArray()) + .build(); + SSLConnectionSocketFactory sslConFactory = new SSLConnectionSocketFactory(sslContext); + HttpClientConnectionManager cm = + PoolingHttpClientConnectionManagerBuilder.create() + .setSSLSocketFactory(sslConFactory) + .build(); + CloseableHttpClient httpClient = HttpClients.custom().setConnectionManager(cm).build(); + ClientHttpRequestFactory requestFactory = + new HttpComponentsClientHttpRequestFactory(httpClient); + restTemplate = new RestTemplate(requestFactory); } + + return restTemplate; + } } diff --git a/openbas-api/src/main/java/io/openbas/importer/ImportException.java b/openbas-api/src/main/java/io/openbas/importer/ImportException.java index 09ed74e1a2..59e49f9d70 100644 --- a/openbas-api/src/main/java/io/openbas/importer/ImportException.java +++ b/openbas-api/src/main/java/io/openbas/importer/ImportException.java @@ -2,11 +2,11 @@ public class ImportException extends RuntimeException { - public ImportException(Throwable cause) { - super(cause); - } + public ImportException(Throwable cause) { + super(cause); + } - public ImportException(String message) { - super(message); - } + public ImportException(String message) { + super(message); + } } diff --git a/openbas-api/src/main/java/io/openbas/importer/Importer.java b/openbas-api/src/main/java/io/openbas/importer/Importer.java index 5b30dc6529..94935b12a7 100644 --- a/openbas-api/src/main/java/io/openbas/importer/Importer.java +++ b/openbas-api/src/main/java/io/openbas/importer/Importer.java @@ -1,8 +1,9 @@ package io.openbas.importer; +import static java.util.Spliterators.spliteratorUnknownSize; + import com.fasterxml.jackson.databind.JsonNode; import io.openbas.service.ImportEntry; - import java.util.Iterator; import java.util.List; import java.util.Map; @@ -10,23 +11,21 @@ import java.util.stream.Stream; import java.util.stream.StreamSupport; -import static java.util.Spliterators.spliteratorUnknownSize; - public interface Importer { - void importData(JsonNode importNode, Map docReferences); + void importData(JsonNode importNode, Map docReferences); - default Stream resolveJsonElements(JsonNode node, String key) { - JsonNode dataNode = node.get(key); - if (dataNode == null) { - return Stream.empty(); - } - Iterator elements = dataNode.elements(); - Spliterator elementsSplit = spliteratorUnknownSize(elements, Spliterator.ORDERED); - return StreamSupport.stream(elementsSplit, false); + default Stream resolveJsonElements(JsonNode node, String key) { + JsonNode dataNode = node.get(key); + if (dataNode == null) { + return Stream.empty(); } + Iterator elements = dataNode.elements(); + Spliterator elementsSplit = spliteratorUnknownSize(elements, Spliterator.ORDERED); + return StreamSupport.stream(elementsSplit, false); + } - default List resolveJsonIds(JsonNode node, String key) { - return resolveJsonElements(node, key).map(JsonNode::asText).toList(); - } + default List resolveJsonIds(JsonNode node, String key) { + return resolveJsonElements(node, key).map(JsonNode::asText).toList(); + } } diff --git a/openbas-api/src/main/java/io/openbas/importer/V1_DataImporter.java b/openbas-api/src/main/java/io/openbas/importer/V1_DataImporter.java index 527bdd8428..f69c280dc6 100644 --- a/openbas-api/src/main/java/io/openbas/importer/V1_DataImporter.java +++ b/openbas-api/src/main/java/io/openbas/importer/V1_DataImporter.java @@ -1,5 +1,13 @@ package io.openbas.importer; +import static io.openbas.helper.StreamHelper.iterableToSet; +import static io.openbas.injectors.challenge.ChallengeContract.CHALLENGE_PUBLISH; +import static io.openbas.injectors.channel.ChannelContract.CHANNEL_PUBLISH; +import static io.openbas.rest.exercise.exports.ExerciseFileExport.EXERCISE_VARIABLES; +import static io.openbas.rest.scenario.export.ScenarioFileExport.SCENARIO_VARIABLES; +import static java.util.Optional.ofNullable; +import static org.springframework.util.StringUtils.hasText; + import com.fasterxml.jackson.databind.JsonNode; import com.fasterxml.jackson.databind.ObjectMapper; import io.openbas.database.model.*; @@ -14,31 +22,21 @@ import jakarta.activation.MimetypesFileTypeMap; import jakarta.annotation.Resource; import jakarta.validation.constraints.NotNull; -import lombok.extern.java.Log; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.stereotype.Component; -import org.springframework.transaction.annotation.Transactional; - import java.time.Instant; import java.util.*; import java.util.stream.Collectors; import java.util.stream.Stream; - -import static io.openbas.helper.StreamHelper.iterableToSet; -import static io.openbas.injectors.challenge.ChallengeContract.CHALLENGE_PUBLISH; -import static io.openbas.injectors.channel.ChannelContract.CHANNEL_PUBLISH; -import static io.openbas.rest.exercise.exports.ExerciseFileExport.EXERCISE_VARIABLES; -import static io.openbas.rest.scenario.export.ScenarioFileExport.SCENARIO_VARIABLES; -import static java.util.Optional.ofNullable; -import static org.springframework.util.StringUtils.hasText; +import lombok.extern.java.Log; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Component; +import org.springframework.transaction.annotation.Transactional; @Component @Log public class V1_DataImporter implements Importer { // region variables - @Resource - protected ObjectMapper mapper; + @Resource protected ObjectMapper mapper; private FileService documentService; private DocumentRepository documentRepository; private TagRepository tagRepository; @@ -56,6 +54,7 @@ public class V1_DataImporter implements Importer { private LessonsCategoryRepository lessonsCategoryRepository; private LessonsQuestionRepository lessonsQuestionRepository; private VariableRepository variableRepository; + // endregion // region setter @@ -143,9 +142,11 @@ public void setTagRepository(TagRepository tagRepository) { public void setVariableRepository(@NotNull final VariableRepository variableRepository) { this.variableRepository = variableRepository; } + // endregion - private String handleInjectContent(Map baseIds, String contract, JsonNode injectNode) { + private String handleInjectContent( + Map baseIds, String contract, JsonNode injectNode) { if (contract == null) { return null; } @@ -157,8 +158,12 @@ private String handleInjectContent(Map baseIds, String contract, J try { JsonNode jsonNode = mapper.readTree(content); ChallengeContent challengeContent = mapper.treeToValue(jsonNode, ChallengeContent.class); - List remappedIds = challengeContent.getChallenges().stream() - .map(baseIds::get).filter(Objects::nonNull).map(Base::getId).toList(); + List remappedIds = + challengeContent.getChallenges().stream() + .map(baseIds::get) + .filter(Objects::nonNull) + .map(Base::getId) + .toList(); challengeContent.setChallenges(remappedIds); content = mapper.writeValueAsString(challengeContent); } catch (Exception e) { @@ -172,8 +177,12 @@ private String handleInjectContent(Map baseIds, String contract, J try { JsonNode jsonNode = mapper.readTree(content); ChannelContent channelContent = mapper.treeToValue(jsonNode, ChannelContent.class); - List remappedIds = channelContent.getArticles().stream() - .map(baseIds::get).filter(Objects::nonNull).map(Base::getId).toList(); + List remappedIds = + channelContent.getArticles().stream() + .map(baseIds::get) + .filter(Objects::nonNull) + .map(Base::getId) + .toList(); channelContent.setArticles(remappedIds); content = mapper.writeValueAsString(channelContent); } catch (Exception e) { @@ -185,12 +194,11 @@ private String handleInjectContent(Map baseIds, String contract, J return content; } - private Set computeTagsCompletion(Set existingTags, List lookingIds, Map baseIds) { + private Set computeTagsCompletion( + Set existingTags, List lookingIds, Map baseIds) { Set tags = new HashSet<>(existingTags); - Set tagsForOrganization = lookingIds.stream() - .map(baseIds::get) - .map(Tag.class::cast) - .collect(Collectors.toSet()); + Set tagsForOrganization = + lookingIds.stream().map(baseIds::get).map(Tag.class::cast).collect(Collectors.toSet()); tags.addAll(tagsForOrganization); return tags; } @@ -220,21 +228,23 @@ public void importData(JsonNode importNode, Map docReferenc // -- TAGS -- private void importTags(JsonNode importNode, String prefix, Map baseIds) { - resolveJsonElements(importNode, prefix + "tags").forEach(nodeTag -> { - String id = nodeTag.get("tag_id").textValue(); - if (baseIds.get(id) != null) { - // Already import - return; - } - String name = nodeTag.get("tag_name").textValue(); - - List existingTags = this.tagRepository.findByNameIgnoreCase(name); - if (!existingTags.isEmpty()) { - baseIds.put(id, existingTags.getFirst()); - } else { - baseIds.put(id, this.tagRepository.save(createTag(nodeTag))); - } - }); + resolveJsonElements(importNode, prefix + "tags") + .forEach( + nodeTag -> { + String id = nodeTag.get("tag_id").textValue(); + if (baseIds.get(id) != null) { + // Already import + return; + } + String name = nodeTag.get("tag_name").textValue(); + + List existingTags = this.tagRepository.findByNameIgnoreCase(name); + if (!existingTags.isEmpty()) { + baseIds.put(id, existingTags.getFirst()); + } else { + baseIds.put(id, this.tagRepository.save(createTag(nodeTag))); + } + }); } private Tag createTag(JsonNode jsonNode) { @@ -261,12 +271,10 @@ private Exercise importExercise(JsonNode importNode, Map baseIds) exercise.setFooter(exerciseNode.get("exercise_message_footer").textValue()); exercise.setFrom(exerciseNode.get("exercise_mail_from").textValue()); exercise.setTags( - resolveJsonIds(exerciseNode, "exercise_tags") - .stream() + resolveJsonIds(exerciseNode, "exercise_tags").stream() .map(baseIds::get) .map(Tag.class::cast) - .collect(Collectors.toSet()) - ); + .collect(Collectors.toSet())); return exerciseRepository.save(exercise); } @@ -301,32 +309,40 @@ private Scenario importScenario(JsonNode importNode, Map baseIds) scenario.setFooter(scenarioNode.get("scenario_message_footer").textValue()); scenario.setFrom(scenarioNode.get("scenario_mail_from").textValue()); scenario.setTags( - resolveJsonIds(scenarioNode, "scenario_tags") - .stream() + resolveJsonIds(scenarioNode, "scenario_tags").stream() .map(baseIds::get) .map(Tag.class::cast) - .collect(Collectors.toSet()) - ); + .collect(Collectors.toSet())); return scenarioService.createScenario(scenario); } - private void importDocuments(JsonNode importNode, String prefix, Map docReferences, - Exercise savedExercise, Scenario savedScenario, Map baseIds) { + private void importDocuments( + JsonNode importNode, + String prefix, + Map docReferences, + Exercise savedExercise, + Scenario savedScenario, + Map baseIds) { Stream documentsStream = resolveJsonElements(importNode, prefix + "documents"); - documentsStream.forEach(nodeDoc -> { - String target = nodeDoc.get("document_target").textValue(); - ImportEntry entry = docReferences.get(target); + documentsStream.forEach( + nodeDoc -> { + String target = nodeDoc.get("document_target").textValue(); + ImportEntry entry = docReferences.get(target); - if (entry != null) { - handleDocumentWithEntry(nodeDoc, entry, target, savedExercise, savedScenario, baseIds); - } - }); + if (entry != null) { + handleDocumentWithEntry(nodeDoc, entry, target, savedExercise, savedScenario, baseIds); + } + }); } private void handleDocumentWithEntry( - JsonNode nodeDoc, ImportEntry entry, String target, Exercise savedExercise, - Scenario savedScenario, Map baseIds) { + JsonNode nodeDoc, + ImportEntry entry, + String target, + Exercise savedExercise, + Scenario savedScenario, + Map baseIds) { String contentType = new MimetypesFileTypeMap().getContentType(entry.getEntry().getName()); Optional targetDocument = this.documentRepository.findByTarget(target); @@ -338,22 +354,34 @@ private void handleDocumentWithEntry( } private void updateExistingDocument( - JsonNode nodeDoc, Document document, Exercise savedExercise, - Scenario savedScenario, Map baseIds) { + JsonNode nodeDoc, + Document document, + Exercise savedExercise, + Scenario savedScenario, + Map baseIds) { if (savedExercise != null) { document.getExercises().add(savedExercise); } else if (savedScenario != null) { document.getScenarios().add(savedScenario); } - document.setTags(computeTagsCompletion(document.getTags(), resolveJsonIds(nodeDoc, "document_tags"), baseIds)); + document.setTags( + computeTagsCompletion( + document.getTags(), resolveJsonIds(nodeDoc, "document_tags"), baseIds)); Document savedDocument = this.documentRepository.save(document); baseIds.put(nodeDoc.get("document_id").textValue(), savedDocument); } - private void uploadNewDocument(JsonNode nodeDoc, ImportEntry entry, String target, Exercise savedExercise, - Scenario savedScenario, String contentType, Map baseIds) { + private void uploadNewDocument( + JsonNode nodeDoc, + ImportEntry entry, + String target, + Exercise savedExercise, + Scenario savedScenario, + String contentType, + Map baseIds) { try { - this.documentService.uploadFile(target, entry.getData(), entry.getEntry().getSize(), contentType); + this.documentService.uploadFile( + target, entry.getData(), entry.getEntry().getSize(), contentType); } catch (Exception e) { throw new ImportException(e); } @@ -367,7 +395,8 @@ private void uploadNewDocument(JsonNode nodeDoc, ImportEntry entry, String targe } else if (savedScenario != null) { document.setScenarios(Set.of(savedScenario)); } - document.setTags(iterableToSet(tagRepository.findAllById(resolveJsonIds(nodeDoc, "document_tags")))); + document.setTags( + iterableToSet(tagRepository.findAllById(resolveJsonIds(nodeDoc, "document_tags")))); document.setType(contentType); Document savedDocument = this.documentRepository.save(document); baseIds.put(nodeDoc.get("document_id").textValue(), savedDocument); @@ -377,22 +406,27 @@ private void uploadNewDocument(JsonNode nodeDoc, ImportEntry entry, String targe private void importOrganizations(JsonNode importNode, String prefix, Map baseIds) { resolveJsonElements(importNode, prefix + "organizations") - .forEach(nodeOrganization -> { - String id = nodeOrganization.get("organization_id").textValue(); - if (baseIds.get(id) != null) { - // Already import - return; - } - String name = nodeOrganization.get("organization_name").textValue(); - - List existingOrganizations = this.organizationRepository.findByNameIgnoreCase(name); - - if (!existingOrganizations.isEmpty()) { - baseIds.put(id, existingOrganizations.getFirst()); - } else { - baseIds.put(id, this.organizationRepository.save(createOrganization(nodeOrganization, baseIds))); - } - }); + .forEach( + nodeOrganization -> { + String id = nodeOrganization.get("organization_id").textValue(); + if (baseIds.get(id) != null) { + // Already import + return; + } + String name = nodeOrganization.get("organization_name").textValue(); + + List existingOrganizations = + this.organizationRepository.findByNameIgnoreCase(name); + + if (!existingOrganizations.isEmpty()) { + baseIds.put(id, existingOrganizations.getFirst()); + } else { + baseIds.put( + id, + this.organizationRepository.save( + createOrganization(nodeOrganization, baseIds))); + } + }); } private Organization createOrganization(JsonNode importNode, Map baseIds) { @@ -400,12 +434,10 @@ private Organization createOrganization(JsonNode importNode, Map b organization.setName(importNode.get("organization_name").textValue()); organization.setDescription(getNodeValue(importNode.get("organization_description"))); organization.setTags( - resolveJsonIds(importNode, "organization_tags") - .stream() + resolveJsonIds(importNode, "organization_tags").stream() .map(baseIds::get) .map(Tag.class::cast) - .collect(Collectors.toSet()) - ); + .collect(Collectors.toSet())); return organization; } @@ -413,22 +445,23 @@ private Organization createOrganization(JsonNode importNode, Map b private void importUsers(JsonNode importNode, String prefix, Map baseIds) { resolveJsonElements(importNode, prefix + "users") - .forEach(nodeUser -> { - String id = nodeUser.get("user_id").textValue(); - if (baseIds.get(id) != null) { - // Already import - return; - } - String email = nodeUser.get("user_email").textValue(); + .forEach( + nodeUser -> { + String id = nodeUser.get("user_id").textValue(); + if (baseIds.get(id) != null) { + // Already import + return; + } + String email = nodeUser.get("user_email").textValue(); - User existingUser = this.userRepository.findByEmailIgnoreCase(email).orElse(null); + User existingUser = this.userRepository.findByEmailIgnoreCase(email).orElse(null); - if (existingUser != null) { - baseIds.put(id, existingUser); - } else { - baseIds.put(id, this.userRepository.save(createUser(nodeUser, baseIds))); - } - }); + if (existingUser != null) { + baseIds.put(id, existingUser); + } else { + baseIds.put(id, this.userRepository.save(createUser(nodeUser, baseIds))); + } + }); } private User createUser(JsonNode jsonNode, Map baseIds) { @@ -446,72 +479,79 @@ private User createUser(JsonNode jsonNode, Map baseIds) { user.setOrganization((Organization) userOrganization); } user.setTags( - resolveJsonIds(jsonNode, "user_tags") - .stream() + resolveJsonIds(jsonNode, "user_tags").stream() .map(baseIds::get) .map(Tag.class::cast) - .collect(Collectors.toSet()) - ); + .collect(Collectors.toSet())); return user; } // -- TEAMS -- private void importTeams( - JsonNode importNode, String prefix, Exercise savedExercise, Scenario savedScenario, Map baseIds - ) { + JsonNode importNode, + String prefix, + Exercise savedExercise, + Scenario savedScenario, + Map baseIds) { Map baseTeams = handlingTeams(importNode, prefix, baseIds); - baseTeams.values().forEach((team) -> { - if (savedExercise != null) { - team.getExercises().add(savedExercise); - } else if (savedScenario != null) { - team.getScenarios().add(savedScenario); - } - }); + baseTeams + .values() + .forEach( + (team) -> { + if (savedExercise != null) { + team.getExercises().add(savedExercise); + } else if (savedScenario != null) { + team.getScenarios().add(savedScenario); + } + }); baseIds.putAll(baseTeams); } private Map handlingTeams( - JsonNode importNode, - String prefix, - Map baseIds) { + JsonNode importNode, String prefix, Map baseIds) { Map baseTeams = new HashMap<>(); - resolveJsonElements(importNode, prefix + "teams").forEach(nodeTeam -> { - String id = nodeTeam.get("team_id").textValue(); - if (baseIds.get(id) != null) { - // Already import - return; - } - String name = nodeTeam.get("team_name").textValue(); - - // Prevent duplication of team, based on the team name and not contextual - List existingTeams = this.teamRepository.findByNameIgnoreCaseAndNotContextual(name); - - if (!existingTeams.isEmpty()) { - baseTeams.put(id, existingTeams.getFirst()); - } else { - Team team = createTeam(nodeTeam, baseIds); - // Tags - List teamTagIds = resolveJsonIds(nodeTeam, "team_tags"); - Set tagsForTeam = teamTagIds.stream() - .map(baseIds::get) - .filter(Objects::nonNull) - .map(Tag.class::cast) - .collect(Collectors.toSet()); - team.setTags(tagsForTeam); - // Users - List teamUserIds = resolveJsonIds(nodeTeam, "team_users"); - List usersForTeam = teamUserIds.stream() - .map(baseIds::get) - .filter(Objects::nonNull) - .map(User.class::cast) - .toList(); - team.setUsers(usersForTeam); - Team savedTeam = this.teamRepository.save(team); - baseTeams.put(id, savedTeam); - } - }); + resolveJsonElements(importNode, prefix + "teams") + .forEach( + nodeTeam -> { + String id = nodeTeam.get("team_id").textValue(); + if (baseIds.get(id) != null) { + // Already import + return; + } + String name = nodeTeam.get("team_name").textValue(); + + // Prevent duplication of team, based on the team name and not contextual + List existingTeams = + this.teamRepository.findByNameIgnoreCaseAndNotContextual(name); + + if (!existingTeams.isEmpty()) { + baseTeams.put(id, existingTeams.getFirst()); + } else { + Team team = createTeam(nodeTeam, baseIds); + // Tags + List teamTagIds = resolveJsonIds(nodeTeam, "team_tags"); + Set tagsForTeam = + teamTagIds.stream() + .map(baseIds::get) + .filter(Objects::nonNull) + .map(Tag.class::cast) + .collect(Collectors.toSet()); + team.setTags(tagsForTeam); + // Users + List teamUserIds = resolveJsonIds(nodeTeam, "team_users"); + List usersForTeam = + teamUserIds.stream() + .map(baseIds::get) + .filter(Objects::nonNull) + .map(User.class::cast) + .toList(); + team.setUsers(usersForTeam); + Team savedTeam = this.teamRepository.save(team); + baseTeams.put(id, savedTeam); + } + }); return baseTeams; } @@ -532,21 +572,24 @@ private Team createTeam(JsonNode jsonNode, Map baseIds) { private void importChallenges(JsonNode importNode, String prefix, Map baseIds) { resolveJsonElements(importNode, prefix + "challenges") - .forEach(nodeChallenge -> { - String id = nodeChallenge.get("challenge_id").textValue(); - if (baseIds.get(id) != null) { - // Already import - return; - } - String name = nodeChallenge.get("challenge_name").textValue(); - - List existingChallenges =this.challengeRepository.findByNameIgnoreCase(name); - if (!existingChallenges.isEmpty()) { - baseIds.put(id, existingChallenges.getFirst()); - } else { - baseIds.put(id, this.challengeRepository.save(createChallenge(nodeChallenge, baseIds))); - } - }); + .forEach( + nodeChallenge -> { + String id = nodeChallenge.get("challenge_id").textValue(); + if (baseIds.get(id) != null) { + // Already import + return; + } + String name = nodeChallenge.get("challenge_name").textValue(); + + List existingChallenges = + this.challengeRepository.findByNameIgnoreCase(name); + if (!existingChallenges.isEmpty()) { + baseIds.put(id, existingChallenges.getFirst()); + } else { + baseIds.put( + id, this.challengeRepository.save(createChallenge(nodeChallenge, baseIds))); + } + }); } private Challenge createChallenge(JsonNode nodeChallenge, Map baseIds) { @@ -557,24 +600,19 @@ private Challenge createChallenge(JsonNode nodeChallenge, Map base challenge.setScore(nodeChallenge.get("challenge_score").asDouble(0.0)); challenge.setMaxAttempts(nodeChallenge.get("challenge_max_attempts").asInt(0)); challenge.setDocuments( - resolveJsonIds(nodeChallenge, "challenge_documents") - .stream() + resolveJsonIds(nodeChallenge, "challenge_documents").stream() .map(docId -> (Document) baseIds.get(docId)) .filter(Objects::nonNull) - .toList() - ); + .toList()); challenge.setFlags( resolveJsonElements(nodeChallenge, "challenge_flags") .map(node -> this.createChallengeFlag(node, challenge)) - .toList() - ); + .toList()); challenge.setTags( - resolveJsonIds(nodeChallenge, "challenge_tags") - .stream() + resolveJsonIds(nodeChallenge, "challenge_tags").stream() .map(baseIds::get) .map(Tag.class::cast) - .collect(Collectors.toSet()) - ); + .collect(Collectors.toSet())); return challenge; } @@ -591,21 +629,23 @@ private ChallengeFlag createChallengeFlag(JsonNode flagNode, Challenge challenge private void importChannels(JsonNode importNode, String prefix, Map baseIds) { resolveJsonElements(importNode, prefix + "channels") - .forEach(nodeChannel -> { - String id = nodeChannel.get("channel_id").textValue(); - if (baseIds.get(id) != null) { - // Already import - return; - } - String channelName = nodeChannel.get("channel_name").textValue(); - - List existingChannels = this.channelRepository.findByNameIgnoreCase(channelName); - if (!existingChannels.isEmpty()) { - baseIds.put(id, existingChannels.getFirst()); - } else { - baseIds.put(id, this.channelRepository.save(createChannel(nodeChannel, baseIds))); - } - }); + .forEach( + nodeChannel -> { + String id = nodeChannel.get("channel_id").textValue(); + if (baseIds.get(id) != null) { + // Already import + return; + } + String channelName = nodeChannel.get("channel_name").textValue(); + + List existingChannels = + this.channelRepository.findByNameIgnoreCase(channelName); + if (!existingChannels.isEmpty()) { + baseIds.put(id, existingChannels.getFirst()); + } else { + baseIds.put(id, this.channelRepository.save(createChannel(nodeChannel, baseIds))); + } + }); } private Channel createChannel(JsonNode nodeChannel, Map baseIds) { @@ -631,17 +671,25 @@ private Channel createChannel(JsonNode nodeChannel, Map baseIds) { return channel; } - private void importArticles(JsonNode importNode, String prefix, Exercise savedExercise, Scenario savedScenario, + private void importArticles( + JsonNode importNode, + String prefix, + Exercise savedExercise, + Scenario savedScenario, Map baseIds) { resolveJsonElements(importNode, prefix + "articles") - .forEach(nodeArticle -> { - String id = nodeArticle.get("article_id").textValue(); - Article article = createArticle(nodeArticle, savedExercise, savedScenario, baseIds); - baseIds.put(id, this.articleRepository.save(article)); - }); - } - - private Article createArticle(JsonNode nodeArticle, Exercise savedExercise, Scenario savedScenario, + .forEach( + nodeArticle -> { + String id = nodeArticle.get("article_id").textValue(); + Article article = createArticle(nodeArticle, savedExercise, savedScenario, baseIds); + baseIds.put(id, this.articleRepository.save(article)); + }); + } + + private Article createArticle( + JsonNode nodeArticle, + Exercise savedExercise, + Scenario savedScenario, Map baseIds) { Article article = new Article(); article.setName(nodeArticle.get("article_name").textValue()); @@ -656,28 +704,32 @@ private Article createArticle(JsonNode nodeArticle, Exercise savedExercise, Scen article.setScenario(savedScenario); } article.setDocuments( - resolveJsonIds(nodeArticle, "article_documents") - .stream() + resolveJsonIds(nodeArticle, "article_documents").stream() .map(docId -> (Document) baseIds.get(docId)) .filter(Objects::nonNull) - .toList() - ); + .toList()); article.setChannel((Channel) baseIds.get(nodeArticle.get("article_channel").textValue())); return article; } - private void importObjectives(JsonNode importNode, String prefix, Exercise savedExercise, Scenario savedScenario, + private void importObjectives( + JsonNode importNode, + String prefix, + Exercise savedExercise, + Scenario savedScenario, Map baseIds) { resolveJsonElements(importNode, prefix + "objectives") - .forEach(nodeObjective -> { - String id = nodeObjective.get("objective_id").textValue(); - Objective objective = createObjective(nodeObjective, savedExercise, savedScenario); - baseIds.put(id, this.objectiveRepository.save(objective)); - }); + .forEach( + nodeObjective -> { + String id = nodeObjective.get("objective_id").textValue(); + Objective objective = createObjective(nodeObjective, savedExercise, savedScenario); + baseIds.put(id, this.objectiveRepository.save(objective)); + }); } - private Objective createObjective(JsonNode nodeObjective, Exercise savedExercise, Scenario savedScenario) { + private Objective createObjective( + JsonNode nodeObjective, Exercise savedExercise, Scenario savedScenario) { Objective objective = new Objective(); objective.setTitle(nodeObjective.get("objective_title").textValue()); objective.setDescription(nodeObjective.get("objective_description").textValue()); @@ -691,28 +743,38 @@ private Objective createObjective(JsonNode nodeObjective, Exercise savedExercise return objective; } - private void importLessons(JsonNode importNode, String prefix, Exercise savedExercise, Scenario savedScenario, + private void importLessons( + JsonNode importNode, + String prefix, + Exercise savedExercise, + Scenario savedScenario, Map baseIds) { resolveJsonElements(importNode, prefix + "lessons_categories") - .forEach(nodeLessonCategory -> { - String id = nodeLessonCategory.get("lessonscategory_id").textValue(); - LessonsCategory lessonsCategory = createLessonsCategory(nodeLessonCategory, savedExercise, savedScenario, - baseIds); - baseIds.put(id, this.lessonsCategoryRepository.save(lessonsCategory)); - }); + .forEach( + nodeLessonCategory -> { + String id = nodeLessonCategory.get("lessonscategory_id").textValue(); + LessonsCategory lessonsCategory = + createLessonsCategory(nodeLessonCategory, savedExercise, savedScenario, baseIds); + baseIds.put(id, this.lessonsCategoryRepository.save(lessonsCategory)); + }); resolveJsonElements(importNode, prefix + "lessons_questions") - .forEach(nodeLessonQuestion -> { - String id = nodeLessonQuestion.get("lessonsquestion_id").textValue(); - LessonsQuestion lessonsQuestion = createLessonsQuestion(nodeLessonQuestion, baseIds); - baseIds.put(id, this.lessonsQuestionRepository.save(lessonsQuestion)); - }); - } - - private LessonsCategory createLessonsCategory(JsonNode nodeLessonCategory, Exercise savedExercise, - Scenario savedScenario, Map baseIds) { + .forEach( + nodeLessonQuestion -> { + String id = nodeLessonQuestion.get("lessonsquestion_id").textValue(); + LessonsQuestion lessonsQuestion = createLessonsQuestion(nodeLessonQuestion, baseIds); + baseIds.put(id, this.lessonsQuestionRepository.save(lessonsQuestion)); + }); + } + + private LessonsCategory createLessonsCategory( + JsonNode nodeLessonCategory, + Exercise savedExercise, + Scenario savedScenario, + Map baseIds) { LessonsCategory lessonsCategory = new LessonsCategory(); lessonsCategory.setName(nodeLessonCategory.get("lessons_category_name").textValue()); - lessonsCategory.setDescription(nodeLessonCategory.get("lessons_category_description").textValue()); + lessonsCategory.setDescription( + nodeLessonCategory.get("lessons_category_description").textValue()); lessonsCategory.setOrder(nodeLessonCategory.get("lessons_category_order").intValue()); if (savedExercise != null) { lessonsCategory.setExercise(savedExercise); @@ -720,23 +782,24 @@ private LessonsCategory createLessonsCategory(JsonNode nodeLessonCategory, Exerc lessonsCategory.setScenario(savedScenario); } lessonsCategory.setTeams( - resolveJsonIds(nodeLessonCategory, "lessons_category_teams") - .stream() + resolveJsonIds(nodeLessonCategory, "lessons_category_teams").stream() .map(teamId -> (Team) baseIds.get(teamId)) .filter(Objects::nonNull) - .toList() - ); + .toList()); return lessonsCategory; } - private LessonsQuestion createLessonsQuestion(JsonNode nodeLessonQuestion, Map baseIds) { + private LessonsQuestion createLessonsQuestion( + JsonNode nodeLessonQuestion, Map baseIds) { LessonsQuestion lessonsQuestion = new LessonsQuestion(); lessonsQuestion.setContent(nodeLessonQuestion.get("lessons_question_content").textValue()); - lessonsQuestion.setExplanation(nodeLessonQuestion.get("lessons_question_explanation").textValue()); + lessonsQuestion.setExplanation( + nodeLessonQuestion.get("lessons_question_explanation").textValue()); lessonsQuestion.setOrder(nodeLessonQuestion.get("lessons_question_order").intValue()); lessonsQuestion.setCategory( - (LessonsCategory) baseIds.get(nodeLessonQuestion.get("lessons_question_category").textValue())); + (LessonsCategory) + baseIds.get(nodeLessonQuestion.get("lessons_question_category").textValue())); String categoryId = nodeLessonQuestion.get("lessons_question_category").asText(); LessonsCategory lessonsCategory = (LessonsCategory) baseIds.get(categoryId); lessonsQuestion.setCategory(lessonsCategory); @@ -744,10 +807,15 @@ private LessonsQuestion createLessonsQuestion(JsonNode nodeLessonQuestion, Map baseIds) { Stream injectsStream = resolveJsonElements(importNode, prefix + "injects"); - Stream injectsNoParent = injectsStream.filter(jsonNode -> jsonNode.get("inject_depends_on").isNull()); + Stream injectsNoParent = + injectsStream.filter(jsonNode -> jsonNode.get("inject_depends_on").isNull()); if (savedExercise != null) { importInjects(baseIds, savedExercise.getId(), null, injectsNoParent.toList()); @@ -756,81 +824,113 @@ private void importInjects(JsonNode importNode, String prefix, Exercise savedExe } } - private void importInjects(Map baseIds, String exerciseId, String scenarioId, List injects) { + private void importInjects( + Map baseIds, String exerciseId, String scenarioId, List injects) { List injected = new ArrayList<>(); - injects.forEach(injectNode -> { - String injectId = UUID.randomUUID().toString(); - injected.add(injectId); - String id = injectNode.get("inject_id").textValue(); - String title = injectNode.get("inject_title").textValue(); - String description = injectNode.get("inject_description").textValue(); - String country = injectNode.get("inject_country").textValue(); - String city = injectNode.get("inject_city").textValue(); - String injectorContractId = null; - JsonNode injectContractNode = injectNode.get("inject_injector_contract"); - if (injectContractNode != null) { - injectorContractId = injectContractNode.get("injector_contract_id").textValue(); - } - // If contract is not know, inject can't be imported - String content = handleInjectContent(baseIds, injectorContractId, injectNode); - JsonNode dependsOnNode = injectNode.get("inject_depends_on"); - String dependsOn = !dependsOnNode.isNull() ? baseIds.get(dependsOnNode.asText()).getId() : null; - Long dependsDuration = injectNode.get("inject_depends_duration").asLong(); - boolean allTeams = injectNode.get("inject_all_teams").booleanValue(); - if (hasText(exerciseId)) { - injectRepository.importSaveForExercise( - injectId, title, description, country, city, injectorContractId, allTeams, - true, exerciseId, dependsOn, dependsDuration, content - ); - } else if (hasText(scenarioId)) { - injectRepository.importSaveForScenario( - injectId, title, description, country, city, injectorContractId, - allTeams, true, scenarioId, dependsOn, dependsDuration, content - ); - } - baseIds.put(id, new BaseHolder(injectId)); - // Tags - List injectTagIds = resolveJsonIds(injectNode, "inject_tags"); - injectTagIds.forEach(tagId -> { - Base base = baseIds.get(tagId); - if (base == null || base.getId() == null) { - return; - } - injectRepository.addTag(injectId, base.getId()); - }); - // Teams - List injectTeamIds = resolveJsonIds(injectNode, "inject_teams"); - injectTeamIds.forEach(teamId -> { - Base base = baseIds.get(teamId); - if (base == null || base.getId() == null) { - return; - } - injectRepository.addTeam(injectId, base.getId()); - }); - // Documents - List injectDocuments = resolveJsonElements(injectNode, "inject_documents").toList(); - injectDocuments.forEach(jsonNode -> { - String docId = jsonNode.get("document_id").textValue(); - if (!hasText(docId)) { - String documentId = baseIds.get(docId).getId(); - boolean docAttached = jsonNode.get("document_attached").booleanValue(); - injectDocumentRepository.addInjectDoc(injectId, documentId, docAttached); - } else { - log.warning("Missing document in the exercise_documents property"); - } - }); - }); + injects.forEach( + injectNode -> { + String injectId = UUID.randomUUID().toString(); + injected.add(injectId); + String id = injectNode.get("inject_id").textValue(); + String title = injectNode.get("inject_title").textValue(); + String description = injectNode.get("inject_description").textValue(); + String country = injectNode.get("inject_country").textValue(); + String city = injectNode.get("inject_city").textValue(); + String injectorContractId = null; + JsonNode injectContractNode = injectNode.get("inject_injector_contract"); + if (injectContractNode != null) { + injectorContractId = injectContractNode.get("injector_contract_id").textValue(); + } + // If contract is not know, inject can't be imported + String content = handleInjectContent(baseIds, injectorContractId, injectNode); + JsonNode dependsOnNode = injectNode.get("inject_depends_on"); + String dependsOn = + !dependsOnNode.isNull() ? baseIds.get(dependsOnNode.asText()).getId() : null; + Long dependsDuration = injectNode.get("inject_depends_duration").asLong(); + boolean allTeams = injectNode.get("inject_all_teams").booleanValue(); + if (hasText(exerciseId)) { + injectRepository.importSaveForExercise( + injectId, + title, + description, + country, + city, + injectorContractId, + allTeams, + true, + exerciseId, + dependsOn, + dependsDuration, + content); + } else if (hasText(scenarioId)) { + injectRepository.importSaveForScenario( + injectId, + title, + description, + country, + city, + injectorContractId, + allTeams, + true, + scenarioId, + dependsOn, + dependsDuration, + content); + } + baseIds.put(id, new BaseHolder(injectId)); + // Tags + List injectTagIds = resolveJsonIds(injectNode, "inject_tags"); + injectTagIds.forEach( + tagId -> { + Base base = baseIds.get(tagId); + if (base == null || base.getId() == null) { + return; + } + injectRepository.addTag(injectId, base.getId()); + }); + // Teams + List injectTeamIds = resolveJsonIds(injectNode, "inject_teams"); + injectTeamIds.forEach( + teamId -> { + Base base = baseIds.get(teamId); + if (base == null || base.getId() == null) { + return; + } + injectRepository.addTeam(injectId, base.getId()); + }); + // Documents + List injectDocuments = + resolveJsonElements(injectNode, "inject_documents").toList(); + injectDocuments.forEach( + jsonNode -> { + String docId = jsonNode.get("document_id").textValue(); + if (!hasText(docId)) { + String documentId = baseIds.get(docId).getId(); + boolean docAttached = jsonNode.get("document_attached").booleanValue(); + injectDocumentRepository.addInjectDoc(injectId, documentId, docAttached); + } else { + log.warning("Missing document in the exercise_documents property"); + } + }); + }); // Looking for child of created injects - List childInjects = injects.stream().filter(jsonNode -> { - String injectDependsOn = jsonNode.get("inject_depends_on").asText(); - return injected.contains(injectDependsOn); - }).toList(); + List childInjects = + injects.stream() + .filter( + jsonNode -> { + String injectDependsOn = jsonNode.get("inject_depends_on").asText(); + return injected.contains(injectDependsOn); + }) + .toList(); if (!childInjects.isEmpty()) { importInjects(baseIds, exerciseId, scenarioId, childInjects); } } - private void importVariables(JsonNode importNode, Exercise savedExercise, Scenario savedScenario, + private void importVariables( + JsonNode importNode, + Exercise savedExercise, + Scenario savedScenario, Map baseIds) { Optional> variableNodesOpt = Optional.empty(); if (ofNullable(importNode.get(EXERCISE_VARIABLES)).isPresent()) { @@ -838,23 +938,24 @@ private void importVariables(JsonNode importNode, Exercise savedExercise, Scenar } else if (ofNullable(importNode.get(SCENARIO_VARIABLES)).isPresent()) { variableNodesOpt = ofNullable(importNode.get(SCENARIO_VARIABLES)).map(JsonNode::elements); } - variableNodesOpt.ifPresent(variableNodes -> variableNodes.forEachRemaining(variableNode -> { - String id = VariableWithValueMixin.getId(variableNode); - Variable variable = VariableWithValueMixin.build(variableNode); - if (savedExercise != null) { - variable.setExercise(savedExercise); - } else if (savedScenario != null) { - variable.setScenario(savedScenario); - } - Variable variableSaved = this.variableRepository.save(variable); - baseIds.put(id, variableSaved); - })); + variableNodesOpt.ifPresent( + variableNodes -> + variableNodes.forEachRemaining( + variableNode -> { + String id = VariableWithValueMixin.getId(variableNode); + Variable variable = VariableWithValueMixin.build(variableNode); + if (savedExercise != null) { + variable.setExercise(savedExercise); + } else if (savedScenario != null) { + variable.setScenario(savedScenario); + } + Variable variableSaved = this.variableRepository.save(variable); + baseIds.put(id, variableSaved); + })); } private String getNodeValue(JsonNode importNode) { - return Optional.ofNullable(importNode) - .map(JsonNode::textValue) - .orElse(null); + return Optional.ofNullable(importNode).map(JsonNode::textValue).orElse(null); } private static class BaseHolder implements Base { diff --git a/openbas-api/src/main/java/io/openbas/injectors/caldera/CalderaContract.java b/openbas-api/src/main/java/io/openbas/injectors/caldera/CalderaContract.java index b3f4f9f427..4c4655636c 100644 --- a/openbas-api/src/main/java/io/openbas/injectors/caldera/CalderaContract.java +++ b/openbas-api/src/main/java/io/openbas/injectors/caldera/CalderaContract.java @@ -1,5 +1,16 @@ package io.openbas.injectors.caldera; +import static io.openbas.executors.caldera.service.CalderaExecutorService.toPlatform; +import static io.openbas.helper.SupportedLanguage.en; +import static io.openbas.helper.SupportedLanguage.fr; +import static io.openbas.injector_contract.Contract.executableContract; +import static io.openbas.injector_contract.ContractCardinality.Multiple; +import static io.openbas.injector_contract.ContractDef.contractBuilder; +import static io.openbas.injector_contract.fields.ContractAsset.assetField; +import static io.openbas.injector_contract.fields.ContractAssetGroup.assetGroupField; +import static io.openbas.injector_contract.fields.ContractExpectations.expectationsField; +import static io.openbas.injector_contract.fields.ContractSelect.selectFieldWithDefault; + import io.openbas.database.model.Endpoint.PLATFORM_TYPE; import io.openbas.expectation.ExpectationBuilderService; import io.openbas.helper.SupportedLanguage; @@ -10,9 +21,6 @@ import io.openbas.injectors.caldera.model.Obfuscator; import io.openbas.injectors.caldera.service.CalderaInjectorService; import jakarta.validation.constraints.NotNull; -import lombok.RequiredArgsConstructor; -import org.springframework.stereotype.Component; - import java.io.InputStream; import java.util.ArrayList; import java.util.List; @@ -20,17 +28,8 @@ import java.util.regex.Matcher; import java.util.regex.Pattern; import java.util.stream.Collectors; - -import static io.openbas.executors.caldera.service.CalderaExecutorService.toPlatform; -import static io.openbas.helper.SupportedLanguage.en; -import static io.openbas.helper.SupportedLanguage.fr; -import static io.openbas.injector_contract.Contract.executableContract; -import static io.openbas.injector_contract.ContractCardinality.Multiple; -import static io.openbas.injector_contract.ContractDef.contractBuilder; -import static io.openbas.injector_contract.fields.ContractAsset.assetField; -import static io.openbas.injector_contract.fields.ContractAssetGroup.assetGroupField; -import static io.openbas.injector_contract.fields.ContractExpectations.expectationsField; -import static io.openbas.injector_contract.fields.ContractSelect.selectFieldWithDefault; +import lombok.RequiredArgsConstructor; +import org.springframework.stereotype.Component; @Component @RequiredArgsConstructor @@ -55,7 +54,8 @@ public String getType() { @Override public ContractConfig getConfig() { Map labels = Map.of(en, "Caldera", fr, "Caldera"); - return new ContractConfig(TYPE, labels, "#8b0000", "#8b0000", "/img/icon-caldera.png", isExpose()); + return new ContractConfig( + TYPE, labels, "#8b0000", "#8b0000", "/img/icon-caldera.png", isExpose()); } @Override @@ -72,14 +72,9 @@ public List contracts() { private ContractSelect obfuscatorField() { List obfuscators = this.injectorCalderaService.obfuscators(); - Map obfuscatorChoices = obfuscators.stream() - .collect(Collectors.toMap(Obfuscator::getName, Obfuscator::getName)); - return selectFieldWithDefault( - "obfuscator", - "Obfuscators", - obfuscatorChoices, - "base64" - ); + Map obfuscatorChoices = + obfuscators.stream().collect(Collectors.toMap(Obfuscator::getName, Obfuscator::getName)); + return selectFieldWithDefault("obfuscator", "Obfuscators", obfuscatorChoices, "base64"); } private ContractExpectations expectations() { @@ -88,9 +83,7 @@ private ContractExpectations expectations() { "Expectations", List.of( this.expectationBuilderService.buildPreventionExpectation(), - this.expectationBuilderService.buildDetectionExpectation() - ) - ); + this.expectationBuilderService.buildDetectionExpectation())); } private List abilityContracts(@NotNull final ContractConfig contractConfig) { @@ -100,57 +93,66 @@ private List abilityContracts(@NotNull final ContractConfig contractCo ContractAssetGroup assetGroupField = assetGroupField("assetgroups", "Asset groups", Multiple); ContractExpectations expectationsField = expectations(); - List abilities = this.injectorCalderaService.abilities().stream() - .filter(ability -> !ability.getTactic().equals("openbas")).toList(); + List abilities = + this.injectorCalderaService.abilities().stream() + .filter(ability -> !ability.getTactic().equals("openbas")) + .toList(); // Build contracts - return abilities.stream().map((ability -> { - ContractDef builder = contractBuilder(); - builder.mandatoryGroup(assetField, assetGroupField); - builder.optional(obfuscatorField); - builder.optional(expectationsField); - List platforms = new ArrayList<>(); - ability.getExecutors().forEach(executor -> { - String command = executor.getCommand(); - if (command != null && !command.isEmpty()) { - Matcher matcher = Pattern.compile("#\\{(.*?)\\}").matcher(command); - while (matcher.find()) { - if (!matcher.group(1).isEmpty()) { - builder.mandatory(ContractText.textField(matcher.group(1), matcher.group(1))); - } - } - } - if (!executor.getPlatform().equals("unknown")) { - PLATFORM_TYPE platform = toPlatform(executor.getPlatform()); - if (!platforms.contains(platform)) { - platforms.add(platform); - } - } else { - if (executor.getName().equals("psh")) { - if (!platforms.contains(PLATFORM_TYPE.Windows)) { - platforms.add(PLATFORM_TYPE.Windows); - } - } else if (executor.getName().equals("sh")) { - if (!platforms.contains(PLATFORM_TYPE.Linux)) { - platforms.add(PLATFORM_TYPE.Linux); - } - } else if (executor.getName().equals("cmd")) { - if (!platforms.contains(PLATFORM_TYPE.Windows)) { - platforms.add(PLATFORM_TYPE.Windows); - } - } - } - }); - Contract contract = executableContract( - contractConfig, - ability.getAbility_id(), - Map.of(en, ability.getName(), fr, ability.getName()), - builder.build(), - platforms, - true - ); - contract.addAttackPattern(ability.getTechnique_id()); - return contract; - })).collect(Collectors.toList()); + return abilities.stream() + .map( + (ability -> { + ContractDef builder = contractBuilder(); + builder.mandatoryGroup(assetField, assetGroupField); + builder.optional(obfuscatorField); + builder.optional(expectationsField); + List platforms = new ArrayList<>(); + ability + .getExecutors() + .forEach( + executor -> { + String command = executor.getCommand(); + if (command != null && !command.isEmpty()) { + Matcher matcher = Pattern.compile("#\\{(.*?)\\}").matcher(command); + while (matcher.find()) { + if (!matcher.group(1).isEmpty()) { + builder.mandatory( + ContractText.textField(matcher.group(1), matcher.group(1))); + } + } + } + if (!executor.getPlatform().equals("unknown")) { + PLATFORM_TYPE platform = toPlatform(executor.getPlatform()); + if (!platforms.contains(platform)) { + platforms.add(platform); + } + } else { + if (executor.getName().equals("psh")) { + if (!platforms.contains(PLATFORM_TYPE.Windows)) { + platforms.add(PLATFORM_TYPE.Windows); + } + } else if (executor.getName().equals("sh")) { + if (!platforms.contains(PLATFORM_TYPE.Linux)) { + platforms.add(PLATFORM_TYPE.Linux); + } + } else if (executor.getName().equals("cmd")) { + if (!platforms.contains(PLATFORM_TYPE.Windows)) { + platforms.add(PLATFORM_TYPE.Windows); + } + } + } + }); + Contract contract = + executableContract( + contractConfig, + ability.getAbility_id(), + Map.of(en, ability.getName(), fr, ability.getName()), + builder.build(), + platforms, + true); + contract.addAttackPattern(ability.getTechnique_id()); + return contract; + })) + .collect(Collectors.toList()); } @Override diff --git a/openbas-api/src/main/java/io/openbas/injectors/caldera/CalderaExecutor.java b/openbas-api/src/main/java/io/openbas/injectors/caldera/CalderaExecutor.java index 69c6edf2a8..3a0df05449 100644 --- a/openbas-api/src/main/java/io/openbas/injectors/caldera/CalderaExecutor.java +++ b/openbas-api/src/main/java/io/openbas/injectors/caldera/CalderaExecutor.java @@ -1,5 +1,15 @@ package io.openbas.injectors.caldera; +import static io.openbas.database.model.InjectExpectationSignature.*; +import static io.openbas.database.model.InjectStatusExecution.*; +import static io.openbas.model.expectation.DetectionExpectation.detectionExpectationForAsset; +import static io.openbas.model.expectation.DetectionExpectation.detectionExpectationForAssetGroup; +import static io.openbas.model.expectation.ManualExpectation.manualExpectationForAsset; +import static io.openbas.model.expectation.ManualExpectation.manualExpectationForAssetGroup; +import static io.openbas.model.expectation.PreventionExpectation.preventionExpectationForAsset; +import static io.openbas.model.expectation.PreventionExpectation.preventionExpectationForAssetGroup; +import static java.time.Instant.now; + import com.fasterxml.jackson.databind.JsonNode; import com.fasterxml.jackson.databind.node.ObjectNode; import io.openbas.asset.AssetGroupService; @@ -21,27 +31,16 @@ import io.openbas.model.expectation.PreventionExpectation; import io.openbas.utils.Time; import jakarta.validation.constraints.NotNull; +import java.util.*; +import java.util.logging.Level; +import java.util.stream.Stream; +import java.util.stream.StreamSupport; import lombok.RequiredArgsConstructor; import lombok.extern.java.Log; import org.hibernate.Hibernate; import org.springframework.stereotype.Component; import org.springframework.transaction.annotation.Transactional; -import java.util.*; -import java.util.logging.Level; -import java.util.stream.Stream; -import java.util.stream.StreamSupport; - -import static io.openbas.database.model.InjectExpectationSignature.*; -import static io.openbas.database.model.InjectStatusExecution.*; -import static io.openbas.model.expectation.DetectionExpectation.detectionExpectationForAsset; -import static io.openbas.model.expectation.DetectionExpectation.detectionExpectationForAssetGroup; -import static io.openbas.model.expectation.ManualExpectation.manualExpectationForAsset; -import static io.openbas.model.expectation.ManualExpectation.manualExpectationForAssetGroup; -import static io.openbas.model.expectation.PreventionExpectation.preventionExpectationForAsset; -import static io.openbas.model.expectation.PreventionExpectation.preventionExpectationForAssetGroup; -import static java.time.Instant.now; - @Component(CalderaContract.TYPE) @RequiredArgsConstructor @Log @@ -56,149 +55,225 @@ public class CalderaExecutor extends Injector { @Override @Transactional - public ExecutionProcess process(@NotNull final Execution execution, @NotNull final ExecutableInject injection) + public ExecutionProcess process( + @NotNull final Execution execution, @NotNull final ExecutableInject injection) throws Exception { CalderaInjectContent content = contentConvert(injection, CalderaInjectContent.class); String obfuscator = content.getObfuscator() != null ? content.getObfuscator() : "base64"; - Inject inject = this.injectRepository.findById(injection.getInjection().getInject().getId()).orElseThrow(); + Inject inject = + this.injectRepository.findById(injection.getInjection().getInject().getId()).orElseThrow(); Map assets = this.resolveAllAssets(injection); // Execute inject for all assets if (assets.isEmpty()) { - execution.addTrace(traceError( - "Found 0 asset to execute the ability on (likely this inject does not have any target or the targeted asset is inactive and has been purged)")); + execution.addTrace( + traceError( + "Found 0 asset to execute the ability on (likely this inject does not have any target or the targeted asset is inactive and has been purged)")); } List asyncIds = new ArrayList<>(); List expectations = new ArrayList<>(); List> additionalFields = new ArrayList<>(); - inject.getInjectorContract().ifPresentOrElse(injectorContract -> { - ObjectNode rawContent = injection.getInjection().getInject().getContent(); - ObjectNode contractContent = injectorContract.getConvertedContent(); - List contractTextFields = StreamSupport.stream(contractContent.get("fields").spliterator(), false) - .filter(contractElement -> contractElement.get("type").asText().equals("text")) - .toList(); + inject + .getInjectorContract() + .ifPresentOrElse( + injectorContract -> { + ObjectNode rawContent = injection.getInjection().getInject().getContent(); + ObjectNode contractContent = injectorContract.getConvertedContent(); + List contractTextFields = + StreamSupport.stream(contractContent.get("fields").spliterator(), false) + .filter( + contractElement -> contractElement.get("type").asText().equals("text")) + .toList(); - if (!contractTextFields.isEmpty()) { - contractTextFields.forEach(jsonField -> { - String key = jsonField.get("key").asText(); - if (rawContent.get(key) != null) { - Map additionalField = new HashMap<>(); - additionalField.put("trait", key); - additionalField.put("value", rawContent.get(key).asText()); - additionalFields.add(additionalField); + if (!contractTextFields.isEmpty()) { + contractTextFields.forEach( + jsonField -> { + String key = jsonField.get("key").asText(); + if (rawContent.get(key) != null) { + Map additionalField = new HashMap<>(); + additionalField.put("trait", key); + additionalField.put("value", rawContent.get(key).asText()); + additionalFields.add(additionalField); + } + }); } - }); - } - String contract; - if (injectorContract.getPayload() != null) { - // This is a payload, need to create the ability on the fly - List abilities = calderaService.abilities().stream() - .filter(ability -> ability.getName().equals(injectorContract.getPayload().getId())).toList(); - if (!abilities.isEmpty()) { - calderaService.deleteAbility(abilities.getFirst()); - } - Ability abilityToExecute = calderaService.createAbility(injectorContract.getPayload()); - contract = abilityToExecute.getAbility_id(); - } else { - contract = injectorContract.getId(); - } - assets.forEach((asset, aBoolean) -> { - try { - Endpoint executionEndpoint = this.findAndRegisterAssetForExecution(injection.getInjection().getInject(), - asset); - if (executionEndpoint != null) { - if (Arrays.stream(injectorContract.getPlatforms()) - .anyMatch(s -> s.equals(executionEndpoint.getPlatform()))) { - String result = this.calderaService.exploit(obfuscator, executionEndpoint.getExternalReference(), - contract, additionalFields); - if (result.contains("complete")) { - ExploitResult exploitResult = this.calderaService.exploitResult( - executionEndpoint.getExternalReference(), contract); - asyncIds.add(exploitResult.getLinkId()); - execution.addTrace(traceInfo(EXECUTION_TYPE_COMMAND, exploitResult.getCommand())); - // Compute expectations - boolean isInGroup = assets.get(executionEndpoint.getParent()); - List injectExpectationSignatures = new ArrayList<>(); - if (injectorContract.getPayload() != null) { - switch (injectorContract.getPayload().getType()) { - case "Command": - injectExpectationSignatures.add( - InjectExpectationSignature.builder().type(EXPECTATION_SIGNATURE_TYPE_PROCESS_NAME) - .value(executionEndpoint.getProcessName()).build()); - injectExpectationSignatures.add( - InjectExpectationSignature.builder().type(EXPECTATION_SIGNATURE_TYPE_COMMAND_LINE) - .value(exploitResult.getCommand()).build()); - break; - case "Executable": - Executable payloadExecutable = (Executable) Hibernate.unproxy(injectorContract.getPayload()); - injectExpectationSignatures.add( - InjectExpectationSignature.builder().type(EXPECTATION_SIGNATURE_TYPE_FILE_NAME) - .value(payloadExecutable.getExecutableFile().getName()).build()); - // TODO File hash - break; - case "FileDrop": - FileDrop payloadFileDrop = (FileDrop) Hibernate.unproxy(injectorContract.getPayload()); - injectExpectationSignatures.add( - InjectExpectationSignature.builder().type(EXPECTATION_SIGNATURE_TYPE_FILE_NAME) - .value(payloadFileDrop.getFileDropFile().getName()).build()); - // TODO File hash - break; - case "DnsResolution": - DnsResolution payloadDnsResolution = (DnsResolution) Hibernate.unproxy( - injectorContract.getPayload()); - injectExpectationSignatures.add( - InjectExpectationSignature.builder().type(EXPECTATION_SIGNATURE_TYPE_HOSTNAME) - .value(payloadDnsResolution.getHostname().split("\\r?\\n")[0]).build()); - break; - default: - throw new UnsupportedOperationException( - "Payload type " + injectorContract.getPayload().getType() + " is not supported"); - } - } else { - injectExpectationSignatures.add( - InjectExpectationSignature.builder().type(EXPECTATION_SIGNATURE_TYPE_PROCESS_NAME) - .value(executionEndpoint.getProcessName()).build()); - injectExpectationSignatures.add( - InjectExpectationSignature.builder().type(EXPECTATION_SIGNATURE_TYPE_COMMAND_LINE) - .value(exploitResult.getCommand()).build()); - } - computeExpectationsForAsset(expectations, content, executionEndpoint.getParent(), isInGroup, - injectExpectationSignatures); - execution.addTrace(traceInfo("Caldera executed the ability on asset " + asset.getName() + " using " - + executionEndpoint.getProcessName() + " (paw: " + executionEndpoint.getExternalReference() - + ", linkID: " + exploitResult.getLinkId() + ")")); - } else { - execution.addTrace(traceError( - "Caldera failed to execute the ability on asset " + asset.getName() + " (" + result + ")")); - } - } else { - execution.addTrace(traceError( - "Caldera failed to execute ability on asset " + asset.getName() + " (platform is not compatible: " - + executionEndpoint.getPlatform().name() + ")")); + String contract; + if (injectorContract.getPayload() != null) { + // This is a payload, need to create the ability on the fly + List abilities = + calderaService.abilities().stream() + .filter( + ability -> + ability.getName().equals(injectorContract.getPayload().getId())) + .toList(); + if (!abilities.isEmpty()) { + calderaService.deleteAbility(abilities.getFirst()); } + Ability abilityToExecute = + calderaService.createAbility(injectorContract.getPayload()); + contract = abilityToExecute.getAbility_id(); } else { - execution.addTrace(traceError("Caldera failed to execute the ability on asset " + asset.getName() - + " (temporary injector not spawned correctly)")); + contract = injectorContract.getId(); } - } catch (Exception e) { - execution.addTrace(traceError( - "Caldera failed to execute the ability on asset " + asset.getName() + " (" + e.getMessage() + ")")); - log.severe(Arrays.toString(e.getStackTrace())); - } - }); - }, - () -> execution.addTrace(traceError("Inject does not have a contract"))); + assets.forEach( + (asset, aBoolean) -> { + try { + Endpoint executionEndpoint = + this.findAndRegisterAssetForExecution( + injection.getInjection().getInject(), asset); + if (executionEndpoint != null) { + if (Arrays.stream(injectorContract.getPlatforms()) + .anyMatch(s -> s.equals(executionEndpoint.getPlatform()))) { + String result = + this.calderaService.exploit( + obfuscator, + executionEndpoint.getExternalReference(), + contract, + additionalFields); + if (result.contains("complete")) { + ExploitResult exploitResult = + this.calderaService.exploitResult( + executionEndpoint.getExternalReference(), contract); + asyncIds.add(exploitResult.getLinkId()); + execution.addTrace( + traceInfo(EXECUTION_TYPE_COMMAND, exploitResult.getCommand())); + // Compute expectations + boolean isInGroup = assets.get(executionEndpoint.getParent()); + List injectExpectationSignatures = + new ArrayList<>(); + if (injectorContract.getPayload() != null) { + switch (injectorContract.getPayload().getType()) { + case "Command": + injectExpectationSignatures.add( + InjectExpectationSignature.builder() + .type(EXPECTATION_SIGNATURE_TYPE_PROCESS_NAME) + .value(executionEndpoint.getProcessName()) + .build()); + injectExpectationSignatures.add( + InjectExpectationSignature.builder() + .type(EXPECTATION_SIGNATURE_TYPE_COMMAND_LINE) + .value(exploitResult.getCommand()) + .build()); + break; + case "Executable": + Executable payloadExecutable = + (Executable) Hibernate.unproxy(injectorContract.getPayload()); + injectExpectationSignatures.add( + InjectExpectationSignature.builder() + .type(EXPECTATION_SIGNATURE_TYPE_FILE_NAME) + .value(payloadExecutable.getExecutableFile().getName()) + .build()); + // TODO File hash + break; + case "FileDrop": + FileDrop payloadFileDrop = + (FileDrop) Hibernate.unproxy(injectorContract.getPayload()); + injectExpectationSignatures.add( + InjectExpectationSignature.builder() + .type(EXPECTATION_SIGNATURE_TYPE_FILE_NAME) + .value(payloadFileDrop.getFileDropFile().getName()) + .build()); + // TODO File hash + break; + case "DnsResolution": + DnsResolution payloadDnsResolution = + (DnsResolution) + Hibernate.unproxy(injectorContract.getPayload()); + injectExpectationSignatures.add( + InjectExpectationSignature.builder() + .type(EXPECTATION_SIGNATURE_TYPE_HOSTNAME) + .value( + payloadDnsResolution.getHostname() + .split("\\r?\\n")[0]) + .build()); + break; + default: + throw new UnsupportedOperationException( + "Payload type " + + injectorContract.getPayload().getType() + + " is not supported"); + } + } else { + injectExpectationSignatures.add( + InjectExpectationSignature.builder() + .type(EXPECTATION_SIGNATURE_TYPE_PROCESS_NAME) + .value(executionEndpoint.getProcessName()) + .build()); + injectExpectationSignatures.add( + InjectExpectationSignature.builder() + .type(EXPECTATION_SIGNATURE_TYPE_COMMAND_LINE) + .value(exploitResult.getCommand()) + .build()); + } + computeExpectationsForAsset( + expectations, + content, + executionEndpoint.getParent(), + isInGroup, + injectExpectationSignatures); + execution.addTrace( + traceInfo( + "Caldera executed the ability on asset " + + asset.getName() + + " using " + + executionEndpoint.getProcessName() + + " (paw: " + + executionEndpoint.getExternalReference() + + ", linkID: " + + exploitResult.getLinkId() + + ")")); + } else { + execution.addTrace( + traceError( + "Caldera failed to execute the ability on asset " + + asset.getName() + + " (" + + result + + ")")); + } + } else { + execution.addTrace( + traceError( + "Caldera failed to execute ability on asset " + + asset.getName() + + " (platform is not compatible: " + + executionEndpoint.getPlatform().name() + + ")")); + } + } else { + execution.addTrace( + traceError( + "Caldera failed to execute the ability on asset " + + asset.getName() + + " (temporary injector not spawned correctly)")); + } + } catch (Exception e) { + execution.addTrace( + traceError( + "Caldera failed to execute the ability on asset " + + asset.getName() + + " (" + + e.getMessage() + + ")")); + log.severe(Arrays.toString(e.getStackTrace())); + } + }); + }, + () -> execution.addTrace(traceError("Inject does not have a contract"))); if (asyncIds.isEmpty()) { - throw new UnsupportedOperationException("Caldera failed to execute the ability due to above errors"); + throw new UnsupportedOperationException( + "Caldera failed to execute the ability due to above errors"); } List assetGroups = injection.getAssetGroups(); assetGroups.forEach( - (assetGroup -> computeExpectationsForAssetGroup(expectations, content, assetGroup, new ArrayList<>()))); + (assetGroup -> + computeExpectationsForAssetGroup( + expectations, content, assetGroup, new ArrayList<>()))); String message = "Caldera executed the ability on " + asyncIds.size() + " asset(s)"; execution.addTrace(traceInfo(message, asyncIds)); return new ExecutionProcess(true, expectations); @@ -211,14 +286,17 @@ public InjectStatusCommandLine getCommandsLines(String externalId) { Set cleanCommands = new HashSet<>(); Ability ability = calderaService.findAbilityById(externalId); if (ability != null) { - ability.getExecutors().forEach(executor -> { - if (executor.getCommand() != null && !executor.getCommand().isBlank()) { - contents.add(executor.getCommand()); - } - if (executor.getCleanup() != null && !executor.getCleanup().isEmpty()) { - cleanCommands.addAll(executor.getCleanup()); - } - }); + ability + .getExecutors() + .forEach( + executor -> { + if (executor.getCommand() != null && !executor.getCommand().isBlank()) { + contents.add(executor.getCommand()); + } + if (executor.getCleanup() != null && !executor.getCleanup().isEmpty()) { + cleanCommands.addAll(executor.getCleanup()); + } + }); } commandLine.setExternalId(externalId); commandLine.setContent(contents.stream().toList()); @@ -230,25 +308,35 @@ public InjectStatusCommandLine getCommandsLines(String externalId) { private Map resolveAllAssets(@NotNull final ExecutableInject inject) { Map assets = new HashMap<>(); - inject.getAssets().forEach((asset -> { - assets.put(asset, false); - })); - inject.getAssetGroups().forEach((assetGroup -> { - List assetsFromGroup = this.assetGroupService.assetsFromAssetGroup(assetGroup.getId()); - // Verify asset validity - assetsFromGroup.forEach((asset) -> { - assets.put(asset, true); - }); - })); + inject + .getAssets() + .forEach( + (asset -> { + assets.put(asset, false); + })); + inject + .getAssetGroups() + .forEach( + (assetGroup -> { + List assetsFromGroup = + this.assetGroupService.assetsFromAssetGroup(assetGroup.getId()); + // Verify asset validity + assetsFromGroup.forEach( + (asset) -> { + assets.put(asset, true); + }); + })); return assets; } - private Endpoint findAndRegisterAssetForExecution(@NotNull final Inject inject, @NotNull final Asset asset) - throws InterruptedException { + private Endpoint findAndRegisterAssetForExecution( + @NotNull final Inject inject, @NotNull final Asset asset) throws InterruptedException { Endpoint endpointForExecution = null; if (!asset.getType().equals("Endpoint")) { - log.log(Level.SEVERE, - "Caldera failed to execute ability on the asset because type is not supported: " + asset.getType()); + log.log( + Level.SEVERE, + "Caldera failed to execute ability on the asset because type is not supported: " + + asset.getType()); return null; } log.log(Level.INFO, "Trying to find an available executor for " + asset.getName()); @@ -256,19 +344,30 @@ private Endpoint findAndRegisterAssetForExecution(@NotNull final Inject inject, for (int i = 0; i < RETRY_NUMBER; i++) { // Find an executor agent matching the asset log.log(Level.INFO, "Listing agents..."); - List agents = this.calderaService.agents().stream().filter(agent -> - agent.getExe_name().contains("implant") - && (now().toEpochMilli() - Time.toInstant(agent.getCreated()).toEpochMilli()) < Asset.ACTIVE_THRESHOLD - && (agent.getHost().equals(assetEndpoint.getHostname()) || agent.getHost().split("\\.")[0].equals( - assetEndpoint.getHostname().split("\\.")[0])) - && Arrays.stream(assetEndpoint.getIps()) - .anyMatch(s -> Arrays.stream(agent.getHost_ip_addrs()).toList().contains(s)) - ).toList(); + List agents = + this.calderaService.agents().stream() + .filter( + agent -> + agent.getExe_name().contains("implant") + && (now().toEpochMilli() + - Time.toInstant(agent.getCreated()).toEpochMilli()) + < Asset.ACTIVE_THRESHOLD + && (agent.getHost().equals(assetEndpoint.getHostname()) + || agent + .getHost() + .split("\\.")[0] + .equals(assetEndpoint.getHostname().split("\\.")[0])) + && Arrays.stream(assetEndpoint.getIps()) + .anyMatch( + s -> + Arrays.stream(agent.getHost_ip_addrs()).toList().contains(s))) + .toList(); log.log(Level.INFO, "List return with " + agents.size() + " agents"); if (!agents.isEmpty()) { for (Agent agent : agents) { // Check in the database if not exist - Optional resolvedExistingEndpoint = this.endpointService.findByExternalReference(agent.getPaw()); + Optional resolvedExistingEndpoint = + this.endpointService.findByExternalReference(agent.getPaw()); if (resolvedExistingEndpoint.isEmpty()) { log.log(Level.INFO, "Agent found and not present in the database, creating it..."); Endpoint newEndpoint = new Endpoint(); @@ -295,78 +394,156 @@ private Endpoint findAndRegisterAssetForExecution(@NotNull final Inject inject, return endpointForExecution; } - /** - * In case of direct asset, we have an individual expectation for the asset - */ - private void computeExpectationsForAsset(@NotNull final List expectations, - @NotNull final CalderaInjectContent content, @NotNull final Asset asset, final boolean expectationGroup, + /** In case of direct asset, we have an individual expectation for the asset */ + private void computeExpectationsForAsset( + @NotNull final List expectations, + @NotNull final CalderaInjectContent content, + @NotNull final Asset asset, + final boolean expectationGroup, final List injectExpectationSignatures) { if (!content.getExpectations().isEmpty()) { - expectations.addAll(content.getExpectations().stream().flatMap((expectation) -> switch (expectation.getType()) { - case PREVENTION -> Stream.of( - preventionExpectationForAsset(expectation.getScore(), expectation.getName(), expectation.getDescription(), - asset, expectationGroup, expectation.getExpirationTime(), - injectExpectationSignatures)); // expectationGroup usefully in front-end - case DETECTION -> Stream.of( - detectionExpectationForAsset(expectation.getScore(), expectation.getName(), expectation.getDescription(), - asset, expectationGroup, expectation.getExpirationTime(), injectExpectationSignatures)); - case MANUAL -> Stream.of( - manualExpectationForAsset(expectation.getScore(), expectation.getName(), expectation.getDescription(), - asset, expectation.getExpirationTime(), expectationGroup)); - default -> Stream.of(); - }).toList()); + expectations.addAll( + content.getExpectations().stream() + .flatMap( + (expectation) -> + switch (expectation.getType()) { + case PREVENTION -> + Stream.of( + preventionExpectationForAsset( + expectation.getScore(), + expectation.getName(), + expectation.getDescription(), + asset, + expectationGroup, + expectation.getExpirationTime(), + injectExpectationSignatures)); // expectationGroup usefully in + // front-end + case DETECTION -> + Stream.of( + detectionExpectationForAsset( + expectation.getScore(), + expectation.getName(), + expectation.getDescription(), + asset, + expectationGroup, + expectation.getExpirationTime(), + injectExpectationSignatures)); + case MANUAL -> + Stream.of( + manualExpectationForAsset( + expectation.getScore(), + expectation.getName(), + expectation.getDescription(), + asset, + expectation.getExpirationTime(), + expectationGroup)); + default -> Stream.of(); + }) + .toList()); } } /** - * In case of asset group if expectation group -> we have an expectation for the group and one for each asset if not - * expectation group -> we have an individual expectation for each asset + * In case of asset group if expectation group -> we have an expectation for the group and one for + * each asset if not expectation group -> we have an individual expectation for each asset */ - private void computeExpectationsForAssetGroup(@NotNull final List expectations, - @NotNull final CalderaInjectContent content, @NotNull final AssetGroup assetGroup, + private void computeExpectationsForAssetGroup( + @NotNull final List expectations, + @NotNull final CalderaInjectContent content, + @NotNull final AssetGroup assetGroup, final List injectExpectationSignatures) { if (!content.getExpectations().isEmpty()) { - expectations.addAll(content.getExpectations().stream().flatMap((expectation) -> switch (expectation.getType()) { - case PREVENTION -> { - // Verify that at least one asset in the group has been executed - List assets = this.assetGroupService.assetsFromAssetGroup(assetGroup.getId()); - if (assets.stream().anyMatch( - (asset) -> expectations.stream().filter(e -> EXPECTATION_TYPE.PREVENTION == e.type()).anyMatch( - (e) -> ((PreventionExpectation) e).getAsset() != null && ((PreventionExpectation) e).getAsset() - .getId().equals(asset.getId())))) { - yield Stream.of(preventionExpectationForAssetGroup(expectation.getScore(), expectation.getName(), - expectation.getDescription(), assetGroup, expectation.isExpectationGroup(), - expectation.getExpirationTime(), injectExpectationSignatures)); - } - yield Stream.of(); - } - case DETECTION -> { - // Verify that at least one asset in the group has been executed - List assets = this.assetGroupService.assetsFromAssetGroup(assetGroup.getId()); - if (assets.stream().anyMatch( - (asset) -> expectations.stream().filter(e -> EXPECTATION_TYPE.DETECTION == e.type()).anyMatch( - (e) -> ((DetectionExpectation) e).getAsset() != null && ((DetectionExpectation) e).getAsset().getId() - .equals(asset.getId())))) { - yield Stream.of(detectionExpectationForAssetGroup(expectation.getScore(), expectation.getName(), - expectation.getDescription(), assetGroup, expectation.isExpectationGroup(), - expectation.getExpirationTime(), injectExpectationSignatures)); - } - yield Stream.of(); - } - case MANUAL -> { - // Verify that at least one asset in the group has been executed - List assets = this.assetGroupService.assetsFromAssetGroup(assetGroup.getId()); - if (assets.stream().anyMatch((asset) -> expectations.stream().filter(e -> EXPECTATION_TYPE.MANUAL == e.type()) - .anyMatch((e) -> ((ManualExpectation) e).getAsset() != null && ((ManualExpectation) e).getAsset().getId() - .equals(asset.getId())))) { - yield Stream.of(manualExpectationForAssetGroup(expectation.getScore(), expectation.getName(), - expectation.getDescription(), assetGroup, expectation.getExpirationTime(), - expectation.isExpectationGroup())); - } - yield Stream.of(); - } - default -> Stream.of(); - }).toList()); + expectations.addAll( + content.getExpectations().stream() + .flatMap( + (expectation) -> + switch (expectation.getType()) { + case PREVENTION -> { + // Verify that at least one asset in the group has been executed + List assets = + this.assetGroupService.assetsFromAssetGroup(assetGroup.getId()); + if (assets.stream() + .anyMatch( + (asset) -> + expectations.stream() + .filter(e -> EXPECTATION_TYPE.PREVENTION == e.type()) + .anyMatch( + (e) -> + ((PreventionExpectation) e).getAsset() != null + && ((PreventionExpectation) e) + .getAsset() + .getId() + .equals(asset.getId())))) { + yield Stream.of( + preventionExpectationForAssetGroup( + expectation.getScore(), + expectation.getName(), + expectation.getDescription(), + assetGroup, + expectation.isExpectationGroup(), + expectation.getExpirationTime(), + injectExpectationSignatures)); + } + yield Stream.of(); + } + case DETECTION -> { + // Verify that at least one asset in the group has been executed + List assets = + this.assetGroupService.assetsFromAssetGroup(assetGroup.getId()); + if (assets.stream() + .anyMatch( + (asset) -> + expectations.stream() + .filter(e -> EXPECTATION_TYPE.DETECTION == e.type()) + .anyMatch( + (e) -> + ((DetectionExpectation) e).getAsset() != null + && ((DetectionExpectation) e) + .getAsset() + .getId() + .equals(asset.getId())))) { + yield Stream.of( + detectionExpectationForAssetGroup( + expectation.getScore(), + expectation.getName(), + expectation.getDescription(), + assetGroup, + expectation.isExpectationGroup(), + expectation.getExpirationTime(), + injectExpectationSignatures)); + } + yield Stream.of(); + } + case MANUAL -> { + // Verify that at least one asset in the group has been executed + List assets = + this.assetGroupService.assetsFromAssetGroup(assetGroup.getId()); + if (assets.stream() + .anyMatch( + (asset) -> + expectations.stream() + .filter(e -> EXPECTATION_TYPE.MANUAL == e.type()) + .anyMatch( + (e) -> + ((ManualExpectation) e).getAsset() != null + && ((ManualExpectation) e) + .getAsset() + .getId() + .equals(asset.getId())))) { + yield Stream.of( + manualExpectationForAssetGroup( + expectation.getScore(), + expectation.getName(), + expectation.getDescription(), + assetGroup, + expectation.getExpirationTime(), + expectation.isExpectationGroup())); + } + yield Stream.of(); + } + default -> Stream.of(); + }) + .toList()); } } } diff --git a/openbas-api/src/main/java/io/openbas/injectors/caldera/CalderaGarbageCollector.java b/openbas-api/src/main/java/io/openbas/injectors/caldera/CalderaGarbageCollector.java index d489c4a88d..0108a66cef 100644 --- a/openbas-api/src/main/java/io/openbas/injectors/caldera/CalderaGarbageCollector.java +++ b/openbas-api/src/main/java/io/openbas/injectors/caldera/CalderaGarbageCollector.java @@ -5,29 +5,29 @@ import io.openbas.injectors.caldera.config.CalderaInjectorConfig; import io.openbas.injectors.caldera.service.CalderaGarbageCollectorService; import jakarta.annotation.PostConstruct; +import java.time.Duration; import lombok.RequiredArgsConstructor; import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty; import org.springframework.scheduling.concurrent.ThreadPoolTaskScheduler; import org.springframework.stereotype.Service; -import java.time.Duration; - @ConditionalOnProperty(prefix = "executor.caldera", name = "enable") @RequiredArgsConstructor @Service public class CalderaGarbageCollector { - private final CalderaInjectorConfig config; - private final ThreadPoolTaskScheduler taskScheduler; - private final CalderaInjectorClient client; - private final EndpointService endpointService; + private final CalderaInjectorConfig config; + private final ThreadPoolTaskScheduler taskScheduler; + private final CalderaInjectorClient client; + private final EndpointService endpointService; - @PostConstruct - public void init() { - // If enabled, scheduled every X seconds - if (this.config.isEnable()) { - CalderaGarbageCollectorService service = new CalderaGarbageCollectorService(this.client, this.endpointService); - this.taskScheduler.scheduleAtFixedRate(service, Duration.ofSeconds(120)); - } + @PostConstruct + public void init() { + // If enabled, scheduled every X seconds + if (this.config.isEnable()) { + CalderaGarbageCollectorService service = + new CalderaGarbageCollectorService(this.client, this.endpointService); + this.taskScheduler.scheduleAtFixedRate(service, Duration.ofSeconds(120)); } + } } diff --git a/openbas-api/src/main/java/io/openbas/injectors/caldera/CalderaInjector.java b/openbas-api/src/main/java/io/openbas/injectors/caldera/CalderaInjector.java index 85acc7e4e1..5eb366c070 100644 --- a/openbas-api/src/main/java/io/openbas/injectors/caldera/CalderaInjector.java +++ b/openbas-api/src/main/java/io/openbas/injectors/caldera/CalderaInjector.java @@ -4,46 +4,86 @@ import io.openbas.database.model.Endpoint; import io.openbas.injectors.caldera.config.CalderaInjectorConfig; import io.openbas.integrations.InjectorService; -import lombok.extern.java.Log; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.stereotype.Component; - import java.util.Arrays; import java.util.HashMap; import java.util.Map; import java.util.logging.Level; +import lombok.extern.java.Log; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Component; @Component @Log public class CalderaInjector { - private static final String CALDERA_INJECTOR_NAME = "Caldera"; + private static final String CALDERA_INJECTOR_NAME = "Caldera"; - @Autowired - public CalderaInjector(InjectorService injectorService, CalderaContract contract, CalderaInjectorConfig calderaInjectorConfig, OpenBASConfig openBASConfig) { - Map executorCommands = new HashMap<>(); - executorCommands.put(Endpoint.PLATFORM_TYPE.Windows.name() + "." + Endpoint.PLATFORM_ARCH.x86_64, "$x=\"#{location}\";$location=$x.Replace(\"\\obas-agent-caldera.exe\", \"\");[Environment]::CurrentDirectory = $location;$random=-join ((65..90) + (97..122) | Get-Random -Count 5 | % {[char]$_});$filename=\"obas-implant-caldera-$random.exe\";$server=\"" + calderaInjectorConfig.getPublicUrl() + "\";$url=\"" + openBASConfig.getBaseUrl() + "/api/implant/caldera/windows/x86_64\";$wc=New-Object System.Net.WebClient;$data=$wc.DownloadData($url);[io.file]::WriteAllBytes($filename,$data) | Out-Null;Remove-NetFirewallRule -DisplayName \"Allow OpenBAS Inbound\";New-NetFirewallRule -DisplayName \"Allow OpenBAS Inbound\" -Direction Inbound -Program \"$location\\$filename\" -Action Allow | Out-Null;Remove-NetFirewallRule -DisplayName \"Allow OpenBAS Outbound\";New-NetFirewallRule -DisplayName \"Allow OpenBAS Outbound\" -Direction Outbound -Program \"$location\\$filename\" -Action Allow | Out-Null;Start-Process -FilePath \"$location\\$filename\" -ArgumentList \"-server $server -group red\" -WindowStyle hidden;"); - executorCommands.put(Endpoint.PLATFORM_TYPE.Linux.name() + "." + Endpoint.PLATFORM_ARCH.x86_64, "x=\"#{location}\";location=$(echo \"$x\" | sed \"s#/openbas-caldera-agent##\");filename=obas-implant-caldera-$(tr -dc A-Za-z0-9 $location/$filename;chmod +x $location/$filename;$location/$filename -server $server -group red &"); - executorCommands.put(Endpoint.PLATFORM_TYPE.MacOS.name() + "." + Endpoint.PLATFORM_ARCH.x86_64, "x=\"#{location}\";location=$(echo \"$x\" | sed \"s#/openbas-caldera-agent##\");filename=obas-implant-caldera-$(tr -dc A-Za-z0-9 $location/$filename;chmod +x $location/$filename;$location/$filename -server $server -group red &"); - executorCommands.put(Endpoint.PLATFORM_TYPE.MacOS.name() + "." + Endpoint.PLATFORM_ARCH.arm64, "x=\"#{location}\";location=$(echo \"$x\" | sed \"s#/openbas-caldera-agent##\");filename=obas-implant-caldera-$(tr -dc A-Za-z0-9 $location/$filename;chmod +x $location/$filename;$location/$filename -server $server -group red &"); - Map executorClearCommands = new HashMap<>(); - executorClearCommands.put(Endpoint.PLATFORM_TYPE.Windows.name() + "." + Endpoint.PLATFORM_ARCH.x86_64, "$x=\"#{location}\";$location=$x.Replace(\"\\obas-agent-caldera.exe\", \"\");[Environment]::CurrentDirectory = $location;cd \"$location\";Get-ChildItem -Recurse -Filter *implant* | Remove-Item"); - executorClearCommands.put(Endpoint.PLATFORM_TYPE.Linux.name() + "." + Endpoint.PLATFORM_ARCH.x86_64, "x=\"#{location}\";location=$(echo \"$x\" | sed \"s#/openbas-caldera-agent##\");cd \"$location\"; rm *implant*"); - executorClearCommands.put(Endpoint.PLATFORM_TYPE.MacOS.name() + "." + Endpoint.PLATFORM_ARCH.x86_64, "x=\"#{location}\";location=$(echo \"$x\" | sed \"s#/openbas-caldera-agent##\");cd \"$location\"; rm *implant*"); - executorClearCommands.put(Endpoint.PLATFORM_TYPE.MacOS.name() + "." + Endpoint.PLATFORM_ARCH.arm64, "x=\"#{location}\";location=$(echo \"$x\" | sed \"s#/openbas-caldera-agent##\");cd \"$location\"; rm *implant*"); - try { - injectorService.register( - calderaInjectorConfig.getId(), - CALDERA_INJECTOR_NAME, - contract, - false, - "simulation-implant", - executorCommands, - executorClearCommands, - false - ); - } catch (Exception e) { - log.log(Level.SEVERE, "Error creating Caldera injector (" + e.getMessage() + ")" + "\n" + Arrays.toString(e.getStackTrace())); - } + @Autowired + public CalderaInjector( + InjectorService injectorService, + CalderaContract contract, + CalderaInjectorConfig calderaInjectorConfig, + OpenBASConfig openBASConfig) { + Map executorCommands = new HashMap<>(); + executorCommands.put( + Endpoint.PLATFORM_TYPE.Windows.name() + "." + Endpoint.PLATFORM_ARCH.x86_64, + "$x=\"#{location}\";$location=$x.Replace(\"\\obas-agent-caldera.exe\", \"\");[Environment]::CurrentDirectory = $location;$random=-join ((65..90) + (97..122) | Get-Random -Count 5 | % {[char]$_});$filename=\"obas-implant-caldera-$random.exe\";$server=\"" + + calderaInjectorConfig.getPublicUrl() + + "\";$url=\"" + + openBASConfig.getBaseUrl() + + "/api/implant/caldera/windows/x86_64\";$wc=New-Object System.Net.WebClient;$data=$wc.DownloadData($url);[io.file]::WriteAllBytes($filename,$data) | Out-Null;Remove-NetFirewallRule -DisplayName \"Allow OpenBAS Inbound\";New-NetFirewallRule -DisplayName \"Allow OpenBAS Inbound\" -Direction Inbound -Program \"$location\\$filename\" -Action Allow | Out-Null;Remove-NetFirewallRule -DisplayName \"Allow OpenBAS Outbound\";New-NetFirewallRule -DisplayName \"Allow OpenBAS Outbound\" -Direction Outbound -Program \"$location\\$filename\" -Action Allow | Out-Null;Start-Process -FilePath \"$location\\$filename\" -ArgumentList \"-server $server -group red\" -WindowStyle hidden;"); + executorCommands.put( + Endpoint.PLATFORM_TYPE.Linux.name() + "." + Endpoint.PLATFORM_ARCH.x86_64, + "x=\"#{location}\";location=$(echo \"$x\" | sed \"s#/openbas-caldera-agent##\");filename=obas-implant-caldera-$(tr -dc A-Za-z0-9 $location/$filename;chmod +x $location/$filename;$location/$filename -server $server -group red &"); + executorCommands.put( + Endpoint.PLATFORM_TYPE.MacOS.name() + "." + Endpoint.PLATFORM_ARCH.x86_64, + "x=\"#{location}\";location=$(echo \"$x\" | sed \"s#/openbas-caldera-agent##\");filename=obas-implant-caldera-$(tr -dc A-Za-z0-9 $location/$filename;chmod +x $location/$filename;$location/$filename -server $server -group red &"); + executorCommands.put( + Endpoint.PLATFORM_TYPE.MacOS.name() + "." + Endpoint.PLATFORM_ARCH.arm64, + "x=\"#{location}\";location=$(echo \"$x\" | sed \"s#/openbas-caldera-agent##\");filename=obas-implant-caldera-$(tr -dc A-Za-z0-9 $location/$filename;chmod +x $location/$filename;$location/$filename -server $server -group red &"); + Map executorClearCommands = new HashMap<>(); + executorClearCommands.put( + Endpoint.PLATFORM_TYPE.Windows.name() + "." + Endpoint.PLATFORM_ARCH.x86_64, + "$x=\"#{location}\";$location=$x.Replace(\"\\obas-agent-caldera.exe\", \"\");[Environment]::CurrentDirectory = $location;cd \"$location\";Get-ChildItem -Recurse -Filter *implant* | Remove-Item"); + executorClearCommands.put( + Endpoint.PLATFORM_TYPE.Linux.name() + "." + Endpoint.PLATFORM_ARCH.x86_64, + "x=\"#{location}\";location=$(echo \"$x\" | sed \"s#/openbas-caldera-agent##\");cd \"$location\"; rm *implant*"); + executorClearCommands.put( + Endpoint.PLATFORM_TYPE.MacOS.name() + "." + Endpoint.PLATFORM_ARCH.x86_64, + "x=\"#{location}\";location=$(echo \"$x\" | sed \"s#/openbas-caldera-agent##\");cd \"$location\"; rm *implant*"); + executorClearCommands.put( + Endpoint.PLATFORM_TYPE.MacOS.name() + "." + Endpoint.PLATFORM_ARCH.arm64, + "x=\"#{location}\";location=$(echo \"$x\" | sed \"s#/openbas-caldera-agent##\");cd \"$location\"; rm *implant*"); + try { + injectorService.register( + calderaInjectorConfig.getId(), + CALDERA_INJECTOR_NAME, + contract, + false, + "simulation-implant", + executorCommands, + executorClearCommands, + false); + } catch (Exception e) { + log.log( + Level.SEVERE, + "Error creating Caldera injector (" + + e.getMessage() + + ")" + + "\n" + + Arrays.toString(e.getStackTrace())); } + } } diff --git a/openbas-api/src/main/java/io/openbas/injectors/caldera/CalderaResultCollector.java b/openbas-api/src/main/java/io/openbas/injectors/caldera/CalderaResultCollector.java index e180a86037..f278234c81 100644 --- a/openbas-api/src/main/java/io/openbas/injectors/caldera/CalderaResultCollector.java +++ b/openbas-api/src/main/java/io/openbas/injectors/caldera/CalderaResultCollector.java @@ -6,30 +6,31 @@ import io.openbas.injectors.caldera.service.CalderaInjectorService; import io.openbas.injectors.caldera.service.CalderaResultCollectorService; import jakarta.annotation.PostConstruct; +import java.time.Duration; import lombok.RequiredArgsConstructor; import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty; import org.springframework.scheduling.concurrent.ThreadPoolTaskScheduler; import org.springframework.stereotype.Service; -import java.time.Duration; - @ConditionalOnProperty(prefix = "executor.caldera", name = "enable") @RequiredArgsConstructor @Service public class CalderaResultCollector { - private final CalderaInjectorConfig config; - private final ThreadPoolTaskScheduler taskScheduler; - private final InjectRepository injectRepository; - private final InjectStatusRepository injectStatusRepository; - private final CalderaInjectorService calderaService; + private final CalderaInjectorConfig config; + private final ThreadPoolTaskScheduler taskScheduler; + private final InjectRepository injectRepository; + private final InjectStatusRepository injectStatusRepository; + private final CalderaInjectorService calderaService; - @PostConstruct - public void init() { - // If enabled, scheduled every X seconds - if (this.config.isEnable()) { - CalderaResultCollectorService service = new CalderaResultCollectorService(this.injectRepository, this.injectStatusRepository, this.calderaService); - this.taskScheduler.scheduleAtFixedRate(service, Duration.ofSeconds(60)); - } + @PostConstruct + public void init() { + // If enabled, scheduled every X seconds + if (this.config.isEnable()) { + CalderaResultCollectorService service = + new CalderaResultCollectorService( + this.injectRepository, this.injectStatusRepository, this.calderaService); + this.taskScheduler.scheduleAtFixedRate(service, Duration.ofSeconds(60)); } + } } diff --git a/openbas-api/src/main/java/io/openbas/injectors/caldera/client/CalderaInjectorClient.java b/openbas-api/src/main/java/io/openbas/injectors/caldera/client/CalderaInjectorClient.java index a66074c774..be184d85c0 100644 --- a/openbas-api/src/main/java/io/openbas/injectors/caldera/client/CalderaInjectorClient.java +++ b/openbas-api/src/main/java/io/openbas/injectors/caldera/client/CalderaInjectorClient.java @@ -10,6 +10,10 @@ import io.openbas.injectors.caldera.model.Obfuscator; import jakarta.validation.constraints.NotBlank; import jakarta.validation.constraints.NotNull; +import java.io.IOException; +import java.util.HashMap; +import java.util.List; +import java.util.Map; import lombok.RequiredArgsConstructor; import lombok.extern.java.Log; import org.apache.hc.client5.http.ClientProtocolException; @@ -24,252 +28,227 @@ import org.springframework.stereotype.Service; import org.springframework.util.StringUtils; -import java.io.IOException; -import java.util.HashMap; -import java.util.List; -import java.util.Map; - @RequiredArgsConstructor @Service @Log public class CalderaInjectorClient { - private static final String KEY_HEADER = "KEY"; - - private final CalderaInjectorConfig config; - private final ObjectMapper objectMapper = new ObjectMapper(); - - // -- ABILITIES -- - - private final static String ABILITIES_URI = "/abilities"; + private static final String KEY_HEADER = "KEY"; + + private final CalderaInjectorConfig config; + private final ObjectMapper objectMapper = new ObjectMapper(); + + // -- ABILITIES -- + + private static final String ABILITIES_URI = "/abilities"; + + public List abilities() { + try { + String jsonResponse = this.get(this.config.getRestApiV2Url() + ABILITIES_URI); + return this.objectMapper.readValue(jsonResponse, new TypeReference<>() {}); + } catch (IOException e) { + throw new RuntimeException(e); + } + } - public List abilities() { - try { - String jsonResponse = this.get(this.config.getRestApiV2Url() + ABILITIES_URI); - return this.objectMapper.readValue(jsonResponse, new TypeReference<>() { - }); - } catch (IOException e) { - throw new RuntimeException(e); - } - } - - public Ability findAbilityById(String abilityId) { - try { - String jsonResponse = this.get(this.config.getRestApiV2Url() + ABILITIES_URI + "/" + abilityId); - return this.objectMapper.readValue(jsonResponse, new TypeReference<>() { - }); - } catch (IOException e) { - throw new RuntimeException(e); - } - } - - public Ability createAbility(Map body) { - try { - String jsonResponse = this.post( - this.config.getRestApiV2Url() + ABILITIES_URI, - body - ); - return this.objectMapper.readValue(jsonResponse, new TypeReference<>() { - }); - } catch (IOException e) { - throw new RuntimeException(e); - } - } - - public void deleteAbility(Ability ability) { - try { - this.delete(this.config.getRestApiV2Url() + ABILITIES_URI + "/" + ability.getAbility_id()); - } catch (IOException e) { - throw new RuntimeException(e); - } - } - - // -- AGENTS -- - - private final static String AGENT_URI = "/agents"; + public Ability findAbilityById(String abilityId) { + try { + String jsonResponse = + this.get(this.config.getRestApiV2Url() + ABILITIES_URI + "/" + abilityId); + return this.objectMapper.readValue(jsonResponse, new TypeReference<>() {}); + } catch (IOException e) { + throw new RuntimeException(e); + } + } + + public Ability createAbility(Map body) { + try { + String jsonResponse = this.post(this.config.getRestApiV2Url() + ABILITIES_URI, body); + return this.objectMapper.readValue(jsonResponse, new TypeReference<>() {}); + } catch (IOException e) { + throw new RuntimeException(e); + } + } + + public void deleteAbility(Ability ability) { + try { + this.delete(this.config.getRestApiV2Url() + ABILITIES_URI + "/" + ability.getAbility_id()); + } catch (IOException e) { + throw new RuntimeException(e); + } + } - public List agents() { - try { - String jsonResponse = this.get(this.config.getRestApiV2Url() + AGENT_URI); - return this.objectMapper.readValue(jsonResponse, new TypeReference<>() { - }); - } catch (IOException e) { - log.severe("Cannot retrieve agent list"); - throw new RuntimeException(e); - } - } - - public Agent agent(@NotBlank final String paw, final String include) { - try { - String url = this.config.getRestApiV2Url() + AGENT_URI + "/" + paw; - if (StringUtils.hasText(include)) { - url = url + "?include=" + include; - } - String jsonResponse = this.get(url); - return this.objectMapper.readValue(jsonResponse, new TypeReference<>() { - }); - } catch (IOException e) { - throw new RuntimeException(e); - } - } + // -- AGENTS -- - public void killAgent(Endpoint endpoint) { - try { - Map body = new HashMap<>(); - body.put("watchdog", 1); - body.put("sleep_min", 3); - body.put("sleep_max", 3); - this.patch(this.config.getRestApiV2Url() + AGENT_URI + "/" + endpoint.getExternalReference(), body); - } catch (IOException e) { - throw new RuntimeException(e); - } - } - - public void killAgent(Agent agent) { - try { - Map body = new HashMap<>(); - body.put("watchdog", 1); - body.put("sleep_min", 3); - body.put("sleep_max", 3); - this.patch(this.config.getRestApiV2Url() + AGENT_URI + "/" + agent.getPaw(), body); - } catch (IOException e) { - throw new RuntimeException(e); - } - } - - public void deleteAgent(Endpoint endpoint) { - try { - this.delete(this.config.getRestApiV2Url() + AGENT_URI + "/" + endpoint.getExternalReference()); - } catch (IOException e) { - throw new RuntimeException(e); - } - } - - public void deleteAgent(Agent agent) { - try { - this.delete(this.config.getRestApiV2Url() + AGENT_URI + "/" + agent.getPaw()); - } catch (IOException e) { - throw new RuntimeException(e); - } - } - - // -- OBFUSCATORS -- - - private final static String OBFUSCATOR_URI = "/obfuscators"; - - public List obfuscators() { - try { - String jsonResponse = this.get(this.config.getRestApiV2Url() + OBFUSCATOR_URI); - return this.objectMapper.readValue(jsonResponse, new TypeReference<>() { - }); - } catch (IOException e) { - throw new RuntimeException(e); - } - } - - // -- RESULTS -- - - private final static String RESULT_INDEX = "result"; - - public Result results(@NotBlank final String linkId) { - try { - Map body = new HashMap<>(); - body.put("index", RESULT_INDEX); - body.put("link_id", linkId); - String jsonResponse = this.post(this.config.getRestApiV1Url(), body); - return this.objectMapper.readValue(jsonResponse, new TypeReference<>() { - }); - } catch (IOException e) { - throw new RuntimeException(e); - } - } - - // -- PLUGIN ACCESS -- - - private final static String EXPLOIT_URI = "/exploit"; - - public String exploit( - @NotBlank final String obfuscator, - @NotBlank final String paw, - @NotBlank final String abilityId, - final List> additionalFields - ) { - try { - Map body = new HashMap<>(); - body.put("obfuscator", obfuscator); - body.put("paw", paw); - body.put("ability_id", abilityId); - body.put("facts", additionalFields); - return this.post( - this.config.getPluginAccessApiUrl() + EXPLOIT_URI, - body - ); - } catch (IOException e) { - throw new RuntimeException(e); - } - } - - // -- PRIVATE -- - - private String get(@NotBlank final String url) throws IOException { - try (CloseableHttpClient httpClient = HttpClients.createDefault()) { - HttpGet httpGet = new HttpGet(url); - // Headers - httpGet.addHeader(KEY_HEADER, this.config.getApiKey()); - return httpClient.execute( - httpGet, - response -> EntityUtils.toString(response.getEntity()) - ); - } catch (IOException e) { - throw new ClientProtocolException("Unexpected response for request on: " + url); - } - } - - private String post( - @NotBlank final String url, - @NotNull final Map body) throws IOException { - try (CloseableHttpClient httpClient = HttpClients.createDefault()) { - HttpPost httpPost = new HttpPost(url); - // Headers - httpPost.addHeader(KEY_HEADER, this.config.getApiKey()); - // Body - StringEntity entity = new StringEntity(this.objectMapper.writeValueAsString(body)); - httpPost.setEntity(entity); - - return httpClient.execute( - httpPost, - response -> EntityUtils.toString(response.getEntity()) - ); - } catch (IOException e) { - throw new ClientProtocolException("Unexpected response for request on: " + url); - } - } - - private void patch( - @NotBlank final String url, - @NotNull final Map body) throws IOException { - try (CloseableHttpClient httpClient = HttpClients.createDefault()) { - HttpPatch httpPatch = new HttpPatch(url); - // Headers - httpPatch.addHeader(KEY_HEADER, this.config.getApiKey()); - // Body - StringEntity entity = new StringEntity(this.objectMapper.writeValueAsString(body)); - httpPatch.setEntity(entity); - httpClient.execute(httpPatch); - } catch (IOException e) { - throw new ClientProtocolException("Unexpected response for request on: " + url); - } - } - - private void delete(@NotBlank final String url) throws IOException { - try (CloseableHttpClient httpClient = HttpClients.createDefault()) { - HttpDelete httpdelete = new HttpDelete(url); - // Headers - httpdelete.addHeader(KEY_HEADER, this.config.getApiKey()); - httpClient.execute(httpdelete); - } catch (IOException e) { - throw new ClientProtocolException("Unexpected response for request on: " + url); - } - } + private static final String AGENT_URI = "/agents"; + public List agents() { + try { + String jsonResponse = this.get(this.config.getRestApiV2Url() + AGENT_URI); + return this.objectMapper.readValue(jsonResponse, new TypeReference<>() {}); + } catch (IOException e) { + log.severe("Cannot retrieve agent list"); + throw new RuntimeException(e); + } + } + + public Agent agent(@NotBlank final String paw, final String include) { + try { + String url = this.config.getRestApiV2Url() + AGENT_URI + "/" + paw; + if (StringUtils.hasText(include)) { + url = url + "?include=" + include; + } + String jsonResponse = this.get(url); + return this.objectMapper.readValue(jsonResponse, new TypeReference<>() {}); + } catch (IOException e) { + throw new RuntimeException(e); + } + } + + public void killAgent(Endpoint endpoint) { + try { + Map body = new HashMap<>(); + body.put("watchdog", 1); + body.put("sleep_min", 3); + body.put("sleep_max", 3); + this.patch( + this.config.getRestApiV2Url() + AGENT_URI + "/" + endpoint.getExternalReference(), body); + } catch (IOException e) { + throw new RuntimeException(e); + } + } + + public void killAgent(Agent agent) { + try { + Map body = new HashMap<>(); + body.put("watchdog", 1); + body.put("sleep_min", 3); + body.put("sleep_max", 3); + this.patch(this.config.getRestApiV2Url() + AGENT_URI + "/" + agent.getPaw(), body); + } catch (IOException e) { + throw new RuntimeException(e); + } + } + + public void deleteAgent(Endpoint endpoint) { + try { + this.delete( + this.config.getRestApiV2Url() + AGENT_URI + "/" + endpoint.getExternalReference()); + } catch (IOException e) { + throw new RuntimeException(e); + } + } + + public void deleteAgent(Agent agent) { + try { + this.delete(this.config.getRestApiV2Url() + AGENT_URI + "/" + agent.getPaw()); + } catch (IOException e) { + throw new RuntimeException(e); + } + } + + // -- OBFUSCATORS -- + + private static final String OBFUSCATOR_URI = "/obfuscators"; + + public List obfuscators() { + try { + String jsonResponse = this.get(this.config.getRestApiV2Url() + OBFUSCATOR_URI); + return this.objectMapper.readValue(jsonResponse, new TypeReference<>() {}); + } catch (IOException e) { + throw new RuntimeException(e); + } + } + + // -- RESULTS -- + + private static final String RESULT_INDEX = "result"; + + public Result results(@NotBlank final String linkId) { + try { + Map body = new HashMap<>(); + body.put("index", RESULT_INDEX); + body.put("link_id", linkId); + String jsonResponse = this.post(this.config.getRestApiV1Url(), body); + return this.objectMapper.readValue(jsonResponse, new TypeReference<>() {}); + } catch (IOException e) { + throw new RuntimeException(e); + } + } + + // -- PLUGIN ACCESS -- + + private static final String EXPLOIT_URI = "/exploit"; + + public String exploit( + @NotBlank final String obfuscator, + @NotBlank final String paw, + @NotBlank final String abilityId, + final List> additionalFields) { + try { + Map body = new HashMap<>(); + body.put("obfuscator", obfuscator); + body.put("paw", paw); + body.put("ability_id", abilityId); + body.put("facts", additionalFields); + return this.post(this.config.getPluginAccessApiUrl() + EXPLOIT_URI, body); + } catch (IOException e) { + throw new RuntimeException(e); + } + } + + // -- PRIVATE -- + + private String get(@NotBlank final String url) throws IOException { + try (CloseableHttpClient httpClient = HttpClients.createDefault()) { + HttpGet httpGet = new HttpGet(url); + // Headers + httpGet.addHeader(KEY_HEADER, this.config.getApiKey()); + return httpClient.execute(httpGet, response -> EntityUtils.toString(response.getEntity())); + } catch (IOException e) { + throw new ClientProtocolException("Unexpected response for request on: " + url); + } + } + + private String post(@NotBlank final String url, @NotNull final Map body) + throws IOException { + try (CloseableHttpClient httpClient = HttpClients.createDefault()) { + HttpPost httpPost = new HttpPost(url); + // Headers + httpPost.addHeader(KEY_HEADER, this.config.getApiKey()); + // Body + StringEntity entity = new StringEntity(this.objectMapper.writeValueAsString(body)); + httpPost.setEntity(entity); + + return httpClient.execute(httpPost, response -> EntityUtils.toString(response.getEntity())); + } catch (IOException e) { + throw new ClientProtocolException("Unexpected response for request on: " + url); + } + } + + private void patch(@NotBlank final String url, @NotNull final Map body) + throws IOException { + try (CloseableHttpClient httpClient = HttpClients.createDefault()) { + HttpPatch httpPatch = new HttpPatch(url); + // Headers + httpPatch.addHeader(KEY_HEADER, this.config.getApiKey()); + // Body + StringEntity entity = new StringEntity(this.objectMapper.writeValueAsString(body)); + httpPatch.setEntity(entity); + httpClient.execute(httpPatch); + } catch (IOException e) { + throw new ClientProtocolException("Unexpected response for request on: " + url); + } + } + + private void delete(@NotBlank final String url) throws IOException { + try (CloseableHttpClient httpClient = HttpClients.createDefault()) { + HttpDelete httpdelete = new HttpDelete(url); + // Headers + httpdelete.addHeader(KEY_HEADER, this.config.getApiKey()); + httpClient.execute(httpdelete); + } catch (IOException e) { + throw new ClientProtocolException("Unexpected response for request on: " + url); + } + } } diff --git a/openbas-api/src/main/java/io/openbas/injectors/caldera/client/model/Ability.java b/openbas-api/src/main/java/io/openbas/injectors/caldera/client/model/Ability.java index 22c64bb263..6e5e53a7cf 100644 --- a/openbas-api/src/main/java/io/openbas/injectors/caldera/client/model/Ability.java +++ b/openbas-api/src/main/java/io/openbas/injectors/caldera/client/model/Ability.java @@ -1,9 +1,8 @@ package io.openbas.injectors.caldera.client.model; import com.fasterxml.jackson.annotation.JsonIgnoreProperties; -import lombok.Data; - import java.util.List; +import lombok.Data; @Data @JsonIgnoreProperties(ignoreUnknown = true) @@ -16,5 +15,4 @@ public class Ability { private String name; private String description; private List executors; - } diff --git a/openbas-api/src/main/java/io/openbas/injectors/caldera/client/model/Agent.java b/openbas-api/src/main/java/io/openbas/injectors/caldera/client/model/Agent.java index d6c4b811ff..d0bb51e654 100644 --- a/openbas-api/src/main/java/io/openbas/injectors/caldera/client/model/Agent.java +++ b/openbas-api/src/main/java/io/openbas/injectors/caldera/client/model/Agent.java @@ -1,10 +1,9 @@ package io.openbas.injectors.caldera.client.model; import com.fasterxml.jackson.annotation.JsonIgnoreProperties; -import lombok.Data; - import java.util.ArrayList; import java.util.List; +import lombok.Data; @Data @JsonIgnoreProperties(ignoreUnknown = true) @@ -20,5 +19,4 @@ public class Agent { private String[] host_ip_addrs; private String exe_name; private List links = new ArrayList<>(); - } diff --git a/openbas-api/src/main/java/io/openbas/injectors/caldera/client/model/Executor.java b/openbas-api/src/main/java/io/openbas/injectors/caldera/client/model/Executor.java index 8bd4e61a8a..66e5a44c9d 100644 --- a/openbas-api/src/main/java/io/openbas/injectors/caldera/client/model/Executor.java +++ b/openbas-api/src/main/java/io/openbas/injectors/caldera/client/model/Executor.java @@ -1,9 +1,8 @@ package io.openbas.injectors.caldera.client.model; import com.fasterxml.jackson.annotation.JsonIgnoreProperties; -import lombok.Data; - import java.util.List; +import lombok.Data; @Data @JsonIgnoreProperties(ignoreUnknown = true) diff --git a/openbas-api/src/main/java/io/openbas/injectors/caldera/client/model/ExploitResult.java b/openbas-api/src/main/java/io/openbas/injectors/caldera/client/model/ExploitResult.java index 111a5e241b..4dc668214a 100644 --- a/openbas-api/src/main/java/io/openbas/injectors/caldera/client/model/ExploitResult.java +++ b/openbas-api/src/main/java/io/openbas/injectors/caldera/client/model/ExploitResult.java @@ -9,5 +9,4 @@ public class ExploitResult { private String linkId; private String command; - } diff --git a/openbas-api/src/main/java/io/openbas/injectors/caldera/client/model/Fact.java b/openbas-api/src/main/java/io/openbas/injectors/caldera/client/model/Fact.java index c9c1826984..8a2ff072ac 100644 --- a/openbas-api/src/main/java/io/openbas/injectors/caldera/client/model/Fact.java +++ b/openbas-api/src/main/java/io/openbas/injectors/caldera/client/model/Fact.java @@ -9,5 +9,4 @@ public class Fact { private String name; private String value; - } diff --git a/openbas-api/src/main/java/io/openbas/injectors/caldera/client/model/Link.java b/openbas-api/src/main/java/io/openbas/injectors/caldera/client/model/Link.java index 26e817399b..9aaa91ea16 100644 --- a/openbas-api/src/main/java/io/openbas/injectors/caldera/client/model/Link.java +++ b/openbas-api/src/main/java/io/openbas/injectors/caldera/client/model/Link.java @@ -14,5 +14,4 @@ public class Link { private Ability ability; private String finish; private String command; - } diff --git a/openbas-api/src/main/java/io/openbas/injectors/caldera/client/model/Result.java b/openbas-api/src/main/java/io/openbas/injectors/caldera/client/model/Result.java index 8aca59bf3f..61888abb88 100644 --- a/openbas-api/src/main/java/io/openbas/injectors/caldera/client/model/Result.java +++ b/openbas-api/src/main/java/io/openbas/injectors/caldera/client/model/Result.java @@ -9,5 +9,4 @@ public class Result { private Link link; private String output; - } diff --git a/openbas-api/src/main/java/io/openbas/injectors/caldera/config/CalderaInjectorConfig.java b/openbas-api/src/main/java/io/openbas/injectors/caldera/config/CalderaInjectorConfig.java index 82ed303b76..f51585e2fd 100644 --- a/openbas-api/src/main/java/io/openbas/injectors/caldera/config/CalderaInjectorConfig.java +++ b/openbas-api/src/main/java/io/openbas/injectors/caldera/config/CalderaInjectorConfig.java @@ -13,27 +13,19 @@ public class CalderaInjectorConfig { public static final String PRODUCT_NAME = "Caldera"; - private final static String REST_V1_URI = "/api/rest"; - private final static String REST_V2_URI = "/api/v2"; - private final static String PLUGIN_ACCESS_URI = "/plugin/access"; + private static final String REST_V1_URI = "/api/rest"; + private static final String REST_V2_URI = "/api/v2"; + private static final String PLUGIN_ACCESS_URI = "/plugin/access"; - @Getter - private boolean enable; + @Getter private boolean enable; - @Getter - @NotBlank - private String id; + @Getter @NotBlank private String id; - @NotBlank - private String url; + @NotBlank private String url; - @Getter - @NotBlank - private String publicUrl; + @Getter @NotBlank private String publicUrl; - @Getter - @NotBlank - private String apiKey; + @Getter @NotBlank private String apiKey; public String getRestApiV1Url() { return url + REST_V1_URI; diff --git a/openbas-api/src/main/java/io/openbas/injectors/caldera/model/CalderaInjectContent.java b/openbas-api/src/main/java/io/openbas/injectors/caldera/model/CalderaInjectContent.java index 8820031f44..7b7fd74588 100644 --- a/openbas-api/src/main/java/io/openbas/injectors/caldera/model/CalderaInjectContent.java +++ b/openbas-api/src/main/java/io/openbas/injectors/caldera/model/CalderaInjectContent.java @@ -2,11 +2,10 @@ import com.fasterxml.jackson.annotation.JsonProperty; import io.openbas.model.inject.form.Expectation; -import lombok.Getter; -import lombok.Setter; - import java.util.ArrayList; import java.util.List; +import lombok.Getter; +import lombok.Setter; @Getter @Setter @@ -17,5 +16,4 @@ public class CalderaInjectContent { @JsonProperty("expectations") private List expectations = new ArrayList<>(); - } diff --git a/openbas-api/src/main/java/io/openbas/injectors/caldera/model/Obfuscator.java b/openbas-api/src/main/java/io/openbas/injectors/caldera/model/Obfuscator.java index f7e692c539..69a179f259 100644 --- a/openbas-api/src/main/java/io/openbas/injectors/caldera/model/Obfuscator.java +++ b/openbas-api/src/main/java/io/openbas/injectors/caldera/model/Obfuscator.java @@ -7,5 +7,4 @@ public class Obfuscator { private String name; private String description; - } diff --git a/openbas-api/src/main/java/io/openbas/injectors/caldera/model/ResultStatus.java b/openbas-api/src/main/java/io/openbas/injectors/caldera/model/ResultStatus.java index b27dae766a..97abf70efa 100644 --- a/openbas-api/src/main/java/io/openbas/injectors/caldera/model/ResultStatus.java +++ b/openbas-api/src/main/java/io/openbas/injectors/caldera/model/ResultStatus.java @@ -1,8 +1,7 @@ package io.openbas.injectors.caldera.model; -import lombok.Data; - import java.time.Instant; +import lombok.Data; @Data public class ResultStatus { @@ -12,5 +11,4 @@ public class ResultStatus { private boolean fail; private Instant finish; private String content; - } diff --git a/openbas-api/src/main/java/io/openbas/injectors/caldera/service/CalderaGarbageCollectorService.java b/openbas-api/src/main/java/io/openbas/injectors/caldera/service/CalderaGarbageCollectorService.java index 2e89c6eefd..892a583c36 100644 --- a/openbas-api/src/main/java/io/openbas/injectors/caldera/service/CalderaGarbageCollectorService.java +++ b/openbas-api/src/main/java/io/openbas/injectors/caldera/service/CalderaGarbageCollectorService.java @@ -1,91 +1,89 @@ package io.openbas.injectors.caldera.service; -import com.fasterxml.jackson.core.JsonProcessingException; +import static java.time.Instant.now; + import io.openbas.asset.EndpointService; import io.openbas.database.model.Endpoint; import io.openbas.database.specification.EndpointSpecification; import io.openbas.injectors.caldera.client.CalderaInjectorClient; import io.openbas.injectors.caldera.client.model.Agent; -import io.openbas.injectors.caldera.config.CalderaInjectorConfig; import io.openbas.utils.Time; import jakarta.validation.constraints.NotBlank; -import jakarta.validation.constraints.NotNull; +import java.util.ArrayList; +import java.util.List; import lombok.extern.java.Log; -import org.apache.hc.client5.http.ClientProtocolException; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Service; -import java.time.Instant; -import java.time.LocalDateTime; -import java.time.ZonedDateTime; -import java.time.format.DateTimeFormatter; -import java.util.ArrayList; -import java.util.List; -import java.util.Locale; - -import static java.time.Instant.now; -import static java.time.ZoneOffset.UTC; - @Log @Service public class CalderaGarbageCollectorService implements Runnable { - private final int KILL_TTL = 900000; // 15 min - private final int DELETE_TTL = 1200000; // 20 min + private final int KILL_TTL = 900000; // 15 min + private final int DELETE_TTL = 1200000; // 20 min - private final CalderaInjectorClient client; - private final EndpointService endpointService; + private final CalderaInjectorClient client; + private final EndpointService endpointService; - public static Endpoint.PLATFORM_TYPE toPlatform(@NotBlank final String platform) { - return switch (platform) { - case "linux" -> Endpoint.PLATFORM_TYPE.Linux; - case "windows" -> Endpoint.PLATFORM_TYPE.Windows; - case "darwin" -> Endpoint.PLATFORM_TYPE.MacOS; - default -> throw new IllegalArgumentException("This platform is not supported : " + platform); - }; - } + public static Endpoint.PLATFORM_TYPE toPlatform(@NotBlank final String platform) { + return switch (platform) { + case "linux" -> Endpoint.PLATFORM_TYPE.Linux; + case "windows" -> Endpoint.PLATFORM_TYPE.Windows; + case "darwin" -> Endpoint.PLATFORM_TYPE.MacOS; + default -> throw new IllegalArgumentException("This platform is not supported : " + platform); + }; + } - @Autowired - public CalderaGarbageCollectorService( - CalderaInjectorClient client, - EndpointService endpointService - ) { - this.client = client; - this.endpointService = endpointService; - } + @Autowired + public CalderaGarbageCollectorService( + CalderaInjectorClient client, EndpointService endpointService) { + this.client = client; + this.endpointService = endpointService; + } - @Override - public void run() { - log.info("Running Caldera injector garbage collector..."); - List endpoints = this.endpointService.endpoints(EndpointSpecification.findEndpointsForExecution()); - log.info("Running Caldera injector garbage collector on " + endpoints.size() + " endpoints"); - endpoints.forEach(endpoint -> { - if ((now().toEpochMilli() - endpoint.getCreatedAt().toEpochMilli()) > DELETE_TTL) { - this.endpointService.deleteEndpoint(endpoint.getId()); - } + @Override + public void run() { + log.info("Running Caldera injector garbage collector..."); + List endpoints = + this.endpointService.endpoints(EndpointSpecification.findEndpointsForExecution()); + log.info("Running Caldera injector garbage collector on " + endpoints.size() + " endpoints"); + endpoints.forEach( + endpoint -> { + if ((now().toEpochMilli() - endpoint.getCreatedAt().toEpochMilli()) > DELETE_TTL) { + this.endpointService.deleteEndpoint(endpoint.getId()); + } }); - List agents = this.client.agents(); - log.info("Running Caldera injector garbage collector on " + agents.size() + " agents"); - List killedAgents = new ArrayList<>(); - agents.forEach(agent -> { - if (agent.getExe_name().contains("implant") && (now().toEpochMilli() - Time.toInstant(agent.getCreated()).toEpochMilli()) > KILL_TTL && (now().toEpochMilli() - Time.toInstant(agent.getLast_seen()).toEpochMilli()) < KILL_TTL) { - try { - log.info("Killing agent " + agent.getHost()); - client.killAgent(agent); - killedAgents.add(agent.getPaw()); - } catch (RuntimeException e) { - log.info("Failed to kill agent, probably already killed"); - } + List agents = this.client.agents(); + log.info("Running Caldera injector garbage collector on " + agents.size() + " agents"); + List killedAgents = new ArrayList<>(); + agents.forEach( + agent -> { + if (agent.getExe_name().contains("implant") + && (now().toEpochMilli() - Time.toInstant(agent.getCreated()).toEpochMilli()) + > KILL_TTL + && (now().toEpochMilli() - Time.toInstant(agent.getLast_seen()).toEpochMilli()) + < KILL_TTL) { + try { + log.info("Killing agent " + agent.getHost()); + client.killAgent(agent); + killedAgents.add(agent.getPaw()); + } catch (RuntimeException e) { + log.info("Failed to kill agent, probably already killed"); } + } }); - agents.forEach(agent -> { - if (agent.getExe_name().contains("implant") && (now().toEpochMilli() - Time.toInstant(agent.getCreated()).toEpochMilli()) > DELETE_TTL && !killedAgents.contains(agent.getPaw())) { - try { - log.info("Deleting agent " + agent.getHost()); - client.deleteAgent(agent); - } catch (RuntimeException e) { - log.severe("Failed to delete agent"); - } + agents.forEach( + agent -> { + if (agent.getExe_name().contains("implant") + && (now().toEpochMilli() - Time.toInstant(agent.getCreated()).toEpochMilli()) + > DELETE_TTL + && !killedAgents.contains(agent.getPaw())) { + try { + log.info("Deleting agent " + agent.getHost()); + client.deleteAgent(agent); + } catch (RuntimeException e) { + log.severe("Failed to delete agent"); } + } }); - } + } } diff --git a/openbas-api/src/main/java/io/openbas/injectors/caldera/service/CalderaInjectorService.java b/openbas-api/src/main/java/io/openbas/injectors/caldera/service/CalderaInjectorService.java index bcaeb77b50..8ef4698bc4 100644 --- a/openbas-api/src/main/java/io/openbas/injectors/caldera/service/CalderaInjectorService.java +++ b/openbas-api/src/main/java/io/openbas/injectors/caldera/service/CalderaInjectorService.java @@ -1,5 +1,7 @@ package io.openbas.injectors.caldera.service; +import static org.springframework.util.StringUtils.hasText; + import io.openbas.config.OpenBASAdminConfig; import io.openbas.config.OpenBASConfig; import io.openbas.database.model.*; @@ -9,180 +11,251 @@ import io.openbas.injectors.caldera.model.Obfuscator; import io.openbas.injectors.caldera.model.ResultStatus; import jakarta.validation.constraints.NotBlank; -import lombok.RequiredArgsConstructor; -import lombok.extern.java.Log; -import org.hibernate.Hibernate; -import org.springframework.stereotype.Service; - import java.nio.charset.StandardCharsets; import java.time.Instant; import java.util.*; import java.util.concurrent.atomic.AtomicReference; import java.util.logging.Level; - -import static org.springframework.util.StringUtils.hasText; +import lombok.RequiredArgsConstructor; +import lombok.extern.java.Log; +import org.hibernate.Hibernate; +import org.springframework.stereotype.Service; @Service @RequiredArgsConstructor @Log public class CalderaInjectorService { - private final CalderaInjectorClient client; - private final OpenBASConfig openBASConfig; - private final OpenBASAdminConfig openBASAdminConfig; + private final CalderaInjectorClient client; + private final OpenBASConfig openBASConfig; + private final OpenBASAdminConfig openBASAdminConfig; - // -- ABILITIES -- + // -- ABILITIES -- - public List abilities() { - return this.client.abilities(); - } + public List abilities() { + return this.client.abilities(); + } - public Ability findAbilityById(String abilityId) { - return this.client.findAbilityById(abilityId); - } + public Ability findAbilityById(String abilityId) { + return this.client.findAbilityById(abilityId); + } - public String exploit( - @NotBlank final String obfuscator, - @NotBlank final String paw, - @NotBlank final String abilityId, - final List> additionalFields - ) { - return this.client.exploit(obfuscator, paw, abilityId, additionalFields); - } + public String exploit( + @NotBlank final String obfuscator, + @NotBlank final String paw, + @NotBlank final String abilityId, + final List> additionalFields) { + return this.client.exploit(obfuscator, paw, abilityId, additionalFields); + } - public List obfuscators() { - return this.client.obfuscators(); - } + public List obfuscators() { + return this.client.obfuscators(); + } - public void deleteAbility(Ability ability) { - this.client.deleteAbility(ability); - } + public void deleteAbility(Ability ability) { + this.client.deleteAbility(ability); + } - public Ability createAbility(Payload payload) { - List> executors = new ArrayList<>(); - List cleanupCommands = new ArrayList<>(); - if (payload.getCleanupCommand() != null) { - cleanupCommands.add(payload.getCleanupCommand()); - } - switch (payload.getType()) { - case "Command": - Command payloadCommand = (Command) Hibernate.unproxy(payload); - Arrays.stream(payloadCommand.getPlatforms()).forEach(platform -> { - Map executor = new HashMap<>(); - executor.put("platform", platform.equals(PLATFORM_TYPE.MacOS) ? "darwin" : platform.name().toLowerCase()); - executor.put("name", payloadCommand.getExecutor().equals("bash") ? "sh" : payloadCommand.getExecutor()); - executor.put("command", payloadCommand.getContent()); - executor.put("cleanup", cleanupCommands); - executors.add(executor); + public Ability createAbility(Payload payload) { + List> executors = new ArrayList<>(); + List cleanupCommands = new ArrayList<>(); + if (payload.getCleanupCommand() != null) { + cleanupCommands.add(payload.getCleanupCommand()); + } + switch (payload.getType()) { + case "Command": + Command payloadCommand = (Command) Hibernate.unproxy(payload); + Arrays.stream(payloadCommand.getPlatforms()) + .forEach( + platform -> { + Map executor = new HashMap<>(); + executor.put( + "platform", + platform.equals(PLATFORM_TYPE.MacOS) + ? "darwin" + : platform.name().toLowerCase()); + executor.put( + "name", + payloadCommand.getExecutor().equals("bash") + ? "sh" + : payloadCommand.getExecutor()); + executor.put("command", payloadCommand.getContent()); + executor.put("cleanup", cleanupCommands); + executors.add(executor); }); - break; - case "Executable": - Executable payloadExecutable = (Executable) Hibernate.unproxy(payload); - Arrays.stream(payloadExecutable.getPlatforms()).forEach(platform -> { - Map executor = new HashMap<>(); - executor.put("platform", platform.equals(PLATFORM_TYPE.MacOS) ? "darwin" : platform.name().toLowerCase()); - executor.put("name", platform.equals(PLATFORM_TYPE.Windows.name()) ? "psh" : "sh"); - String windowsCommand = "Invoke-WebRequest -Method GET -Uri " + openBASConfig.getBaseUrl() + "/api/documents/" + payloadExecutable.getExecutableFile().getId() + "/file -Headers @{'Authorization' = 'Bearer " + openBASAdminConfig.getToken() + "'} -OutFile " + payloadExecutable.getExecutableFile().getName() + "; " + payloadExecutable.getExecutableFile().getName() + ";"; - String unixCommand = "curl -H \"Authorization: Bearer " + openBASAdminConfig.getToken() + "\" " + openBASConfig.getBaseUrl() + "/api/documents/" + payloadExecutable.getExecutableFile().getId() + "/file -o " + payloadExecutable.getExecutableFile().getName() + ";./" + payloadExecutable.getExecutableFile().getName() + ";"; - executor.put("command", platform.equals(PLATFORM_TYPE.Windows.name()) ? windowsCommand : unixCommand); - executor.put("cleanup", cleanupCommands); - executors.add(executor); + break; + case "Executable": + Executable payloadExecutable = (Executable) Hibernate.unproxy(payload); + Arrays.stream(payloadExecutable.getPlatforms()) + .forEach( + platform -> { + Map executor = new HashMap<>(); + executor.put( + "platform", + platform.equals(PLATFORM_TYPE.MacOS) + ? "darwin" + : platform.name().toLowerCase()); + executor.put( + "name", platform.equals(PLATFORM_TYPE.Windows.name()) ? "psh" : "sh"); + String windowsCommand = + "Invoke-WebRequest -Method GET -Uri " + + openBASConfig.getBaseUrl() + + "/api/documents/" + + payloadExecutable.getExecutableFile().getId() + + "/file -Headers @{'Authorization' = 'Bearer " + + openBASAdminConfig.getToken() + + "'} -OutFile " + + payloadExecutable.getExecutableFile().getName() + + "; " + + payloadExecutable.getExecutableFile().getName() + + ";"; + String unixCommand = + "curl -H \"Authorization: Bearer " + + openBASAdminConfig.getToken() + + "\" " + + openBASConfig.getBaseUrl() + + "/api/documents/" + + payloadExecutable.getExecutableFile().getId() + + "/file -o " + + payloadExecutable.getExecutableFile().getName() + + ";./" + + payloadExecutable.getExecutableFile().getName() + + ";"; + executor.put( + "command", + platform.equals(PLATFORM_TYPE.Windows.name()) ? windowsCommand : unixCommand); + executor.put("cleanup", cleanupCommands); + executors.add(executor); }); - break; - case "FileDrop": - FileDrop payloadFileDrop = (FileDrop) Hibernate.unproxy(payload); - Arrays.stream(payloadFileDrop.getPlatforms()).forEach(platform -> { - Map executor = new HashMap<>(); - executor.put("platform", platform.equals(PLATFORM_TYPE.MacOS) ? "darwin" : platform.name().toLowerCase()); - executor.put("name", platform.equals(PLATFORM_TYPE.Windows) ? "psh" : "sh"); - String windowsCommand = "Invoke-WebRequest -Method GET -Uri " + openBASConfig.getBaseUrl() + "/api/documents/" + payloadFileDrop.getFileDropFile().getId() + "/file -Headers @{'Authorization' = 'Bearer " + openBASAdminConfig.getToken() + "'} -OutFile " + payloadFileDrop.getFileDropFile().getName(); - String unixCommand = "curl -H \"Authorization: Bearer " + openBASAdminConfig.getToken() + "\" " + openBASConfig.getBaseUrl() + "/api/documents/" + payloadFileDrop.getFileDropFile().getId() + "/file -o " + payloadFileDrop.getFileDropFile().getName(); - executor.put("command", platform.equals(PLATFORM_TYPE.Windows) ? windowsCommand : unixCommand); - executor.put("cleanup", cleanupCommands); - executors.add(executor); + break; + case "FileDrop": + FileDrop payloadFileDrop = (FileDrop) Hibernate.unproxy(payload); + Arrays.stream(payloadFileDrop.getPlatforms()) + .forEach( + platform -> { + Map executor = new HashMap<>(); + executor.put( + "platform", + platform.equals(PLATFORM_TYPE.MacOS) + ? "darwin" + : platform.name().toLowerCase()); + executor.put("name", platform.equals(PLATFORM_TYPE.Windows) ? "psh" : "sh"); + String windowsCommand = + "Invoke-WebRequest -Method GET -Uri " + + openBASConfig.getBaseUrl() + + "/api/documents/" + + payloadFileDrop.getFileDropFile().getId() + + "/file -Headers @{'Authorization' = 'Bearer " + + openBASAdminConfig.getToken() + + "'} -OutFile " + + payloadFileDrop.getFileDropFile().getName(); + String unixCommand = + "curl -H \"Authorization: Bearer " + + openBASAdminConfig.getToken() + + "\" " + + openBASConfig.getBaseUrl() + + "/api/documents/" + + payloadFileDrop.getFileDropFile().getId() + + "/file -o " + + payloadFileDrop.getFileDropFile().getName(); + executor.put( + "command", + platform.equals(PLATFORM_TYPE.Windows) ? windowsCommand : unixCommand); + executor.put("cleanup", cleanupCommands); + executors.add(executor); }); - break; - case "DnsResolution": - DnsResolution payloadDnsResolution = (DnsResolution) Hibernate.unproxy(payload); - Arrays.stream(payloadDnsResolution.getPlatforms()).forEach(platform -> { - Map executor = new HashMap<>(); - executor.put("platform", platform.equals(PLATFORM_TYPE.MacOS) ? "darwin" : platform.name().toLowerCase()); - executor.put("name", platform.equals(PLATFORM_TYPE.Windows) ? "psh" : "sh"); - AtomicReference command = new AtomicReference<>(""); - Arrays.stream(payloadDnsResolution.getHostname().split("\\r?\\n")).forEach(s -> { - command.set(command + "nslookup " + s + ";"); - }); - executor.put("command", command.get()); - executor.put("cleanup", cleanupCommands); - executors.add(executor); + break; + case "DnsResolution": + DnsResolution payloadDnsResolution = (DnsResolution) Hibernate.unproxy(payload); + Arrays.stream(payloadDnsResolution.getPlatforms()) + .forEach( + platform -> { + Map executor = new HashMap<>(); + executor.put( + "platform", + platform.equals(PLATFORM_TYPE.MacOS) + ? "darwin" + : platform.name().toLowerCase()); + executor.put("name", platform.equals(PLATFORM_TYPE.Windows) ? "psh" : "sh"); + AtomicReference command = new AtomicReference<>(""); + Arrays.stream(payloadDnsResolution.getHostname().split("\\r?\\n")) + .forEach( + s -> { + command.set(command + "nslookup " + s + ";"); + }); + executor.put("command", command.get()); + executor.put("cleanup", cleanupCommands); + executors.add(executor); }); - break; - default: - throw new UnsupportedOperationException("Payload type " + payload.getType() + " is not supported"); - } - Map body = new HashMap<>(); - body.put("name", payload.getId()); - body.put("tactic", "openbas"); - body.put("technique_id", "openbas"); - body.put("technique_name", "openbas"); - body.put("executors", executors); - return this.client.createAbility(body); + break; + default: + throw new UnsupportedOperationException( + "Payload type " + payload.getType() + " is not supported"); } + Map body = new HashMap<>(); + body.put("name", payload.getId()); + body.put("tactic", "openbas"); + body.put("technique_id", "openbas"); + body.put("technique_name", "openbas"); + body.put("executors", executors); + return this.client.createAbility(body); + } - // -- AGENTS -- + // -- AGENTS -- - public List agents() { - try { - return this.client.agents().stream().toList(); - } catch (RuntimeException e) { - log.log(Level.SEVERE, "Error getting the list of Caldera agents", e); - return new ArrayList<>(); - } + public List agents() { + try { + return this.client.agents().stream().toList(); + } catch (RuntimeException e) { + log.log(Level.SEVERE, "Error getting the list of Caldera agents", e); + return new ArrayList<>(); } + } - // -- LINK -- - - public ExploitResult exploitResult( - @NotBlank final String paw, - @NotBlank final String abilityId) throws RuntimeException { - Agent agent = this.client.agent(paw, "links"); - // Take the last created - Link agentLink = agent.getLinks() - .stream() - .filter((l) -> l.getAbility().getAbility_id().equals(abilityId)) - .max(Comparator.comparing(l -> Instant.parse(l.getDecide()))) - .orElseThrow(() -> new RuntimeException("Caldera fail to execute ability " + abilityId + " on paw " + paw)); - assert paw.equals(agentLink.getPaw()); - ExploitResult exploitResult = new ExploitResult(); - exploitResult.setLinkId(agentLink.getId()); - byte[] decodedBytes = Base64.getDecoder().decode(agentLink.getCommand()); - exploitResult.setCommand(new String(decodedBytes, StandardCharsets.UTF_8)); - return exploitResult; - } + // -- LINK -- - public ResultStatus results(@NotBlank final String linkId) { - ResultStatus resultStatus = new ResultStatus(); - Result result = this.client.results(linkId); - // No result or not finish -> in progress #see caldera code - if (Optional.ofNullable(result).map(Result::getLink).map(Link::getFinish).isEmpty()) { - resultStatus.setComplete(false); - } else { - resultStatus.setComplete(true); - Link resultLink = result.getLink(); - resultStatus.setPaw(resultLink.getPaw()); - resultStatus.setFinish(Instant.parse(resultLink.getFinish())); - // Status == 0 -> success || Status > 0 -> failed #see caldera code - resultStatus.setFail(resultLink.getStatus() > 0); - - // Result output can be : #see caldera code - // - empty if ability execution return nothing - // - json object with stdout & stderr if ability execution return something - String resultOutput = result.getOutput(); - byte[] decodedBytes = Base64.getDecoder().decode(resultOutput); - String decodedString = new String(decodedBytes, StandardCharsets.UTF_8); - resultStatus.setContent(hasText(decodedString) ? decodedString : "no output to show"); - } - return resultStatus; - } + public ExploitResult exploitResult(@NotBlank final String paw, @NotBlank final String abilityId) + throws RuntimeException { + Agent agent = this.client.agent(paw, "links"); + // Take the last created + Link agentLink = + agent.getLinks().stream() + .filter((l) -> l.getAbility().getAbility_id().equals(abilityId)) + .max(Comparator.comparing(l -> Instant.parse(l.getDecide()))) + .orElseThrow( + () -> + new RuntimeException( + "Caldera fail to execute ability " + abilityId + " on paw " + paw)); + assert paw.equals(agentLink.getPaw()); + ExploitResult exploitResult = new ExploitResult(); + exploitResult.setLinkId(agentLink.getId()); + byte[] decodedBytes = Base64.getDecoder().decode(agentLink.getCommand()); + exploitResult.setCommand(new String(decodedBytes, StandardCharsets.UTF_8)); + return exploitResult; + } + public ResultStatus results(@NotBlank final String linkId) { + ResultStatus resultStatus = new ResultStatus(); + Result result = this.client.results(linkId); + // No result or not finish -> in progress #see caldera code + if (Optional.ofNullable(result).map(Result::getLink).map(Link::getFinish).isEmpty()) { + resultStatus.setComplete(false); + } else { + resultStatus.setComplete(true); + Link resultLink = result.getLink(); + resultStatus.setPaw(resultLink.getPaw()); + resultStatus.setFinish(Instant.parse(resultLink.getFinish())); + // Status == 0 -> success || Status > 0 -> failed #see caldera code + resultStatus.setFail(resultLink.getStatus() > 0); + + // Result output can be : #see caldera code + // - empty if ability execution return nothing + // - json object with stdout & stderr if ability execution return something + String resultOutput = result.getOutput(); + byte[] decodedBytes = Base64.getDecoder().decode(resultOutput); + String decodedString = new String(decodedBytes, StandardCharsets.UTF_8); + resultStatus.setContent(hasText(decodedString) ? decodedString : "no output to show"); + } + return resultStatus; + } } diff --git a/openbas-api/src/main/java/io/openbas/injectors/caldera/service/CalderaResultCollectorService.java b/openbas-api/src/main/java/io/openbas/injectors/caldera/service/CalderaResultCollectorService.java index 9ac9d0cd85..5bc07491ae 100644 --- a/openbas-api/src/main/java/io/openbas/injectors/caldera/service/CalderaResultCollectorService.java +++ b/openbas-api/src/main/java/io/openbas/injectors/caldera/service/CalderaResultCollectorService.java @@ -1,5 +1,7 @@ package io.openbas.injectors.caldera.service; +import static io.openbas.database.model.InjectStatusExecution.*; + import io.openbas.database.model.ExecutionStatus; import io.openbas.database.model.Inject; import io.openbas.database.model.InjectStatus; @@ -8,141 +10,199 @@ import io.openbas.injectors.caldera.CalderaContract; import io.openbas.injectors.caldera.model.ResultStatus; import jakarta.validation.constraints.NotNull; -import lombok.extern.java.Log; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.stereotype.Service; -import org.springframework.transaction.annotation.Transactional; - import java.time.Instant; import java.time.temporal.ChronoUnit; import java.util.ArrayList; import java.util.List; import java.util.logging.Level; - -import static io.openbas.database.model.InjectStatusExecution.*; +import lombok.extern.java.Log; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; @Log @Service public class CalderaResultCollectorService implements Runnable { - private final int EXPIRATION_TIME = 900; + private final int EXPIRATION_TIME = 900; - private final InjectRepository injectRepository; - private final InjectStatusRepository injectStatusRepository; - private final CalderaInjectorService calderaService; + private final InjectRepository injectRepository; + private final InjectStatusRepository injectStatusRepository; + private final CalderaInjectorService calderaService; - @Autowired - public CalderaResultCollectorService( - InjectRepository injectRepository, - InjectStatusRepository injectStatusRepository, - CalderaInjectorService calderaService - ) { - this.injectRepository = injectRepository; - this.injectStatusRepository = injectStatusRepository; - this.calderaService = calderaService; - } + @Autowired + public CalderaResultCollectorService( + InjectRepository injectRepository, + InjectStatusRepository injectStatusRepository, + CalderaInjectorService calderaService) { + this.injectRepository = injectRepository; + this.injectStatusRepository = injectStatusRepository; + this.calderaService = calderaService; + } - @Override - @Transactional - public void run() { - // Retrieve Caldera inject not done - List injectStatuses = this.injectStatusRepository.pendingForInjectType(CalderaContract.TYPE); - // For each one ask for traces and status - injectStatuses.forEach((injectStatus -> { - log.log(Level.INFO, "Found inject status: " + injectStatus.getId()); - // Add traces and close inject if needed. - Instant finalExecutionTime = injectStatus.getTrackingSentDate(); - List linkIds = injectStatus.statusIdentifiers(); - if (linkIds.isEmpty()) { - computeInjectStatus(injectStatus, finalExecutionTime, 0, 0); - computeInject(injectStatus); - } else { - log.log(Level.INFO, "Found links IDs: " + linkIds); - List completedActions = new ArrayList<>(); - for (String linkId : linkIds) { - ResultStatus resultStatus = new ResultStatus(); - try { - log.log(Level.INFO, "Trying to get result for " + linkId); - resultStatus = this.calderaService.results(linkId); - } catch (Exception e) { - injectStatus.getTraces().add(traceMaybePrevented("Cannot get result for linkID " + linkId + ", injection has failed")); - log.log(Level.INFO, "Cannot get result for linkID " + linkId + ", injection has failed"); - resultStatus.setFail(true); - completedActions.add(resultStatus); - injectStatus.setTrackingTotalError(injectStatus.getTrackingTotalError() + 1); - } - if (resultStatus.getPaw() == null) { - if (injectStatus.getTrackingSentDate().isBefore(Instant.now().minus(EXPIRATION_TIME / 60, ChronoUnit.MINUTES))) { - injectStatus.getTraces().add(traceMaybePrevented("Cannot get result for linkID " + linkId + ", injection has failed")); - log.log(Level.INFO, "Cannot get result for linkID " + linkId + ", injection has failed"); - resultStatus.setFail(true); - completedActions.add(resultStatus); - injectStatus.setTrackingTotalError(injectStatus.getTrackingTotalError() + 1); - } - } else { - if (resultStatus.isComplete()) { - completedActions.add(resultStatus); - if (resultStatus.isFail()) { - injectStatus.setTrackingTotalError(injectStatus.getTrackingTotalError() + 1); - injectStatus.getTraces().add(traceMaybePrevented("Failed result for linkID " + linkId + " (" + resultStatus.getContent() + ")")); - } else { - injectStatus.setTrackingTotalSuccess(injectStatus.getTrackingTotalSuccess() + 1); - injectStatus.getTraces().add(traceSuccess("Success result for linkID " + linkId + " (" + resultStatus.getContent() + ")")); - } - // Compute biggest execution time - if (resultStatus.getFinish().isAfter(finalExecutionTime)) { - finalExecutionTime = resultStatus.getFinish(); - } - } else if (injectStatus.getTrackingSentDate().isBefore(Instant.now().minus(5L, ChronoUnit.MINUTES))) { - injectStatus.getTraces().add(traceMaybePrevented("Timeout on linkID " + linkId + ", injection has failed")); - log.log(Level.INFO, "Timeout on linkID " + linkId + ", injection has failed"); - resultStatus.setFail(true); - completedActions.add(resultStatus); - injectStatus.setTrackingTotalError(injectStatus.getTrackingTotalError() + 1); - } - } + @Override + @Transactional + public void run() { + // Retrieve Caldera inject not done + List injectStatuses = + this.injectStatusRepository.pendingForInjectType(CalderaContract.TYPE); + // For each one ask for traces and status + injectStatuses.forEach( + (injectStatus -> { + log.log(Level.INFO, "Found inject status: " + injectStatus.getId()); + // Add traces and close inject if needed. + Instant finalExecutionTime = injectStatus.getTrackingSentDate(); + List linkIds = injectStatus.statusIdentifiers(); + if (linkIds.isEmpty()) { + computeInjectStatus(injectStatus, finalExecutionTime, 0, 0); + computeInject(injectStatus); + } else { + log.log(Level.INFO, "Found links IDs: " + linkIds); + List completedActions = new ArrayList<>(); + for (String linkId : linkIds) { + ResultStatus resultStatus = new ResultStatus(); + try { + log.log(Level.INFO, "Trying to get result for " + linkId); + resultStatus = this.calderaService.results(linkId); + } catch (Exception e) { + injectStatus + .getTraces() + .add( + traceMaybePrevented( + "Cannot get result for linkID " + linkId + ", injection has failed")); + log.log( + Level.INFO, + "Cannot get result for linkID " + linkId + ", injection has failed"); + resultStatus.setFail(true); + completedActions.add(resultStatus); + injectStatus.setTrackingTotalError(injectStatus.getTrackingTotalError() + 1); + } + if (resultStatus.getPaw() == null) { + if (injectStatus + .getTrackingSentDate() + .isBefore(Instant.now().minus(EXPIRATION_TIME / 60, ChronoUnit.MINUTES))) { + injectStatus + .getTraces() + .add( + traceMaybePrevented( + "Cannot get result for linkID " + linkId + ", injection has failed")); + log.log( + Level.INFO, + "Cannot get result for linkID " + linkId + ", injection has failed"); + resultStatus.setFail(true); + completedActions.add(resultStatus); + injectStatus.setTrackingTotalError(injectStatus.getTrackingTotalError() + 1); } - // Compute status only if all actions are completed - if (completedActions.size() == linkIds.size()) { - int failedActions = (int) completedActions.stream().filter(ResultStatus::isFail).count(); - computeInjectStatus(injectStatus, finalExecutionTime, completedActions.size(), failedActions); - // Update related inject - computeInject(injectStatus); + } else { + if (resultStatus.isComplete()) { + completedActions.add(resultStatus); + if (resultStatus.isFail()) { + injectStatus.setTrackingTotalError(injectStatus.getTrackingTotalError() + 1); + injectStatus + .getTraces() + .add( + traceMaybePrevented( + "Failed result for linkID " + + linkId + + " (" + + resultStatus.getContent() + + ")")); + } else { + injectStatus.setTrackingTotalSuccess( + injectStatus.getTrackingTotalSuccess() + 1); + injectStatus + .getTraces() + .add( + traceSuccess( + "Success result for linkID " + + linkId + + " (" + + resultStatus.getContent() + + ")")); + } + // Compute biggest execution time + if (resultStatus.getFinish().isAfter(finalExecutionTime)) { + finalExecutionTime = resultStatus.getFinish(); + } + } else if (injectStatus + .getTrackingSentDate() + .isBefore(Instant.now().minus(5L, ChronoUnit.MINUTES))) { + injectStatus + .getTraces() + .add( + traceMaybePrevented( + "Timeout on linkID " + linkId + ", injection has failed")); + log.log(Level.INFO, "Timeout on linkID " + linkId + ", injection has failed"); + resultStatus.setFail(true); + completedActions.add(resultStatus); + injectStatus.setTrackingTotalError(injectStatus.getTrackingTotalError() + 1); } + } } + // Compute status only if all actions are completed + if (completedActions.size() == linkIds.size()) { + int failedActions = + (int) completedActions.stream().filter(ResultStatus::isFail).count(); + computeInjectStatus( + injectStatus, finalExecutionTime, completedActions.size(), failedActions); + // Update related inject + computeInject(injectStatus); + } + } })); - } + } - // -- INJECT STATUS -- + // -- INJECT STATUS -- - public void computeInjectStatus( - @NotNull final InjectStatus injectStatus, - @NotNull final Instant finalExecutionTime, - final int completedActions, - final int failedActions) { - if (injectStatus.getTraces().stream().filter(injectStatusExecution -> injectStatusExecution.getStatus().equals(ExecutionStatus.ERROR)).count() >= completedActions) { - injectStatus.setName(ExecutionStatus.ERROR); - } else if (injectStatus.getTraces().stream().anyMatch(trace -> trace.getStatus().equals(ExecutionStatus.ERROR))) { - injectStatus.setName(ExecutionStatus.PARTIAL); - } else if (injectStatus.getTraces().stream().filter(injectStatusExecution -> injectStatusExecution.getStatus().equals(ExecutionStatus.MAYBE_PREVENTED)).count() >= completedActions) { - injectStatus.setName(ExecutionStatus.MAYBE_PREVENTED); - } else if (injectStatus.getTraces().stream().anyMatch(trace -> trace.getStatus().equals(ExecutionStatus.MAYBE_PREVENTED))) { - injectStatus.setName(ExecutionStatus.MAYBE_PARTIAL_PREVENTED); - } else { - injectStatus.setName(ExecutionStatus.SUCCESS); - } - injectStatus.getTraces().add(traceInfo("caldera", "Caldera executed the ability on " + (completedActions - failedActions) + "/" + completedActions + " asset(s)")); - long executionTime = (finalExecutionTime.toEpochMilli() - injectStatus.getTrackingSentDate().toEpochMilli()); - injectStatus.setTrackingTotalExecutionTime(executionTime); - injectStatus.setTrackingEndDate(Instant.now()); - this.injectStatusRepository.save(injectStatus); + public void computeInjectStatus( + @NotNull final InjectStatus injectStatus, + @NotNull final Instant finalExecutionTime, + final int completedActions, + final int failedActions) { + if (injectStatus.getTraces().stream() + .filter( + injectStatusExecution -> + injectStatusExecution.getStatus().equals(ExecutionStatus.ERROR)) + .count() + >= completedActions) { + injectStatus.setName(ExecutionStatus.ERROR); + } else if (injectStatus.getTraces().stream() + .anyMatch(trace -> trace.getStatus().equals(ExecutionStatus.ERROR))) { + injectStatus.setName(ExecutionStatus.PARTIAL); + } else if (injectStatus.getTraces().stream() + .filter( + injectStatusExecution -> + injectStatusExecution.getStatus().equals(ExecutionStatus.MAYBE_PREVENTED)) + .count() + >= completedActions) { + injectStatus.setName(ExecutionStatus.MAYBE_PREVENTED); + } else if (injectStatus.getTraces().stream() + .anyMatch(trace -> trace.getStatus().equals(ExecutionStatus.MAYBE_PREVENTED))) { + injectStatus.setName(ExecutionStatus.MAYBE_PARTIAL_PREVENTED); + } else { + injectStatus.setName(ExecutionStatus.SUCCESS); } + injectStatus + .getTraces() + .add( + traceInfo( + "caldera", + "Caldera executed the ability on " + + (completedActions - failedActions) + + "/" + + completedActions + + " asset(s)")); + long executionTime = + (finalExecutionTime.toEpochMilli() - injectStatus.getTrackingSentDate().toEpochMilli()); + injectStatus.setTrackingTotalExecutionTime(executionTime); + injectStatus.setTrackingEndDate(Instant.now()); + this.injectStatusRepository.save(injectStatus); + } -// -- INJECT -- - - public void computeInject(@NotNull final InjectStatus injectStatus) { - Inject relatedInject = injectStatus.getInject(); - relatedInject.setUpdatedAt(Instant.now()); - this.injectRepository.save(relatedInject); - } + // -- INJECT -- + public void computeInject(@NotNull final InjectStatus injectStatus) { + Inject relatedInject = injectStatus.getInject(); + relatedInject.setUpdatedAt(Instant.now()); + this.injectRepository.save(relatedInject); + } } diff --git a/openbas-api/src/main/java/io/openbas/injectors/challenge/ChallengeContract.java b/openbas-api/src/main/java/io/openbas/injectors/challenge/ChallengeContract.java index d1689a564c..30ed7cc7e3 100644 --- a/openbas-api/src/main/java/io/openbas/injectors/challenge/ChallengeContract.java +++ b/openbas-api/src/main/java/io/openbas/injectors/challenge/ChallengeContract.java @@ -1,20 +1,5 @@ package io.openbas.injectors.challenge; -import io.openbas.database.model.Endpoint; -import io.openbas.expectation.ExpectationBuilderService; -import io.openbas.injector_contract.Contract; -import io.openbas.injector_contract.ContractConfig; -import io.openbas.injector_contract.Contractor; -import io.openbas.injector_contract.ContractorIcon; -import io.openbas.injector_contract.fields.ContractElement; -import io.openbas.injector_contract.fields.ContractExpectations; -import lombok.RequiredArgsConstructor; -import org.springframework.stereotype.Component; - -import java.io.InputStream; -import java.util.List; -import java.util.Map; - import static io.openbas.helper.SupportedLanguage.en; import static io.openbas.helper.SupportedLanguage.fr; import static io.openbas.injector_contract.Contract.executableContract; @@ -28,6 +13,20 @@ import static io.openbas.injector_contract.fields.ContractText.textField; import static io.openbas.injector_contract.fields.ContractTextArea.richTextareaField; +import io.openbas.database.model.Endpoint; +import io.openbas.expectation.ExpectationBuilderService; +import io.openbas.injector_contract.Contract; +import io.openbas.injector_contract.ContractConfig; +import io.openbas.injector_contract.Contractor; +import io.openbas.injector_contract.ContractorIcon; +import io.openbas.injector_contract.fields.ContractElement; +import io.openbas.injector_contract.fields.ContractExpectations; +import java.io.InputStream; +import java.util.List; +import java.util.Map; +import lombok.RequiredArgsConstructor; +import org.springframework.stereotype.Component; + @Component @RequiredArgsConstructor public class ChallengeContract extends Contractor { @@ -50,8 +49,13 @@ public String getType() { @Override public ContractConfig getConfig() { - return new ContractConfig(TYPE, Map.of(en, "Challenge", fr, "Challenge"), "#e91e63", "#e91e63", - "/img/challenge.png", isExpose()); + return new ContractConfig( + TYPE, + Map.of(en, "Challenge", fr, "Challenge"), + "#e91e63", + "#e91e63", + "/img/challenge.png", + isExpose()); } @Override @@ -59,7 +63,8 @@ public List contracts() { ContractConfig contractConfig = getConfig(); // In this "internal" contract we can't express choices. // Choices are contextual to a specific exercise. - String messageBody = """ + String messageBody = + """ Dear player,

News challenges have been published.

<#list challenges as challenge> @@ -70,24 +75,31 @@ public List contracts() { The animation team """; // We include the expectations for challenges - ContractExpectations expectationsField = expectationsField( - "expectations", - "Expectations", - List.of(this.expectationBuilderService.buildChallengeExpectation()) - ); - List publishInstance = contractBuilder() - .mandatory(challengeField("challenges", "Challenges", Multiple)) - // Contract specific - .optional(expectationsField) - .mandatory(textField("subject", "Subject", "New challenges published for ${user.email}")) - .mandatory(richTextareaField("body", "Body", messageBody)) - .optional(checkboxField("encrypted", "Encrypted", false)) - .mandatory(teamField("teams", "Teams", Multiple)) - .optional(attachmentField("attachments", "Attachments", Multiple)) - .build(); - Contract publishChallenge = executableContract(contractConfig, - CHALLENGE_PUBLISH, Map.of(en, "Publish challenges", fr, "Publier des challenges"), publishInstance, - List.of(Endpoint.PLATFORM_TYPE.Internal), false); + ContractExpectations expectationsField = + expectationsField( + "expectations", + "Expectations", + List.of(this.expectationBuilderService.buildChallengeExpectation())); + List publishInstance = + contractBuilder() + .mandatory(challengeField("challenges", "Challenges", Multiple)) + // Contract specific + .optional(expectationsField) + .mandatory( + textField("subject", "Subject", "New challenges published for ${user.email}")) + .mandatory(richTextareaField("body", "Body", messageBody)) + .optional(checkboxField("encrypted", "Encrypted", false)) + .mandatory(teamField("teams", "Teams", Multiple)) + .optional(attachmentField("attachments", "Attachments", Multiple)) + .build(); + Contract publishChallenge = + executableContract( + contractConfig, + CHALLENGE_PUBLISH, + Map.of(en, "Publish challenges", fr, "Publier des challenges"), + publishInstance, + List.of(Endpoint.PLATFORM_TYPE.Internal), + false); publishChallenge.setAtomicTesting(false); return List.of(publishChallenge); } diff --git a/openbas-api/src/main/java/io/openbas/injectors/challenge/ChallengeExecutor.java b/openbas-api/src/main/java/io/openbas/injectors/challenge/ChallengeExecutor.java index 8bd81eeed4..ed520df857 100644 --- a/openbas-api/src/main/java/io/openbas/injectors/challenge/ChallengeExecutor.java +++ b/openbas-api/src/main/java/io/openbas/injectors/challenge/ChallengeExecutor.java @@ -1,5 +1,10 @@ package io.openbas.injectors.challenge; +import static io.openbas.database.model.InjectStatusExecution.traceError; +import static io.openbas.database.model.InjectStatusExecution.traceSuccess; +import static io.openbas.helper.StreamHelper.fromIterable; +import static io.openbas.injectors.challenge.ChallengeContract.CHALLENGE_PUBLISH; + import io.openbas.config.OpenBASConfig; import io.openbas.database.model.*; import io.openbas.database.repository.ChallengeRepository; @@ -15,25 +20,18 @@ import io.openbas.model.expectation.ManualExpectation; import jakarta.annotation.Resource; import jakarta.validation.constraints.NotNull; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.beans.factory.annotation.Value; -import org.springframework.stereotype.Component; - import java.util.ArrayList; import java.util.List; import java.util.stream.Collectors; import java.util.stream.Stream; - -import static io.openbas.database.model.InjectStatusExecution.traceError; -import static io.openbas.database.model.InjectStatusExecution.traceSuccess; -import static io.openbas.helper.StreamHelper.fromIterable; -import static io.openbas.injectors.challenge.ChallengeContract.CHALLENGE_PUBLISH; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.stereotype.Component; @Component(ChallengeContract.TYPE) public class ChallengeExecutor extends Injector { - @Resource - private OpenBASConfig openBASConfig; + @Resource private OpenBASConfig openBASConfig; private ChallengeRepository challengeRepository; @@ -52,28 +50,40 @@ public void setEmailService(EmailService emailService) { this.emailService = emailService; } - private String buildChallengeUri(ExecutionContext context, Exercise exercise, Challenge challenge) { + private String buildChallengeUri( + ExecutionContext context, Exercise exercise, Challenge challenge) { String userId = context.getUser().getId(); String challengeId = challenge.getId(); String exerciseId = exercise.getId(); - return openBASConfig.getBaseUrl() + "/challenges/" + exerciseId + "?user=" + userId + "&challenge=" + challengeId; + return openBASConfig.getBaseUrl() + + "/challenges/" + + exerciseId + + "?user=" + + userId + + "&challenge=" + + challengeId; } @Override - public ExecutionProcess process(@NotNull final Execution execution, @NotNull final ExecutableInject injection) { + public ExecutionProcess process( + @NotNull final Execution execution, @NotNull final ExecutableInject injection) { try { ChallengeContent content = contentConvert(injection, ChallengeContent.class); - List challenges = fromIterable(challengeRepository.findAllById(content.getChallenges())); - String contract = injection - .getInjection() - .getInject() - .getInjectorContract() - .map(InjectorContract::getId) - .orElseThrow(() -> new UnsupportedOperationException("Inject does not have a contract")); + List challenges = + fromIterable(challengeRepository.findAllById(content.getChallenges())); + String contract = + injection + .getInjection() + .getInject() + .getInjectorContract() + .map(InjectorContract::getId) + .orElseThrow( + () -> new UnsupportedOperationException("Inject does not have a contract")); if (contract.equals(CHALLENGE_PUBLISH)) { // Challenge publishing is only linked to execution date of this inject. - String challengeNames = challenges.stream().map(Challenge::getName).collect(Collectors.joining(",")); + String challengeNames = + challenges.stream().map(Challenge::getName).collect(Collectors.joining(",")); String publishedMessage = "Challenges (" + challengeNames + ") marked as published"; execution.addTrace(traceSuccess(publishedMessage)); // Send the publication message. @@ -81,42 +91,61 @@ public ExecutionProcess process(@NotNull final Execution execution, @NotNull fin String from = exercise.getFrom(); List replyTos = exercise.getReplyTos(); List users = injection.getUsers(); - List documents = injection.getInjection().getInject().getDocuments().stream() - .filter(InjectDocument::isAttached).map(InjectDocument::getDocument).toList(); + List documents = + injection.getInjection().getInject().getDocuments().stream() + .filter(InjectDocument::isAttached) + .map(InjectDocument::getDocument) + .toList(); List attachments = resolveAttachments(execution, injection, documents); String message = content.buildMessage(injection, imapEnabled); boolean encrypted = content.isEncrypted(); - users.forEach(userInjectContext -> { - try { - // Put the challenges variables in the injection context - List challengeVariables = challenges.stream() - .map(challenge -> new ChallengeVariable(challenge.getId(), challenge.getName(), - buildChallengeUri(userInjectContext, exercise, challenge))) - .toList(); - userInjectContext.put("challenges", challengeVariables); - // Send the email. - emailService.sendEmail(execution, userInjectContext, from, replyTos, content.getInReplyTo(), encrypted, - content.getSubject(), message, attachments); - } catch (Exception e) { - execution.addTrace(traceError(e.getMessage())); - } - }); + users.forEach( + userInjectContext -> { + try { + // Put the challenges variables in the injection context + List challengeVariables = + challenges.stream() + .map( + challenge -> + new ChallengeVariable( + challenge.getId(), + challenge.getName(), + buildChallengeUri(userInjectContext, exercise, challenge))) + .toList(); + userInjectContext.put("challenges", challengeVariables); + // Send the email. + emailService.sendEmail( + execution, + userInjectContext, + from, + replyTos, + content.getInReplyTo(), + encrypted, + content.getSubject(), + message, + attachments); + } catch (Exception e) { + execution.addTrace(traceError(e.getMessage())); + } + }); // Return expectations List expectations = new ArrayList<>(); if (!content.getExpectations().isEmpty()) { expectations.addAll( - content.getExpectations() - .stream() - .flatMap((entry) -> switch (entry.getType()) { - case MANUAL -> Stream.of( - (Expectation) new ManualExpectation(entry) - ); - case CHALLENGE -> challenges.stream() - .map(challenge -> (Expectation) new ChallengeExpectation(entry, challenge)); - default -> Stream.of(); - }) - .toList() - ); + content.getExpectations().stream() + .flatMap( + (entry) -> + switch (entry.getType()) { + case MANUAL -> Stream.of((Expectation) new ManualExpectation(entry)); + case CHALLENGE -> + challenges.stream() + .map( + challenge -> + (Expectation) + new ChallengeExpectation(entry, challenge)); + default -> Stream.of(); + }) + .toList()); } return new ExecutionProcess(false, expectations); } else { diff --git a/openbas-api/src/main/java/io/openbas/injectors/challenge/ChallengeInjector.java b/openbas-api/src/main/java/io/openbas/injectors/challenge/ChallengeInjector.java index 4e96893b6e..ba955e7668 100644 --- a/openbas-api/src/main/java/io/openbas/injectors/challenge/ChallengeInjector.java +++ b/openbas-api/src/main/java/io/openbas/injectors/challenge/ChallengeInjector.java @@ -7,24 +7,23 @@ @Component public class ChallengeInjector { - private static final String CHALLENGE_INJECTOR_NAME = "Challenges"; - private static final String CHALLENGE_INJECTOR_ID = "49229430-b5b5-431f-ba5b-f36f599b0233"; + private static final String CHALLENGE_INJECTOR_NAME = "Challenges"; + private static final String CHALLENGE_INJECTOR_ID = "49229430-b5b5-431f-ba5b-f36f599b0233"; - @Autowired - public ChallengeInjector(InjectorService injectorService, ChallengeContract contract) { - try { - injectorService.register( - CHALLENGE_INJECTOR_ID, - CHALLENGE_INJECTOR_NAME, - contract, - false, - "capture-the-flag", - null, - null, - false - ); - } catch (Exception e) { - throw new RuntimeException(e); - } + @Autowired + public ChallengeInjector(InjectorService injectorService, ChallengeContract contract) { + try { + injectorService.register( + CHALLENGE_INJECTOR_ID, + CHALLENGE_INJECTOR_NAME, + contract, + false, + "capture-the-flag", + null, + null, + false); + } catch (Exception e) { + throw new RuntimeException(e); } + } } diff --git a/openbas-api/src/main/java/io/openbas/injectors/challenge/model/ChallengeContent.java b/openbas-api/src/main/java/io/openbas/injectors/challenge/model/ChallengeContent.java index 6b58cfe16a..5d472a918e 100644 --- a/openbas-api/src/main/java/io/openbas/injectors/challenge/model/ChallengeContent.java +++ b/openbas-api/src/main/java/io/openbas/injectors/challenge/model/ChallengeContent.java @@ -3,11 +3,10 @@ import com.fasterxml.jackson.annotation.JsonProperty; import io.openbas.injectors.email.model.EmailContent; import io.openbas.model.inject.form.Expectation; -import lombok.Getter; -import lombok.Setter; - import java.util.ArrayList; import java.util.List; +import lombok.Getter; +import lombok.Setter; @Getter @Setter @@ -18,5 +17,4 @@ public class ChallengeContent extends EmailContent { @JsonProperty("expectations") private List expectations = new ArrayList<>(); - } diff --git a/openbas-api/src/main/java/io/openbas/injectors/challenge/model/ChallengeVariable.java b/openbas-api/src/main/java/io/openbas/injectors/challenge/model/ChallengeVariable.java index e73f33b979..9ba8d1bd39 100644 --- a/openbas-api/src/main/java/io/openbas/injectors/challenge/model/ChallengeVariable.java +++ b/openbas-api/src/main/java/io/openbas/injectors/challenge/model/ChallengeVariable.java @@ -1,37 +1,37 @@ package io.openbas.injectors.challenge.model; public class ChallengeVariable { - private String id; - private String name; - private String uri; - - public ChallengeVariable(String id, String name, String uri) { - this.id = id; - this.name = name; - this.uri = uri; - } - - public String getId() { - return id; - } - - public void setId(String id) { - this.id = id; - } - - public String getName() { - return name; - } - - public void setName(String name) { - this.name = name; - } - - public String getUri() { - return uri; - } - - public void setUri(String uri) { - this.uri = uri; - } + private String id; + private String name; + private String uri; + + public ChallengeVariable(String id, String name, String uri) { + this.id = id; + this.name = name; + this.uri = uri; + } + + public String getId() { + return id; + } + + public void setId(String id) { + this.id = id; + } + + public String getName() { + return name; + } + + public void setName(String name) { + this.name = name; + } + + public String getUri() { + return uri; + } + + public void setUri(String uri) { + this.uri = uri; + } } diff --git a/openbas-api/src/main/java/io/openbas/injectors/channel/ChannelContract.java b/openbas-api/src/main/java/io/openbas/injectors/channel/ChannelContract.java index 48ad6ba542..b0b5bdbe2d 100644 --- a/openbas-api/src/main/java/io/openbas/injectors/channel/ChannelContract.java +++ b/openbas-api/src/main/java/io/openbas/injectors/channel/ChannelContract.java @@ -1,22 +1,5 @@ package io.openbas.injectors.channel; -import io.openbas.database.model.Endpoint; -import io.openbas.database.model.Variable.VariableType; -import io.openbas.expectation.ExpectationBuilderService; -import io.openbas.injector_contract.Contract; -import io.openbas.injector_contract.ContractConfig; -import io.openbas.injector_contract.Contractor; -import io.openbas.injector_contract.ContractorIcon; -import io.openbas.injector_contract.fields.ContractCheckbox; -import io.openbas.injector_contract.fields.ContractElement; -import io.openbas.injector_contract.fields.ContractExpectations; -import lombok.RequiredArgsConstructor; -import org.springframework.stereotype.Component; - -import java.io.InputStream; -import java.util.List; -import java.util.Map; - import static io.openbas.helper.SupportedLanguage.en; import static io.openbas.helper.SupportedLanguage.fr; import static io.openbas.injector_contract.Contract.executableContract; @@ -34,6 +17,22 @@ import static io.openbas.injectors.channel.ChannelExecutor.VARIABLE_ARTICLE; import static io.openbas.injectors.channel.ChannelExecutor.VARIABLE_ARTICLES; +import io.openbas.database.model.Endpoint; +import io.openbas.database.model.Variable.VariableType; +import io.openbas.expectation.ExpectationBuilderService; +import io.openbas.injector_contract.Contract; +import io.openbas.injector_contract.ContractConfig; +import io.openbas.injector_contract.Contractor; +import io.openbas.injector_contract.ContractorIcon; +import io.openbas.injector_contract.fields.ContractCheckbox; +import io.openbas.injector_contract.fields.ContractElement; +import io.openbas.injector_contract.fields.ContractExpectations; +import java.io.InputStream; +import java.util.List; +import java.util.Map; +import lombok.RequiredArgsConstructor; +import org.springframework.stereotype.Component; + @Component @RequiredArgsConstructor public class ChannelContract extends Contractor { @@ -56,8 +55,13 @@ public String getType() { @Override public ContractConfig getConfig() { - return new ContractConfig(TYPE, Map.of(en, "Media pressure", fr, "Pression médiatique"), "#ff9800", "#ff9800", - "/img/channel.png", isExpose()); + return new ContractConfig( + TYPE, + Map.of(en, "Media pressure", fr, "Pression médiatique"), + "#ff9800", + "#ff9800", + "/img/channel.png", + isExpose()); } @Override @@ -65,7 +69,8 @@ public List contracts() { ContractConfig contractConfig = getConfig(); // In this "internal" contract we can't express choices. // Choices are contextual to a specific exercise. - String messageBody = """ + String messageBody = + """ Dear player,

New media pressure entries have been published.

<#list articles as article> @@ -76,38 +81,58 @@ public List contracts() { The animation team """; ContractCheckbox emailingField = checkboxField("emailing", "Send email", true); - ContractExpectations expectationsField = expectationsField( - "expectations", - "Expectations", - List.of(this.expectationBuilderService.buildArticleExpectation()) - ); - List publishInstance = contractBuilder() - // built in - .optional(teamField("teams", "Teams", Multiple)) - .optional(attachmentField("attachments", "Attachments", Multiple)) - .mandatory(articleField("articles", "Articles", Multiple)) - // Contract specific - .optional(expectationsField) - // Emailing zone - .optional(emailingField) - .mandatory(textField("subject", "Subject", "New media pressure entries published for ${user.email}", - List.of(emailingField))) - .mandatory(richTextareaField("body", "Body", messageBody, - List.of(emailingField))) - .optional(checkboxField("encrypted", "Encrypted", false, - List.of(emailingField))) - .build(); - Contract publishArticle = executableContract(contractConfig, - CHANNEL_PUBLISH, Map.of(en, "Publish a media pressure", fr, "Publier de la pression médiatique"), - publishInstance, List.of(Endpoint.PLATFORM_TYPE.Internal), false); + ContractExpectations expectationsField = + expectationsField( + "expectations", + "Expectations", + List.of(this.expectationBuilderService.buildArticleExpectation())); + List publishInstance = + contractBuilder() + // built in + .optional(teamField("teams", "Teams", Multiple)) + .optional(attachmentField("attachments", "Attachments", Multiple)) + .mandatory(articleField("articles", "Articles", Multiple)) + // Contract specific + .optional(expectationsField) + // Emailing zone + .optional(emailingField) + .mandatory( + textField( + "subject", + "Subject", + "New media pressure entries published for ${user.email}", + List.of(emailingField))) + .mandatory(richTextareaField("body", "Body", messageBody, List.of(emailingField))) + .optional(checkboxField("encrypted", "Encrypted", false, List.of(emailingField))) + .build(); + Contract publishArticle = + executableContract( + contractConfig, + CHANNEL_PUBLISH, + Map.of(en, "Publish a media pressure", fr, "Publier de la pression médiatique"), + publishInstance, + List.of(Endpoint.PLATFORM_TYPE.Internal), + false); // Adding generated variables publishArticle.addVariable( - variable(VARIABLE_ARTICLES, "List of articles published by the injection", VariableType.Object, Multiple, + variable( + VARIABLE_ARTICLES, + "List of articles published by the injection", + VariableType.Object, + Multiple, List.of( - variable(VARIABLE_ARTICLE + ".id", "Id of the article in the platform", VariableType.String, One), - variable(VARIABLE_ARTICLE + ".name", "Name of the article", VariableType.String, One), - variable(VARIABLE_ARTICLE + ".uri", "Http user link to access the article", VariableType.String, One) - ))); + variable( + VARIABLE_ARTICLE + ".id", + "Id of the article in the platform", + VariableType.String, + One), + variable( + VARIABLE_ARTICLE + ".name", "Name of the article", VariableType.String, One), + variable( + VARIABLE_ARTICLE + ".uri", + "Http user link to access the article", + VariableType.String, + One)))); publishArticle.setAtomicTesting(false); return List.of(publishArticle); } diff --git a/openbas-api/src/main/java/io/openbas/injectors/channel/ChannelExecutor.java b/openbas-api/src/main/java/io/openbas/injectors/channel/ChannelExecutor.java index aa700c10d3..c7b3bf41db 100644 --- a/openbas-api/src/main/java/io/openbas/injectors/channel/ChannelExecutor.java +++ b/openbas-api/src/main/java/io/openbas/injectors/channel/ChannelExecutor.java @@ -1,5 +1,10 @@ package io.openbas.injectors.channel; +import static io.openbas.database.model.InjectStatusExecution.traceError; +import static io.openbas.database.model.InjectStatusExecution.traceSuccess; +import static io.openbas.helper.StreamHelper.fromIterable; +import static io.openbas.injectors.channel.ChannelContract.CHANNEL_PUBLISH; + import io.openbas.config.OpenBASConfig; import io.openbas.database.model.*; import io.openbas.database.repository.ArticleRepository; @@ -15,19 +20,13 @@ import io.openbas.model.expectation.ManualExpectation; import jakarta.annotation.Resource; import jakarta.validation.constraints.NotNull; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.beans.factory.annotation.Value; -import org.springframework.stereotype.Component; - import java.util.ArrayList; import java.util.List; import java.util.stream.Collectors; import java.util.stream.Stream; - -import static io.openbas.database.model.InjectStatusExecution.traceError; -import static io.openbas.database.model.InjectStatusExecution.traceSuccess; -import static io.openbas.helper.StreamHelper.fromIterable; -import static io.openbas.injectors.channel.ChannelContract.CHANNEL_PUBLISH; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.stereotype.Component; @Component(ChannelContract.TYPE) public class ChannelExecutor extends Injector { @@ -36,8 +35,7 @@ public class ChannelExecutor extends Injector { public static final String VARIABLE_ARTICLE = "article"; - @Resource - private OpenBASConfig openBASConfig; + @Resource private OpenBASConfig openBASConfig; private ArticleRepository articleRepository; @@ -61,25 +59,35 @@ private String buildArticleUri(ExecutionContext context, Article article) { String channelId = article.getChannel().getId(); String exerciseId = article.getExercise().getId(); String queryOptions = "article=" + article.getId() + "&user=" + userId; - return openBASConfig.getBaseUrl() + "/channels/" + exerciseId + "/" + channelId + "?" + queryOptions; + return openBASConfig.getBaseUrl() + + "/channels/" + + exerciseId + + "/" + + channelId + + "?" + + queryOptions; } @Override - public ExecutionProcess process(@NotNull final Execution execution, @NotNull final ExecutableInject injection) { + public ExecutionProcess process( + @NotNull final Execution execution, @NotNull final ExecutableInject injection) { try { ChannelContent content = contentConvert(injection, ChannelContent.class); List
articles = fromIterable(articleRepository.findAllById(content.getArticles())); - String contract = injection - .getInjection() - .getInject() - .getInjectorContract() - .map(InjectorContract::getId) - .orElseThrow(() -> new UnsupportedOperationException("Inject does not have a contract")); + String contract = + injection + .getInjection() + .getInject() + .getInjectorContract() + .map(InjectorContract::getId) + .orElseThrow( + () -> new UnsupportedOperationException("Inject does not have a contract")); if (contract.equals(CHANNEL_PUBLISH)) { // Article publishing is only linked to execution date of this inject. - String articleNames = articles.stream().map(Article::getName).collect(Collectors.joining(",")); + String articleNames = + articles.stream().map(Article::getName).collect(Collectors.joining(",")); String publishedMessage = "Articles (" + articleNames + ") marked as published"; execution.addTrace(traceSuccess(publishedMessage)); Exercise exercise = injection.getInjection().getExercise(); @@ -88,44 +96,62 @@ public ExecutionProcess process(@NotNull final Execution execution, @NotNull fin String from = exercise.getFrom(); List replyTos = exercise.getReplyTos(); List users = injection.getUsers(); - List documents = injection.getInjection().getInject().getDocuments().stream() - .filter(InjectDocument::isAttached).map(InjectDocument::getDocument).toList(); + List documents = + injection.getInjection().getInject().getDocuments().stream() + .filter(InjectDocument::isAttached) + .map(InjectDocument::getDocument) + .toList(); List attachments = resolveAttachments(execution, injection, documents); String message = content.buildMessage(injection, imapEnabled); boolean encrypted = content.isEncrypted(); - users.forEach(userInjectContext -> { - try { - // Put the challenges variables in the injection context - List articleVariables = articles.stream() - .map(article -> new ArticleVariable(article.getId(), article.getName(), - buildArticleUri(userInjectContext, article))) - .toList(); - userInjectContext.put(VARIABLE_ARTICLES, articleVariables); - // Send the email. - emailService.sendEmail(execution, userInjectContext, from, replyTos, content.getInReplyTo(), encrypted, - content.getSubject(), message, attachments); - } catch (Exception e) { - execution.addTrace(traceError(e.getMessage())); - } - }); + users.forEach( + userInjectContext -> { + try { + // Put the challenges variables in the injection context + List articleVariables = + articles.stream() + .map( + article -> + new ArticleVariable( + article.getId(), + article.getName(), + buildArticleUri(userInjectContext, article))) + .toList(); + userInjectContext.put(VARIABLE_ARTICLES, articleVariables); + // Send the email. + emailService.sendEmail( + execution, + userInjectContext, + from, + replyTos, + content.getInReplyTo(), + encrypted, + content.getSubject(), + message, + attachments); + } catch (Exception e) { + execution.addTrace(traceError(e.getMessage())); + } + }); } else { execution.addTrace(traceSuccess("Email disabled for this inject")); } List expectations = new ArrayList<>(); if (!content.getExpectations().isEmpty()) { expectations.addAll( - content.getExpectations() - .stream() - .flatMap((entry) -> switch (entry.getType()) { - case MANUAL -> Stream.of( - (Expectation) new ManualExpectation(entry) - ); - case ARTICLE -> articles.stream() - .map(article -> (Expectation) new ChannelExpectation(entry, article)); - default -> Stream.of(); - }) - .toList() - ); + content.getExpectations().stream() + .flatMap( + (entry) -> + switch (entry.getType()) { + case MANUAL -> Stream.of((Expectation) new ManualExpectation(entry)); + case ARTICLE -> + articles.stream() + .map( + article -> + (Expectation) new ChannelExpectation(entry, article)); + default -> Stream.of(); + }) + .toList()); } return new ExecutionProcess(false, expectations); } else { diff --git a/openbas-api/src/main/java/io/openbas/injectors/channel/ChannelInjector.java b/openbas-api/src/main/java/io/openbas/injectors/channel/ChannelInjector.java index 9f7f4f2bea..eb0ef01eb5 100644 --- a/openbas-api/src/main/java/io/openbas/injectors/channel/ChannelInjector.java +++ b/openbas-api/src/main/java/io/openbas/injectors/channel/ChannelInjector.java @@ -7,24 +7,23 @@ @Component public class ChannelInjector { - private static final String CHANNEL_INJECTOR_NAME = "Media pressure"; - private static final String CHANNEL_INJECTOR_ID = "8d932e36-353c-48fa-ba6f-86cb7b02ed19"; + private static final String CHANNEL_INJECTOR_NAME = "Media pressure"; + private static final String CHANNEL_INJECTOR_ID = "8d932e36-353c-48fa-ba6f-86cb7b02ed19"; - @Autowired - public ChannelInjector(InjectorService injectorService, ChannelContract contract) { - try { - injectorService.register( - CHANNEL_INJECTOR_ID, - CHANNEL_INJECTOR_NAME, - contract, - false, - "media-pressure", - null, - null, - false - ); - } catch (Exception e) { - throw new RuntimeException(e); - } + @Autowired + public ChannelInjector(InjectorService injectorService, ChannelContract contract) { + try { + injectorService.register( + CHANNEL_INJECTOR_ID, + CHANNEL_INJECTOR_NAME, + contract, + false, + "media-pressure", + null, + null, + false); + } catch (Exception e) { + throw new RuntimeException(e); } + } } diff --git a/openbas-api/src/main/java/io/openbas/injectors/channel/model/ArticleVariable.java b/openbas-api/src/main/java/io/openbas/injectors/channel/model/ArticleVariable.java index 6ed0867831..0a19747a77 100644 --- a/openbas-api/src/main/java/io/openbas/injectors/channel/model/ArticleVariable.java +++ b/openbas-api/src/main/java/io/openbas/injectors/channel/model/ArticleVariable.java @@ -16,5 +16,4 @@ public ArticleVariable(String id, String name, String uri) { this.name = name; this.uri = uri; } - } diff --git a/openbas-api/src/main/java/io/openbas/injectors/channel/model/ChannelContent.java b/openbas-api/src/main/java/io/openbas/injectors/channel/model/ChannelContent.java index ed623f4d15..a3da2944b8 100644 --- a/openbas-api/src/main/java/io/openbas/injectors/channel/model/ChannelContent.java +++ b/openbas-api/src/main/java/io/openbas/injectors/channel/model/ChannelContent.java @@ -3,11 +3,10 @@ import com.fasterxml.jackson.annotation.JsonProperty; import io.openbas.injectors.email.model.EmailContent; import io.openbas.model.inject.form.Expectation; -import lombok.Getter; -import lombok.Setter; - import java.util.ArrayList; import java.util.List; +import lombok.Getter; +import lombok.Setter; @Setter @Getter @@ -21,5 +20,4 @@ public class ChannelContent extends EmailContent { @JsonProperty("emailing") private boolean emailing; - } diff --git a/openbas-api/src/main/java/io/openbas/injectors/email/EmailContract.java b/openbas-api/src/main/java/io/openbas/injectors/email/EmailContract.java index 5919da59a4..e0a3af599b 100644 --- a/openbas-api/src/main/java/io/openbas/injectors/email/EmailContract.java +++ b/openbas-api/src/main/java/io/openbas/injectors/email/EmailContract.java @@ -1,93 +1,109 @@ package io.openbas.injectors.email; -import io.openbas.injector_contract.*; -import io.openbas.injector_contract.fields.ContractElement; -import io.openbas.injector_contract.fields.ContractExpectations; -import io.openbas.database.model.Endpoint; -import io.openbas.database.model.Variable.VariableType; -import org.springframework.stereotype.Component; - -import java.io.InputStream; -import java.util.List; -import java.util.Map; - +import static io.openbas.helper.SupportedLanguage.en; +import static io.openbas.helper.SupportedLanguage.fr; import static io.openbas.injector_contract.Contract.executableContract; import static io.openbas.injector_contract.ContractCardinality.Multiple; import static io.openbas.injector_contract.ContractCardinality.One; import static io.openbas.injector_contract.ContractDef.contractBuilder; import static io.openbas.injector_contract.ContractVariable.variable; import static io.openbas.injector_contract.fields.ContractAttachment.attachmentField; -import static io.openbas.injector_contract.fields.ContractTeam.teamField; import static io.openbas.injector_contract.fields.ContractCheckbox.checkboxField; import static io.openbas.injector_contract.fields.ContractExpectations.expectationsField; +import static io.openbas.injector_contract.fields.ContractTeam.teamField; import static io.openbas.injector_contract.fields.ContractText.textField; import static io.openbas.injector_contract.fields.ContractTextArea.richTextareaField; -import static io.openbas.helper.SupportedLanguage.en; -import static io.openbas.helper.SupportedLanguage.fr; + +import io.openbas.database.model.Endpoint; +import io.openbas.database.model.Variable.VariableType; +import io.openbas.injector_contract.*; +import io.openbas.injector_contract.fields.ContractElement; +import io.openbas.injector_contract.fields.ContractExpectations; +import java.io.InputStream; +import java.util.List; +import java.util.Map; +import org.springframework.stereotype.Component; @Component public class EmailContract extends Contractor { - public static final String TYPE = "openbas_email"; - public static final String EMAIL_DEFAULT = "138ad8f8-32f8-4a22-8114-aaa12322bd09"; - public static final String EMAIL_GLOBAL = "2790bd39-37d4-4e39-be7e-53f3ca783f86"; + public static final String TYPE = "openbas_email"; + public static final String EMAIL_DEFAULT = "138ad8f8-32f8-4a22-8114-aaa12322bd09"; + public static final String EMAIL_GLOBAL = "2790bd39-37d4-4e39-be7e-53f3ca783f86"; - @Override - public boolean isExpose() { - return true; - } + @Override + public boolean isExpose() { + return true; + } - @Override - public String getType() { - return TYPE; - } + @Override + public String getType() { + return TYPE; + } - @Override - public ContractConfig getConfig() { - return new ContractConfig(TYPE, Map.of(en, "Email", fr, "Email"), "#cddc39", "#cddc39", "/img/email.png", isExpose()); - } + @Override + public ContractConfig getConfig() { + return new ContractConfig( + TYPE, Map.of(en, "Email", fr, "Email"), "#cddc39", "#cddc39", "/img/email.png", isExpose()); + } - @Override - public List contracts() { - // variables - ContractVariable documentUriVariable = variable("document_uri", - "Http user link to upload the document (only for document expectation)", VariableType.String, One); - // Contracts - ContractExpectations expectationsField = expectationsField( - "expectations", "Expectations" - ); - ContractConfig contractConfig = getConfig(); - // Standard contract - List standardInstance = contractBuilder() - .mandatory(teamField("teams", "Teams", Multiple)) - .mandatory(textField("subject", "Subject")) - .mandatory(richTextareaField("body", "Body")) - // .optional(textField("inReplyTo", "InReplyTo", "HIDDEN")) - Use for direct injection - .optional(checkboxField("encrypted", "Encrypted", false)) - .optional(attachmentField("attachments", "Attachments", Multiple)) - .optional(expectationsField) - .build(); - Contract standardEmail = executableContract(contractConfig, EMAIL_DEFAULT, - Map.of(en, "Send individual mails", fr, "Envoyer des mails individuels"), standardInstance, List.of(Endpoint.PLATFORM_TYPE.Service), false); - standardEmail.addVariable(documentUriVariable); - // Global contract - List globalInstance = contractBuilder() - .mandatory(teamField("teams", "Teams", Multiple)) - .mandatory(textField("subject", "Subject")) - .mandatory(richTextareaField("body", "Body")) - // .mandatory(textField("inReplyTo", "InReplyTo", "HIDDEN")) - Use for direct injection - .optional(attachmentField("attachments", "Attachments", Multiple)) - .optional(expectationsField) - .build(); - Contract globalEmail = executableContract(contractConfig, EMAIL_GLOBAL, - Map.of(en, "Send multi-recipients mail", fr, "Envoyer un mail multi-destinataires"), globalInstance, List.of(Endpoint.PLATFORM_TYPE.Service), false); - globalEmail.addVariable(documentUriVariable); - return List.of(standardEmail, globalEmail); - } + @Override + public List contracts() { + // variables + ContractVariable documentUriVariable = + variable( + "document_uri", + "Http user link to upload the document (only for document expectation)", + VariableType.String, + One); + // Contracts + ContractExpectations expectationsField = expectationsField("expectations", "Expectations"); + ContractConfig contractConfig = getConfig(); + // Standard contract + List standardInstance = + contractBuilder() + .mandatory(teamField("teams", "Teams", Multiple)) + .mandatory(textField("subject", "Subject")) + .mandatory(richTextareaField("body", "Body")) + // .optional(textField("inReplyTo", "InReplyTo", "HIDDEN")) - Use for direct injection + .optional(checkboxField("encrypted", "Encrypted", false)) + .optional(attachmentField("attachments", "Attachments", Multiple)) + .optional(expectationsField) + .build(); + Contract standardEmail = + executableContract( + contractConfig, + EMAIL_DEFAULT, + Map.of(en, "Send individual mails", fr, "Envoyer des mails individuels"), + standardInstance, + List.of(Endpoint.PLATFORM_TYPE.Service), + false); + standardEmail.addVariable(documentUriVariable); + // Global contract + List globalInstance = + contractBuilder() + .mandatory(teamField("teams", "Teams", Multiple)) + .mandatory(textField("subject", "Subject")) + .mandatory(richTextareaField("body", "Body")) + // .mandatory(textField("inReplyTo", "InReplyTo", "HIDDEN")) - Use for direct injection + .optional(attachmentField("attachments", "Attachments", Multiple)) + .optional(expectationsField) + .build(); + Contract globalEmail = + executableContract( + contractConfig, + EMAIL_GLOBAL, + Map.of(en, "Send multi-recipients mail", fr, "Envoyer un mail multi-destinataires"), + globalInstance, + List.of(Endpoint.PLATFORM_TYPE.Service), + false); + globalEmail.addVariable(documentUriVariable); + return List.of(standardEmail, globalEmail); + } - @Override - public ContractorIcon getIcon() { - InputStream iconStream = getClass().getResourceAsStream("/img/icon-email.png"); - return new ContractorIcon(iconStream); - } + @Override + public ContractorIcon getIcon() { + InputStream iconStream = getClass().getResourceAsStream("/img/icon-email.png"); + return new ContractorIcon(iconStream); + } } diff --git a/openbas-api/src/main/java/io/openbas/injectors/email/EmailExecutor.java b/openbas-api/src/main/java/io/openbas/injectors/email/EmailExecutor.java index 248f40d909..a7deb4ed54 100644 --- a/openbas-api/src/main/java/io/openbas/injectors/email/EmailExecutor.java +++ b/openbas-api/src/main/java/io/openbas/injectors/email/EmailExecutor.java @@ -1,5 +1,8 @@ package io.openbas.injectors.email; +import static io.openbas.database.model.InjectStatusExecution.traceError; +import static io.openbas.injectors.email.EmailContract.EMAIL_GLOBAL; + import io.openbas.config.OpenBASConfig; import io.openbas.database.model.*; import io.openbas.execution.ExecutableInject; @@ -12,21 +15,16 @@ import io.openbas.model.expectation.ManualExpectation; import jakarta.annotation.Resource; import jakarta.validation.constraints.NotNull; +import java.util.List; +import java.util.stream.Stream; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Value; import org.springframework.stereotype.Component; -import java.util.List; -import java.util.stream.Stream; - -import static io.openbas.database.model.InjectStatusExecution.traceError; -import static io.openbas.injectors.email.EmailContract.EMAIL_GLOBAL; - @Component(EmailContract.TYPE) public class EmailExecutor extends Injector { - @Resource - private OpenBASConfig openBASConfig; + @Resource private OpenBASConfig openBASConfig; private EmailService emailService; @@ -38,36 +36,63 @@ public void setEmailService(EmailService emailService) { this.emailService = emailService; } - private void sendMulti(Execution execution, List users, String from, List replyTos, + private void sendMulti( + Execution execution, + List users, + String from, + List replyTos, String inReplyTo, - String subject, String message, List attachments) { + String subject, + String message, + List attachments) { try { - emailService.sendEmail(execution, users, from, replyTos, inReplyTo, subject, message, attachments); + emailService.sendEmail( + execution, users, from, replyTos, inReplyTo, subject, message, attachments); } catch (Exception e) { execution.addTrace(traceError(e.getMessage())); } } - private void sendSingle(Execution execution, List users, String from, List replyTos, + private void sendSingle( + Execution execution, + List users, + String from, + List replyTos, String inReplyTo, - boolean mustBeEncrypted, String subject, String message, List attachments) { - users.forEach(user -> { - try { - emailService.sendEmail(execution, user, from, replyTos, inReplyTo, mustBeEncrypted, subject, message, - attachments); - } catch (Exception e) { - execution.addTrace(traceError(e.getMessage())); - } - }); + boolean mustBeEncrypted, + String subject, + String message, + List attachments) { + users.forEach( + user -> { + try { + emailService.sendEmail( + execution, + user, + from, + replyTos, + inReplyTo, + mustBeEncrypted, + subject, + message, + attachments); + } catch (Exception e) { + execution.addTrace(traceError(e.getMessage())); + } + }); } @Override - public ExecutionProcess process(@NotNull final Execution execution, @NotNull final ExecutableInject injection) + public ExecutionProcess process( + @NotNull final Execution execution, @NotNull final ExecutableInject injection) throws Exception { Inject inject = injection.getInjection().getInject(); EmailContent content = contentConvert(injection, EmailContent.class); - List documents = inject.getDocuments().stream().filter(InjectDocument::isAttached) - .map(InjectDocument::getDocument).toList(); + List documents = + inject.getDocuments().stream() + .filter(InjectDocument::isAttached) + .map(InjectDocument::getDocument) + .toList(); List attachments = resolveAttachments(execution, injection, documents); String inReplyTo = content.getInReplyTo(); String subject = content.getSubject(); @@ -80,22 +105,36 @@ public ExecutionProcess process(@NotNull final Execution execution, @NotNull fin } Exercise exercise = injection.getInjection().getExercise(); String from = exercise != null ? exercise.getFrom() : this.openBASConfig.getDefaultMailer(); - List replyTos = exercise != null ? exercise.getReplyTos() : List.of(this.openBASConfig.getDefaultReplyTo()); + List replyTos = + exercise != null ? exercise.getReplyTos() : List.of(this.openBASConfig.getDefaultReplyTo()); //noinspection SwitchStatementWithTooFewBranches - switch (inject.getInjectorContract().map(InjectorContract::getId) + switch (inject + .getInjectorContract() + .map(InjectorContract::getId) .orElseThrow(() -> new UnsupportedOperationException("Inject does not have a contract"))) { - case EMAIL_GLOBAL -> sendMulti(execution, users, from, replyTos, inReplyTo, subject, message, attachments); + case EMAIL_GLOBAL -> + sendMulti(execution, users, from, replyTos, inReplyTo, subject, message, attachments); default -> - sendSingle(execution, users, from, replyTos, inReplyTo, mustBeEncrypted, subject, message, attachments); + sendSingle( + execution, + users, + from, + replyTos, + inReplyTo, + mustBeEncrypted, + subject, + message, + attachments); } - List expectations = content.getExpectations() - .stream() - .flatMap((entry) -> switch (entry.getType()) { - case MANUAL -> Stream.of( - (Expectation) new ManualExpectation(entry)); - default -> Stream.of(); - }) - .toList(); + List expectations = + content.getExpectations().stream() + .flatMap( + (entry) -> + switch (entry.getType()) { + case MANUAL -> Stream.of((Expectation) new ManualExpectation(entry)); + default -> Stream.of(); + }) + .toList(); return new ExecutionProcess(false, expectations); } } diff --git a/openbas-api/src/main/java/io/openbas/injectors/email/EmailInjector.java b/openbas-api/src/main/java/io/openbas/injectors/email/EmailInjector.java index 7ea21d2c32..361ba9fb55 100644 --- a/openbas-api/src/main/java/io/openbas/injectors/email/EmailInjector.java +++ b/openbas-api/src/main/java/io/openbas/injectors/email/EmailInjector.java @@ -7,24 +7,23 @@ @Component public class EmailInjector { - private static final String EMAIL_INJECTOR_NAME = "Email"; - private static final String EMAIL_INJECTOR_ID = "41b4dd55-5bd1-4614-98cd-9e3770753306"; + private static final String EMAIL_INJECTOR_NAME = "Email"; + private static final String EMAIL_INJECTOR_ID = "41b4dd55-5bd1-4614-98cd-9e3770753306"; - @Autowired - public EmailInjector(InjectorService injectorService, EmailContract contract) { - try { - injectorService.register( - EMAIL_INJECTOR_ID, - EMAIL_INJECTOR_NAME, - contract, - false, - "communication", - null, - null, - false - ); - } catch (Exception e) { - throw new RuntimeException(e); - } + @Autowired + public EmailInjector(InjectorService injectorService, EmailContract contract) { + try { + injectorService.register( + EMAIL_INJECTOR_ID, + EMAIL_INJECTOR_NAME, + contract, + false, + "communication", + null, + null, + false); + } catch (Exception e) { + throw new RuntimeException(e); } + } } diff --git a/openbas-api/src/main/java/io/openbas/injectors/email/model/EmailContent.java b/openbas-api/src/main/java/io/openbas/injectors/email/model/EmailContent.java index e99e2f5681..e8c2accf15 100644 --- a/openbas-api/src/main/java/io/openbas/injectors/email/model/EmailContent.java +++ b/openbas-api/src/main/java/io/openbas/injectors/email/model/EmailContent.java @@ -3,19 +3,19 @@ import com.fasterxml.jackson.annotation.JsonProperty; import io.openbas.execution.ExecutableInject; import io.openbas.model.inject.form.Expectation; -import lombok.Getter; -import lombok.Setter; -import org.springframework.util.StringUtils; - import java.util.ArrayList; import java.util.List; import java.util.Objects; +import lombok.Getter; +import lombok.Setter; +import org.springframework.util.StringUtils; @Getter @Setter public class EmailContent { - private static final String HEADER_DIV = "
"; + private static final String HEADER_DIV = + "
"; private static final String START_DIV = "
"; private static final String END_DIV = "
"; @@ -50,10 +50,14 @@ public String buildMessage(ExecutableInject injection, boolean imapEnabled) { if (injection.isRuntime() && imapEnabled) { data.append(START_DIV) .append("



") - .append("---------------------------------------------------------------------------------
") + .append( + "---------------------------------------------------------------------------------
") .append("OpenBAS internal information, do not remove!
") - .append("[inject_id=").append(injection.getInjection().getId()).append("]
") - .append("---------------------------------------------------------------------------------
") + .append("[inject_id=") + .append(injection.getInjection().getId()) + .append("]
") + .append( + "---------------------------------------------------------------------------------
") .append(END_DIV); } return data.toString(); @@ -68,7 +72,8 @@ public boolean equals(Object o) { return false; } EmailContent that = (EmailContent) o; - return encrypted == that.encrypted && Objects.equals(body, that.body) + return encrypted == that.encrypted + && Objects.equals(body, that.body) && Objects.equals(subject, that.subject); } diff --git a/openbas-api/src/main/java/io/openbas/injectors/email/service/EmailPgp.java b/openbas-api/src/main/java/io/openbas/injectors/email/service/EmailPgp.java index 8db8e1a629..7a80d85167 100644 --- a/openbas-api/src/main/java/io/openbas/injectors/email/service/EmailPgp.java +++ b/openbas-api/src/main/java/io/openbas/injectors/email/service/EmailPgp.java @@ -1,14 +1,9 @@ package io.openbas.injectors.email.service; -import io.openbas.execution.ProtectUser; -import org.bouncycastle.bcpg.ArmoredOutputStream; -import org.bouncycastle.bcpg.CompressionAlgorithmTags; -import org.bouncycastle.openpgp.*; -import org.bouncycastle.openpgp.jcajce.JcaPGPPublicKeyRing; -import org.bouncycastle.openpgp.operator.bc.BcPGPDataEncryptorBuilder; -import org.bouncycastle.openpgp.operator.bc.BcPublicKeyKeyEncryptionMethodGenerator; -import org.springframework.stereotype.Component; +import static java.util.Spliterators.spliteratorUnknownSize; +import static org.springframework.util.StringUtils.hasLength; +import io.openbas.execution.ProtectUser; import java.io.*; import java.nio.charset.StandardCharsets; import java.security.SecureRandom; @@ -16,9 +11,13 @@ import java.util.Spliterator; import java.util.stream.Stream; import java.util.stream.StreamSupport; - -import static java.util.Spliterators.spliteratorUnknownSize; -import static org.springframework.util.StringUtils.hasLength; +import org.bouncycastle.bcpg.ArmoredOutputStream; +import org.bouncycastle.bcpg.CompressionAlgorithmTags; +import org.bouncycastle.openpgp.*; +import org.bouncycastle.openpgp.jcajce.JcaPGPPublicKeyRing; +import org.bouncycastle.openpgp.operator.bc.BcPGPDataEncryptorBuilder; +import org.bouncycastle.openpgp.operator.bc.BcPublicKeyKeyEncryptionMethodGenerator; +import org.springframework.stereotype.Component; @Component public class EmailPgp { @@ -31,10 +30,14 @@ public PGPPublicKey getUserPgpKey(ProtectUser user) throws IOException { InputStream in = new ByteArrayInputStream(userPgpKey.getBytes()); InputStream decoderStream = PGPUtil.getDecoderStream(in); PGPPublicKeyRing keyRing = new JcaPGPPublicKeyRing(decoderStream); - Spliterator splitIterator = spliteratorUnknownSize(keyRing.getPublicKeys(), Spliterator.ORDERED); + Spliterator splitIterator = + spliteratorUnknownSize(keyRing.getPublicKeys(), Spliterator.ORDERED); Stream targetStream = StreamSupport.stream(splitIterator, false); - return targetStream.filter(pgpPublicKey -> pgpPublicKey.isEncryptionKey() && !pgpPublicKey.isMasterKey()) - .findFirst().orElseThrow(() -> new IllegalArgumentException(user.getEmail() + " has invalid PGP public key")); + return targetStream + .filter(pgpPublicKey -> pgpPublicKey.isEncryptionKey() && !pgpPublicKey.isMasterKey()) + .findFirst() + .orElseThrow( + () -> new IllegalArgumentException(user.getEmail() + " has invalid PGP public key")); } public String encrypt(PGPPublicKey encKey, String clearData) { @@ -46,9 +49,11 @@ private byte[] encrypt(byte[] clearData, PGPPublicKey encKey) { byte[] compressedData = compress(clearData); ByteArrayOutputStream bOut = new ByteArrayOutputStream(); OutputStream out = new ArmoredOutputStream(bOut); - PGPEncryptedDataGenerator encGen = new PGPEncryptedDataGenerator( - new BcPGPDataEncryptorBuilder(PGPEncryptedDataGenerator.CAST5) - .setSecureRandom(new SecureRandom()).setWithIntegrityPacket(true)); + PGPEncryptedDataGenerator encGen = + new PGPEncryptedDataGenerator( + new BcPGPDataEncryptorBuilder(PGPEncryptedDataGenerator.CAST5) + .setSecureRandom(new SecureRandom()) + .setWithIntegrityPacket(true)); encGen.addMethod(new BcPublicKeyKeyEncryptionMethodGenerator(encKey)); OutputStream encOut = encGen.open(out, compressedData.length); encOut.write(compressedData); @@ -62,15 +67,18 @@ private byte[] encrypt(byte[] clearData, PGPPublicKey encKey) { private byte[] compress(byte[] clearData) throws IOException { ByteArrayOutputStream bOut = new ByteArrayOutputStream(); - PGPCompressedDataGenerator comData = new PGPCompressedDataGenerator(CompressionAlgorithmTags.ZIP); + PGPCompressedDataGenerator comData = + new PGPCompressedDataGenerator(CompressionAlgorithmTags.ZIP); OutputStream cos = comData.open(bOut); // open it with the final destination PGPLiteralDataGenerator lData = new PGPLiteralDataGenerator(); - OutputStream pOut = lData.open(cos, // the compressed output stream - PGPLiteralData.BINARY, - PGPLiteralData.CONSOLE, - clearData.length, // length of clear data - new Date() // current time - ); + OutputStream pOut = + lData.open( + cos, // the compressed output stream + PGPLiteralData.BINARY, + PGPLiteralData.CONSOLE, + clearData.length, // length of clear data + new Date() // current time + ); pOut.write(clearData); pOut.close(); comData.close(); diff --git a/openbas-api/src/main/java/io/openbas/injectors/email/service/EmailService.java b/openbas-api/src/main/java/io/openbas/injectors/email/service/EmailService.java index c631acbb32..789d306803 100644 --- a/openbas-api/src/main/java/io/openbas/injectors/email/service/EmailService.java +++ b/openbas-api/src/main/java/io/openbas/injectors/email/service/EmailService.java @@ -1,5 +1,9 @@ package io.openbas.injectors.email.service; +import static io.openbas.database.model.InjectStatusExecution.*; +import static io.openbas.helper.TemplateHelper.buildContextualContent; +import static java.util.stream.Collectors.joining; + import io.openbas.database.model.DataAttachment; import io.openbas.database.model.Execution; import io.openbas.execution.ExecutionContext; @@ -9,184 +13,214 @@ import jakarta.mail.Multipart; import jakarta.mail.internet.*; import jakarta.mail.util.ByteArrayDataSource; +import java.io.ByteArrayOutputStream; +import java.io.IOException; +import java.util.ArrayList; +import java.util.List; import org.bouncycastle.openpgp.PGPPublicKey; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Value; import org.springframework.mail.javamail.JavaMailSender; import org.springframework.stereotype.Component; -import java.io.ByteArrayOutputStream; -import java.io.IOException; -import java.util.ArrayList; -import java.util.List; - -import static io.openbas.database.model.InjectStatusExecution.*; -import static io.openbas.helper.TemplateHelper.buildContextualContent; -import static java.util.stream.Collectors.joining; - @Component public class EmailService { - private JavaMailSender emailSender; - private EmailPgp emailPgp; - - @Value("${openbas.mail.imap.enabled}") - private boolean imapEnabled; - - private ImapService imapService; - - @Autowired - public void setImapService(ImapService imapService) { - this.imapService = imapService; - } - - @Autowired - public void setEmailSender(JavaMailSender emailSender) { - this.emailSender = emailSender; - } - - @Autowired - public void setEmailPgp(EmailPgp emailPgp) { - this.emailPgp = emailPgp; + private JavaMailSender emailSender; + private EmailPgp emailPgp; + + @Value("${openbas.mail.imap.enabled}") + private boolean imapEnabled; + + private ImapService imapService; + + @Autowired + public void setImapService(ImapService imapService) { + this.imapService = imapService; + } + + @Autowired + public void setEmailSender(JavaMailSender emailSender) { + this.emailSender = emailSender; + } + + @Autowired + public void setEmailPgp(EmailPgp emailPgp) { + this.emailPgp = emailPgp; + } + + public void sendEmail( + Execution execution, + List usersContext, + String from, + List replyTos, + String inReplyTo, + String subject, + String message, + List attachments) + throws Exception { + MimeMessage mimeMessage = + buildMimeMessage(from, replyTos, inReplyTo, subject, message, attachments); + List recipients = new ArrayList<>(); + for (ExecutionContext userContext : usersContext) { + recipients.add(new InternetAddress(userContext.getUser().getEmail())); } - - - public void sendEmail(Execution execution, List usersContext, String from, List replyTos, String inReplyTo, - String subject, String message, List attachments) throws Exception { - MimeMessage mimeMessage = buildMimeMessage(from, replyTos, inReplyTo, subject, message, attachments); - List recipients = new ArrayList<>(); - for (ExecutionContext userContext : usersContext) { - recipients.add(new InternetAddress(userContext.getUser().getEmail())); - } - mimeMessage.setRecipients(Message.RecipientType.TO, recipients.toArray(InternetAddress[]::new)); - this.sendEmailWithRetry(mimeMessage); - String emails = usersContext.stream().map(c -> c.getUser().getEmail()).collect(joining(", ")); - List userIds = usersContext.stream().map(c -> c.getUser().getId()).toList(); - execution.addTrace(traceSuccess("Mail sent to " + emails, userIds)); - // Store message in Imap after sending - storeMessageImap(execution, mimeMessage); + mimeMessage.setRecipients(Message.RecipientType.TO, recipients.toArray(InternetAddress[]::new)); + this.sendEmailWithRetry(mimeMessage); + String emails = usersContext.stream().map(c -> c.getUser().getEmail()).collect(joining(", ")); + List userIds = usersContext.stream().map(c -> c.getUser().getId()).toList(); + execution.addTrace(traceSuccess("Mail sent to " + emails, userIds)); + // Store message in Imap after sending + storeMessageImap(execution, mimeMessage); + } + + public void sendEmail( + Execution execution, + ExecutionContext userContext, + String from, + List replyTos, + String inReplyTo, + boolean mustBeEncrypted, + String subject, + String message, + List attachments) + throws Exception { + String email = userContext.getUser().getEmail(); + String contextualSubject = buildContextualContent(subject, userContext); + String contextualBody = buildContextualContent(message, userContext); + + MimeMessage mimeMessage = + buildMimeMessage(from, replyTos, inReplyTo, contextualSubject, contextualBody, attachments); + mimeMessage.setRecipient(Message.RecipientType.TO, new InternetAddress(email)); + // Crypt if needed + if (mustBeEncrypted) { + MimeMessage encMessage = + getEncryptedMimeMessage(userContext, from, replyTos, subject, email, mimeMessage); + this.sendEmailWithRetry(encMessage); + } else { + this.sendEmailWithRetry(mimeMessage); } - - public void sendEmail(Execution execution, ExecutionContext userContext, String from, List replyTos, String inReplyTo, - boolean mustBeEncrypted, String subject, String message, List attachments) - throws Exception { - String email = userContext.getUser().getEmail(); - String contextualSubject = buildContextualContent(subject, userContext); - String contextualBody = buildContextualContent(message, userContext); - - MimeMessage mimeMessage = buildMimeMessage(from, replyTos, inReplyTo, contextualSubject, contextualBody, attachments); - mimeMessage.setRecipient(Message.RecipientType.TO, new InternetAddress(email)); - // Crypt if needed - if (mustBeEncrypted) { - MimeMessage encMessage = getEncryptedMimeMessage(userContext, from, replyTos, subject, email, mimeMessage); - this.sendEmailWithRetry(encMessage); - } else { - this.sendEmailWithRetry(mimeMessage); - } - List userIds = List.of(userContext.getUser().getId()); - execution.addTrace(traceSuccess("Mail sent to " + email, userIds)); - // Store message in Imap after sending - storeMessageImap(execution, mimeMessage); + List userIds = List.of(userContext.getUser().getId()); + execution.addTrace(traceSuccess("Mail sent to " + email, userIds)); + // Store message in Imap after sending + storeMessageImap(execution, mimeMessage); + } + + private InternetAddress getInternetAddress(String email) { + try { + return new InternetAddress(email); + } catch (AddressException e) { + throw new IllegalArgumentException("Invalid email address: " + email, e); } + } - private InternetAddress getInternetAddress(String email){ + private void storeMessageImap(Execution execution, MimeMessage mimeMessage) + throws InterruptedException { + if (execution.isRuntime() && imapEnabled) { + for (int i = 0; i < 3; i++) { try { - return new InternetAddress(email); - } catch (AddressException e) { - throw new IllegalArgumentException("Invalid email address: " + email, e); + imapService.storeSentMessage(mimeMessage); + execution.addTrace(traceSuccess("Mail successfully stored in IMAP")); + return; + } catch (Exception e) { + execution.addTrace(traceInfo("Fail to store mail in IMAP" + e.getMessage())); + Thread.sleep(2000); } + } + execution.addTrace(traceError("Fail to store mail in IMAP after 3 attempts")); } - - private void storeMessageImap(Execution execution, MimeMessage mimeMessage) throws InterruptedException { - if (execution.isRuntime() && imapEnabled) { - for (int i = 0; i < 3; i++) { - try { - imapService.storeSentMessage(mimeMessage); - execution.addTrace(traceSuccess("Mail successfully stored in IMAP")); - return; - } catch (Exception e) { - execution.addTrace(traceInfo("Fail to store mail in IMAP" + e.getMessage())); - Thread.sleep(2000); - } - } - execution.addTrace(traceError("Fail to store mail in IMAP after 3 attempts")); - } + } + + private MimeMessage buildMimeMessage( + String from, + List replyTos, + String inReplyTo, + String subject, + String body, + List attachments) + throws Exception { + MimeMessage mimeMessage = emailSender.createMimeMessage(); + mimeMessage.setFrom(from); + mimeMessage.setReplyTo( + replyTos.stream().map(this::getInternetAddress).toArray(InternetAddress[]::new)); + + if (inReplyTo != null) { + mimeMessage.setHeader("In-Reply-To", inReplyTo); + mimeMessage.setHeader("References", inReplyTo); } - - private MimeMessage buildMimeMessage(String from, List replyTos, String inReplyTo, String subject, String body, - List attachments) throws Exception { - MimeMessage mimeMessage = emailSender.createMimeMessage(); - mimeMessage.setFrom(from); - mimeMessage.setReplyTo(replyTos.stream().map(this::getInternetAddress).toArray(InternetAddress[]::new)); - - if (inReplyTo != null) { - mimeMessage.setHeader("In-Reply-To", inReplyTo); - mimeMessage.setHeader("References", inReplyTo); - } - mimeMessage.setSubject(subject, "utf-8"); - Multipart mailMultipart = new MimeMultipart("mixed"); - // Add mail content - MimeBodyPart bodyPart = new MimeBodyPart(); - bodyPart.setContent(body, "text/html;charset=utf-8"); - mailMultipart.addBodyPart(bodyPart); - // Add Attachments - for (DataAttachment attachment : attachments) { - MimeBodyPart aBodyPart = new MimeBodyPart(); - aBodyPart.setFileName(attachment.name()); - aBodyPart.setHeader("Content-Type", attachment.contentType()); - ByteArrayDataSource bds = new ByteArrayDataSource(attachment.data(), attachment.contentType()); - aBodyPart.setDataHandler(new DataHandler(bds)); - mailMultipart.addBodyPart(aBodyPart); - } - mimeMessage.setContent(mailMultipart); - return mimeMessage; - } - - private MimeMessage getEncryptedMimeMessage(ExecutionContext userContext, String from, List replyTos, String subject, String email, MimeMessage mimeMessage) throws IOException, MessagingException { - PGPPublicKey userPgpKey = emailPgp.getUserPgpKey(userContext.getUser()); - // Need to create another email that will wrap everything. - MimeMessage encMessage = emailSender.createMimeMessage(); - encMessage.setFrom(from); - encMessage.setReplyTo(replyTos.stream().map(this::getInternetAddress).toArray(InternetAddress[]::new)); - encMessage.setSubject(subject, "utf-8"); - encMessage.setRecipient(Message.RecipientType.TO, new InternetAddress(email)); - - Multipart encMultipart = new MimeMultipart("encrypted; protocol=\"application/pgp-encrypted\""); - // This is an OpenPGP/MIME encrypted message (RFC 4880 and 3156) - InternetHeaders headers = new InternetHeaders(); - headers.addHeader("Content-Type", "application/pgp-encrypted"); - - MimeBodyPart mimeExPart = new MimeBodyPart(headers, "Version: 1".getBytes()); - mimeExPart.setDescription("PGP/MIME version identification"); - encMultipart.addBodyPart(mimeExPart); - - // Export and crypt to basic email - ByteArrayOutputStream multiEncStream = new ByteArrayOutputStream(); - mimeMessage.writeTo(multiEncStream); - - String encryptedEmail = emailPgp.encrypt(userPgpKey, multiEncStream.toString()); - - MimeBodyPart encBodyPart = new MimeBodyPart(); - encBodyPart.setDisposition("inline"); - encBodyPart.setFileName("openpgp-encrypted-message.asc"); - encBodyPart.setContent(encryptedEmail, "application/octet-stream"); - encMultipart.addBodyPart(encBodyPart); - // Fill the message with the multipart content - encMessage.setContent(encMultipart); - return encMessage; + mimeMessage.setSubject(subject, "utf-8"); + Multipart mailMultipart = new MimeMultipart("mixed"); + // Add mail content + MimeBodyPart bodyPart = new MimeBodyPart(); + bodyPart.setContent(body, "text/html;charset=utf-8"); + mailMultipart.addBodyPart(bodyPart); + // Add Attachments + for (DataAttachment attachment : attachments) { + MimeBodyPart aBodyPart = new MimeBodyPart(); + aBodyPart.setFileName(attachment.name()); + aBodyPart.setHeader("Content-Type", attachment.contentType()); + ByteArrayDataSource bds = + new ByteArrayDataSource(attachment.data(), attachment.contentType()); + aBodyPart.setDataHandler(new DataHandler(bds)); + mailMultipart.addBodyPart(aBodyPart); } - - private void sendEmailWithRetry(MimeMessage mimeMessage) throws Exception { - for (int i = 0; i < 3; i++) { - try { - emailSender.send(mimeMessage); - break; - } catch (Exception e) { - if( i == 2 ) { - throw e; - } - Thread.sleep(2000); - } + mimeMessage.setContent(mailMultipart); + return mimeMessage; + } + + private MimeMessage getEncryptedMimeMessage( + ExecutionContext userContext, + String from, + List replyTos, + String subject, + String email, + MimeMessage mimeMessage) + throws IOException, MessagingException { + PGPPublicKey userPgpKey = emailPgp.getUserPgpKey(userContext.getUser()); + // Need to create another email that will wrap everything. + MimeMessage encMessage = emailSender.createMimeMessage(); + encMessage.setFrom(from); + encMessage.setReplyTo( + replyTos.stream().map(this::getInternetAddress).toArray(InternetAddress[]::new)); + encMessage.setSubject(subject, "utf-8"); + encMessage.setRecipient(Message.RecipientType.TO, new InternetAddress(email)); + + Multipart encMultipart = new MimeMultipart("encrypted; protocol=\"application/pgp-encrypted\""); + // This is an OpenPGP/MIME encrypted message (RFC 4880 and 3156) + InternetHeaders headers = new InternetHeaders(); + headers.addHeader("Content-Type", "application/pgp-encrypted"); + + MimeBodyPart mimeExPart = new MimeBodyPart(headers, "Version: 1".getBytes()); + mimeExPart.setDescription("PGP/MIME version identification"); + encMultipart.addBodyPart(mimeExPart); + + // Export and crypt to basic email + ByteArrayOutputStream multiEncStream = new ByteArrayOutputStream(); + mimeMessage.writeTo(multiEncStream); + + String encryptedEmail = emailPgp.encrypt(userPgpKey, multiEncStream.toString()); + + MimeBodyPart encBodyPart = new MimeBodyPart(); + encBodyPart.setDisposition("inline"); + encBodyPart.setFileName("openpgp-encrypted-message.asc"); + encBodyPart.setContent(encryptedEmail, "application/octet-stream"); + encMultipart.addBodyPart(encBodyPart); + // Fill the message with the multipart content + encMessage.setContent(encMultipart); + return encMessage; + } + + private void sendEmailWithRetry(MimeMessage mimeMessage) throws Exception { + for (int i = 0; i < 3; i++) { + try { + emailSender.send(mimeMessage); + break; + } catch (Exception e) { + if (i == 2) { + throw e; } + Thread.sleep(2000); + } } + } } diff --git a/openbas-api/src/main/java/io/openbas/injectors/email/service/ImapService.java b/openbas-api/src/main/java/io/openbas/injectors/email/service/ImapService.java index 97bc934c28..709a590dad 100644 --- a/openbas-api/src/main/java/io/openbas/injectors/email/service/ImapService.java +++ b/openbas-api/src/main/java/io/openbas/injectors/email/service/ImapService.java @@ -1,5 +1,7 @@ package io.openbas.injectors.email.service; +import static java.lang.Integer.parseInt; +import static java.time.Instant.now; import io.openbas.database.model.*; import io.openbas.database.repository.CommunicationRepository; @@ -13,14 +15,6 @@ import jakarta.mail.internet.InternetAddress; import jakarta.mail.internet.MimeMessage; import jakarta.mail.internet.MimeMultipart; -import lombok.extern.java.Log; -import org.apache.commons.mail.util.MimeMessageParser; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.beans.factory.annotation.Value; -import org.springframework.core.env.Environment; -import org.springframework.scheduling.annotation.Scheduled; -import org.springframework.stereotype.Service; - import java.io.IOException; import java.util.*; import java.util.logging.Level; @@ -28,335 +22,364 @@ import java.util.regex.Matcher; import java.util.regex.Pattern; import java.util.stream.Stream; - -import static java.lang.Integer.parseInt; -import static java.time.Instant.now; +import lombok.extern.java.Log; +import org.apache.commons.mail.util.MimeMessageParser; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.core.env.Environment; +import org.springframework.scheduling.annotation.Scheduled; +import org.springframework.stereotype.Service; @Service @Log public class ImapService { - private static final Logger LOGGER = Logger.getLogger(ImapService.class.getName()); - private final static Pattern INJECT_ID_PATTERN = Pattern.compile("\\[inject_id=(.*)\\]"); - private final static String PROVIDER = "imap"; + private static final Logger LOGGER = Logger.getLogger(ImapService.class.getName()); + private static final Pattern INJECT_ID_PATTERN = Pattern.compile("\\[inject_id=(.*)\\]"); + private static final String PROVIDER = "imap"; - private Store imapStore; + private Store imapStore; - @Value("${openbas.mail.imap.enabled}") - private boolean enabled; + @Value("${openbas.mail.imap.enabled}") + private boolean enabled; - @Value("${openbas.mail.imap.host}") - private String host; + @Value("${openbas.mail.imap.host}") + private String host; - @Value("${openbas.mail.imap.port}") - private Integer port; + @Value("${openbas.mail.imap.port}") + private Integer port; - @Value("${openbas.mail.imap.username}") - private String username; + @Value("${openbas.mail.imap.username}") + private String username; - @Value("${openbas.mail.imap.password}") - private String password; + @Value("${openbas.mail.imap.password}") + private String password; - @Value("${openbas.mail.imap.inbox}") - private List inboxFolders; + @Value("${openbas.mail.imap.inbox}") + private List inboxFolders; - @Value("${openbas.mail.imap.sent}") - private String sentFolder; + @Value("${openbas.mail.imap.sent}") + private String sentFolder; - private UserRepository userRepository; - private InjectRepository injectRepository; - private CommunicationRepository communicationRepository; - private SettingRepository settingRepository; - private FileService fileService; - private final PlatformSettingsService platformSettingsService; + private UserRepository userRepository; + private InjectRepository injectRepository; + private CommunicationRepository communicationRepository; + private SettingRepository settingRepository; + private FileService fileService; + private final PlatformSettingsService platformSettingsService; - public ImapService(Environment env, @Autowired PlatformSettingsService platformSettingsService) { - this.platformSettingsService = platformSettingsService; - try { - initStore(env); - this.platformSettingsService.cleanMessage(BannerMessage.BANNER_KEYS.IMAP_UNAVAILABLE); - } catch (Exception e) { - log.severe(e.getMessage()); - this.platformSettingsService.errorMessage(BannerMessage.BANNER_KEYS.IMAP_UNAVAILABLE); - } + public ImapService(Environment env, @Autowired PlatformSettingsService platformSettingsService) { + this.platformSettingsService = platformSettingsService; + try { + initStore(env); + this.platformSettingsService.cleanMessage(BannerMessage.BANNER_KEYS.IMAP_UNAVAILABLE); + } catch (Exception e) { + log.severe(e.getMessage()); + this.platformSettingsService.errorMessage(BannerMessage.BANNER_KEYS.IMAP_UNAVAILABLE); } - - @Autowired - public void setFileService(FileService fileService) { - this.fileService = fileService; + } + + @Autowired + public void setFileService(FileService fileService) { + this.fileService = fileService; + } + + @Autowired + public void setSettingRepository(SettingRepository settingRepository) { + this.settingRepository = settingRepository; + } + + @Autowired + public void setInjectRepository(InjectRepository injectRepository) { + this.injectRepository = injectRepository; + } + + @Autowired + public void setUserRepository(UserRepository userRepository) { + this.userRepository = userRepository; + } + + @Autowired + public void setCommunicationRepository(CommunicationRepository communicationRepository) { + this.communicationRepository = communicationRepository; + } + + private void initStore(Environment env) throws Exception { + Session session = Session.getDefaultInstance(buildProperties(env), null); + imapStore = session.getStore(PROVIDER); + String host = env.getProperty("openbas.mail.imap.host"); + int port = env.getProperty("openbas.mail.imap.port", Integer.class, 995); + String username = env.getProperty("openbas.mail.imap.username"); + String password = env.getProperty("openbas.mail.imap.password"); + String sentFolder = env.getProperty("openbas.mail.imap.sent"); + boolean isEnabled = env.getProperty("openbas.mail.imap.enabled", Boolean.class, false); + if (isEnabled) { + LOGGER.log(Level.INFO, "IMAP sync started"); + imapStore.connect(host, port, username, password); + try { + Folder defaultFolder = imapStore.getDefaultFolder(); + Folder sentBox = defaultFolder.getFolder(sentFolder); + if (!sentBox.exists()) { + sentBox.create(Folder.READ_WRITE); + sentBox.setSubscribed(true); + } + } catch (Exception e) { + LOGGER.log(Level.SEVERE, e.getMessage(), e); + } + } else { + LOGGER.log(Level.INFO, "IMAP sync disabled"); } - - @Autowired - public void setSettingRepository(SettingRepository settingRepository) { - this.settingRepository = settingRepository; + } + + private String getTextFromMimeMultipart(MimeMultipart mimeMultipart) + throws MessagingException, IOException { + StringBuilder result = new StringBuilder(); + int count = mimeMultipart.getCount(); + for (int i = 0; i < count; i++) { + BodyPart bodyPart = mimeMultipart.getBodyPart(i); + if (bodyPart.isMimeType("text/plain")) { + result.append(bodyPart.getContent()); + break; + } else if (bodyPart.getContent() instanceof MimeMultipart) { + result.append(getTextFromMimeMultipart((MimeMultipart) bodyPart.getContent())); + } } - - @Autowired - public void setInjectRepository(InjectRepository injectRepository) { - this.injectRepository = injectRepository; + return result.toString(); + } + + private String getHtmlFromMimeMultipart(MimeMultipart mimeMultipart) + throws MessagingException, IOException { + StringBuilder result = new StringBuilder(); + int count = mimeMultipart.getCount(); + for (int i = 0; i < count; i++) { + BodyPart bodyPart = mimeMultipart.getBodyPart(i); + if (bodyPart.isMimeType("text/html")) { + result.append((String) bodyPart.getContent()); + break; + } else if (bodyPart.getContent() instanceof MimeMultipart) { + result.append(getHtmlFromMimeMultipart((MimeMultipart) bodyPart.getContent())); + } } - - @Autowired - public void setUserRepository(UserRepository userRepository) { - this.userRepository = userRepository; + return result.toString(); + } + + private String getTextFromMessage(Message message) throws MessagingException, IOException { + String result = ""; + if (message.isMimeType("multipart/*")) { + MimeMultipart mimeMultipart = (MimeMultipart) message.getContent(); + result = getTextFromMimeMultipart(mimeMultipart); + } else if (message.isMimeType("text/plain")) { + result = message.getContent().toString(); } - - @Autowired - public void setCommunicationRepository(CommunicationRepository communicationRepository) { - this.communicationRepository = communicationRepository; + return result; + } + + private String getHtmlFromMessage(Message message) throws MessagingException, IOException { + String result = ""; + if (message.isMimeType("multipart/*")) { + MimeMultipart mimeMultipart = (MimeMultipart) message.getContent(); + result = getHtmlFromMimeMultipart(mimeMultipart); + } else if (message.isMimeType("text/html")) { + result = message.getContent().toString(); } - - private void initStore(Environment env) throws Exception { - Session session = Session.getDefaultInstance(buildProperties(env), null); - imapStore = session.getStore(PROVIDER); - String host = env.getProperty("openbas.mail.imap.host"); - int port = env.getProperty("openbas.mail.imap.port", Integer.class, 995); - String username = env.getProperty("openbas.mail.imap.username"); - String password = env.getProperty("openbas.mail.imap.password"); - String sentFolder = env.getProperty("openbas.mail.imap.sent"); - boolean isEnabled = env.getProperty("openbas.mail.imap.enabled", Boolean.class, false); - if (isEnabled) { - LOGGER.log(Level.INFO, "IMAP sync started"); - imapStore.connect(host, port, username, password); - try { - Folder defaultFolder = imapStore.getDefaultFolder(); - Folder sentBox = defaultFolder.getFolder(sentFolder); - if (!sentBox.exists()) { - sentBox.create(Folder.READ_WRITE); - sentBox.setSubscribed(true); - } - } catch (Exception e) { - LOGGER.log(Level.SEVERE, e.getMessage(), e); - } - } else { - LOGGER.log(Level.INFO, "IMAP sync disabled"); - } + return result; + } + + private Properties buildProperties(Environment env) { + String sslEnable = env.getProperty("openbas.mail.imap.ssl.enable"); + String sslTrust = env.getProperty("openbas.mail.imap.ssl.trust"); + String sslAuth = env.getProperty("openbas.mail.imap.auth"); + String sslStartTLS = env.getProperty("openbas.mail.imap.starttls.enable"); + Properties props = new Properties(); + props.setProperty("mail.imap.ssl.enable", sslEnable); + props.setProperty("mail.imap.ssl.trust", sslTrust); + props.setProperty("mail.imap.auth", sslAuth); + props.setProperty("mail.imap.starttls.enable", sslStartTLS); + return props; + } + + private List computeParticipants(Message message) throws Exception { + List from = + Arrays.stream(message.getFrom()) + .map(addr -> (((InternetAddress) addr).getAddress())) + .toList(); + List recipients = + Arrays.stream(message.getAllRecipients()) + .map(addr -> (((InternetAddress) addr).getAddress())) + .toList(); + return Stream.concat(from.stream(), recipients.stream()) + .map(String::toLowerCase) + .filter(recipient -> !recipient.equals(username)) + .distinct() + .toList(); + } + + private Inject injectResolver(String content, String contentHtml) { + Matcher matcher = + content.length() > 10 + ? INJECT_ID_PATTERN.matcher(content) + : INJECT_ID_PATTERN.matcher(contentHtml); + if (matcher.find()) { + String injectId = matcher.group(1); + return injectRepository.findById(injectId).orElse(null); } - - private String getTextFromMimeMultipart(MimeMultipart mimeMultipart) throws MessagingException, IOException { - StringBuilder result = new StringBuilder(); - int count = mimeMultipart.getCount(); - for (int i = 0; i < count; i++) { - BodyPart bodyPart = mimeMultipart.getBodyPart(i); - if (bodyPart.isMimeType("text/plain")) { - result.append(bodyPart.getContent()); - break; - } else if (bodyPart.getContent() instanceof MimeMultipart) { - result.append(getTextFromMimeMultipart((MimeMultipart) bodyPart.getContent())); + return null; + } + + private void parseMessages(Message[] messages, Boolean isSent) throws Exception { + for (Message message : messages) { + MimeMessage mimeMessage = (MimeMessage) message; + String messageID = mimeMessage.getMessageID(); + boolean messageAlreadyAvailable = communicationRepository.existsByIdentifier(messageID); + if (!messageAlreadyAvailable) { + String content = getTextFromMessage(message); + String contentHtml = getHtmlFromMessage(message); + Inject inject = injectResolver(content, contentHtml); + List participants = computeParticipants(message); + List users = userRepository.findAllByEmailInIgnoreCase(participants); + if (inject != null && !users.isEmpty()) { + String subject = message.getSubject(); + String from = String.valueOf(Arrays.stream(message.getFrom()).toList().get(0)); + String to = String.valueOf(Arrays.stream(message.getAllRecipients()).toList()); + Date receivedDate = message.getReceivedDate(); + Date sentDate = message.getSentDate(); + // Save messaging + Communication communication = new Communication(); + communication.setReceivedAt(receivedDate.toInstant()); + communication.setSentAt(sentDate.toInstant()); + communication.setSubject(subject); + communication.setContent(content); + communication.setContentHtml(contentHtml); + communication.setIdentifier(messageID); + communication.setUsers(users); + communication.setInject(inject); + communication.setAnimation(isSent); + communication.setFrom(from); + communication.setTo(to); + try { + // Save the communication + Communication comm = communicationRepository.save(communication); + // Update inject for real time + inject.setUpdatedAt(now()); + injectRepository.save(inject); + // Upload attachments in communication + final MimeMessageParser mimeParser = new MimeMessageParser(mimeMessage).parse(); + final List attachmentList = mimeParser.getAttachmentList(); + final List uploads = new ArrayList<>(); + String exerciseId = null; + if (inject.getExercise() != null) { + exerciseId = inject.getExercise().getId(); } - } - return result.toString(); - } - - private String getHtmlFromMimeMultipart(MimeMultipart mimeMultipart) throws MessagingException, IOException { - StringBuilder result = new StringBuilder(); - int count = mimeMultipart.getCount(); - for (int i = 0; i < count; i++) { - BodyPart bodyPart = mimeMultipart.getBodyPart(i); - if (bodyPart.isMimeType("text/html")) { - result.append((String) bodyPart.getContent()); - break; - } else if (bodyPart.getContent() instanceof MimeMultipart) { - result.append(getHtmlFromMimeMultipart((MimeMultipart) bodyPart.getContent())); + for (DataSource dataSource : attachmentList) { + final String fileName = dataSource.getName(); + String path = + exerciseId != null + ? "/" + exerciseId + "/communications/" + comm.getId() + : "/communications/" + comm.getId(); + String uploadName = + fileService.uploadStream(path, fileName, dataSource.getInputStream()); + uploads.add(uploadName); } + // Add attachment in the communication + comm.setAttachments(uploads.toArray(String[]::new)); + communicationRepository.save(comm); + } catch (Exception e) { + LOGGER.log(Level.SEVERE, e.getMessage(), e); + } } - return result.toString(); + } } - - private String getTextFromMessage(Message message) throws MessagingException, IOException { - String result = ""; - if (message.isMimeType("multipart/*")) { - MimeMultipart mimeMultipart = (MimeMultipart) message.getContent(); - result = getTextFromMimeMultipart(mimeMultipart); - } else if (message.isMimeType("text/plain")) { - result = message.getContent().toString(); - } - return result; + } + + private void synchronizeBox(Folder inbox, Boolean isSent) throws Exception { + String inboxKey = username + "-imap-" + inbox.getName(); + Optional state = settingRepository.findByKey(inboxKey); + Setting currentState = state.orElse(null); + if (currentState == null) { + currentState = settingRepository.save(new Setting(inboxKey, "0")); } - - private String getHtmlFromMessage(Message message) throws MessagingException, IOException { - String result = ""; - if (message.isMimeType("multipart/*")) { - MimeMultipart mimeMultipart = (MimeMultipart) message.getContent(); - result = getHtmlFromMimeMultipart(mimeMultipart); - } else if (message.isMimeType("text/html")) { - result = message.getContent().toString(); - } - return result; + int startMessageNumber = parseInt(currentState.getValue()); + int messageCount = inbox.getMessageCount(); + if (startMessageNumber < messageCount) { + LOGGER.log( + Level.INFO, + "synchronizeInbox " + + inbox.getName() + + " from " + + startMessageNumber + + " to " + + messageCount); + int start = startMessageNumber + 1; + Message[] messages = inbox.getMessages(start, messageCount); + if (messages.length > 0) { + parseMessages(messages, isSent); + } } - - private Properties buildProperties(Environment env) { - String sslEnable = env.getProperty("openbas.mail.imap.ssl.enable"); - String sslTrust = env.getProperty("openbas.mail.imap.ssl.trust"); - String sslAuth = env.getProperty("openbas.mail.imap.auth"); - String sslStartTLS = env.getProperty("openbas.mail.imap.starttls.enable"); - Properties props = new Properties(); - props.setProperty("mail.imap.ssl.enable", sslEnable); - props.setProperty("mail.imap.ssl.trust", sslTrust); - props.setProperty("mail.imap.auth", sslAuth); - props.setProperty("mail.imap.starttls.enable", sslStartTLS); - return props; + currentState.setValue(String.valueOf(messageCount)); + settingRepository.save(currentState); + } + + private void tryToSynchronizeFolderFromBox(String folderName, Boolean isSent) throws Exception { + try (Folder folderBox = imapStore.getFolder(folderName)) { + folderBox.open(Folder.READ_ONLY); + synchronizeBox(folderBox, isSent); } - - private List computeParticipants(Message message) throws Exception { - List from = Arrays.stream(message.getFrom()).map(addr -> (((InternetAddress) addr).getAddress())).toList(); - List recipients = Arrays.stream(message.getAllRecipients()).map(addr -> (((InternetAddress) addr).getAddress())).toList(); - return Stream.concat(from.stream(), recipients.stream()).map(String::toLowerCase).filter(recipient -> !recipient.equals(username)).distinct().toList(); + } + + private void syncFolders() throws Exception { + try { + // Sync sent + tryToSynchronizeFolderFromBox(sentFolder, true); + // Sync received + for (String listeningFolder : inboxFolders) { + tryToSynchronizeFolderFromBox(listeningFolder, false); + } + } catch (MessagingException e) { + log.warning("Connection failure: " + e.getMessage()); + // Retry logic or rethrow the exception + retrySyncFolders(); } - - private Inject injectResolver(String content, String contentHtml) { - Matcher matcher = content.length() > 10 - ? INJECT_ID_PATTERN.matcher(content) : INJECT_ID_PATTERN.matcher(contentHtml); - if (matcher.find()) { - String injectId = matcher.group(1); - return injectRepository.findById(injectId).orElse(null); + } + + private void retrySyncFolders() throws Exception { + for (int i = 0; i < 3; i++) { + try { + syncFolders(); + break; + } catch (MessagingException e) { + log.warning("Retrying connection..." + e.getMessage()); + Thread.sleep(2000); + if (i == 2 && imapStore != null && imapStore.isConnected()) { + imapStore.close(); } - return null; + } } + } - private void parseMessages(Message[] messages, Boolean isSent) throws Exception { - for (Message message : messages) { - MimeMessage mimeMessage = (MimeMessage) message; - String messageID = mimeMessage.getMessageID(); - boolean messageAlreadyAvailable = communicationRepository.existsByIdentifier(messageID); - if (!messageAlreadyAvailable) { - String content = getTextFromMessage(message); - String contentHtml = getHtmlFromMessage(message); - Inject inject = injectResolver(content, contentHtml); - List participants = computeParticipants(message); - List users = userRepository.findAllByEmailInIgnoreCase(participants); - if (inject != null && !users.isEmpty()) { - String subject = message.getSubject(); - String from = String.valueOf(Arrays.stream(message.getFrom()).toList().get(0)); - String to = String.valueOf(Arrays.stream(message.getAllRecipients()).toList()); - Date receivedDate = message.getReceivedDate(); - Date sentDate = message.getSentDate(); - // Save messaging - Communication communication = new Communication(); - communication.setReceivedAt(receivedDate.toInstant()); - communication.setSentAt(sentDate.toInstant()); - communication.setSubject(subject); - communication.setContent(content); - communication.setContentHtml(contentHtml); - communication.setIdentifier(messageID); - communication.setUsers(users); - communication.setInject(inject); - communication.setAnimation(isSent); - communication.setFrom(from); - communication.setTo(to); - try { - // Save the communication - Communication comm = communicationRepository.save(communication); - // Update inject for real time - inject.setUpdatedAt(now()); - injectRepository.save(inject); - // Upload attachments in communication - final MimeMessageParser mimeParser = new MimeMessageParser(mimeMessage).parse(); - final List attachmentList = mimeParser.getAttachmentList(); - final List uploads = new ArrayList<>(); - String exerciseId = null; - if( inject.getExercise() != null ) { - exerciseId = inject.getExercise().getId(); - } - for (DataSource dataSource : attachmentList) { - final String fileName = dataSource.getName(); - String path = exerciseId != null ? "/" + exerciseId + "/communications/" + comm.getId() : "/communications/" + comm.getId(); - String uploadName = fileService.uploadStream(path, fileName, dataSource.getInputStream()); - uploads.add(uploadName); - } - // Add attachment in the communication - comm.setAttachments(uploads.toArray(String[]::new)); - communicationRepository.save(comm); - } catch (Exception e) { - LOGGER.log(Level.SEVERE, e.getMessage(), e); - } - } - } - } - } - - private void synchronizeBox(Folder inbox, Boolean isSent) throws Exception { - String inboxKey = username + "-imap-" + inbox.getName(); - Optional state = settingRepository.findByKey(inboxKey); - Setting currentState = state.orElse(null); - if (currentState == null) { - currentState = settingRepository.save(new Setting(inboxKey, "0")); - } - int startMessageNumber = parseInt(currentState.getValue()); - int messageCount = inbox.getMessageCount(); - if (startMessageNumber < messageCount) { - LOGGER.log(Level.INFO, "synchronizeInbox " + inbox.getName() + " from " + startMessageNumber + " to " + messageCount); - int start = startMessageNumber + 1; - Message[] messages = inbox.getMessages(start, messageCount); - if (messages.length > 0) { - parseMessages(messages, isSent); - } - } - currentState.setValue(String.valueOf(messageCount)); - settingRepository.save(currentState); - } - - private void tryToSynchronizeFolderFromBox(String folderName, Boolean isSent) throws Exception { - try(Folder folderBox = imapStore.getFolder(folderName)) { - folderBox.open(Folder.READ_ONLY); - synchronizeBox(folderBox, isSent); - } - } - - private void syncFolders() throws Exception { + // Sync folders every 10 sec + @Scheduled(fixedDelay = 10000, initialDelay = 10000) + public void connectionListener() throws Exception { + if (enabled) { + if (!imapStore.isConnected()) { try { - // Sync sent - tryToSynchronizeFolderFromBox(sentFolder, true); - // Sync received - for (String listeningFolder : inboxFolders) { - tryToSynchronizeFolderFromBox(listeningFolder, false); - } + imapStore.connect(host, port, username, password); + this.platformSettingsService.cleanMessage(BannerMessage.BANNER_KEYS.IMAP_UNAVAILABLE); } catch (MessagingException e) { - log.warning("Connection failure: " + e.getMessage()); - // Retry logic or rethrow the exception - retrySyncFolders(); - } - } - - private void retrySyncFolders() throws Exception { - for (int i = 0; i < 3; i++) { - try { - syncFolders(); - break; - } catch (MessagingException e) { - log.warning("Retrying connection..." + e.getMessage()); - Thread.sleep(2000); - if(i == 2 && imapStore != null && imapStore.isConnected()) { - imapStore.close(); - } - } - } - } - - // Sync folders every 10 sec - @Scheduled(fixedDelay = 10000, initialDelay = 10000) - public void connectionListener() throws Exception { - if (enabled) { - if (!imapStore.isConnected()) { - try { - imapStore.connect(host, port, username, password); - this.platformSettingsService.cleanMessage(BannerMessage.BANNER_KEYS.IMAP_UNAVAILABLE); - } catch (MessagingException e) { - log.severe(e.getMessage()); - this.platformSettingsService.errorMessage(BannerMessage.BANNER_KEYS.IMAP_UNAVAILABLE); - } - } - syncFolders(); + log.severe(e.getMessage()); + this.platformSettingsService.errorMessage(BannerMessage.BANNER_KEYS.IMAP_UNAVAILABLE); } + } + syncFolders(); } - - public void storeSentMessage(MimeMessage message) throws Exception { - if (enabled) { - try (Folder folder = imapStore.getFolder(sentFolder)) { - folder.open(Folder.READ_WRITE); - message.setFlag(Flags.Flag.SEEN, true); - folder.appendMessages(new Message[]{message}); - } - } + } + + public void storeSentMessage(MimeMessage message) throws Exception { + if (enabled) { + try (Folder folder = imapStore.getFolder(sentFolder)) { + folder.open(Folder.READ_WRITE); + message.setFlag(Flags.Flag.SEEN, true); + folder.appendMessages(new Message[] {message}); + } } + } } diff --git a/openbas-api/src/main/java/io/openbas/injectors/lade/LadeContract.java b/openbas-api/src/main/java/io/openbas/injectors/lade/LadeContract.java index 15d9bbcb60..85a2735f6b 100644 --- a/openbas-api/src/main/java/io/openbas/injectors/lade/LadeContract.java +++ b/openbas-api/src/main/java/io/openbas/injectors/lade/LadeContract.java @@ -1,67 +1,67 @@ package io.openbas.injectors.lade; +import static io.openbas.helper.SupportedLanguage.en; + import io.openbas.injector_contract.Contract; import io.openbas.injector_contract.ContractConfig; import io.openbas.injector_contract.Contractor; import io.openbas.injector_contract.ContractorIcon; import io.openbas.injectors.lade.config.LadeConfig; import io.openbas.injectors.lade.service.LadeService; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.stereotype.Component; - import java.io.InputStream; import java.util.List; import java.util.Map; import java.util.Optional; - -import static io.openbas.helper.SupportedLanguage.en; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Component; @Component public class LadeContract extends Contractor { - public static final String TYPE = "openbas_lade"; + public static final String TYPE = "openbas_lade"; - public static final String LADE_DEFAULT = "0a6439e4-671d-4a57-9446-9648005b36ef"; - private LadeConfig config; - private LadeService ladeService; + public static final String LADE_DEFAULT = "0a6439e4-671d-4a57-9446-9648005b36ef"; + private LadeConfig config; + private LadeService ladeService; - @Autowired - public void setLadeService(LadeService ladeService) { - this.ladeService = ladeService; - } + @Autowired + public void setLadeService(LadeService ladeService) { + this.ladeService = ladeService; + } - @Override - public boolean isExpose() { - return Optional.ofNullable(config.getEnable()).orElse(false); - } + @Override + public boolean isExpose() { + return Optional.ofNullable(config.getEnable()).orElse(false); + } - @Override - public String getType() { - return TYPE; - } + @Override + public String getType() { + return TYPE; + } - @Override - public ContractConfig getConfig() { - return new ContractConfig(TYPE, Map.of(en, "Airbus LADE"), "#673AB7", "#673AB7", "/img/icon-lade.png", isExpose()); - } + @Override + public ContractConfig getConfig() { + return new ContractConfig( + TYPE, Map.of(en, "Airbus LADE"), "#673AB7", "#673AB7", "/img/icon-lade.png", isExpose()); + } - @Autowired - public void setConfig(LadeConfig config) { - this.config = config; - } + @Autowired + public void setConfig(LadeConfig config) { + this.config = config; + } - @Override - public List contracts() throws Exception { - if (Optional.ofNullable(config.getEnable()).orElse(false)) { - ContractConfig contractConfig = getConfig(); - return ladeService.buildContracts(contractConfig); - } - return List.of(); + @Override + public List contracts() throws Exception { + if (Optional.ofNullable(config.getEnable()).orElse(false)) { + ContractConfig contractConfig = getConfig(); + return ladeService.buildContracts(contractConfig); } + return List.of(); + } - @Override - public ContractorIcon getIcon() { - InputStream iconStream = getClass().getResourceAsStream("/img/icon-lade.png"); - return new ContractorIcon(iconStream); - } + @Override + public ContractorIcon getIcon() { + InputStream iconStream = getClass().getResourceAsStream("/img/icon-lade.png"); + return new ContractorIcon(iconStream); + } } diff --git a/openbas-api/src/main/java/io/openbas/injectors/lade/LadeExecutor.java b/openbas-api/src/main/java/io/openbas/injectors/lade/LadeExecutor.java index 746bd3f6d2..3ba78bb4cc 100644 --- a/openbas-api/src/main/java/io/openbas/injectors/lade/LadeExecutor.java +++ b/openbas-api/src/main/java/io/openbas/injectors/lade/LadeExecutor.java @@ -1,5 +1,8 @@ package io.openbas.injectors.lade; +import static io.openbas.database.model.InjectStatusExecution.traceError; +import static io.openbas.database.model.InjectStatusExecution.traceInfo; + import com.fasterxml.jackson.databind.node.ObjectNode; import io.openbas.database.model.Execution; import io.openbas.database.model.Inject; @@ -9,14 +12,10 @@ import io.openbas.injectors.lade.service.LadeService; import io.openbas.model.ExecutionProcess; import jakarta.validation.constraints.NotNull; +import java.util.List; import lombok.RequiredArgsConstructor; import org.springframework.stereotype.Component; -import java.util.List; - -import static io.openbas.database.model.InjectStatusExecution.traceError; -import static io.openbas.database.model.InjectStatusExecution.traceInfo; - @Component(LadeContract.TYPE) @RequiredArgsConstructor public class LadeExecutor extends Injector { @@ -25,19 +24,25 @@ public class LadeExecutor extends Injector { @Override public ExecutionProcess process( - @NotNull final Execution execution, - @NotNull final ExecutableInject injection) { + @NotNull final Execution execution, @NotNull final ExecutableInject injection) { Inject inject = injection.getInjection().getInject(); String bundleIdentifier = ""; // contract.getContext().get("bundle_identifier"); String ladeType = ""; // contract.getContext().get("lade_type"); ObjectNode content = inject.getContent(); try { String actionWorkflowId; - final InjectorContract injectorContract = inject.getInjectorContract().orElseThrow(() -> new UnsupportedOperationException("Inject does not have a contract")); + final InjectorContract injectorContract = + inject + .getInjectorContract() + .orElseThrow( + () -> new UnsupportedOperationException("Inject does not have a contract")); switch (ladeType) { - case "action" -> actionWorkflowId = ladeService.executeAction(bundleIdentifier, injectorContract.getId(), content); + case "action" -> + actionWorkflowId = + ladeService.executeAction(bundleIdentifier, injectorContract.getId(), content); case "scenario" -> - actionWorkflowId = ladeService.executeScenario(bundleIdentifier, injectorContract.getId(), content); + actionWorkflowId = + ladeService.executeScenario(bundleIdentifier, injectorContract.getId(), content); default -> throw new UnsupportedOperationException(ladeType + " not supported"); } String message = "Lade " + ladeType + " sent with workflow (" + actionWorkflowId + ")"; diff --git a/openbas-api/src/main/java/io/openbas/injectors/lade/LadeInjector.java b/openbas-api/src/main/java/io/openbas/injectors/lade/LadeInjector.java index 2825df0fa0..75779ec544 100644 --- a/openbas-api/src/main/java/io/openbas/injectors/lade/LadeInjector.java +++ b/openbas-api/src/main/java/io/openbas/injectors/lade/LadeInjector.java @@ -7,24 +7,16 @@ @Component public class LadeInjector { - private static final String LADE_INJECTOR_NAME = "Airbus CyberRange (Lade)"; - private static final String LADE_INJECTOR_ID = "0097265b-0515-48a5-9bff-71d0f375fcc4"; + private static final String LADE_INJECTOR_NAME = "Airbus CyberRange (Lade)"; + private static final String LADE_INJECTOR_ID = "0097265b-0515-48a5-9bff-71d0f375fcc4"; - @Autowired - public LadeInjector(InjectorService injectorService, LadeContract contract) { - try { - injectorService.register( - LADE_INJECTOR_ID, - LADE_INJECTOR_NAME, - contract, - false, - "cyber-range", - null, - null, - false - ); - } catch (Exception e) { - throw new RuntimeException(e); - } + @Autowired + public LadeInjector(InjectorService injectorService, LadeContract contract) { + try { + injectorService.register( + LADE_INJECTOR_ID, LADE_INJECTOR_NAME, contract, false, "cyber-range", null, null, false); + } catch (Exception e) { + throw new RuntimeException(e); } + } } diff --git a/openbas-api/src/main/java/io/openbas/injectors/lade/config/LadeConfig.java b/openbas-api/src/main/java/io/openbas/injectors/lade/config/LadeConfig.java index 569c1e3f62..253a6489e6 100644 --- a/openbas-api/src/main/java/io/openbas/injectors/lade/config/LadeConfig.java +++ b/openbas-api/src/main/java/io/openbas/injectors/lade/config/LadeConfig.java @@ -1,31 +1,24 @@ package io.openbas.injectors.lade.config; +import jakarta.validation.constraints.NotNull; import lombok.Getter; import lombok.Setter; import org.springframework.boot.context.properties.ConfigurationProperties; import org.springframework.stereotype.Component; -import jakarta.validation.constraints.NotNull; - @Setter @Getter @Component @ConfigurationProperties(prefix = "lade") public class LadeConfig { - @NotNull - private Boolean enable; - - @NotNull - private String url; + @NotNull private Boolean enable; - @NotNull - private Integer session; + @NotNull private String url; - @NotNull - private String username; + @NotNull private Integer session; - @NotNull - private String password; + @NotNull private String username; + @NotNull private String password; } diff --git a/openbas-api/src/main/java/io/openbas/injectors/lade/model/LadeAuth.java b/openbas-api/src/main/java/io/openbas/injectors/lade/model/LadeAuth.java index 71598ece31..c46e260fad 100644 --- a/openbas-api/src/main/java/io/openbas/injectors/lade/model/LadeAuth.java +++ b/openbas-api/src/main/java/io/openbas/injectors/lade/model/LadeAuth.java @@ -5,43 +5,43 @@ public class LadeAuth { - public enum TokenStatus { - empty, - set, - expire, - } - - private String token; - - private Instant validity; - - public TokenStatus getTokenStatus(Integer sessionTime) { - if (token == null || validity == null) { - return TokenStatus.empty; - } - int maxBeforeRefresh = sessionTime / 2; - long sinceExpire = ChronoUnit.MINUTES.between(validity, Instant.now()); - if (sinceExpire > maxBeforeRefresh) { - return TokenStatus.expire; - } - return TokenStatus.set; - } + public enum TokenStatus { + empty, + set, + expire, + } - public String getToken() { - return token; - } + private String token; - public void setToken(String token) { - this.token = token; - this.validity = Instant.now(); - } + private Instant validity; - public void refreshValidity() { - this.validity = Instant.now(); + public TokenStatus getTokenStatus(Integer sessionTime) { + if (token == null || validity == null) { + return TokenStatus.empty; } - - public void clear() { - this.token = null; - this.validity = null; + int maxBeforeRefresh = sessionTime / 2; + long sinceExpire = ChronoUnit.MINUTES.between(validity, Instant.now()); + if (sinceExpire > maxBeforeRefresh) { + return TokenStatus.expire; } + return TokenStatus.set; + } + + public String getToken() { + return token; + } + + public void setToken(String token) { + this.token = token; + this.validity = Instant.now(); + } + + public void refreshValidity() { + this.validity = Instant.now(); + } + + public void clear() { + this.token = null; + this.validity = null; + } } diff --git a/openbas-api/src/main/java/io/openbas/injectors/lade/model/LadeWorkflow.java b/openbas-api/src/main/java/io/openbas/injectors/lade/model/LadeWorkflow.java index 272da57ba8..0254349f21 100644 --- a/openbas-api/src/main/java/io/openbas/injectors/lade/model/LadeWorkflow.java +++ b/openbas-api/src/main/java/io/openbas/injectors/lade/model/LadeWorkflow.java @@ -1,29 +1,24 @@ package io.openbas.injectors.lade.model; import io.openbas.database.model.InjectStatusExecution; -import lombok.Getter; -import lombok.Setter; - import java.time.Instant; import java.util.ArrayList; import java.util.List; +import lombok.Getter; +import lombok.Setter; @Getter public class LadeWorkflow { - private final List traces = new ArrayList<>(); - - @Setter - private boolean done = false; + private final List traces = new ArrayList<>(); - @Setter - private boolean fail = false; + @Setter private boolean done = false; - @Setter - private Instant stopTime; + @Setter private boolean fail = false; - public void addTrace(InjectStatusExecution trace) { - this.traces.add(trace); - } + @Setter private Instant stopTime; + public void addTrace(InjectStatusExecution trace) { + this.traces.add(trace); + } } diff --git a/openbas-api/src/main/java/io/openbas/injectors/lade/model/LadeWorkzone.java b/openbas-api/src/main/java/io/openbas/injectors/lade/model/LadeWorkzone.java index 470e81226f..86ffb4748d 100644 --- a/openbas-api/src/main/java/io/openbas/injectors/lade/model/LadeWorkzone.java +++ b/openbas-api/src/main/java/io/openbas/injectors/lade/model/LadeWorkzone.java @@ -4,48 +4,48 @@ import java.util.Map; public class LadeWorkzone { - private String id; + private String id; - private String name; + private String name; - private Map hostsByName = new HashMap<>(); + private Map hostsByName = new HashMap<>(); - private Map hostsByIp = new HashMap<>(); + private Map hostsByIp = new HashMap<>(); - public LadeWorkzone(String id, String name) { - this.id = id; - this.name = name; - } + public LadeWorkzone(String id, String name) { + this.id = id; + this.name = name; + } - public String getId() { - return id; - } + public String getId() { + return id; + } - public void setId(String id) { - this.id = id; - } + public void setId(String id) { + this.id = id; + } - public String getName() { - return name; - } + public String getName() { + return name; + } - public void setName(String name) { - this.name = name; - } + public void setName(String name) { + this.name = name; + } - public Map getHostsByName() { - return hostsByName; - } + public Map getHostsByName() { + return hostsByName; + } - public void setHostsByName(Map hostsByName) { - this.hostsByName = hostsByName; - } + public void setHostsByName(Map hostsByName) { + this.hostsByName = hostsByName; + } - public Map getHostsByIp() { - return hostsByIp; - } + public Map getHostsByIp() { + return hostsByIp; + } - public void setHostsByIp(Map hostsByIp) { - this.hostsByIp = hostsByIp; - } + public void setHostsByIp(Map hostsByIp) { + this.hostsByIp = hostsByIp; + } } diff --git a/openbas-api/src/main/java/io/openbas/injectors/lade/service/LadeListener.java b/openbas-api/src/main/java/io/openbas/injectors/lade/service/LadeListener.java index f3448d68fd..d4311c9b45 100644 --- a/openbas-api/src/main/java/io/openbas/injectors/lade/service/LadeListener.java +++ b/openbas-api/src/main/java/io/openbas/injectors/lade/service/LadeListener.java @@ -7,15 +7,14 @@ import io.openbas.database.repository.InjectStatusRepository; import io.openbas.injectors.lade.LadeContract; import io.openbas.injectors.lade.model.LadeWorkflow; +import java.time.Instant; +import java.util.List; +import java.util.logging.Level; import lombok.RequiredArgsConstructor; import lombok.extern.java.Log; import org.springframework.scheduling.annotation.Scheduled; import org.springframework.stereotype.Service; -import java.time.Instant; -import java.util.List; -import java.util.logging.Level; - @Service @Log @RequiredArgsConstructor @@ -28,28 +27,36 @@ public class LadeListener { @Scheduled(fixedDelay = 15000, initialDelay = 0) public void listenWorkflows() { // Get all lade inject with workflow_id that are not done yet - List injectStatuses = this.injectStatusRepository.pendingForInjectType(LadeContract.TYPE); + List injectStatuses = + this.injectStatusRepository.pendingForInjectType(LadeContract.TYPE); // For each workflow ask for traces and status - injectStatuses.forEach(injectStatus -> { - // Add traces and close inject if needed. - String asyncId = injectStatus.statusIdentifiers().stream().findFirst().orElse(null); // Lade handle only one asyncID for now - try { - LadeWorkflow workflowStatus = this.ladeService.getWorkflowStatus(asyncId); - if (workflowStatus.isDone()) { - ExecutionStatus name = workflowStatus.isFail() ? ExecutionStatus.ERROR : ExecutionStatus.SUCCESS; - injectStatus.setName(name); - long executionTime = workflowStatus.getStopTime().toEpochMilli() - injectStatus.getTrackingSentDate().toEpochMilli(); - injectStatus.setTrackingTotalExecutionTime(executionTime); - } - injectStatus.setTraces(workflowStatus.getTraces()); - this.injectStatusRepository.save(injectStatus); - // Update related inject - Inject relatedInject = injectStatus.getInject(); - relatedInject.setUpdatedAt(Instant.now()); - this.injectRepository.save(relatedInject); - } catch (Exception e) { - log.log(Level.SEVERE, e.getMessage(), e); - } - }); + injectStatuses.forEach( + injectStatus -> { + // Add traces and close inject if needed. + String asyncId = + injectStatus.statusIdentifiers().stream() + .findFirst() + .orElse(null); // Lade handle only one asyncID for now + try { + LadeWorkflow workflowStatus = this.ladeService.getWorkflowStatus(asyncId); + if (workflowStatus.isDone()) { + ExecutionStatus name = + workflowStatus.isFail() ? ExecutionStatus.ERROR : ExecutionStatus.SUCCESS; + injectStatus.setName(name); + long executionTime = + workflowStatus.getStopTime().toEpochMilli() + - injectStatus.getTrackingSentDate().toEpochMilli(); + injectStatus.setTrackingTotalExecutionTime(executionTime); + } + injectStatus.setTraces(workflowStatus.getTraces()); + this.injectStatusRepository.save(injectStatus); + // Update related inject + Inject relatedInject = injectStatus.getInject(); + relatedInject.setUpdatedAt(Instant.now()); + this.injectRepository.save(relatedInject); + } catch (Exception e) { + log.log(Level.SEVERE, e.getMessage(), e); + } + }); } } diff --git a/openbas-api/src/main/java/io/openbas/injectors/lade/service/LadeService.java b/openbas-api/src/main/java/io/openbas/injectors/lade/service/LadeService.java index d56389b160..d27679b05e 100644 --- a/openbas-api/src/main/java/io/openbas/injectors/lade/service/LadeService.java +++ b/openbas-api/src/main/java/io/openbas/injectors/lade/service/LadeService.java @@ -1,5 +1,15 @@ package io.openbas.injectors.lade.service; +import static io.openbas.helper.StreamHelper.asStream; +import static io.openbas.helper.SupportedLanguage.en; +import static io.openbas.injector_contract.Contract.executableContract; +import static io.openbas.injector_contract.ContractDef.contractBuilder; +import static io.openbas.injector_contract.fields.ContractCheckbox.checkboxField; +import static io.openbas.injector_contract.fields.ContractDependencySelect.dependencySelectField; +import static io.openbas.injector_contract.fields.ContractSelect.selectFieldWithDefault; +import static io.openbas.injector_contract.fields.ContractText.textField; +import static java.text.MessageFormat.format; + import com.fasterxml.jackson.databind.JsonNode; import com.fasterxml.jackson.databind.ObjectMapper; import com.fasterxml.jackson.databind.node.NullNode; @@ -15,6 +25,11 @@ import io.openbas.injectors.lade.model.LadeWorkflow; import io.openbas.injectors.lade.model.LadeWorkzone; import jakarta.annotation.Resource; +import java.io.IOException; +import java.time.Instant; +import java.util.*; +import java.util.logging.Level; +import java.util.logging.Logger; import org.apache.hc.client5.http.ClientProtocolException; import org.apache.hc.client5.http.classic.methods.HttpGet; import org.apache.hc.client5.http.classic.methods.HttpPost; @@ -25,301 +40,334 @@ import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Component; -import java.io.IOException; -import java.time.Instant; -import java.util.*; -import java.util.logging.Level; -import java.util.logging.Logger; - -import static io.openbas.helper.StreamHelper.asStream; -import static io.openbas.helper.SupportedLanguage.en; -import static io.openbas.injector_contract.Contract.executableContract; -import static io.openbas.injector_contract.ContractDef.contractBuilder; -import static io.openbas.injector_contract.fields.ContractCheckbox.checkboxField; -import static io.openbas.injector_contract.fields.ContractDependencySelect.dependencySelectField; -import static io.openbas.injector_contract.fields.ContractSelect.selectFieldWithDefault; -import static io.openbas.injector_contract.fields.ContractText.textField; -import static java.text.MessageFormat.format; - @Component public class LadeService { - private static final Logger LOGGER = Logger.getLogger(LadeService.class.getName()); + private static final Logger LOGGER = Logger.getLogger(LadeService.class.getName()); - @Resource - private io.openbas.injectors.lade.config.LadeConfig config; + @Resource private io.openbas.injectors.lade.config.LadeConfig config; - @Resource - private ObjectMapper mapper; + @Resource private ObjectMapper mapper; - @Autowired - public void setConfig(LadeConfig config) { - this.config = config; - } + @Autowired + public void setConfig(LadeConfig config) { + this.config = config; + } - // Authentication cache - private final LadeAuth ladeAuth = new LadeAuth(); + // Authentication cache + private final LadeAuth ladeAuth = new LadeAuth(); - private String ladeAuthentication() throws IOException { - try (CloseableHttpClient httpClient = HttpClients.createDefault()) { - // Renew token before access token expiration. - // Timeout is configurable, 30 minutes by default, renew 50% before timeout - switch (ladeAuth.getTokenStatus(config.getSession())) { - case set -> { - return ladeAuth.getToken(); - } - case empty -> { - HttpPost authPost = new HttpPost(config.getUrl() + "/api/token/issue"); - authPost.setHeader("Accept", "application/json"); - authPost.setHeader("Content-type", "application/json"); - ObjectNode objectNode = mapper.createObjectNode(); - objectNode.set("username", mapper.convertValue(config.getUsername(), JsonNode.class)); - objectNode.set("password", mapper.convertValue(config.getPassword(), JsonNode.class)); - authPost.setEntity(new StringEntity(mapper.writeValueAsString(objectNode))); - JsonNode auth = httpClient.execute(authPost, postResponse -> { - String body = EntityUtils.toString(postResponse.getEntity()); - return mapper.readTree(body); - }); - String token = auth.get("access_token").asText(); - ladeAuth.setToken(token); - return ladeAuth.getToken(); - } - case expire -> { - HttpPost authPost = new HttpPost(config.getUrl() + "/api/token/renew"); - authPost.setHeader("Accept", "application/json"); - authPost.setHeader("Content-type", "application/json"); - authPost.setHeader("lade-authorization", "Bearer " + ladeAuth.getToken()); - httpClient.execute(authPost); - ladeAuth.refreshValidity(); - return ladeAuth.getToken(); - } - default -> throw new UnsupportedOperationException("Token status not supported"); - } - } catch (IOException e) { - throw new ClientProtocolException("Unexpected response for request on: " + config.getUrl() + "/graphql"); + private String ladeAuthentication() throws IOException { + try (CloseableHttpClient httpClient = HttpClients.createDefault()) { + // Renew token before access token expiration. + // Timeout is configurable, 30 minutes by default, renew 50% before timeout + switch (ladeAuth.getTokenStatus(config.getSession())) { + case set -> { + return ladeAuth.getToken(); + } + case empty -> { + HttpPost authPost = new HttpPost(config.getUrl() + "/api/token/issue"); + authPost.setHeader("Accept", "application/json"); + authPost.setHeader("Content-type", "application/json"); + ObjectNode objectNode = mapper.createObjectNode(); + objectNode.set("username", mapper.convertValue(config.getUsername(), JsonNode.class)); + objectNode.set("password", mapper.convertValue(config.getPassword(), JsonNode.class)); + authPost.setEntity(new StringEntity(mapper.writeValueAsString(objectNode))); + JsonNode auth = + httpClient.execute( + authPost, + postResponse -> { + String body = EntityUtils.toString(postResponse.getEntity()); + return mapper.readTree(body); + }); + String token = auth.get("access_token").asText(); + ladeAuth.setToken(token); + return ladeAuth.getToken(); + } + case expire -> { + HttpPost authPost = new HttpPost(config.getUrl() + "/api/token/renew"); + authPost.setHeader("Accept", "application/json"); + authPost.setHeader("Content-type", "application/json"); + authPost.setHeader("lade-authorization", "Bearer " + ladeAuth.getToken()); + httpClient.execute(authPost); + ladeAuth.refreshValidity(); + return ladeAuth.getToken(); } + default -> throw new UnsupportedOperationException("Token status not supported"); + } + } catch (IOException e) { + throw new ClientProtocolException( + "Unexpected response for request on: " + config.getUrl() + "/graphql"); } + } - private JsonNode executeGet(String uri, boolean retry) throws IOException { - try (CloseableHttpClient httpClient = HttpClients.createDefault()) { - HttpGet actionsGet = new HttpGet(config.getUrl() + uri); - actionsGet.setHeader("lade-authorization", "Bearer " + ladeAuthentication()); - return httpClient.execute(actionsGet, getResponse -> { - String body = EntityUtils.toString(getResponse.getEntity()); - JsonNode resultNode = mapper.readTree(body); - // Session can be killed, so can catch 401, invalidate token and retry - if (getResponse.getCode() == 401 && !retry) { - ladeAuth.clear(); - return executeGet(uri, true); - } - if (getResponse.getCode() >= 200 && getResponse.getCode() < 300) { - return resultNode; - } else { - String message = resultNode.get("message").asText(); - throw new UnsupportedOperationException(message); - } - }); - } catch (IOException e) { - throw new ClientProtocolException("Unexpected response for request on: " + config.getUrl() + "/graphql"); - } + private JsonNode executeGet(String uri, boolean retry) throws IOException { + try (CloseableHttpClient httpClient = HttpClients.createDefault()) { + HttpGet actionsGet = new HttpGet(config.getUrl() + uri); + actionsGet.setHeader("lade-authorization", "Bearer " + ladeAuthentication()); + return httpClient.execute( + actionsGet, + getResponse -> { + String body = EntityUtils.toString(getResponse.getEntity()); + JsonNode resultNode = mapper.readTree(body); + // Session can be killed, so can catch 401, invalidate token and retry + if (getResponse.getCode() == 401 && !retry) { + ladeAuth.clear(); + return executeGet(uri, true); + } + if (getResponse.getCode() >= 200 && getResponse.getCode() < 300) { + return resultNode; + } else { + String message = resultNode.get("message").asText(); + throw new UnsupportedOperationException(message); + } + }); + } catch (IOException e) { + throw new ClientProtocolException( + "Unexpected response for request on: " + config.getUrl() + "/graphql"); } + } - private JsonNode executePost(String uri, ObjectNode postContent, boolean retry) throws IOException { - try (CloseableHttpClient httpClient = HttpClients.createDefault()) { - HttpPost runPost = new HttpPost(config.getUrl() + uri); - runPost.setHeader("lade-authorization", "Bearer " + ladeAuthentication()); - runPost.setHeader("Accept", "application/json"); - runPost.setHeader("Content-type", "application/json"); - runPost.setEntity(new StringEntity(mapper.writeValueAsString(postContent))); - return httpClient.execute(runPost, postResponse -> { - String body = EntityUtils.toString(postResponse.getEntity()); - ObjectNode resultNode = mapper.readValue(body, ObjectNode.class); - // Session can be killed, so can catch 401, invalidate token and retry - if (postResponse.getCode() == 401 && !retry) { - ladeAuth.clear(); - return executePost(uri, postContent, true); - } - if (postResponse.getCode() >= 200 && postResponse.getCode() < 300) { - return resultNode; - } else { - String message = resultNode.get("message").asText(); - throw new UnsupportedOperationException(message); - } - }); - } catch (IOException e) { - throw new ClientProtocolException("Unexpected response for request on: " + config.getUrl() + "/graphql"); - } + private JsonNode executePost(String uri, ObjectNode postContent, boolean retry) + throws IOException { + try (CloseableHttpClient httpClient = HttpClients.createDefault()) { + HttpPost runPost = new HttpPost(config.getUrl() + uri); + runPost.setHeader("lade-authorization", "Bearer " + ladeAuthentication()); + runPost.setHeader("Accept", "application/json"); + runPost.setHeader("Content-type", "application/json"); + runPost.setEntity(new StringEntity(mapper.writeValueAsString(postContent))); + return httpClient.execute( + runPost, + postResponse -> { + String body = EntityUtils.toString(postResponse.getEntity()); + ObjectNode resultNode = mapper.readValue(body, ObjectNode.class); + // Session can be killed, so can catch 401, invalidate token and retry + if (postResponse.getCode() == 401 && !retry) { + ladeAuth.clear(); + return executePost(uri, postContent, true); + } + if (postResponse.getCode() >= 200 && postResponse.getCode() < 300) { + return resultNode; + } else { + String message = resultNode.get("message").asText(); + throw new UnsupportedOperationException(message); + } + }); + } catch (IOException e) { + throw new ClientProtocolException( + "Unexpected response for request on: " + config.getUrl() + "/graphql"); } + } - private Map getWorkzones() throws Exception { - JsonNode workzones = executeGet("/api/workzones", false); - Optional workzoneDatas = Optional.ofNullable(workzones).map(jsonNode -> jsonNode.get("data")); - Map zones = new HashMap<>(); - workzoneDatas.ifPresent((datas) -> { - datas.forEach(jsonNode -> { + private Map getWorkzones() throws Exception { + JsonNode workzones = executeGet("/api/workzones", false); + Optional workzoneDatas = + Optional.ofNullable(workzones).map(jsonNode -> jsonNode.get("data")); + Map zones = new HashMap<>(); + workzoneDatas.ifPresent( + (datas) -> { + datas.forEach( + jsonNode -> { String name = jsonNode.get("name").asText(); String identifier = jsonNode.get("identifier").asText(); // FETCH HOSTS LadeWorkzone ladeWorkzone = new LadeWorkzone(identifier, name); try { - // Fetch hosts - JsonNode nodeHosts = executeGet("/api/workzones/" + identifier + "/hosts", false); - Map hostsByName = new HashMap<>(); - Map hostsByIp = new HashMap<>(); - nodeHosts.forEach(nodeHost -> { + // Fetch hosts + JsonNode nodeHosts = executeGet("/api/workzones/" + identifier + "/hosts", false); + Map hostsByName = new HashMap<>(); + Map hostsByIp = new HashMap<>(); + nodeHosts.forEach( + nodeHost -> { // String hostIdentifier = nodeHost.get("identifier").asText(); String hostname = nodeHost.get("hostname").asText(); String os = nodeHost.get("os").asText(); hostsByName.put(hostname, hostname + " (" + os + ")"); - nodeHost.get("nics").forEach(nic -> { - String ip = nic.get("ip").asText(); - hostsByIp.put(ip, hostname + " (" + os + ")" + " - " + ip); - }); - }); - ladeWorkzone.setHostsByName(hostsByName); - ladeWorkzone.setHostsByIp(hostsByIp); - // Add new built workzone - zones.put(ladeWorkzone.getId(), ladeWorkzone); + nodeHost + .get("nics") + .forEach( + nic -> { + String ip = nic.get("ip").asText(); + hostsByIp.put(ip, hostname + " (" + os + ")" + " - " + ip); + }); + }); + ladeWorkzone.setHostsByName(hostsByName); + ladeWorkzone.setHostsByIp(hostsByIp); + // Add new built workzone + zones.put(ladeWorkzone.getId(), ladeWorkzone); } catch (Exception e) { - LOGGER.log(Level.SEVERE, e.getMessage(), e); + LOGGER.log(Level.SEVERE, e.getMessage(), e); } - }); + }); }); - return zones; - } + return zones; + } - public List buildContracts(ContractConfig contractConfig) throws Exception { - Map workzoneContract = getWorkzones(); - Map workzoneChoices = new HashMap<>(); - workzoneContract.values().forEach(ladeWorkzone -> workzoneChoices.put(ladeWorkzone.getId(), ladeWorkzone.getName())); - String defaultChoice = workzoneChoices.keySet().stream().findFirst().orElseThrow(); - ContractSelect workContract = selectFieldWithDefault("workzone", "Workzone", workzoneChoices, defaultChoice); - Map> workzoneHostsMap = new HashMap<>(); - workzoneContract.forEach((k, value) -> workzoneHostsMap.put(k, value.getHostsByName())); - Map> workzoneHostsIps = new HashMap<>(); - workzoneContract.forEach((k, value) -> workzoneHostsIps.put(k, value.getHostsByIp())); - List contracts = new ArrayList<>(); - // region actions - JsonNode actions = executeGet("/api/actions", false); - Iterator actionElements = actions.get("data").elements(); - actionElements.forEachRemaining(jsonNode -> { - ContractDef builder = contractBuilder(); - builder.mandatory(workContract); - String contractName = jsonNode.get("name").asText(); - String identifier = jsonNode.get("identifier").asText(); - String bundleIdentifier = jsonNode.get("bundle_identifier").asText(); - JsonNode categoryIdentifierNode = jsonNode.get("category_identifier"); - if (!(categoryIdentifierNode instanceof NullNode)) { - JsonNode specs = jsonNode.get("specs"); - JsonNode source = specs.get("source"); - if (source != null) { - builder.mandatory(dependencySelectField("source", "Source", - "workzone", workzoneHostsMap)); - } - JsonNode parameters = specs.get("parameters"); - Iterator> fields = parameters.fields(); - fields.forEachRemaining(entry -> { - String key = entry.getKey(); - JsonNode parameter = entry.getValue(); - JsonNode nameNode = parameter.get("name"); - String name = nameNode != null ? nameNode.asText() : key; - List types = asStream(parameter.get("types").elements()).map(JsonNode::asText).toList(); - if (types.contains("host.nics.ip")) { - builder.mandatory(dependencySelectField(key, name, "workzone", workzoneHostsIps)); - } else if (types.contains("boolean")) { - JsonNode defaultNode = parameter.get("default"); - builder.optional(checkboxField(key, name, defaultNode.booleanValue())); - } else if (types.contains("string")) { - JsonNode defaultNode = parameter.get("default"); - builder.optional(textField(key, name, defaultNode != null ? defaultNode.asText() : "")); - } - }); - Contract contractInstance = executableContract(contractConfig, - identifier, Map.of(en, contractName), builder.build(), List.of(Endpoint.PLATFORM_TYPE.Service), false); - contractInstance.addContext("lade_type", "action"); - contractInstance.addContext("bundle_identifier", bundleIdentifier); - contracts.add(contractInstance); + public List buildContracts(ContractConfig contractConfig) throws Exception { + Map workzoneContract = getWorkzones(); + Map workzoneChoices = new HashMap<>(); + workzoneContract + .values() + .forEach(ladeWorkzone -> workzoneChoices.put(ladeWorkzone.getId(), ladeWorkzone.getName())); + String defaultChoice = workzoneChoices.keySet().stream().findFirst().orElseThrow(); + ContractSelect workContract = + selectFieldWithDefault("workzone", "Workzone", workzoneChoices, defaultChoice); + Map> workzoneHostsMap = new HashMap<>(); + workzoneContract.forEach((k, value) -> workzoneHostsMap.put(k, value.getHostsByName())); + Map> workzoneHostsIps = new HashMap<>(); + workzoneContract.forEach((k, value) -> workzoneHostsIps.put(k, value.getHostsByIp())); + List contracts = new ArrayList<>(); + // region actions + JsonNode actions = executeGet("/api/actions", false); + Iterator actionElements = actions.get("data").elements(); + actionElements.forEachRemaining( + jsonNode -> { + ContractDef builder = contractBuilder(); + builder.mandatory(workContract); + String contractName = jsonNode.get("name").asText(); + String identifier = jsonNode.get("identifier").asText(); + String bundleIdentifier = jsonNode.get("bundle_identifier").asText(); + JsonNode categoryIdentifierNode = jsonNode.get("category_identifier"); + if (!(categoryIdentifierNode instanceof NullNode)) { + JsonNode specs = jsonNode.get("specs"); + JsonNode source = specs.get("source"); + if (source != null) { + builder.mandatory( + dependencySelectField("source", "Source", "workzone", workzoneHostsMap)); } - }); - // endregion - // region scenarios - JsonNode scenarios = executeGet("/api/scenarios", false); - Iterator scenarioElements = scenarios.get("data").elements(); - scenarioElements.forEachRemaining(jsonNode -> { - ContractDef builder = contractBuilder(); - builder.mandatory(workContract); - String contractName = jsonNode.get("name").asText(); - String identifier = jsonNode.get("identifier").asText(); - String qualifier = jsonNode.get("qualifier") != null ? "( " + jsonNode.get("qualifier").asText() + ")" : ""; - String bundleIdentifier = jsonNode.get("bundle_identifier").asText(); - Contract contractInstance = executableContract(contractConfig, - identifier, Map.of(en, contractName + qualifier), builder.build(), List.of(Endpoint.PLATFORM_TYPE.Service), false); - contractInstance.addContext("lade_type", "scenario"); + JsonNode parameters = specs.get("parameters"); + Iterator> fields = parameters.fields(); + fields.forEachRemaining( + entry -> { + String key = entry.getKey(); + JsonNode parameter = entry.getValue(); + JsonNode nameNode = parameter.get("name"); + String name = nameNode != null ? nameNode.asText() : key; + List types = + asStream(parameter.get("types").elements()).map(JsonNode::asText).toList(); + if (types.contains("host.nics.ip")) { + builder.mandatory( + dependencySelectField(key, name, "workzone", workzoneHostsIps)); + } else if (types.contains("boolean")) { + JsonNode defaultNode = parameter.get("default"); + builder.optional(checkboxField(key, name, defaultNode.booleanValue())); + } else if (types.contains("string")) { + JsonNode defaultNode = parameter.get("default"); + builder.optional( + textField(key, name, defaultNode != null ? defaultNode.asText() : "")); + } + }); + Contract contractInstance = + executableContract( + contractConfig, + identifier, + Map.of(en, contractName), + builder.build(), + List.of(Endpoint.PLATFORM_TYPE.Service), + false); + contractInstance.addContext("lade_type", "action"); contractInstance.addContext("bundle_identifier", bundleIdentifier); contracts.add(contractInstance); + } }); - // endregion - return contracts; - } + // endregion + // region scenarios + JsonNode scenarios = executeGet("/api/scenarios", false); + Iterator scenarioElements = scenarios.get("data").elements(); + scenarioElements.forEachRemaining( + jsonNode -> { + ContractDef builder = contractBuilder(); + builder.mandatory(workContract); + String contractName = jsonNode.get("name").asText(); + String identifier = jsonNode.get("identifier").asText(); + String qualifier = + jsonNode.get("qualifier") != null + ? "( " + jsonNode.get("qualifier").asText() + ")" + : ""; + String bundleIdentifier = jsonNode.get("bundle_identifier").asText(); + Contract contractInstance = + executableContract( + contractConfig, + identifier, + Map.of(en, contractName + qualifier), + builder.build(), + List.of(Endpoint.PLATFORM_TYPE.Service), + false); + contractInstance.addContext("lade_type", "scenario"); + contractInstance.addContext("bundle_identifier", bundleIdentifier); + contracts.add(contractInstance); + }); + // endregion + return contracts; + } - public String executeAction(String bundleIdentifier, String actionIdentifier, ObjectNode content) throws Exception { - String workzone = content.get("workzone").asText(); - ObjectNode parameters = content.deepCopy(); - parameters.remove("workzone"); - parameters.remove("source"); - String uri = format("/api/workzones/{0}/bundles/{1}/actions/{2}/run", workzone, bundleIdentifier, actionIdentifier); - // Generate object to action post - ObjectNode postContent = mapper.createObjectNode(); - JsonNode source = content.get("source"); - if (source != null) { - postContent.set("source", mapper.convertValue(source.asText(), JsonNode.class)); - } - postContent.set("parameters", parameters); - JsonNode postData = executePost(uri, postContent, false); - return postData.get("workflow_id").asText(); + public String executeAction(String bundleIdentifier, String actionIdentifier, ObjectNode content) + throws Exception { + String workzone = content.get("workzone").asText(); + ObjectNode parameters = content.deepCopy(); + parameters.remove("workzone"); + parameters.remove("source"); + String uri = + format( + "/api/workzones/{0}/bundles/{1}/actions/{2}/run", + workzone, bundleIdentifier, actionIdentifier); + // Generate object to action post + ObjectNode postContent = mapper.createObjectNode(); + JsonNode source = content.get("source"); + if (source != null) { + postContent.set("source", mapper.convertValue(source.asText(), JsonNode.class)); } + postContent.set("parameters", parameters); + JsonNode postData = executePost(uri, postContent, false); + return postData.get("workflow_id").asText(); + } - public String executeScenario(String bundleIdentifier, String scenarioIdentifier, ObjectNode content) throws Exception { - String workzone = content.get("workzone").asText(); - String uri = format("/api/workzones/{0}/bundles/{1}/scenarios/{2}/run", workzone, bundleIdentifier, scenarioIdentifier); - // Generate object to action post - ObjectNode postContent = mapper.createObjectNode(); - JsonNode postData = executePost(uri, postContent, false); - return postData.get("workflow_id").asText(); - } + public String executeScenario( + String bundleIdentifier, String scenarioIdentifier, ObjectNode content) throws Exception { + String workzone = content.get("workzone").asText(); + String uri = + format( + "/api/workzones/{0}/bundles/{1}/scenarios/{2}/run", + workzone, bundleIdentifier, scenarioIdentifier); + // Generate object to action post + ObjectNode postContent = mapper.createObjectNode(); + JsonNode postData = executePost(uri, postContent, false); + return postData.get("workflow_id").asText(); + } - public LadeWorkflow getWorkflowStatus(String workflowId) { - LadeWorkflow ladeWorkflow = new LadeWorkflow(); - try { - JsonNode workflowStatus = executeGet("/api/workflows/" + workflowId, false); - String status = workflowStatus.get("status").asText(); // running | failed - String workzone = workflowStatus.get("workzone_identifier").asText(); - boolean isFail = status.equals("failed") || status.equals("cancelled"); - ladeWorkflow.setFail(isFail); - boolean isDone = isFail || status.equals("done") || status.equals("succeeded"); - ladeWorkflow.setDone(isDone); - if (isDone) { - String completeTime = workflowStatus.get("complete_time").asText(); - ladeWorkflow.setStopTime(Instant.parse(completeTime)); + public LadeWorkflow getWorkflowStatus(String workflowId) { + LadeWorkflow ladeWorkflow = new LadeWorkflow(); + try { + JsonNode workflowStatus = executeGet("/api/workflows/" + workflowId, false); + String status = workflowStatus.get("status").asText(); // running | failed + String workzone = workflowStatus.get("workzone_identifier").asText(); + boolean isFail = status.equals("failed") || status.equals("cancelled"); + ladeWorkflow.setFail(isFail); + boolean isDone = isFail || status.equals("done") || status.equals("succeeded"); + ladeWorkflow.setDone(isDone); + if (isDone) { + String completeTime = workflowStatus.get("complete_time").asText(); + ladeWorkflow.setStopTime(Instant.parse(completeTime)); + } + String uri = format("/api/workzones/{0}/workflows/{1}/events", workzone, workflowId); + JsonNode workflowEvents = executeGet(uri, false); + workflowEvents.forEach( + workflowEvent -> { + String eventLevel = workflowEvent.get("level").asText(); + String message = workflowEvent.get("message").asText(); + if (!message.isEmpty() && !message.equals("null")) { + InjectStatusExecution trace; + if (eventLevel.equals("error")) { + trace = InjectStatusExecution.traceError(message); + } else { + trace = InjectStatusExecution.traceSuccess(message); + } + ladeWorkflow.addTrace(trace); } - String uri = format("/api/workzones/{0}/workflows/{1}/events", workzone, workflowId); - JsonNode workflowEvents = executeGet(uri, false); - workflowEvents.forEach(workflowEvent -> { - String eventLevel = workflowEvent.get("level").asText(); - String message = workflowEvent.get("message").asText(); - if (!message.isEmpty() && !message.equals("null")) { - InjectStatusExecution trace; - if (eventLevel.equals("error")) { - trace = InjectStatusExecution.traceError(message); - } else { - trace = InjectStatusExecution.traceSuccess(message); - } - ladeWorkflow.addTrace(trace); - } - }); - return ladeWorkflow; - } catch (IOException e) { - throw new RuntimeException(e); - } + }); + return ladeWorkflow; + } catch (IOException e) { + throw new RuntimeException(e); } + } } diff --git a/openbas-api/src/main/java/io/openbas/injectors/manual/ManualContract.java b/openbas-api/src/main/java/io/openbas/injectors/manual/ManualContract.java index 8b52be1d92..6e0e09c63a 100644 --- a/openbas-api/src/main/java/io/openbas/injectors/manual/ManualContract.java +++ b/openbas-api/src/main/java/io/openbas/injectors/manual/ManualContract.java @@ -1,58 +1,63 @@ package io.openbas.injectors.manual; +import static io.openbas.helper.SupportedLanguage.en; +import static io.openbas.helper.SupportedLanguage.fr; +import static io.openbas.injector_contract.Contract.manualContract; +import static io.openbas.injector_contract.ContractDef.contractBuilder; +import static io.openbas.injector_contract.fields.ContractTextArea.textareaField; + +import io.openbas.database.model.Endpoint; +import io.openbas.helper.SupportedLanguage; import io.openbas.injector_contract.Contract; import io.openbas.injector_contract.ContractConfig; import io.openbas.injector_contract.Contractor; import io.openbas.injector_contract.ContractorIcon; import io.openbas.injector_contract.fields.ContractElement; -import io.openbas.database.model.Endpoint; -import io.openbas.helper.SupportedLanguage; -import org.springframework.stereotype.Component; - import java.io.InputStream; import java.util.List; import java.util.Map; - -import static io.openbas.injector_contract.Contract.manualContract; -import static io.openbas.injector_contract.ContractDef.contractBuilder; -import static io.openbas.injector_contract.fields.ContractTextArea.textareaField; -import static io.openbas.helper.SupportedLanguage.en; -import static io.openbas.helper.SupportedLanguage.fr; +import org.springframework.stereotype.Component; @Component public class ManualContract extends Contractor { - public static final String TYPE = "openbas_manual"; - - public static final String MANUAL_DEFAULT = "d02e9132-b9d0-4daa-b3b1-4b9871f8472c"; - - @Override - public boolean isExpose() { - return true; - } - - @Override - public String getType() { - return TYPE; - } - - @Override - public ContractConfig getConfig() { - Map label = Map.of(en, "Manual", fr, "Manuel"); - return new ContractConfig(TYPE, label, "#009688", "#009688", "/img/manual.png", isExpose()); - } - - @Override - public List contracts() { - ContractConfig contractConfig = getConfig(); - List instance = contractBuilder() - .mandatory(textareaField("content", "Content")).build(); - return List.of(manualContract(contractConfig, MANUAL_DEFAULT, - Map.of(en, "Manual", fr, "Manuel"), instance, List.of(Endpoint.PLATFORM_TYPE.Internal), false)); - } - - @Override - public ContractorIcon getIcon() { - InputStream iconStream = getClass().getResourceAsStream("/img/icon-manual.png"); - return new ContractorIcon(iconStream); - } + public static final String TYPE = "openbas_manual"; + + public static final String MANUAL_DEFAULT = "d02e9132-b9d0-4daa-b3b1-4b9871f8472c"; + + @Override + public boolean isExpose() { + return true; + } + + @Override + public String getType() { + return TYPE; + } + + @Override + public ContractConfig getConfig() { + Map label = Map.of(en, "Manual", fr, "Manuel"); + return new ContractConfig(TYPE, label, "#009688", "#009688", "/img/manual.png", isExpose()); + } + + @Override + public List contracts() { + ContractConfig contractConfig = getConfig(); + List instance = + contractBuilder().mandatory(textareaField("content", "Content")).build(); + return List.of( + manualContract( + contractConfig, + MANUAL_DEFAULT, + Map.of(en, "Manual", fr, "Manuel"), + instance, + List.of(Endpoint.PLATFORM_TYPE.Internal), + false)); + } + + @Override + public ContractorIcon getIcon() { + InputStream iconStream = getClass().getResourceAsStream("/img/icon-manual.png"); + return new ContractorIcon(iconStream); + } } diff --git a/openbas-api/src/main/java/io/openbas/injectors/manual/ManualExecutor.java b/openbas-api/src/main/java/io/openbas/injectors/manual/ManualExecutor.java index 8f7c130ffe..73d61ee124 100644 --- a/openbas-api/src/main/java/io/openbas/injectors/manual/ManualExecutor.java +++ b/openbas-api/src/main/java/io/openbas/injectors/manual/ManualExecutor.java @@ -12,8 +12,7 @@ public class ManualExecutor extends Injector { @Override public ExecutionProcess process( - @NotNull final Execution execution, - @NotNull final ExecutableInject injection) { + @NotNull final Execution execution, @NotNull final ExecutableInject injection) { throw new UnsupportedOperationException("Manual inject cannot be executed"); } } diff --git a/openbas-api/src/main/java/io/openbas/injectors/manual/ManualInjector.java b/openbas-api/src/main/java/io/openbas/injectors/manual/ManualInjector.java index 299cabe510..b4a7bdc670 100644 --- a/openbas-api/src/main/java/io/openbas/injectors/manual/ManualInjector.java +++ b/openbas-api/src/main/java/io/openbas/injectors/manual/ManualInjector.java @@ -7,24 +7,16 @@ @Component public class ManualInjector { - private static final String MANUAL_INJECTOR_NAME = "Manual"; - private static final String MANUAL_INJECTOR_ID = "6981a39d-e219-4016-a235-cf7747994abc"; + private static final String MANUAL_INJECTOR_NAME = "Manual"; + private static final String MANUAL_INJECTOR_ID = "6981a39d-e219-4016-a235-cf7747994abc"; - @Autowired - public ManualInjector(InjectorService injectorService, ManualContract contract) { - try { - injectorService.register( - MANUAL_INJECTOR_ID, - MANUAL_INJECTOR_NAME, - contract, - true, - "generic", - null, - null, - false - ); - } catch (Exception e) { - throw new RuntimeException(e); - } + @Autowired + public ManualInjector(InjectorService injectorService, ManualContract contract) { + try { + injectorService.register( + MANUAL_INJECTOR_ID, MANUAL_INJECTOR_NAME, contract, true, "generic", null, null, false); + } catch (Exception e) { + throw new RuntimeException(e); } + } } diff --git a/openbas-api/src/main/java/io/openbas/injectors/mastodon/MastodonContract.java b/openbas-api/src/main/java/io/openbas/injectors/mastodon/MastodonContract.java index 953791c458..72c29d6aca 100644 --- a/openbas-api/src/main/java/io/openbas/injectors/mastodon/MastodonContract.java +++ b/openbas-api/src/main/java/io/openbas/injectors/mastodon/MastodonContract.java @@ -1,70 +1,79 @@ package io.openbas.injectors.mastodon; +import static io.openbas.helper.SupportedLanguage.en; +import static io.openbas.injector_contract.Contract.executableContract; +import static io.openbas.injector_contract.ContractCardinality.Multiple; +import static io.openbas.injector_contract.ContractDef.contractBuilder; +import static io.openbas.injector_contract.fields.ContractAttachment.attachmentField; +import static io.openbas.injector_contract.fields.ContractText.textField; +import static io.openbas.injector_contract.fields.ContractTextArea.textareaField; + +import io.openbas.database.model.Endpoint; import io.openbas.injector_contract.Contract; import io.openbas.injector_contract.ContractConfig; import io.openbas.injector_contract.Contractor; import io.openbas.injector_contract.ContractorIcon; import io.openbas.injector_contract.fields.ContractElement; -import io.openbas.database.model.Endpoint; import io.openbas.injectors.mastodon.config.MastodonConfig; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.stereotype.Component; - import java.io.InputStream; import java.util.List; import java.util.Map; import java.util.Optional; - -import static io.openbas.injector_contract.Contract.executableContract; -import static io.openbas.injector_contract.ContractCardinality.Multiple; -import static io.openbas.injector_contract.ContractDef.contractBuilder; -import static io.openbas.injector_contract.fields.ContractAttachment.attachmentField; -import static io.openbas.injector_contract.fields.ContractText.textField; -import static io.openbas.injector_contract.fields.ContractTextArea.textareaField; -import static io.openbas.helper.SupportedLanguage.en; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Component; @Component public class MastodonContract extends Contractor { - public static final String TYPE = "openbas_mastodon"; + public static final String TYPE = "openbas_mastodon"; - public static final String MASTODON_DEFAULT = "aeab9ed6-ae98-4b48-b8cc-2e91ac54f2f9"; + public static final String MASTODON_DEFAULT = "aeab9ed6-ae98-4b48-b8cc-2e91ac54f2f9"; - private MastodonConfig config; + private MastodonConfig config; - @Autowired - public void setConfig(MastodonConfig config) { - this.config = config; - } + @Autowired + public void setConfig(MastodonConfig config) { + this.config = config; + } - @Override - public boolean isExpose() { - return Optional.ofNullable(config.getEnable()).orElse(false); - } + @Override + public boolean isExpose() { + return Optional.ofNullable(config.getEnable()).orElse(false); + } - @Override - public String getType() { - return TYPE; - } + @Override + public String getType() { + return TYPE; + } - @Override - public ContractConfig getConfig() { - return new ContractConfig(TYPE, Map.of(en, "Mastodon"), "#ad1457", "#ad1457", "/img/mastodon.png", isExpose()); - } + @Override + public ContractConfig getConfig() { + return new ContractConfig( + TYPE, Map.of(en, "Mastodon"), "#ad1457", "#ad1457", "/img/mastodon.png", isExpose()); + } - @Override - public List contracts() { - ContractConfig contractConfig = getConfig(); - List instance = contractBuilder() - .mandatory(textField("token", "Token")) - .mandatory(textareaField("status", "Status")) - .optional(attachmentField("attachments", "Attachments", Multiple)).build(); - return List.of(executableContract(contractConfig, MASTODON_DEFAULT, Map.of(en, "Mastodon"), instance, List.of(Endpoint.PLATFORM_TYPE.Service), false)); - } + @Override + public List contracts() { + ContractConfig contractConfig = getConfig(); + List instance = + contractBuilder() + .mandatory(textField("token", "Token")) + .mandatory(textareaField("status", "Status")) + .optional(attachmentField("attachments", "Attachments", Multiple)) + .build(); + return List.of( + executableContract( + contractConfig, + MASTODON_DEFAULT, + Map.of(en, "Mastodon"), + instance, + List.of(Endpoint.PLATFORM_TYPE.Service), + false)); + } - @Override - public ContractorIcon getIcon() { - InputStream iconStream = getClass().getResourceAsStream("/img/icon-mastodon.png"); - return new ContractorIcon(iconStream); - } + @Override + public ContractorIcon getIcon() { + InputStream iconStream = getClass().getResourceAsStream("/img/icon-mastodon.png"); + return new ContractorIcon(iconStream); + } } diff --git a/openbas-api/src/main/java/io/openbas/injectors/mastodon/MastodonExecutor.java b/openbas-api/src/main/java/io/openbas/injectors/mastodon/MastodonExecutor.java index 921899ff8b..880ae62035 100644 --- a/openbas-api/src/main/java/io/openbas/injectors/mastodon/MastodonExecutor.java +++ b/openbas-api/src/main/java/io/openbas/injectors/mastodon/MastodonExecutor.java @@ -1,5 +1,8 @@ package io.openbas.injectors.mastodon; +import static io.openbas.database.model.InjectStatusExecution.traceError; +import static io.openbas.database.model.InjectStatusExecution.traceSuccess; + import io.openbas.database.model.*; import io.openbas.execution.ExecutableInject; import io.openbas.execution.Injector; @@ -7,38 +10,37 @@ import io.openbas.injectors.mastodon.service.MastodonService; import io.openbas.model.ExecutionProcess; import jakarta.validation.constraints.NotNull; +import java.util.List; import lombok.RequiredArgsConstructor; import org.springframework.stereotype.Component; -import java.util.List; - -import static io.openbas.database.model.InjectStatusExecution.traceError; -import static io.openbas.database.model.InjectStatusExecution.traceSuccess; - @Component(MastodonContract.TYPE) @RequiredArgsConstructor public class MastodonExecutor extends Injector { - private final MastodonService mastodonService; + private final MastodonService mastodonService; - @Override - public ExecutionProcess process( - @NotNull final Execution execution, - @NotNull final ExecutableInject injection) throws Exception { - Inject inject = injection.getInjection().getInject(); - MastodonContent content = contentConvert(injection, MastodonContent.class); - String token = content.getToken(); - String status = content.buildStatus(inject.getFooter(), inject.getHeader()); - List documents = inject.getDocuments().stream() - .filter(InjectDocument::isAttached).map(InjectDocument::getDocument).toList(); - List attachments = resolveAttachments(execution, injection, documents); - try { - String callResult = mastodonService.sendStatus(execution, token, status, attachments); - String message = "Mastodon status sent (" + callResult + ")"; - execution.addTrace(traceSuccess(message)); - } catch (Exception e) { - execution.addTrace(traceError(e.getMessage())); - } - return new ExecutionProcess(false, List.of()); + @Override + public ExecutionProcess process( + @NotNull final Execution execution, @NotNull final ExecutableInject injection) + throws Exception { + Inject inject = injection.getInjection().getInject(); + MastodonContent content = contentConvert(injection, MastodonContent.class); + String token = content.getToken(); + String status = content.buildStatus(inject.getFooter(), inject.getHeader()); + List documents = + inject.getDocuments().stream() + .filter(InjectDocument::isAttached) + .map(InjectDocument::getDocument) + .toList(); + List attachments = resolveAttachments(execution, injection, documents); + try { + String callResult = mastodonService.sendStatus(execution, token, status, attachments); + String message = "Mastodon status sent (" + callResult + ")"; + execution.addTrace(traceSuccess(message)); + } catch (Exception e) { + execution.addTrace(traceError(e.getMessage())); } + return new ExecutionProcess(false, List.of()); + } } diff --git a/openbas-api/src/main/java/io/openbas/injectors/mastodon/MastodonInjector.java b/openbas-api/src/main/java/io/openbas/injectors/mastodon/MastodonInjector.java index eda98b1433..b61d78661c 100644 --- a/openbas-api/src/main/java/io/openbas/injectors/mastodon/MastodonInjector.java +++ b/openbas-api/src/main/java/io/openbas/injectors/mastodon/MastodonInjector.java @@ -7,24 +7,23 @@ @Component public class MastodonInjector { - private static final String MASTODON_INJECTOR_NAME = "Mastodon"; - private static final String MASTODON_INJECTOR_ID = "37cd1743-8975-43c0-837c-f99970142e72"; + private static final String MASTODON_INJECTOR_NAME = "Mastodon"; + private static final String MASTODON_INJECTOR_ID = "37cd1743-8975-43c0-837c-f99970142e72"; - @Autowired - public MastodonInjector(InjectorService injectorService, MastodonContract contract) { - try { - injectorService.register( - MASTODON_INJECTOR_ID, - MASTODON_INJECTOR_NAME, - contract, - false, - "social-media", - null, - null, - false - ); - } catch (Exception e) { - throw new RuntimeException(e); - } + @Autowired + public MastodonInjector(InjectorService injectorService, MastodonContract contract) { + try { + injectorService.register( + MASTODON_INJECTOR_ID, + MASTODON_INJECTOR_NAME, + contract, + false, + "social-media", + null, + null, + false); + } catch (Exception e) { + throw new RuntimeException(e); } + } } diff --git a/openbas-api/src/main/java/io/openbas/injectors/mastodon/config/MastodonConfig.java b/openbas-api/src/main/java/io/openbas/injectors/mastodon/config/MastodonConfig.java index f043885383..edece744ad 100644 --- a/openbas-api/src/main/java/io/openbas/injectors/mastodon/config/MastodonConfig.java +++ b/openbas-api/src/main/java/io/openbas/injectors/mastodon/config/MastodonConfig.java @@ -1,33 +1,30 @@ package io.openbas.injectors.mastodon.config; +import jakarta.validation.constraints.NotNull; import org.springframework.boot.context.properties.ConfigurationProperties; import org.springframework.stereotype.Component; -import jakarta.validation.constraints.NotNull; - @Component @ConfigurationProperties(prefix = "mastodon") public class MastodonConfig { - @NotNull - private Boolean enable; + @NotNull private Boolean enable; - @NotNull - private String url; + @NotNull private String url; - public Boolean getEnable() { - return enable; - } + public Boolean getEnable() { + return enable; + } - public void setEnable(Boolean enable) { - this.enable = enable; - } + public void setEnable(Boolean enable) { + this.enable = enable; + } - public String getUrl() { - return url; - } + public String getUrl() { + return url; + } - public void setUrl(String url) { - this.url = url; - } + public void setUrl(String url) { + this.url = url; + } } diff --git a/openbas-api/src/main/java/io/openbas/injectors/mastodon/model/MastodonContent.java b/openbas-api/src/main/java/io/openbas/injectors/mastodon/model/MastodonContent.java index b1aceac4b3..cab267a519 100644 --- a/openbas-api/src/main/java/io/openbas/injectors/mastodon/model/MastodonContent.java +++ b/openbas-api/src/main/java/io/openbas/injectors/mastodon/model/MastodonContent.java @@ -2,57 +2,56 @@ import com.fasterxml.jackson.annotation.JsonIgnoreProperties; import com.fasterxml.jackson.annotation.JsonProperty; -import org.springframework.util.StringUtils; - import java.util.Objects; +import org.springframework.util.StringUtils; @JsonIgnoreProperties(ignoreUnknown = true) public class MastodonContent { - @JsonProperty("token") - private String token; - - @JsonProperty("status") - private String status; - - public String buildStatus(String footer, String header) { - StringBuilder data = new StringBuilder(); - if (StringUtils.hasLength(header)) { - data.append(header).append("\r\n"); - } - data.append(status); - if (StringUtils.hasLength(footer)) { - data.append("\r\n").append(footer); - } - return data.toString(); - } - - public String getToken() { - return token; - } - - public void setToken(String token) { - this.token = token; - } - - public String getStatus() { - return status; - } + @JsonProperty("token") + private String token; - public void setStatus(String status) { - this.status = status; - } + @JsonProperty("status") + private String status; - @Override - public boolean equals(Object o) { - if (this == o) return true; - if (o == null || getClass() != o.getClass()) return false; - MastodonContent that = (MastodonContent) o; - return Objects.equals(token, that.token) && Objects.equals(status, that.status); + public String buildStatus(String footer, String header) { + StringBuilder data = new StringBuilder(); + if (StringUtils.hasLength(header)) { + data.append(header).append("\r\n"); } - - @Override - public int hashCode() { - return Objects.hash(token, status); + data.append(status); + if (StringUtils.hasLength(footer)) { + data.append("\r\n").append(footer); } + return data.toString(); + } + + public String getToken() { + return token; + } + + public void setToken(String token) { + this.token = token; + } + + public String getStatus() { + return status; + } + + public void setStatus(String status) { + this.status = status; + } + + @Override + public boolean equals(Object o) { + if (this == o) return true; + if (o == null || getClass() != o.getClass()) return false; + MastodonContent that = (MastodonContent) o; + return Objects.equals(token, that.token) && Objects.equals(status, that.status); + } + + @Override + public int hashCode() { + return Objects.hash(token, status); + } } diff --git a/openbas-api/src/main/java/io/openbas/injectors/mastodon/service/MastodonService.java b/openbas-api/src/main/java/io/openbas/injectors/mastodon/service/MastodonService.java index cf2ed043af..5c0e5637dd 100644 --- a/openbas-api/src/main/java/io/openbas/injectors/mastodon/service/MastodonService.java +++ b/openbas-api/src/main/java/io/openbas/injectors/mastodon/service/MastodonService.java @@ -1,10 +1,15 @@ package io.openbas.injectors.mastodon.service; +import static io.openbas.database.model.InjectStatusExecution.traceError; + import com.fasterxml.jackson.databind.ObjectMapper; import io.openbas.database.model.DataAttachment; import io.openbas.database.model.Execution; import io.openbas.injectors.mastodon.config.MastodonConfig; import jakarta.annotation.Resource; +import java.io.IOException; +import java.util.ArrayList; +import java.util.List; import org.apache.hc.client5.http.ClientProtocolException; import org.apache.hc.client5.http.classic.methods.HttpPost; import org.apache.hc.client5.http.entity.UrlEncodedFormEntity; @@ -18,90 +23,101 @@ import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Component; -import java.io.IOException; -import java.util.ArrayList; -import java.util.List; - -import static io.openbas.database.model.InjectStatusExecution.traceError; - @Component public class MastodonService { - @Resource - private MastodonConfig config; + @Resource private MastodonConfig config; - @Resource - private ObjectMapper mapper; + @Resource private ObjectMapper mapper; - @Autowired - public void setConfig(MastodonConfig config) { - this.config = config; - } + @Autowired + public void setConfig(MastodonConfig config) { + this.config = config; + } - // public List resolveAttachments(Execution execution, List attachments) { - // List resolved = new ArrayList<>(); - // for (Document attachment : attachments) { - // String documentId = attachment.getId(); - // Optional askedDocument = documentRepository.findById(documentId); - // try { - // Document doc = askedDocument.orElseThrow(); - // InputStream fileInputStream = fileService.getFile(doc).orElseThrow(); - // byte[] content = IOUtils.toByteArray(fileInputStream); - // resolved.add(new MastodonAttachment(doc.getName(), content, doc.getType())); - // } catch (Exception e) { - // // Can't fetch the attachments, ignore - // String docInfo = askedDocument.map(Document::getName).orElse(documentId); - // String message = "Error getting document " + docInfo; - // execution.addTrace(ExecutionTrace.traceError(getClass().getSimpleName(), message, e)); - // } - // } - // return resolved; - // } + // public List resolveAttachments(Execution execution, List + // attachments) { + // List resolved = new ArrayList<>(); + // for (Document attachment : attachments) { + // String documentId = attachment.getId(); + // Optional askedDocument = documentRepository.findById(documentId); + // try { + // Document doc = askedDocument.orElseThrow(); + // InputStream fileInputStream = fileService.getFile(doc).orElseThrow(); + // byte[] content = IOUtils.toByteArray(fileInputStream); + // resolved.add(new MastodonAttachment(doc.getName(), content, doc.getType())); + // } catch (Exception e) { + // // Can't fetch the attachments, ignore + // String docInfo = askedDocument.map(Document::getName).orElse(documentId); + // String message = "Error getting document " + docInfo; + // execution.addTrace(ExecutionTrace.traceError(getClass().getSimpleName(), message, + // e)); + // } + // } + // return resolved; + // } - public String sendStatus(Execution execution, String token, String status, List attachments) throws Exception { - try (CloseableHttpClient httpClient = HttpClients.createDefault()) { - // upload files - List attachmentIds = new ArrayList<>(); - attachments.forEach(attachment -> { - HttpPost httpPostAttachment = new HttpPost(config.getUrl() + "/api/v2/media"); - httpPostAttachment.addHeader("Authorization", "Bearer " + token); - httpPostAttachment.addHeader("Accept", "*/*"); - MultipartEntityBuilder multipartEntity = MultipartEntityBuilder.create(); - HttpEntity entity = multipartEntity.addPart("file", new ByteArrayBody(attachment.data(), ContentType.create(attachment.contentType()), attachment.name())).build(); - httpPostAttachment.setEntity(entity); - try { - httpClient.execute(httpPostAttachment, classicHttpResponse -> { - if (classicHttpResponse.getCode() == HttpStatus.SC_ACCEPTED) { - String body = EntityUtils.toString(classicHttpResponse.getEntity()); - attachmentIds.add(mapper.readTree(body).get("id").asText()); - return true; - } else { - execution.addTrace(traceError("Cannot upload attachment " + attachment.name())); - return false; - } - }); - } catch (IOException e) { - execution.addTrace(traceError("Cannot upload attachment " + attachment.name())); - } - }); - Thread.sleep(3000); - HttpPost httpPostStatus = new HttpPost(config.getUrl() + "/api/v1/statuses"); - httpPostStatus.addHeader("Authorization", "Bearer " + token); - httpPostStatus.addHeader("Accept", "*/*"); - List params = new ArrayList(); - params.add(new BasicNameValuePair("status", status)); - attachmentIds.forEach(attachmentId -> { - params.add(new BasicNameValuePair("media_ids[]", attachmentId)); - }); - httpPostStatus.setEntity(new UrlEncodedFormEntity(params)); - ClassicHttpResponse response = httpClient.execute(httpPostStatus, classicHttpResponse -> classicHttpResponse); - if (response.getCode() == HttpStatus.SC_OK) { - return "Mastodon status sent"; - } else { - throw new Exception(response.getEntity().toString()); + public String sendStatus( + Execution execution, String token, String status, List attachments) + throws Exception { + try (CloseableHttpClient httpClient = HttpClients.createDefault()) { + // upload files + List attachmentIds = new ArrayList<>(); + attachments.forEach( + attachment -> { + HttpPost httpPostAttachment = new HttpPost(config.getUrl() + "/api/v2/media"); + httpPostAttachment.addHeader("Authorization", "Bearer " + token); + httpPostAttachment.addHeader("Accept", "*/*"); + MultipartEntityBuilder multipartEntity = MultipartEntityBuilder.create(); + HttpEntity entity = + multipartEntity + .addPart( + "file", + new ByteArrayBody( + attachment.data(), + ContentType.create(attachment.contentType()), + attachment.name())) + .build(); + httpPostAttachment.setEntity(entity); + try { + httpClient.execute( + httpPostAttachment, + classicHttpResponse -> { + if (classicHttpResponse.getCode() == HttpStatus.SC_ACCEPTED) { + String body = EntityUtils.toString(classicHttpResponse.getEntity()); + attachmentIds.add(mapper.readTree(body).get("id").asText()); + return true; + } else { + execution.addTrace( + traceError("Cannot upload attachment " + attachment.name())); + return false; + } + }); + } catch (IOException e) { + execution.addTrace(traceError("Cannot upload attachment " + attachment.name())); } - } catch (IOException e) { - throw new ClientProtocolException("Unexpected response for request on: " + config.getUrl() + "/graphql"); - } + }); + Thread.sleep(3000); + HttpPost httpPostStatus = new HttpPost(config.getUrl() + "/api/v1/statuses"); + httpPostStatus.addHeader("Authorization", "Bearer " + token); + httpPostStatus.addHeader("Accept", "*/*"); + List params = new ArrayList(); + params.add(new BasicNameValuePair("status", status)); + attachmentIds.forEach( + attachmentId -> { + params.add(new BasicNameValuePair("media_ids[]", attachmentId)); + }); + httpPostStatus.setEntity(new UrlEncodedFormEntity(params)); + ClassicHttpResponse response = + httpClient.execute(httpPostStatus, classicHttpResponse -> classicHttpResponse); + if (response.getCode() == HttpStatus.SC_OK) { + return "Mastodon status sent"; + } else { + throw new Exception(response.getEntity().toString()); + } + } catch (IOException e) { + throw new ClientProtocolException( + "Unexpected response for request on: " + config.getUrl() + "/graphql"); } + } } diff --git a/openbas-api/src/main/java/io/openbas/injectors/openbas/OpenBASImplantContract.java b/openbas-api/src/main/java/io/openbas/injectors/openbas/OpenBASImplantContract.java index 3017a71b0f..3bd0a2d3fa 100644 --- a/openbas-api/src/main/java/io/openbas/injectors/openbas/OpenBASImplantContract.java +++ b/openbas-api/src/main/java/io/openbas/injectors/openbas/OpenBASImplantContract.java @@ -1,49 +1,49 @@ package io.openbas.injectors.openbas; +import static io.openbas.helper.SupportedLanguage.en; +import static io.openbas.helper.SupportedLanguage.fr; + import io.openbas.helper.SupportedLanguage; import io.openbas.injector_contract.Contract; import io.openbas.injector_contract.ContractConfig; import io.openbas.injector_contract.Contractor; import io.openbas.injector_contract.ContractorIcon; -import lombok.RequiredArgsConstructor; -import org.springframework.stereotype.Component; - import java.io.InputStream; import java.util.List; import java.util.Map; - -import static io.openbas.helper.SupportedLanguage.en; -import static io.openbas.helper.SupportedLanguage.fr; +import lombok.RequiredArgsConstructor; +import org.springframework.stereotype.Component; @Component @RequiredArgsConstructor public class OpenBASImplantContract extends Contractor { - public static final String TYPE = "openbas_implant"; - - @Override - public boolean isExpose() { - return true; - } - - @Override - public String getType() { - return TYPE; - } - - public ContractorIcon getIcon() { - InputStream iconStream = getClass().getResourceAsStream("/img/icon-openbas.png"); - return new ContractorIcon(iconStream); - } - - @Override - public ContractConfig getConfig() { - Map labels = Map.of(en, "OpenBAS Implant", fr, "OpenBAS Implant"); - return new ContractConfig(TYPE, labels, "#8b0000", "#8b0000", "/img/icon-openbas.png", isExpose()); - } - - @Override - public List contracts() throws Exception { - return List.of(); - } + public static final String TYPE = "openbas_implant"; + + @Override + public boolean isExpose() { + return true; + } + + @Override + public String getType() { + return TYPE; + } + + public ContractorIcon getIcon() { + InputStream iconStream = getClass().getResourceAsStream("/img/icon-openbas.png"); + return new ContractorIcon(iconStream); + } + + @Override + public ContractConfig getConfig() { + Map labels = Map.of(en, "OpenBAS Implant", fr, "OpenBAS Implant"); + return new ContractConfig( + TYPE, labels, "#8b0000", "#8b0000", "/img/icon-openbas.png", isExpose()); + } + + @Override + public List contracts() throws Exception { + return List.of(); + } } diff --git a/openbas-api/src/main/java/io/openbas/injectors/openbas/OpenBASImplantExecutor.java b/openbas-api/src/main/java/io/openbas/injectors/openbas/OpenBASImplantExecutor.java index 38edc4e3c8..8e0ddce516 100644 --- a/openbas-api/src/main/java/io/openbas/injectors/openbas/OpenBASImplantExecutor.java +++ b/openbas-api/src/main/java/io/openbas/injectors/openbas/OpenBASImplantExecutor.java @@ -1,5 +1,14 @@ package io.openbas.injectors.openbas; +import static io.openbas.database.model.InjectExpectationSignature.*; +import static io.openbas.database.model.InjectStatusExecution.traceError; +import static io.openbas.model.expectation.DetectionExpectation.detectionExpectationForAsset; +import static io.openbas.model.expectation.DetectionExpectation.detectionExpectationForAssetGroup; +import static io.openbas.model.expectation.ManualExpectation.manualExpectationForAsset; +import static io.openbas.model.expectation.ManualExpectation.manualExpectationForAssetGroup; +import static io.openbas.model.expectation.PreventionExpectation.preventionExpectationForAsset; +import static io.openbas.model.expectation.PreventionExpectation.preventionExpectationForAssetGroup; + import io.openbas.asset.AssetGroupService; import io.openbas.database.model.*; import io.openbas.database.repository.InjectRepository; @@ -12,25 +21,15 @@ import io.openbas.model.expectation.ManualExpectation; import io.openbas.model.expectation.PreventionExpectation; import jakarta.validation.constraints.NotNull; -import lombok.RequiredArgsConstructor; -import lombok.extern.java.Log; -import org.hibernate.Hibernate; -import org.springframework.stereotype.Component; - import java.util.ArrayList; import java.util.HashMap; import java.util.List; import java.util.Map; import java.util.stream.Stream; - -import static io.openbas.database.model.InjectExpectationSignature.*; -import static io.openbas.database.model.InjectStatusExecution.traceError; -import static io.openbas.model.expectation.DetectionExpectation.detectionExpectationForAsset; -import static io.openbas.model.expectation.DetectionExpectation.detectionExpectationForAssetGroup; -import static io.openbas.model.expectation.ManualExpectation.manualExpectationForAsset; -import static io.openbas.model.expectation.ManualExpectation.manualExpectationForAssetGroup; -import static io.openbas.model.expectation.PreventionExpectation.preventionExpectationForAsset; -import static io.openbas.model.expectation.PreventionExpectation.preventionExpectationForAssetGroup; +import lombok.RequiredArgsConstructor; +import lombok.extern.java.Log; +import org.hibernate.Hibernate; +import org.springframework.stereotype.Component; @Component(OpenBASImplantContract.TYPE) @RequiredArgsConstructor @@ -42,194 +41,320 @@ public class OpenBASImplantExecutor extends Injector { private Map resolveAllAssets(@NotNull final ExecutableInject inject) { Map assets = new HashMap<>(); - inject.getAssets().forEach((asset -> { - assets.put(asset, false); - })); - inject.getAssetGroups().forEach((assetGroup -> { - List assetsFromGroup = this.assetGroupService.assetsFromAssetGroup(assetGroup.getId()); - // Verify asset validity - assetsFromGroup.forEach((asset) -> { - assets.put(asset, true); - }); - })); + inject + .getAssets() + .forEach( + (asset -> { + assets.put(asset, false); + })); + inject + .getAssetGroups() + .forEach( + (assetGroup -> { + List assetsFromGroup = + this.assetGroupService.assetsFromAssetGroup(assetGroup.getId()); + // Verify asset validity + assetsFromGroup.forEach( + (asset) -> { + assets.put(asset, true); + }); + })); return assets; } - /** - * In case of direct asset, we have an individual expectation for the asset - */ - private void computeExpectationsForAsset(@NotNull final List expectations, - @NotNull final OpenBASImplantInjectContent content, @NotNull final Asset asset, final boolean expectationGroup, + /** In case of direct asset, we have an individual expectation for the asset */ + private void computeExpectationsForAsset( + @NotNull final List expectations, + @NotNull final OpenBASImplantInjectContent content, + @NotNull final Asset asset, + final boolean expectationGroup, final List injectExpectationSignatures) { if (!content.getExpectations().isEmpty()) { - expectations.addAll(content.getExpectations().stream().flatMap((expectation) -> switch (expectation.getType()) { - case PREVENTION -> Stream.of( - preventionExpectationForAsset(expectation.getScore(), expectation.getName(), expectation.getDescription(), - asset, expectationGroup, expectation.getExpirationTime(), - injectExpectationSignatures)); // expectationGroup usefully in front-end - case DETECTION -> Stream.of( - detectionExpectationForAsset(expectation.getScore(), expectation.getName(), expectation.getDescription(), - asset, expectationGroup, expectation.getExpirationTime(), injectExpectationSignatures)); - case MANUAL -> Stream.of( - manualExpectationForAsset(expectation.getScore(), expectation.getName(), expectation.getDescription(), - asset, expectation.getExpirationTime(), expectationGroup)); - default -> Stream.of(); - }).toList()); + expectations.addAll( + content.getExpectations().stream() + .flatMap( + (expectation) -> + switch (expectation.getType()) { + case PREVENTION -> + Stream.of( + preventionExpectationForAsset( + expectation.getScore(), + expectation.getName(), + expectation.getDescription(), + asset, + expectationGroup, + expectation.getExpirationTime(), + injectExpectationSignatures)); // expectationGroup usefully in + // front-end + case DETECTION -> + Stream.of( + detectionExpectationForAsset( + expectation.getScore(), + expectation.getName(), + expectation.getDescription(), + asset, + expectationGroup, + expectation.getExpirationTime(), + injectExpectationSignatures)); + case MANUAL -> + Stream.of( + manualExpectationForAsset( + expectation.getScore(), + expectation.getName(), + expectation.getDescription(), + asset, + expectation.getExpirationTime(), + expectationGroup)); + default -> Stream.of(); + }) + .toList()); } } /** - * In case of asset group if expectation group -> we have an expectation for the group and one for each asset if not - * expectation group -> we have an individual expectation for each asset + * In case of asset group if expectation group -> we have an expectation for the group and one for + * each asset if not expectation group -> we have an individual expectation for each asset */ - private void computeExpectationsForAssetGroup(@NotNull final List expectations, - @NotNull final OpenBASImplantInjectContent content, @NotNull final AssetGroup assetGroup, + private void computeExpectationsForAssetGroup( + @NotNull final List expectations, + @NotNull final OpenBASImplantInjectContent content, + @NotNull final AssetGroup assetGroup, final List injectExpectationSignatures) { if (!content.getExpectations().isEmpty()) { - expectations.addAll(content.getExpectations().stream().flatMap((expectation) -> switch (expectation.getType()) { - case PREVENTION -> { - // Verify that at least one asset in the group has been executed - List assets = this.assetGroupService.assetsFromAssetGroup(assetGroup.getId()); - if (assets.stream().anyMatch( - (asset) -> expectations.stream().filter(e -> InjectExpectation.EXPECTATION_TYPE.PREVENTION == e.type()) - .anyMatch( - (e) -> ((PreventionExpectation) e).getAsset() != null && ((PreventionExpectation) e).getAsset() - .getId().equals(asset.getId())))) { - yield Stream.of(preventionExpectationForAssetGroup(expectation.getScore(), expectation.getName(), - expectation.getDescription(), assetGroup, expectation.isExpectationGroup(), - expectation.getExpirationTime(), injectExpectationSignatures)); - } - yield Stream.of(); - } - case DETECTION -> { - // Verify that at least one asset in the group has been executed - List assets = this.assetGroupService.assetsFromAssetGroup(assetGroup.getId()); - if (assets.stream().anyMatch( - (asset) -> expectations.stream().filter(e -> InjectExpectation.EXPECTATION_TYPE.DETECTION == e.type()) - .anyMatch( - (e) -> ((DetectionExpectation) e).getAsset() != null && ((DetectionExpectation) e).getAsset() - .getId().equals(asset.getId())))) { - yield Stream.of(detectionExpectationForAssetGroup(expectation.getScore(), expectation.getName(), - expectation.getDescription(), assetGroup, expectation.isExpectationGroup(), - expectation.getExpirationTime(), injectExpectationSignatures)); - } - yield Stream.of(); - } - case MANUAL -> { - // Verify that at least one asset in the group has been executed - List assets = this.assetGroupService.assetsFromAssetGroup(assetGroup.getId()); - if (assets.stream().anyMatch( - (asset) -> expectations.stream().filter(e -> InjectExpectation.EXPECTATION_TYPE.MANUAL == e.type()) - .anyMatch( - (e) -> ((ManualExpectation) e).getAsset() != null && ((ManualExpectation) e).getAsset().getId() - .equals(asset.getId())))) { - yield Stream.of(manualExpectationForAssetGroup(expectation.getScore(), expectation.getName(), - expectation.getDescription(), assetGroup, expectation.getExpirationTime(), - expectation.isExpectationGroup())); - } - yield Stream.of(); - } - default -> Stream.of(); - }).toList()); + expectations.addAll( + content.getExpectations().stream() + .flatMap( + (expectation) -> + switch (expectation.getType()) { + case PREVENTION -> { + // Verify that at least one asset in the group has been executed + List assets = + this.assetGroupService.assetsFromAssetGroup(assetGroup.getId()); + if (assets.stream() + .anyMatch( + (asset) -> + expectations.stream() + .filter( + e -> + InjectExpectation.EXPECTATION_TYPE.PREVENTION + == e.type()) + .anyMatch( + (e) -> + ((PreventionExpectation) e).getAsset() != null + && ((PreventionExpectation) e) + .getAsset() + .getId() + .equals(asset.getId())))) { + yield Stream.of( + preventionExpectationForAssetGroup( + expectation.getScore(), + expectation.getName(), + expectation.getDescription(), + assetGroup, + expectation.isExpectationGroup(), + expectation.getExpirationTime(), + injectExpectationSignatures)); + } + yield Stream.of(); + } + case DETECTION -> { + // Verify that at least one asset in the group has been executed + List assets = + this.assetGroupService.assetsFromAssetGroup(assetGroup.getId()); + if (assets.stream() + .anyMatch( + (asset) -> + expectations.stream() + .filter( + e -> + InjectExpectation.EXPECTATION_TYPE.DETECTION + == e.type()) + .anyMatch( + (e) -> + ((DetectionExpectation) e).getAsset() != null + && ((DetectionExpectation) e) + .getAsset() + .getId() + .equals(asset.getId())))) { + yield Stream.of( + detectionExpectationForAssetGroup( + expectation.getScore(), + expectation.getName(), + expectation.getDescription(), + assetGroup, + expectation.isExpectationGroup(), + expectation.getExpirationTime(), + injectExpectationSignatures)); + } + yield Stream.of(); + } + case MANUAL -> { + // Verify that at least one asset in the group has been executed + List assets = + this.assetGroupService.assetsFromAssetGroup(assetGroup.getId()); + if (assets.stream() + .anyMatch( + (asset) -> + expectations.stream() + .filter( + e -> + InjectExpectation.EXPECTATION_TYPE.MANUAL + == e.type()) + .anyMatch( + (e) -> + ((ManualExpectation) e).getAsset() != null + && ((ManualExpectation) e) + .getAsset() + .getId() + .equals(asset.getId())))) { + yield Stream.of( + manualExpectationForAssetGroup( + expectation.getScore(), + expectation.getName(), + expectation.getDescription(), + assetGroup, + expectation.getExpirationTime(), + expectation.isExpectationGroup())); + } + yield Stream.of(); + } + default -> Stream.of(); + }) + .toList()); } } @Override - public ExecutionProcess process(Execution execution, ExecutableInject injection) throws Exception { - Inject inject = this.injectRepository.findById(injection.getInjection().getInject().getId()).orElseThrow(); + public ExecutionProcess process(Execution execution, ExecutableInject injection) + throws Exception { + Inject inject = + this.injectRepository.findById(injection.getInjection().getInject().getId()).orElseThrow(); Map assets = this.resolveAllAssets(injection); // Check assets target if (assets.isEmpty()) { - execution.addTrace(traceError( - "Found 0 asset to execute the ability on (likely this inject does not have any target or the targeted asset is inactive and has been purged)")); + execution.addTrace( + traceError( + "Found 0 asset to execute the ability on (likely this inject does not have any target or the targeted asset is inactive and has been purged)")); } // Compute expectations - OpenBASImplantInjectContent content = contentConvert(injection, OpenBASImplantInjectContent.class); + OpenBASImplantInjectContent content = + contentConvert(injection, OpenBASImplantInjectContent.class); List expectations = new ArrayList<>(); - assets.forEach((asset, isInGroup) -> { - List injectExpectationSignatures = new ArrayList<>(); + assets.forEach( + (asset, isInGroup) -> { + List injectExpectationSignatures = new ArrayList<>(); - inject.getInjectorContract().ifPresent(injectorContract -> { - if (injectorContract.getPayload() != null) { - // Put the correct number in inject status - int totalActionsCount = 0; - switch (injectorContract.getPayload().getType()) { - case "Command": - Command payloadCommand = (Command) Hibernate.unproxy(injectorContract.getPayload()); - injectExpectationSignatures.add( - InjectExpectationSignature.builder().type(EXPECTATION_SIGNATURE_TYPE_PROCESS_NAME) - .value("obas-implant-" + inject.getId()).build()); - injectExpectationSignatures.add( - InjectExpectationSignature.builder().type(EXPECTATION_SIGNATURE_TYPE_COMMAND_LINE) - .value(payloadCommand.getContent()).build()); - totalActionsCount = totalActionsCount + 1; - if (payloadCommand.getPrerequisites() != null) { - totalActionsCount = totalActionsCount + payloadCommand.getPrerequisites().size(); - } - if (payloadCommand.getCleanupCommand() != null) { - totalActionsCount = totalActionsCount + 1; - } - break; - case "Executable": - Executable payloadExecutable = (Executable) Hibernate.unproxy(injectorContract.getPayload()); - injectExpectationSignatures.add( - InjectExpectationSignature.builder().type(EXPECTATION_SIGNATURE_TYPE_FILE_NAME) - .value(payloadExecutable.getExecutableFile().getName()).build()); - totalActionsCount = totalActionsCount + 2; - if (payloadExecutable.getPrerequisites() != null) { - totalActionsCount = totalActionsCount + payloadExecutable.getPrerequisites().size(); - } - if (payloadExecutable.getCleanupCommand() != null) { - totalActionsCount = totalActionsCount + 1; - } - // TODO File hash - break; - case "FileDrop": - FileDrop payloadFileDrop = (FileDrop) Hibernate.unproxy(injectorContract.getPayload()); - injectExpectationSignatures.add( - InjectExpectationSignature.builder().type(EXPECTATION_SIGNATURE_TYPE_FILE_NAME) - .value(payloadFileDrop.getFileDropFile().getName()).build()); - totalActionsCount = totalActionsCount + 1; - if (payloadFileDrop.getPrerequisites() != null) { - totalActionsCount = totalActionsCount + payloadFileDrop.getPrerequisites().size(); - } - if (payloadFileDrop.getCleanupCommand() != null) { - totalActionsCount = totalActionsCount + 1; - } - // TODO File hash - break; - case "DnsResolution": - DnsResolution payloadDnsResolution = (DnsResolution) Hibernate.unproxy(injectorContract.getPayload()); - // TODO this is only generating the signature for the first hostname - // Problem is: we are not supporting multiple signatures of the same type with "AND" parameters, and this can be in multiple alerts downstream in security platforms - // Tech pain to refine - injectExpectationSignatures.add( - InjectExpectationSignature.builder().type(EXPECTATION_SIGNATURE_TYPE_HOSTNAME) - .value(payloadDnsResolution.getHostname().split("\\r?\\n")[0]).build()); - totalActionsCount = totalActionsCount + payloadDnsResolution.getHostname().split("\\r?\\n").length; - if (payloadDnsResolution.getPrerequisites() != null) { - totalActionsCount = totalActionsCount + payloadDnsResolution.getPrerequisites().size(); - } - if (payloadDnsResolution.getCleanupCommand() != null) { - totalActionsCount = totalActionsCount + 1; - } - break; - default: - throw new UnsupportedOperationException( - "Payload type " + injectorContract.getPayload().getType() + " is not supported"); - } - execution.setExpectedCount(totalActionsCount); - } - }); - computeExpectationsForAsset(expectations, content, asset, isInGroup, injectExpectationSignatures); - }); + inject + .getInjectorContract() + .ifPresent( + injectorContract -> { + if (injectorContract.getPayload() != null) { + // Put the correct number in inject status + int totalActionsCount = 0; + switch (injectorContract.getPayload().getType()) { + case "Command": + Command payloadCommand = + (Command) Hibernate.unproxy(injectorContract.getPayload()); + injectExpectationSignatures.add( + InjectExpectationSignature.builder() + .type(EXPECTATION_SIGNATURE_TYPE_PROCESS_NAME) + .value("obas-implant-" + inject.getId()) + .build()); + injectExpectationSignatures.add( + InjectExpectationSignature.builder() + .type(EXPECTATION_SIGNATURE_TYPE_COMMAND_LINE) + .value(payloadCommand.getContent()) + .build()); + totalActionsCount = totalActionsCount + 1; + if (payloadCommand.getPrerequisites() != null) { + totalActionsCount = + totalActionsCount + payloadCommand.getPrerequisites().size(); + } + if (payloadCommand.getCleanupCommand() != null) { + totalActionsCount = totalActionsCount + 1; + } + break; + case "Executable": + Executable payloadExecutable = + (Executable) Hibernate.unproxy(injectorContract.getPayload()); + injectExpectationSignatures.add( + InjectExpectationSignature.builder() + .type(EXPECTATION_SIGNATURE_TYPE_FILE_NAME) + .value(payloadExecutable.getExecutableFile().getName()) + .build()); + totalActionsCount = totalActionsCount + 2; + if (payloadExecutable.getPrerequisites() != null) { + totalActionsCount = + totalActionsCount + payloadExecutable.getPrerequisites().size(); + } + if (payloadExecutable.getCleanupCommand() != null) { + totalActionsCount = totalActionsCount + 1; + } + // TODO File hash + break; + case "FileDrop": + FileDrop payloadFileDrop = + (FileDrop) Hibernate.unproxy(injectorContract.getPayload()); + injectExpectationSignatures.add( + InjectExpectationSignature.builder() + .type(EXPECTATION_SIGNATURE_TYPE_FILE_NAME) + .value(payloadFileDrop.getFileDropFile().getName()) + .build()); + totalActionsCount = totalActionsCount + 1; + if (payloadFileDrop.getPrerequisites() != null) { + totalActionsCount = + totalActionsCount + payloadFileDrop.getPrerequisites().size(); + } + if (payloadFileDrop.getCleanupCommand() != null) { + totalActionsCount = totalActionsCount + 1; + } + // TODO File hash + break; + case "DnsResolution": + DnsResolution payloadDnsResolution = + (DnsResolution) Hibernate.unproxy(injectorContract.getPayload()); + // TODO this is only generating the signature for the first hostname + // Problem is: we are not supporting multiple signatures of the same type + // with "AND" parameters, and this can be in multiple alerts downstream in + // security platforms + // Tech pain to refine + injectExpectationSignatures.add( + InjectExpectationSignature.builder() + .type(EXPECTATION_SIGNATURE_TYPE_HOSTNAME) + .value(payloadDnsResolution.getHostname().split("\\r?\\n")[0]) + .build()); + totalActionsCount = + totalActionsCount + + payloadDnsResolution.getHostname().split("\\r?\\n").length; + if (payloadDnsResolution.getPrerequisites() != null) { + totalActionsCount = + totalActionsCount + payloadDnsResolution.getPrerequisites().size(); + } + if (payloadDnsResolution.getCleanupCommand() != null) { + totalActionsCount = totalActionsCount + 1; + } + break; + default: + throw new UnsupportedOperationException( + "Payload type " + + injectorContract.getPayload().getType() + + " is not supported"); + } + execution.setExpectedCount(totalActionsCount); + } + }); + computeExpectationsForAsset( + expectations, content, asset, isInGroup, injectExpectationSignatures); + }); List assetGroups = injection.getAssetGroups(); assetGroups.forEach( - (assetGroup -> computeExpectationsForAssetGroup(expectations, content, assetGroup, new ArrayList<>()))); + (assetGroup -> + computeExpectationsForAssetGroup( + expectations, content, assetGroup, new ArrayList<>()))); return new ExecutionProcess(true, expectations); } } diff --git a/openbas-api/src/main/java/io/openbas/injectors/openbas/OpenBASInjector.java b/openbas-api/src/main/java/io/openbas/injectors/openbas/OpenBASInjector.java index 5a44f0d260..5073dd4581 100644 --- a/openbas-api/src/main/java/io/openbas/injectors/openbas/OpenBASInjector.java +++ b/openbas-api/src/main/java/io/openbas/injectors/openbas/OpenBASInjector.java @@ -3,60 +3,130 @@ import io.openbas.config.OpenBASConfig; import io.openbas.database.model.Endpoint; import io.openbas.integrations.InjectorService; -import lombok.extern.java.Log; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.stereotype.Component; - import java.util.Arrays; import java.util.HashMap; import java.util.Map; import java.util.logging.Level; +import lombok.extern.java.Log; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Component; @Component @Log public class OpenBASInjector { - private static final String OPENBAS_INJECTOR_NAME = "OpenBAS Implant"; - private static final String OPENBAS_INJECTOR_ID = "49229430-b5b5-431f-ba5b-f36f599b0144"; + private static final String OPENBAS_INJECTOR_NAME = "OpenBAS Implant"; + private static final String OPENBAS_INJECTOR_ID = "49229430-b5b5-431f-ba5b-f36f599b0144"; - private String dlUri(OpenBASConfig openBASConfig, String platform, String arch) { - return openBASConfig.getBaseUrlForAgent() + "/api/implant/openbas/" + platform + "/" + arch; - } + private String dlUri(OpenBASConfig openBASConfig, String platform, String arch) { + return openBASConfig.getBaseUrlForAgent() + "/api/implant/openbas/" + platform + "/" + arch; + } - @SuppressWarnings("SameParameterValue") - private String dlVar(OpenBASConfig openBASConfig, String platform, String arch) { - return "$url=\"" + openBASConfig.getBaseUrl() + "/api/implant/openbas/" + platform + "/" + arch + "\""; - } + @SuppressWarnings("SameParameterValue") + private String dlVar(OpenBASConfig openBASConfig, String platform, String arch) { + return "$url=\"" + + openBASConfig.getBaseUrl() + + "/api/implant/openbas/" + + platform + + "/" + + arch + + "\""; + } - @Autowired - public OpenBASInjector(InjectorService injectorService, OpenBASImplantContract contract, OpenBASConfig openBASConfig) { - String tokenVar = "token=\"" + openBASConfig.getAdminToken() + "\""; - String serverVar = "server=\"" + openBASConfig.getBaseUrlForAgent() + "\""; - String unsecuredCertificateVar = "unsecured_certificate=\"" + openBASConfig.isUnsecuredCertificate() + "\""; - String withProxyVar = "with_proxy=\"" + openBASConfig.isWithProxy() + "\""; - Map executorCommands = new HashMap<>(); - executorCommands.put(Endpoint.PLATFORM_TYPE.Windows.name() + "." + Endpoint.PLATFORM_ARCH.x86_64, "$x=\"#{location}\";$location=$x.Replace(\"\\obas-agent-caldera.exe\", \"\");[Environment]::CurrentDirectory = $location;$filename=\"obas-implant-#{inject}.exe\";$" + tokenVar + ";$" + serverVar + ";$" + unsecuredCertificateVar + ";$" + withProxyVar + ";" + dlVar(openBASConfig, "windows", "x86_64") + ";$wc=New-Object System.Net.WebClient;$data=$wc.DownloadData($url);[io.file]::WriteAllBytes($filename,$data) | Out-Null;Remove-NetFirewallRule -DisplayName \"Allow OpenBAS Inbound\";New-NetFirewallRule -DisplayName \"Allow OpenBAS Inbound\" -Direction Inbound -Program \"$location\\$filename\" -Action Allow | Out-Null;Remove-NetFirewallRule -DisplayName \"Allow OpenBAS Outbound\";New-NetFirewallRule -DisplayName \"Allow OpenBAS Outbound\" -Direction Outbound -Program \"$location\\$filename\" -Action Allow | Out-Null;Start-Process -FilePath \"$location\\$filename\" -ArgumentList \"--uri $server --token $token --unsecured-certificate $unsecured_certificate --with-proxy $with_proxy --inject-id #{inject}\" -WindowStyle hidden;"); - executorCommands.put(Endpoint.PLATFORM_TYPE.Linux.name() + "." + Endpoint.PLATFORM_ARCH.x86_64, "x=\"#{location}\";location=$(echo \"$x\" | sed \"s#/openbas-caldera-agent##\");filename=obas-implant-#{inject};" + serverVar + ";" + tokenVar + ";" + unsecuredCertificateVar + ";" + withProxyVar + ";curl -s -X GET " + dlUri(openBASConfig, "linux", "x86_64") + " > $location/$filename;chmod +x $location/$filename;$location/$filename --uri $server --token $token --unsecured-certificate $unsecured_certificate --with-proxy $with_proxy --inject-id #{inject} &"); - executorCommands.put(Endpoint.PLATFORM_TYPE.MacOS.name() + "." + Endpoint.PLATFORM_ARCH.x86_64, "x=\"#{location}\";location=$(echo \"$x\" | sed \"s#/openbas-caldera-agent##\");filename=obas-implant-#{inject};" + serverVar + ";" + tokenVar + ";" + unsecuredCertificateVar + ";" + withProxyVar + ";curl -s -X GET " + dlUri(openBASConfig, "macos", "x86_64") + " > $location/$filename;chmod +x $location/$filename;$location/$filename --uri $server --token $token --unsecured-certificate $unsecured_certificate --with-proxy $with_proxy --inject-id #{inject} &"); - executorCommands.put(Endpoint.PLATFORM_TYPE.MacOS.name() + "." + Endpoint.PLATFORM_ARCH.arm64, "x=\"#{location}\";location=$(echo \"$x\" | sed \"s#/openbas-caldera-agent##\");filename=obas-implant-#{inject};" + serverVar + ";" + tokenVar + ";" + unsecuredCertificateVar + ";" + withProxyVar + ";curl -s -X GET " + dlUri(openBASConfig, "macos", "arm64") + " > $location/$filename;chmod +x $location/$filename;$location/$filename --uri $server --token $token --unsecured-certificate $unsecured_certificate --with-proxy $with_proxy --inject-id #{inject} &"); - Map executorClearCommands = new HashMap<>(); - executorClearCommands.put(Endpoint.PLATFORM_TYPE.Windows.name() + "." + Endpoint.PLATFORM_ARCH.x86_64, "$x=\"#{location}\";$location=$x.Replace(\"\\obas-agent-caldera.exe\", \"\");[Environment]::CurrentDirectory = $location;cd \"$location\";Get-ChildItem -Recurse -Filter *implant* | Remove-Item"); - executorClearCommands.put(Endpoint.PLATFORM_TYPE.Linux.name() + "." + Endpoint.PLATFORM_ARCH.x86_64, "x=\"#{location}\";location=$(echo \"$x\" | sed \"s#/openbas-caldera-agent##\");cd \"$location\"; rm *implant*"); - executorClearCommands.put(Endpoint.PLATFORM_TYPE.MacOS.name() + "." + Endpoint.PLATFORM_ARCH.x86_64, "x=\"#{location}\";location=$(echo \"$x\" | sed \"s#/openbas-caldera-agent##\");cd \"$location\"; rm *implant*"); - executorClearCommands.put(Endpoint.PLATFORM_TYPE.MacOS.name() + "." + Endpoint.PLATFORM_ARCH.arm64, "x=\"#{location}\";location=$(echo \"$x\" | sed \"s#/openbas-caldera-agent##\");cd \"$location\"; rm *implant*"); - try { - injectorService.register( - OPENBAS_INJECTOR_ID, - OPENBAS_INJECTOR_NAME, - contract, - false, - "simulation-implant", - executorCommands, - executorClearCommands, - true - ); - } catch (Exception e) { - log.log(Level.SEVERE, "Error creating OpenBAS implant injector (" + e.getMessage() + ")" + "\n" + Arrays.toString(e.getStackTrace())); - } + @Autowired + public OpenBASInjector( + InjectorService injectorService, + OpenBASImplantContract contract, + OpenBASConfig openBASConfig) { + String tokenVar = "token=\"" + openBASConfig.getAdminToken() + "\""; + String serverVar = "server=\"" + openBASConfig.getBaseUrlForAgent() + "\""; + String unsecuredCertificateVar = + "unsecured_certificate=\"" + openBASConfig.isUnsecuredCertificate() + "\""; + String withProxyVar = "with_proxy=\"" + openBASConfig.isWithProxy() + "\""; + Map executorCommands = new HashMap<>(); + executorCommands.put( + Endpoint.PLATFORM_TYPE.Windows.name() + "." + Endpoint.PLATFORM_ARCH.x86_64, + "$x=\"#{location}\";$location=$x.Replace(\"\\obas-agent-caldera.exe\", \"\");[Environment]::CurrentDirectory = $location;$filename=\"obas-implant-#{inject}.exe\";$" + + tokenVar + + ";$" + + serverVar + + ";$" + + unsecuredCertificateVar + + ";$" + + withProxyVar + + ";" + + dlVar(openBASConfig, "windows", "x86_64") + + ";$wc=New-Object System.Net.WebClient;$data=$wc.DownloadData($url);[io.file]::WriteAllBytes($filename,$data) | Out-Null;Remove-NetFirewallRule -DisplayName \"Allow OpenBAS Inbound\";New-NetFirewallRule -DisplayName \"Allow OpenBAS Inbound\" -Direction Inbound -Program \"$location\\$filename\" -Action Allow | Out-Null;Remove-NetFirewallRule -DisplayName \"Allow OpenBAS Outbound\";New-NetFirewallRule -DisplayName \"Allow OpenBAS Outbound\" -Direction Outbound -Program \"$location\\$filename\" -Action Allow | Out-Null;Start-Process -FilePath \"$location\\$filename\" -ArgumentList \"--uri $server --token $token --unsecured-certificate $unsecured_certificate --with-proxy $with_proxy --inject-id #{inject}\" -WindowStyle hidden;"); + executorCommands.put( + Endpoint.PLATFORM_TYPE.Linux.name() + "." + Endpoint.PLATFORM_ARCH.x86_64, + "x=\"#{location}\";location=$(echo \"$x\" | sed \"s#/openbas-caldera-agent##\");filename=obas-implant-#{inject};" + + serverVar + + ";" + + tokenVar + + ";" + + unsecuredCertificateVar + + ";" + + withProxyVar + + ";curl -s -X GET " + + dlUri(openBASConfig, "linux", "x86_64") + + " > $location/$filename;chmod +x $location/$filename;$location/$filename --uri $server --token $token --unsecured-certificate $unsecured_certificate --with-proxy $with_proxy --inject-id #{inject} &"); + executorCommands.put( + Endpoint.PLATFORM_TYPE.MacOS.name() + "." + Endpoint.PLATFORM_ARCH.x86_64, + "x=\"#{location}\";location=$(echo \"$x\" | sed \"s#/openbas-caldera-agent##\");filename=obas-implant-#{inject};" + + serverVar + + ";" + + tokenVar + + ";" + + unsecuredCertificateVar + + ";" + + withProxyVar + + ";curl -s -X GET " + + dlUri(openBASConfig, "macos", "x86_64") + + " > $location/$filename;chmod +x $location/$filename;$location/$filename --uri $server --token $token --unsecured-certificate $unsecured_certificate --with-proxy $with_proxy --inject-id #{inject} &"); + executorCommands.put( + Endpoint.PLATFORM_TYPE.MacOS.name() + "." + Endpoint.PLATFORM_ARCH.arm64, + "x=\"#{location}\";location=$(echo \"$x\" | sed \"s#/openbas-caldera-agent##\");filename=obas-implant-#{inject};" + + serverVar + + ";" + + tokenVar + + ";" + + unsecuredCertificateVar + + ";" + + withProxyVar + + ";curl -s -X GET " + + dlUri(openBASConfig, "macos", "arm64") + + " > $location/$filename;chmod +x $location/$filename;$location/$filename --uri $server --token $token --unsecured-certificate $unsecured_certificate --with-proxy $with_proxy --inject-id #{inject} &"); + Map executorClearCommands = new HashMap<>(); + executorClearCommands.put( + Endpoint.PLATFORM_TYPE.Windows.name() + "." + Endpoint.PLATFORM_ARCH.x86_64, + "$x=\"#{location}\";$location=$x.Replace(\"\\obas-agent-caldera.exe\", \"\");[Environment]::CurrentDirectory = $location;cd \"$location\";Get-ChildItem -Recurse -Filter *implant* | Remove-Item"); + executorClearCommands.put( + Endpoint.PLATFORM_TYPE.Linux.name() + "." + Endpoint.PLATFORM_ARCH.x86_64, + "x=\"#{location}\";location=$(echo \"$x\" | sed \"s#/openbas-caldera-agent##\");cd \"$location\"; rm *implant*"); + executorClearCommands.put( + Endpoint.PLATFORM_TYPE.MacOS.name() + "." + Endpoint.PLATFORM_ARCH.x86_64, + "x=\"#{location}\";location=$(echo \"$x\" | sed \"s#/openbas-caldera-agent##\");cd \"$location\"; rm *implant*"); + executorClearCommands.put( + Endpoint.PLATFORM_TYPE.MacOS.name() + "." + Endpoint.PLATFORM_ARCH.arm64, + "x=\"#{location}\";location=$(echo \"$x\" | sed \"s#/openbas-caldera-agent##\");cd \"$location\"; rm *implant*"); + try { + injectorService.register( + OPENBAS_INJECTOR_ID, + OPENBAS_INJECTOR_NAME, + contract, + false, + "simulation-implant", + executorCommands, + executorClearCommands, + true); + } catch (Exception e) { + log.log( + Level.SEVERE, + "Error creating OpenBAS implant injector (" + + e.getMessage() + + ")" + + "\n" + + Arrays.toString(e.getStackTrace())); } + } } diff --git a/openbas-api/src/main/java/io/openbas/injectors/openbas/model/OpenBASImplantInjectContent.java b/openbas-api/src/main/java/io/openbas/injectors/openbas/model/OpenBASImplantInjectContent.java index 7736a49dca..04f620c87d 100644 --- a/openbas-api/src/main/java/io/openbas/injectors/openbas/model/OpenBASImplantInjectContent.java +++ b/openbas-api/src/main/java/io/openbas/injectors/openbas/model/OpenBASImplantInjectContent.java @@ -2,11 +2,10 @@ import com.fasterxml.jackson.annotation.JsonProperty; import io.openbas.model.inject.form.Expectation; -import lombok.Getter; -import lombok.Setter; - import java.util.ArrayList; import java.util.List; +import lombok.Getter; +import lombok.Setter; @Getter @Setter @@ -17,5 +16,4 @@ public class OpenBASImplantInjectContent { @JsonProperty("expectations") private List expectations = new ArrayList<>(); - } diff --git a/openbas-api/src/main/java/io/openbas/injectors/opencti/OpenCTIContract.java b/openbas-api/src/main/java/io/openbas/injectors/opencti/OpenCTIContract.java index ebe7e87b1d..a2ab2fb49a 100644 --- a/openbas-api/src/main/java/io/openbas/injectors/opencti/OpenCTIContract.java +++ b/openbas-api/src/main/java/io/openbas/injectors/opencti/OpenCTIContract.java @@ -1,19 +1,7 @@ package io.openbas.injectors.opencti; -import io.openbas.injector_contract.*; -import io.openbas.injector_contract.fields.ContractElement; -import io.openbas.injector_contract.fields.ContractExpectations; -import io.openbas.database.model.Endpoint; -import io.openbas.database.model.Variable.VariableType; -import io.openbas.injectors.opencti.config.OpenCTIConfig; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.stereotype.Component; - -import java.io.InputStream; -import java.util.List; -import java.util.Map; -import java.util.Optional; - +import static io.openbas.helper.SupportedLanguage.en; +import static io.openbas.helper.SupportedLanguage.fr; import static io.openbas.injector_contract.Contract.executableContract; import static io.openbas.injector_contract.ContractCardinality.Multiple; import static io.openbas.injector_contract.ContractCardinality.One; @@ -23,8 +11,19 @@ import static io.openbas.injector_contract.fields.ContractExpectations.expectationsField; import static io.openbas.injector_contract.fields.ContractText.textField; import static io.openbas.injector_contract.fields.ContractTextArea.richTextareaField; -import static io.openbas.helper.SupportedLanguage.en; -import static io.openbas.helper.SupportedLanguage.fr; + +import io.openbas.database.model.Endpoint; +import io.openbas.database.model.Variable.VariableType; +import io.openbas.injector_contract.*; +import io.openbas.injector_contract.fields.ContractElement; +import io.openbas.injector_contract.fields.ContractExpectations; +import io.openbas.injectors.opencti.config.OpenCTIConfig; +import java.io.InputStream; +import java.util.List; +import java.util.Map; +import java.util.Optional; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Component; @Component public class OpenCTIContract extends Contractor { @@ -53,36 +52,58 @@ public String getType() { @Override public ContractConfig getConfig() { - return new ContractConfig(TYPE, Map.of(en, "OpenCTI", fr, "OpenCTI"), "#0fbcff", "#001bda", "/img/icon-opencti.png", isExpose()); + return new ContractConfig( + TYPE, + Map.of(en, "OpenCTI", fr, "OpenCTI"), + "#0fbcff", + "#001bda", + "/img/icon-opencti.png", + isExpose()); } @Override public List contracts() { // variables - ContractVariable documentUriVariable = variable("document_uri", - "Http user link to upload the document (only for document expectation)", VariableType.String, One); + ContractVariable documentUriVariable = + variable( + "document_uri", + "Http user link to upload the document (only for document expectation)", + VariableType.String, + One); // Contracts - ContractExpectations expectationsField = expectationsField( - "expectations", "Expectations" - ); + ContractExpectations expectationsField = expectationsField("expectations", "Expectations"); ContractConfig contractConfig = getConfig(); - List createCaseInstance = contractBuilder() - .mandatory(textField("name", "Name")) - .mandatory(richTextareaField("description", "Description")) - .optional(attachmentField("attachments", "Attachments", Multiple)) - .optional(expectationsField) - .build(); - Contract createCase = executableContract(contractConfig, OPENCTI_CREATE_CASE, - Map.of(en, "Create a new case", fr, "Créer un nouveau case"), createCaseInstance, List.of(Endpoint.PLATFORM_TYPE.Service), false); + List createCaseInstance = + contractBuilder() + .mandatory(textField("name", "Name")) + .mandatory(richTextareaField("description", "Description")) + .optional(attachmentField("attachments", "Attachments", Multiple)) + .optional(expectationsField) + .build(); + Contract createCase = + executableContract( + contractConfig, + OPENCTI_CREATE_CASE, + Map.of(en, "Create a new case", fr, "Créer un nouveau case"), + createCaseInstance, + List.of(Endpoint.PLATFORM_TYPE.Service), + false); createCase.addVariable(documentUriVariable); - List createReportInstance = contractBuilder() - .mandatory(textField("name", "Name")) - .mandatory(richTextareaField("description", "Description")) - .optional(attachmentField("attachments", "Attachments", Multiple)) - .optional(expectationsField) - .build(); - Contract createReport = executableContract(contractConfig, OPENCTI_CREATE_REPORT, - Map.of(en, "Create a new report", fr, "Créer un nouveau rapport"), createReportInstance, List.of(Endpoint.PLATFORM_TYPE.Service), false); + List createReportInstance = + contractBuilder() + .mandatory(textField("name", "Name")) + .mandatory(richTextareaField("description", "Description")) + .optional(attachmentField("attachments", "Attachments", Multiple)) + .optional(expectationsField) + .build(); + Contract createReport = + executableContract( + contractConfig, + OPENCTI_CREATE_REPORT, + Map.of(en, "Create a new report", fr, "Créer un nouveau rapport"), + createReportInstance, + List.of(Endpoint.PLATFORM_TYPE.Service), + false); createReport.addVariable(documentUriVariable); return List.of(createCase, createReport); } diff --git a/openbas-api/src/main/java/io/openbas/injectors/opencti/OpenCTIExecutor.java b/openbas-api/src/main/java/io/openbas/injectors/opencti/OpenCTIExecutor.java index 158833e610..7778c0d07b 100644 --- a/openbas-api/src/main/java/io/openbas/injectors/opencti/OpenCTIExecutor.java +++ b/openbas-api/src/main/java/io/openbas/injectors/opencti/OpenCTIExecutor.java @@ -1,5 +1,8 @@ package io.openbas.injectors.opencti; +import static io.openbas.database.model.InjectStatusExecution.traceError; +import static io.openbas.injectors.opencti.OpenCTIContract.OPENCTI_CREATE_CASE; + import io.openbas.database.model.*; import io.openbas.execution.ExecutableInject; import io.openbas.execution.Injector; @@ -9,14 +12,10 @@ import io.openbas.model.Expectation; import io.openbas.model.expectation.ManualExpectation; import jakarta.validation.constraints.NotNull; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.stereotype.Component; - import java.util.List; import java.util.stream.Stream; - -import static io.openbas.database.model.InjectStatusExecution.traceError; -import static io.openbas.injectors.opencti.OpenCTIContract.OPENCTI_CREATE_CASE; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Component; @Component(OpenCTIContract.TYPE) public class OpenCTIExecutor extends Injector { @@ -28,7 +27,8 @@ public void setOpenCTIService(OpenCTIService openCTIService) { this.openCTIService = openCTIService; } - private void createCase(Execution execution, String name, String description, List attachments) { + private void createCase( + Execution execution, String name, String description, List attachments) { try { openCTIService.createCase(execution, name, description, attachments); } catch (Exception e) { @@ -36,7 +36,8 @@ private void createCase(Execution execution, String name, String description, Li } } - private void createReport(Execution execution, String name, String description, List attachments) { + private void createReport( + Execution execution, String name, String description, List attachments) { try { openCTIService.createReport(execution, name, description, attachments); } catch (Exception e) { @@ -45,30 +46,39 @@ private void createReport(Execution execution, String name, String description, } @Override - public ExecutionProcess process(@NotNull final Execution execution, @NotNull final ExecutableInject injection) + public ExecutionProcess process( + @NotNull final Execution execution, @NotNull final ExecutableInject injection) throws Exception { Inject inject = injection.getInjection().getInject(); CaseContent content = contentConvert(injection, CaseContent.class); - List documents = inject.getDocuments().stream().filter(InjectDocument::isAttached) - .map(InjectDocument::getDocument).toList(); + List documents = + inject.getDocuments().stream() + .filter(InjectDocument::isAttached) + .map(InjectDocument::getDocument) + .toList(); List attachments = resolveAttachments(execution, injection, documents); String name = content.getName(); String description = content.getDescription(); - inject.getInjectorContract().ifPresent(injectorContract -> { - switch (injectorContract.getId()) { - case OPENCTI_CREATE_CASE -> createCase(execution, name, description, attachments); - default -> createReport(execution, name, description, attachments); - } - }); + inject + .getInjectorContract() + .ifPresent( + injectorContract -> { + switch (injectorContract.getId()) { + case OPENCTI_CREATE_CASE -> createCase(execution, name, description, attachments); + default -> createReport(execution, name, description, attachments); + } + }); - List expectations = content.getExpectations() - .stream() - .flatMap((entry) -> switch (entry.getType()) { - case MANUAL -> Stream.of((Expectation) new ManualExpectation(entry)); - default -> Stream.of(); - }) - .toList(); + List expectations = + content.getExpectations().stream() + .flatMap( + (entry) -> + switch (entry.getType()) { + case MANUAL -> Stream.of((Expectation) new ManualExpectation(entry)); + default -> Stream.of(); + }) + .toList(); return new ExecutionProcess(false, expectations); } } diff --git a/openbas-api/src/main/java/io/openbas/injectors/opencti/OpenCTIInjector.java b/openbas-api/src/main/java/io/openbas/injectors/opencti/OpenCTIInjector.java index 2e71c47297..13a9b75a5b 100644 --- a/openbas-api/src/main/java/io/openbas/injectors/opencti/OpenCTIInjector.java +++ b/openbas-api/src/main/java/io/openbas/injectors/opencti/OpenCTIInjector.java @@ -7,24 +7,23 @@ @Component public class OpenCTIInjector { - private static final String OPENCTI_INJECTOR_NAME = "OpenCTI"; - private static final String OPENCTI_INJECTOR_ID = "2cbc77af-67f2-46af-bfd2-755d06a46da0"; + private static final String OPENCTI_INJECTOR_NAME = "OpenCTI"; + private static final String OPENCTI_INJECTOR_ID = "2cbc77af-67f2-46af-bfd2-755d06a46da0"; - @Autowired - public OpenCTIInjector(InjectorService injectorService, OpenCTIContract contract) { - try { - injectorService.register( - OPENCTI_INJECTOR_ID, - OPENCTI_INJECTOR_NAME, - contract, - true, - "incident-response", - null, - null, - false - ); - } catch (Exception e) { - throw new RuntimeException(e); - } + @Autowired + public OpenCTIInjector(InjectorService injectorService, OpenCTIContract contract) { + try { + injectorService.register( + OPENCTI_INJECTOR_ID, + OPENCTI_INJECTOR_NAME, + contract, + true, + "incident-response", + null, + null, + false); + } catch (Exception e) { + throw new RuntimeException(e); } + } } diff --git a/openbas-api/src/main/java/io/openbas/injectors/opencti/config/OpenCTIConfig.java b/openbas-api/src/main/java/io/openbas/injectors/opencti/config/OpenCTIConfig.java index ca7a73b78e..0c5a1cc5ae 100644 --- a/openbas-api/src/main/java/io/openbas/injectors/opencti/config/OpenCTIConfig.java +++ b/openbas-api/src/main/java/io/openbas/injectors/opencti/config/OpenCTIConfig.java @@ -12,12 +12,9 @@ @Setter public class OpenCTIConfig { - @NotBlank - private Boolean enable; + @NotBlank private Boolean enable; - @NotBlank - private String url; + @NotBlank private String url; - @NotBlank - private String token; + @NotBlank private String token; } diff --git a/openbas-api/src/main/java/io/openbas/injectors/opencti/model/CaseContent.java b/openbas-api/src/main/java/io/openbas/injectors/opencti/model/CaseContent.java index b64cc377e6..463d579894 100644 --- a/openbas-api/src/main/java/io/openbas/injectors/opencti/model/CaseContent.java +++ b/openbas-api/src/main/java/io/openbas/injectors/opencti/model/CaseContent.java @@ -2,12 +2,11 @@ import com.fasterxml.jackson.annotation.JsonProperty; import io.openbas.model.inject.form.Expectation; -import lombok.Getter; -import lombok.Setter; - import java.util.ArrayList; import java.util.List; import java.util.Objects; +import lombok.Getter; +import lombok.Setter; @Getter @Setter @@ -35,8 +34,7 @@ public boolean equals(Object o) { return false; } CaseContent that = (CaseContent) o; - return Objects.equals(name, that.name) - && Objects.equals(description, that.description); + return Objects.equals(name, that.name) && Objects.equals(description, that.description); } @Override diff --git a/openbas-api/src/main/java/io/openbas/injectors/opencti/service/OpenCTIService.java b/openbas-api/src/main/java/io/openbas/injectors/opencti/service/OpenCTIService.java index 6eaf92d7f5..1967e5eb30 100644 --- a/openbas-api/src/main/java/io/openbas/injectors/opencti/service/OpenCTIService.java +++ b/openbas-api/src/main/java/io/openbas/injectors/opencti/service/OpenCTIService.java @@ -1,8 +1,14 @@ package io.openbas.injectors.opencti.service; +import static io.openbas.database.model.InjectStatusExecution.traceError; +import static io.openbas.database.model.InjectStatusExecution.traceSuccess; + import io.openbas.database.model.DataAttachment; import io.openbas.database.model.Execution; import io.openbas.injectors.opencti.config.OpenCTIConfig; +import java.io.IOException; +import java.time.Instant; +import java.util.List; import org.apache.hc.client5.http.ClientProtocolException; import org.apache.hc.client5.http.classic.methods.HttpPost; import org.apache.hc.client5.http.impl.classic.CloseableHttpClient; @@ -13,77 +19,86 @@ import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Component; -import java.io.IOException; -import java.time.Instant; -import java.util.List; - -import static io.openbas.database.model.InjectStatusExecution.traceError; -import static io.openbas.database.model.InjectStatusExecution.traceSuccess; - @Component public class OpenCTIService { - private OpenCTIConfig config; + private OpenCTIConfig config; - @Autowired - public void setConfig(OpenCTIConfig config) { - this.config = config; - } + @Autowired + public void setConfig(OpenCTIConfig config) { + this.config = config; + } - public void createCase(Execution execution, String name, String description, List attachments) throws Exception { - try (CloseableHttpClient httpClient = HttpClients.createDefault()) { - // Prepare the query - HttpPost httpPost = new HttpPost(config.getUrl() + "/graphql"); - httpPost.addHeader("Authorization", "Bearer " + config.getToken()); - httpPost.addHeader("Content-Type", "application/json; charset=utf-8"); - httpPost.addHeader("Accept", "application/json"); - // TODO support attachement - // if( attachments.size() > 0 ) { - // DataAttachment attachment = attachments.get(0); - // } - String caseBody = String.format("{\"query\": \"mutation { caseIncidentAdd(input: { name: \\\"%s\\\", description: \\\"%s\\\" }) { id } }\"}", name, description); - StringEntity httpBody = new StringEntity(caseBody); - httpPost.setEntity(httpBody); - httpClient.execute(httpPost, classicHttpResponse -> { - if (classicHttpResponse.getCode() == HttpStatus.SC_OK) { - String body = EntityUtils.toString(classicHttpResponse.getEntity()); - execution.addTrace(traceSuccess("Case created (" + body + ")")); - return true; - } else { - execution.addTrace(traceError("Fail to POST")); - return false; - } - }); - } catch (IOException e) { - throw new ClientProtocolException("Unexpected response for request on: " + config.getUrl() + "/graphql"); - } + public void createCase( + Execution execution, String name, String description, List attachments) + throws Exception { + try (CloseableHttpClient httpClient = HttpClients.createDefault()) { + // Prepare the query + HttpPost httpPost = new HttpPost(config.getUrl() + "/graphql"); + httpPost.addHeader("Authorization", "Bearer " + config.getToken()); + httpPost.addHeader("Content-Type", "application/json; charset=utf-8"); + httpPost.addHeader("Accept", "application/json"); + // TODO support attachement + // if( attachments.size() > 0 ) { + // DataAttachment attachment = attachments.get(0); + // } + String caseBody = + String.format( + "{\"query\": \"mutation { caseIncidentAdd(input: { name: \\\"%s\\\", description: \\\"%s\\\" }) { id } }\"}", + name, description); + StringEntity httpBody = new StringEntity(caseBody); + httpPost.setEntity(httpBody); + httpClient.execute( + httpPost, + classicHttpResponse -> { + if (classicHttpResponse.getCode() == HttpStatus.SC_OK) { + String body = EntityUtils.toString(classicHttpResponse.getEntity()); + execution.addTrace(traceSuccess("Case created (" + body + ")")); + return true; + } else { + execution.addTrace(traceError("Fail to POST")); + return false; + } + }); + } catch (IOException e) { + throw new ClientProtocolException( + "Unexpected response for request on: " + config.getUrl() + "/graphql"); } + } - public void createReport(Execution execution, String name, String description, List attachments) throws Exception { - try (CloseableHttpClient httpClient = HttpClients.createDefault()) { - // Prepare the query - HttpPost httpPost = new HttpPost(config.getUrl() + "/graphql"); - httpPost.addHeader("Authorization", "Bearer " + config.getToken()); - httpPost.addHeader("Content-Type", "application/json; charset=utf-8"); - httpPost.addHeader("Accept", "application/json"); - // TODO support attachement - // if( attachments.size() > 0 ) { - // DataAttachment attachment = attachments.get(0); - // } - String caseBody = String.format("{\"query\": \"mutation { reportAdd(input: { name: \\\"%s\\\", description: \\\"%s\\\", published: \\\"%s\\\" }) { id } }\"}", name, description, Instant.now().toString()); - StringEntity httpBody = new StringEntity(caseBody); - httpPost.setEntity(httpBody); - httpClient.execute(httpPost, classicHttpResponse -> { - if (classicHttpResponse.getCode() == HttpStatus.SC_OK) { - String body = EntityUtils.toString(classicHttpResponse.getEntity()); - execution.addTrace(traceSuccess("Report created (" + body + ")")); - return true; - } else { - execution.addTrace(traceError("Fail to POST")); - return false; - } - }); - } catch (IOException e) { - throw new ClientProtocolException("Unexpected response for request on: " + config.getUrl() + "/graphql"); - } + public void createReport( + Execution execution, String name, String description, List attachments) + throws Exception { + try (CloseableHttpClient httpClient = HttpClients.createDefault()) { + // Prepare the query + HttpPost httpPost = new HttpPost(config.getUrl() + "/graphql"); + httpPost.addHeader("Authorization", "Bearer " + config.getToken()); + httpPost.addHeader("Content-Type", "application/json; charset=utf-8"); + httpPost.addHeader("Accept", "application/json"); + // TODO support attachement + // if( attachments.size() > 0 ) { + // DataAttachment attachment = attachments.get(0); + // } + String caseBody = + String.format( + "{\"query\": \"mutation { reportAdd(input: { name: \\\"%s\\\", description: \\\"%s\\\", published: \\\"%s\\\" }) { id } }\"}", + name, description, Instant.now().toString()); + StringEntity httpBody = new StringEntity(caseBody); + httpPost.setEntity(httpBody); + httpClient.execute( + httpPost, + classicHttpResponse -> { + if (classicHttpResponse.getCode() == HttpStatus.SC_OK) { + String body = EntityUtils.toString(classicHttpResponse.getEntity()); + execution.addTrace(traceSuccess("Report created (" + body + ")")); + return true; + } else { + execution.addTrace(traceError("Fail to POST")); + return false; + } + }); + } catch (IOException e) { + throw new ClientProtocolException( + "Unexpected response for request on: " + config.getUrl() + "/graphql"); } + } } diff --git a/openbas-api/src/main/java/io/openbas/injectors/ovh/OvhSmsContract.java b/openbas-api/src/main/java/io/openbas/injectors/ovh/OvhSmsContract.java index e82ccfa6f1..3fd4d575cb 100644 --- a/openbas-api/src/main/java/io/openbas/injectors/ovh/OvhSmsContract.java +++ b/openbas-api/src/main/java/io/openbas/injectors/ovh/OvhSmsContract.java @@ -1,76 +1,82 @@ package io.openbas.injectors.ovh; +import static io.openbas.helper.SupportedLanguage.en; +import static io.openbas.helper.SupportedLanguage.fr; +import static io.openbas.injector_contract.Contract.executableContract; +import static io.openbas.injector_contract.ContractCardinality.Multiple; +import static io.openbas.injector_contract.ContractDef.contractBuilder; +import static io.openbas.injector_contract.fields.ContractExpectations.expectationsField; +import static io.openbas.injector_contract.fields.ContractTeam.teamField; +import static io.openbas.injector_contract.fields.ContractTextArea.textareaField; + +import io.openbas.database.model.Endpoint; import io.openbas.injector_contract.Contract; import io.openbas.injector_contract.ContractConfig; import io.openbas.injector_contract.Contractor; import io.openbas.injector_contract.ContractorIcon; import io.openbas.injector_contract.fields.ContractElement; import io.openbas.injector_contract.fields.ContractExpectations; -import io.openbas.database.model.Endpoint; import io.openbas.injectors.ovh.config.OvhSmsConfig; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.stereotype.Component; - import java.io.InputStream; import java.util.List; import java.util.Map; import java.util.Optional; - -import static io.openbas.injector_contract.Contract.executableContract; -import static io.openbas.injector_contract.ContractCardinality.Multiple; -import static io.openbas.injector_contract.ContractDef.contractBuilder; -import static io.openbas.injector_contract.fields.ContractExpectations.expectationsField; -import static io.openbas.injector_contract.fields.ContractTeam.teamField; -import static io.openbas.injector_contract.fields.ContractTextArea.textareaField; -import static io.openbas.helper.SupportedLanguage.en; -import static io.openbas.helper.SupportedLanguage.fr; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Component; @Component public class OvhSmsContract extends Contractor { - public static final String TYPE = "openbas_ovh_sms"; + public static final String TYPE = "openbas_ovh_sms"; + + public static final String OVH_DEFAULT = "e9e902bc-b03d-4223-89e1-fca093ac79dd"; - public static final String OVH_DEFAULT = "e9e902bc-b03d-4223-89e1-fca093ac79dd"; + private OvhSmsConfig config; - private OvhSmsConfig config; + @Autowired + public void setConfig(OvhSmsConfig config) { + this.config = config; + } - @Autowired - public void setConfig(OvhSmsConfig config) { - this.config = config; - } + @Override + public boolean isExpose() { + return Optional.ofNullable(config.getEnable()).orElse(false); + } - @Override - public boolean isExpose() { - return Optional.ofNullable(config.getEnable()).orElse(false); - } + @Override + public String getType() { + return TYPE; + } - @Override - public String getType() { - return TYPE; - } + @Override + public ContractConfig getConfig() { + return new ContractConfig( + TYPE, Map.of(en, "SMS (OVH)"), "#9c27b0", "#9c27b0", "/img/sms.png", isExpose()); + } - @Override - public ContractConfig getConfig() { - return new ContractConfig(TYPE, Map.of(en, "SMS (OVH)"), "#9c27b0", "#9c27b0", "/img/sms.png", isExpose()); - } + @Override + public List contracts() { + ContractConfig contractConfig = getConfig(); + ContractExpectations expectationsField = expectationsField("expectations", "Expectations"); + List instance = + contractBuilder() + .mandatory(teamField("teams", "Teams", Multiple)) + .mandatory(textareaField("message", "Message")) + .optional(expectationsField) + .build(); + return List.of( + executableContract( + contractConfig, + OVH_DEFAULT, + Map.of(en, "Send a SMS", fr, "Envoyer un SMS"), + instance, + List.of(Endpoint.PLATFORM_TYPE.Service), + false)); + } - @Override - public List contracts() { - ContractConfig contractConfig = getConfig(); - ContractExpectations expectationsField = expectationsField( - "expectations", "Expectations" - ); - List instance = contractBuilder() - .mandatory(teamField("teams", "Teams", Multiple)) - .mandatory(textareaField("message", "Message")) - .optional(expectationsField) - .build(); - return List.of(executableContract(contractConfig, OVH_DEFAULT, - Map.of(en, "Send a SMS", fr, "Envoyer un SMS"), instance, List.of(Endpoint.PLATFORM_TYPE.Service), false)); - } - @Override - public ContractorIcon getIcon() { - InputStream iconStream = getClass().getResourceAsStream("/img/icon-ovh-sms.png"); - return new ContractorIcon(iconStream); - } + @Override + public ContractorIcon getIcon() { + InputStream iconStream = getClass().getResourceAsStream("/img/icon-ovh-sms.png"); + return new ContractorIcon(iconStream); + } } diff --git a/openbas-api/src/main/java/io/openbas/injectors/ovh/OvhSmsExecutor.java b/openbas-api/src/main/java/io/openbas/injectors/ovh/OvhSmsExecutor.java index f22e9af12a..84307ad64e 100644 --- a/openbas-api/src/main/java/io/openbas/injectors/ovh/OvhSmsExecutor.java +++ b/openbas-api/src/main/java/io/openbas/injectors/ovh/OvhSmsExecutor.java @@ -1,5 +1,8 @@ package io.openbas.injectors.ovh; +import static io.openbas.database.model.InjectStatusExecution.traceError; +import static io.openbas.database.model.InjectStatusExecution.traceSuccess; + import io.openbas.database.model.Execution; import io.openbas.database.model.Inject; import io.openbas.execution.ExecutableInject; @@ -12,17 +15,13 @@ import io.openbas.model.Expectation; import io.openbas.model.expectation.ManualExpectation; import jakarta.validation.constraints.NotNull; -import lombok.RequiredArgsConstructor; -import org.springframework.stereotype.Component; -import org.springframework.util.StringUtils; - import java.util.Collections; import java.util.List; import java.util.concurrent.atomic.AtomicBoolean; import java.util.stream.Stream; - -import static io.openbas.database.model.InjectStatusExecution.traceError; -import static io.openbas.database.model.InjectStatusExecution.traceSuccess; +import lombok.RequiredArgsConstructor; +import org.springframework.stereotype.Component; +import org.springframework.util.StringUtils; @Component(OvhSmsContract.TYPE) @RequiredArgsConstructor @@ -31,7 +30,8 @@ public class OvhSmsExecutor extends Injector { private final OvhSmsService smsService; @Override - public ExecutionProcess process(@NotNull final Execution execution, @NotNull final ExecutableInject injection) + public ExecutionProcess process( + @NotNull final Execution execution, @NotNull final ExecutableInject injection) throws Exception { Inject inject = injection.getInjection().getInject(); OvhSmsContent content = contentConvert(injection, OvhSmsContent.class); @@ -41,35 +41,41 @@ public ExecutionProcess process(@NotNull final Execution execution, @NotNull fin throw new UnsupportedOperationException("Sms needs at least one user"); } - //We check that at least one user receive the sms before to create expectations + // We check that at least one user receive the sms before to create expectations AtomicBoolean isSmsSent = new AtomicBoolean(false); - users.stream().parallel().forEach(context -> { - ProtectUser user = context.getUser(); - String phone = user.getPhone(); - String email = user.getEmail(); - if (!StringUtils.hasLength(phone)) { - String message = "Sms fail for " + email + ": no phone number"; - execution.addTrace(traceError(message)); - } else { - try { - String callResult = smsService.sendSms(context, phone, smsMessage); - isSmsSent.set(true); - String message = "Sms sent to " + email + " through " + phone + " (" + callResult + ")"; - execution.addTrace(traceSuccess(message)); - } catch (Exception e) { - execution.addTrace(traceError(e.getMessage())); - } - } - }); + users.stream() + .parallel() + .forEach( + context -> { + ProtectUser user = context.getUser(); + String phone = user.getPhone(); + String email = user.getEmail(); + if (!StringUtils.hasLength(phone)) { + String message = "Sms fail for " + email + ": no phone number"; + execution.addTrace(traceError(message)); + } else { + try { + String callResult = smsService.sendSms(context, phone, smsMessage); + isSmsSent.set(true); + String message = + "Sms sent to " + email + " through " + phone + " (" + callResult + ")"; + execution.addTrace(traceSuccess(message)); + } catch (Exception e) { + execution.addTrace(traceError(e.getMessage())); + } + } + }); if (isSmsSent.get()) { - List expectations = content.getExpectations() - .stream() - .flatMap(entry -> switch (entry.getType()) { - case MANUAL -> Stream.of((Expectation) new ManualExpectation(entry)); - default -> Stream.of(); - }) - .toList(); + List expectations = + content.getExpectations().stream() + .flatMap( + entry -> + switch (entry.getType()) { + case MANUAL -> Stream.of((Expectation) new ManualExpectation(entry)); + default -> Stream.of(); + }) + .toList(); return new ExecutionProcess(false, expectations); } return new ExecutionProcess(false, Collections.emptyList()); diff --git a/openbas-api/src/main/java/io/openbas/injectors/ovh/OvhSmsInjector.java b/openbas-api/src/main/java/io/openbas/injectors/ovh/OvhSmsInjector.java index a60decf558..f91618a155 100644 --- a/openbas-api/src/main/java/io/openbas/injectors/ovh/OvhSmsInjector.java +++ b/openbas-api/src/main/java/io/openbas/injectors/ovh/OvhSmsInjector.java @@ -7,24 +7,23 @@ @Component public class OvhSmsInjector { - private static final String OVH_SMS_INJECTOR_NAME = "OVHCloud SMS Platform"; - private static final String OVH_SMS_INJECTOR_ID = "e5aefbca-cf8f-4a57-9384-0503a8ffc22f"; + private static final String OVH_SMS_INJECTOR_NAME = "OVHCloud SMS Platform"; + private static final String OVH_SMS_INJECTOR_ID = "e5aefbca-cf8f-4a57-9384-0503a8ffc22f"; - @Autowired - public OvhSmsInjector(InjectorService injectorService, OvhSmsContract contract) { - try { - injectorService.register( - OVH_SMS_INJECTOR_ID, - OVH_SMS_INJECTOR_NAME, - contract, - true, - "communication", - null, - null, - false - ); - } catch (Exception e) { - throw new RuntimeException(e); - } + @Autowired + public OvhSmsInjector(InjectorService injectorService, OvhSmsContract contract) { + try { + injectorService.register( + OVH_SMS_INJECTOR_ID, + OVH_SMS_INJECTOR_NAME, + contract, + true, + "communication", + null, + null, + false); + } catch (Exception e) { + throw new RuntimeException(e); } + } } diff --git a/openbas-api/src/main/java/io/openbas/injectors/ovh/config/OvhSmsConfig.java b/openbas-api/src/main/java/io/openbas/injectors/ovh/config/OvhSmsConfig.java index bc189736f0..8baa80f393 100644 --- a/openbas-api/src/main/java/io/openbas/injectors/ovh/config/OvhSmsConfig.java +++ b/openbas-api/src/main/java/io/openbas/injectors/ovh/config/OvhSmsConfig.java @@ -1,33 +1,26 @@ package io.openbas.injectors.ovh.config; +import jakarta.validation.constraints.NotBlank; import lombok.Getter; import lombok.Setter; import org.springframework.boot.context.properties.ConfigurationProperties; import org.springframework.stereotype.Component; -import jakarta.validation.constraints.NotBlank; - @Component @ConfigurationProperties(prefix = "ovh.sms") @Getter @Setter public class OvhSmsConfig { - @NotBlank - private Boolean enable; + @NotBlank private Boolean enable; - @NotBlank - private String ak; + @NotBlank private String ak; - @NotBlank - private String as; + @NotBlank private String as; - @NotBlank - private String ck; + @NotBlank private String ck; - @NotBlank - private String service; + @NotBlank private String service; - @NotBlank - private String sender; + @NotBlank private String sender; } diff --git a/openbas-api/src/main/java/io/openbas/injectors/ovh/model/OvhSmsContent.java b/openbas-api/src/main/java/io/openbas/injectors/ovh/model/OvhSmsContent.java index 98d50a5445..f50d1a3057 100644 --- a/openbas-api/src/main/java/io/openbas/injectors/ovh/model/OvhSmsContent.java +++ b/openbas-api/src/main/java/io/openbas/injectors/ovh/model/OvhSmsContent.java @@ -3,47 +3,46 @@ import com.fasterxml.jackson.annotation.JsonIgnoreProperties; import com.fasterxml.jackson.annotation.JsonProperty; import io.openbas.model.inject.form.Expectation; -import lombok.Getter; -import lombok.Setter; -import org.springframework.util.StringUtils; - import java.util.ArrayList; import java.util.List; import java.util.Objects; +import lombok.Getter; +import lombok.Setter; +import org.springframework.util.StringUtils; @Setter @Getter @JsonIgnoreProperties(ignoreUnknown = true) public class OvhSmsContent { - @JsonProperty("message") - private String message; + @JsonProperty("message") + private String message; - @JsonProperty("expectations") - private List expectations = new ArrayList<>(); + @JsonProperty("expectations") + private List expectations = new ArrayList<>(); - public String buildMessage(String footer, String header) { - StringBuilder data = new StringBuilder(); - if (StringUtils.hasLength(header)) { - data.append(header).append("\r\n"); - } - data.append(message); - if (StringUtils.hasLength(footer)) { - data.append("\r\n").append(footer); - } - return data.toString(); + public String buildMessage(String footer, String header) { + StringBuilder data = new StringBuilder(); + if (StringUtils.hasLength(header)) { + data.append(header).append("\r\n"); } - - @Override - public boolean equals(Object o) { - if (this == o) return true; - if (o == null || getClass() != o.getClass()) return false; - OvhSmsContent that = (OvhSmsContent) o; - return Objects.equals(message, that.message); - } - - @Override - public int hashCode() { - return Objects.hash(message); + data.append(message); + if (StringUtils.hasLength(footer)) { + data.append("\r\n").append(footer); } + return data.toString(); + } + + @Override + public boolean equals(Object o) { + if (this == o) return true; + if (o == null || getClass() != o.getClass()) return false; + OvhSmsContent that = (OvhSmsContent) o; + return Objects.equals(message, that.message); + } + + @Override + public int hashCode() { + return Objects.hash(message); + } } diff --git a/openbas-api/src/main/java/io/openbas/injectors/ovh/service/OvhSmsMessage.java b/openbas-api/src/main/java/io/openbas/injectors/ovh/service/OvhSmsMessage.java index b8bd4c3f2d..e56c81c886 100644 --- a/openbas-api/src/main/java/io/openbas/injectors/ovh/service/OvhSmsMessage.java +++ b/openbas-api/src/main/java/io/openbas/injectors/ovh/service/OvhSmsMessage.java @@ -1,10 +1,9 @@ package io.openbas.injectors.ovh.service; +import java.util.List; import lombok.Getter; import lombok.Setter; -import java.util.List; - @Getter @Setter public class OvhSmsMessage { diff --git a/openbas-api/src/main/java/io/openbas/injectors/ovh/service/OvhSmsService.java b/openbas-api/src/main/java/io/openbas/injectors/ovh/service/OvhSmsService.java index 9ed260aad4..f188213be9 100644 --- a/openbas-api/src/main/java/io/openbas/injectors/ovh/service/OvhSmsService.java +++ b/openbas-api/src/main/java/io/openbas/injectors/ovh/service/OvhSmsService.java @@ -1,11 +1,11 @@ package io.openbas.injectors.ovh.service; +import static io.openbas.helper.TemplateHelper.buildContextualContent; +import static java.util.Collections.singletonList; + import com.fasterxml.jackson.databind.ObjectMapper; import io.openbas.execution.ExecutionContext; import io.openbas.injectors.ovh.config.OvhSmsConfig; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.stereotype.Component; - import jakarta.annotation.Resource; import java.io.BufferedReader; import java.io.DataOutputStream; @@ -15,20 +15,22 @@ import java.nio.charset.StandardCharsets; import java.security.MessageDigest; import java.util.Date; - -import static io.openbas.helper.TemplateHelper.buildContextualContent; -import static java.util.Collections.singletonList; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Component; @Component public class OvhSmsService { private static final String METHOD = "POST"; - @Resource - private ObjectMapper mapper; + @Resource private ObjectMapper mapper; private OvhSmsConfig config; - @SuppressWarnings({"StringBufferMayBeStringBuilder", "ForLoopReplaceableByForEach", "ConstantConditions"}) + @SuppressWarnings({ + "StringBufferMayBeStringBuilder", + "ForLoopReplaceableByForEach", + "ConstantConditions" + }) private static String convertToHex(byte[] data) { StringBuffer buf = new StringBuffer(); for (int i = 0; i < data.length; i++) { @@ -54,13 +56,25 @@ public void setConfig(OvhSmsConfig config) { public String sendSms(ExecutionContext context, String phone, String message) throws Exception { String smsMessage = buildContextualContent(message, context); URL QUERY = new URL("https://eu.api.ovh.com/1.0/sms/" + config.getService() + "/jobs"); - String isoMessage = new String(smsMessage.getBytes(StandardCharsets.UTF_8), StandardCharsets.ISO_8859_1); - OvhSmsMessage ovhSmsMessage = new OvhSmsMessage(singletonList(phone), isoMessage, config.getSender()); + String isoMessage = + new String(smsMessage.getBytes(StandardCharsets.UTF_8), StandardCharsets.ISO_8859_1); + OvhSmsMessage ovhSmsMessage = + new OvhSmsMessage(singletonList(phone), isoMessage, config.getSender()); String smsBody = mapper.writeValueAsString(ovhSmsMessage); long Timestamp = new Date().getTime() / 1000; String toSign = - config.getAs() + "+" + config.getCk() + "+" + METHOD + "+" + QUERY + "+" + smsBody + "+" + Timestamp; + config.getAs() + + "+" + + config.getCk() + + "+" + + METHOD + + "+" + + QUERY + + "+" + + smsBody + + "+" + + Timestamp; String signature = "$1$" + HashSHA1(toSign); HttpURLConnection req = (HttpURLConnection) QUERY.openConnection(); diff --git a/openbas-api/src/main/java/io/openbas/migration/V1__Init.java b/openbas-api/src/main/java/io/openbas/migration/V1__Init.java index 73ec651c60..bb52f85aba 100644 --- a/openbas-api/src/main/java/io/openbas/migration/V1__Init.java +++ b/openbas-api/src/main/java/io/openbas/migration/V1__Init.java @@ -1,15 +1,13 @@ package io.openbas.migration; -import org.flywaydb.core.api.migration.BaseJavaMigration; -import org.flywaydb.core.api.migration.Context; -import org.springframework.core.io.ClassPathResource; -import org.springframework.stereotype.Component; - import java.io.InputStream; import java.nio.charset.StandardCharsets; import java.sql.Connection; import java.sql.Statement; - +import org.flywaydb.core.api.migration.BaseJavaMigration; +import org.flywaydb.core.api.migration.Context; +import org.springframework.core.io.ClassPathResource; +import org.springframework.stereotype.Component; @Component public class V1__Init extends BaseJavaMigration { diff --git a/openbas-api/src/main/java/io/openbas/migration/V2_10__Improve_audience.java b/openbas-api/src/main/java/io/openbas/migration/V2_10__Improve_audience.java index 36a2b5fd2d..d9be90a306 100644 --- a/openbas-api/src/main/java/io/openbas/migration/V2_10__Improve_audience.java +++ b/openbas-api/src/main/java/io/openbas/migration/V2_10__Improve_audience.java @@ -1,20 +1,20 @@ package io.openbas.migration; +import java.sql.Statement; import org.flywaydb.core.api.migration.BaseJavaMigration; import org.flywaydb.core.api.migration.Context; import org.springframework.stereotype.Component; -import java.sql.Statement; - @Component public class V2_10__Improve_audience extends BaseJavaMigration { - @Override - public void migrate(Context context) throws Exception { - Statement select = context.getConnection().createStatement(); - select.execute("ALTER TABLE audiences ADD audience_description text;"); - // Add association table between audience and tag - select.execute(""" + @Override + public void migrate(Context context) throws Exception { + Statement select = context.getConnection().createStatement(); + select.execute("ALTER TABLE audiences ADD audience_description text;"); + // Add association table between audience and tag + select.execute( + """ CREATE TABLE audiences_tags ( audience_id varchar(255) not null constraint audience_id_fk references audiences, tag_id varchar(255) not null constraint tag_id_fk references tags, @@ -23,5 +23,5 @@ constraint audiences_tags_pkey primary key (audience_id, tag_id) CREATE INDEX idx_audiences_tags_audience on audiences_tags (audience_id); CREATE INDEX idx_audiences_tags_tag on audiences_tags (tag_id); """); - } + } } diff --git a/openbas-api/src/main/java/io/openbas/migration/V2_11__Improve_inject.java b/openbas-api/src/main/java/io/openbas/migration/V2_11__Improve_inject.java index d562e277fa..fd14e96601 100644 --- a/openbas-api/src/main/java/io/openbas/migration/V2_11__Improve_inject.java +++ b/openbas-api/src/main/java/io/openbas/migration/V2_11__Improve_inject.java @@ -1,19 +1,19 @@ package io.openbas.migration; +import java.sql.Statement; import org.flywaydb.core.api.migration.BaseJavaMigration; import org.flywaydb.core.api.migration.Context; import org.springframework.stereotype.Component; -import java.sql.Statement; - @Component public class V2_11__Improve_inject extends BaseJavaMigration { - @Override - public void migrate(Context context) throws Exception { - Statement select = context.getConnection().createStatement(); - // Add association table between inject and tag - select.execute(""" + @Override + public void migrate(Context context) throws Exception { + Statement select = context.getConnection().createStatement(); + // Add association table between inject and tag + select.execute( + """ CREATE TABLE injects_tags ( inject_id varchar(255) not null constraint inject_id_fk references injects, tag_id varchar(255) not null constraint tag_id_fk references tags, @@ -22,5 +22,5 @@ constraint injects_tags_pkey primary key (inject_id, tag_id) CREATE INDEX idx_injects_tags_inject on injects_tags (inject_id); CREATE INDEX idx_injects_tags_tag on injects_tags (tag_id); """); - } + } } diff --git a/openbas-api/src/main/java/io/openbas/migration/V2_12__Improve_audience.java b/openbas-api/src/main/java/io/openbas/migration/V2_12__Improve_audience.java index ccad257831..1c8e6d0fec 100644 --- a/openbas-api/src/main/java/io/openbas/migration/V2_12__Improve_audience.java +++ b/openbas-api/src/main/java/io/openbas/migration/V2_12__Improve_audience.java @@ -1,19 +1,20 @@ package io.openbas.migration; +import java.sql.Statement; import org.flywaydb.core.api.migration.BaseJavaMigration; import org.flywaydb.core.api.migration.Context; import org.springframework.stereotype.Component; -import java.sql.Statement; - @Component public class V2_12__Improve_audience extends BaseJavaMigration { - @Override - public void migrate(Context context) throws Exception { - Statement select = context.getConnection().createStatement(); - // created_at / updated_at - select.execute("ALTER TABLE audiences ADD audience_created_at timestamp not null default now();"); - select.execute("ALTER TABLE audiences ADD audience_updated_at timestamp not null default now();"); - } + @Override + public void migrate(Context context) throws Exception { + Statement select = context.getConnection().createStatement(); + // created_at / updated_at + select.execute( + "ALTER TABLE audiences ADD audience_created_at timestamp not null default now();"); + select.execute( + "ALTER TABLE audiences ADD audience_updated_at timestamp not null default now();"); + } } diff --git a/openbas-api/src/main/java/io/openbas/migration/V2_13__Nullable_inject_description.java b/openbas-api/src/main/java/io/openbas/migration/V2_13__Nullable_inject_description.java index 45482cbb08..b9d8ade680 100644 --- a/openbas-api/src/main/java/io/openbas/migration/V2_13__Nullable_inject_description.java +++ b/openbas-api/src/main/java/io/openbas/migration/V2_13__Nullable_inject_description.java @@ -1,17 +1,16 @@ package io.openbas.migration; +import java.sql.Statement; import org.flywaydb.core.api.migration.BaseJavaMigration; import org.flywaydb.core.api.migration.Context; import org.springframework.stereotype.Component; -import java.sql.Statement; - @Component public class V2_13__Nullable_inject_description extends BaseJavaMigration { - @Override - public void migrate(Context context) throws Exception { - Statement select = context.getConnection().createStatement(); - select.execute("ALTER TABLE injects ALTER COLUMN inject_description DROP NOT NULL;"); - } + @Override + public void migrate(Context context) throws Exception { + Statement select = context.getConnection().createStatement(); + select.execute("ALTER TABLE injects ALTER COLUMN inject_description DROP NOT NULL;"); + } } diff --git a/openbas-api/src/main/java/io/openbas/migration/V2_14__Cleanup_cascade_organization.java b/openbas-api/src/main/java/io/openbas/migration/V2_14__Cleanup_cascade_organization.java index 28fe74d208..da201520fa 100644 --- a/openbas-api/src/main/java/io/openbas/migration/V2_14__Cleanup_cascade_organization.java +++ b/openbas-api/src/main/java/io/openbas/migration/V2_14__Cleanup_cascade_organization.java @@ -1,25 +1,25 @@ package io.openbas.migration; +import java.sql.Statement; import org.flywaydb.core.api.migration.BaseJavaMigration; import org.flywaydb.core.api.migration.Context; import org.springframework.stereotype.Component; -import java.sql.Statement; - @Component public class V2_14__Cleanup_cascade_organization extends BaseJavaMigration { - @Override - public void migrate(Context context) throws Exception { - Statement select = context.getConnection().createStatement(); - // Adapt user column - select.execute("ALTER TABLE users DROP CONSTRAINT fk_1483a5e941221f7e;"); - select.execute("ALTER TABLE users " + - "ADD CONSTRAINT fk_users_organizations " + - "FOREIGN KEY (user_organization) REFERENCES organizations(organization_id) " + - "ON DELETE SET NULL;"); - // Cleanup exercises - select.execute("ALTER TABLE exercises DROP column exercise_animation_group;"); - select.execute("ALTER TABLE exercises DROP column exercise_owner;"); - } + @Override + public void migrate(Context context) throws Exception { + Statement select = context.getConnection().createStatement(); + // Adapt user column + select.execute("ALTER TABLE users DROP CONSTRAINT fk_1483a5e941221f7e;"); + select.execute( + "ALTER TABLE users " + + "ADD CONSTRAINT fk_users_organizations " + + "FOREIGN KEY (user_organization) REFERENCES organizations(organization_id) " + + "ON DELETE SET NULL;"); + // Cleanup exercises + select.execute("ALTER TABLE exercises DROP column exercise_animation_group;"); + select.execute("ALTER TABLE exercises DROP column exercise_owner;"); + } } diff --git a/openbas-api/src/main/java/io/openbas/migration/V2_15__Nullable_exercise_subtitle.java b/openbas-api/src/main/java/io/openbas/migration/V2_15__Nullable_exercise_subtitle.java index b1dc44aa4b..a136d8c08e 100644 --- a/openbas-api/src/main/java/io/openbas/migration/V2_15__Nullable_exercise_subtitle.java +++ b/openbas-api/src/main/java/io/openbas/migration/V2_15__Nullable_exercise_subtitle.java @@ -1,17 +1,16 @@ package io.openbas.migration; +import java.sql.Statement; import org.flywaydb.core.api.migration.BaseJavaMigration; import org.flywaydb.core.api.migration.Context; import org.springframework.stereotype.Component; -import java.sql.Statement; - @Component public class V2_15__Nullable_exercise_subtitle extends BaseJavaMigration { - @Override - public void migrate(Context context) throws Exception { - Statement select = context.getConnection().createStatement(); - select.execute("ALTER TABLE exercises ALTER COLUMN exercise_subtitle DROP NOT NULL;"); - } + @Override + public void migrate(Context context) throws Exception { + Statement select = context.getConnection().createStatement(); + select.execute("ALTER TABLE exercises ALTER COLUMN exercise_subtitle DROP NOT NULL;"); + } } diff --git a/openbas-api/src/main/java/io/openbas/migration/V2_16__Cleanup_exercise.java b/openbas-api/src/main/java/io/openbas/migration/V2_16__Cleanup_exercise.java index c3644574ed..e0bf47db57 100644 --- a/openbas-api/src/main/java/io/openbas/migration/V2_16__Cleanup_exercise.java +++ b/openbas-api/src/main/java/io/openbas/migration/V2_16__Cleanup_exercise.java @@ -1,18 +1,17 @@ package io.openbas.migration; +import java.sql.Statement; import org.flywaydb.core.api.migration.BaseJavaMigration; import org.flywaydb.core.api.migration.Context; import org.springframework.stereotype.Component; -import java.sql.Statement; - @Component public class V2_16__Cleanup_exercise extends BaseJavaMigration { - @Override - public void migrate(Context context) throws Exception { - Statement select = context.getConnection().createStatement(); - // Exercise - select.execute("ALTER TABLE exercises DROP column exercise_canceled;"); - } + @Override + public void migrate(Context context) throws Exception { + Statement select = context.getConnection().createStatement(); + // Exercise + select.execute("ALTER TABLE exercises DROP column exercise_canceled;"); + } } diff --git a/openbas-api/src/main/java/io/openbas/migration/V2_17__Default_group.java b/openbas-api/src/main/java/io/openbas/migration/V2_17__Default_group.java index 66e675e216..1c5e42af3d 100644 --- a/openbas-api/src/main/java/io/openbas/migration/V2_17__Default_group.java +++ b/openbas-api/src/main/java/io/openbas/migration/V2_17__Default_group.java @@ -1,20 +1,20 @@ package io.openbas.migration; +import java.sql.Statement; import org.flywaydb.core.api.migration.BaseJavaMigration; import org.flywaydb.core.api.migration.Context; import org.springframework.stereotype.Component; -import java.sql.Statement; - @Component public class V2_17__Default_group extends BaseJavaMigration { - @Override - public void migrate(Context context) throws Exception { - Statement select = context.getConnection().createStatement(); - // Exercise - select.execute("ALTER TABLE groups ADD group_default_user_assign bool default false;"); - select.execute(""" + @Override + public void migrate(Context context) throws Exception { + Statement select = context.getConnection().createStatement(); + // Exercise + select.execute("ALTER TABLE groups ADD group_default_user_assign bool default false;"); + select.execute( + """ create table groups_exercises_default_grants ( group_id varchar(255) not null @@ -23,5 +23,5 @@ group_id varchar(255) not null exercises_default_grants varchar(255) ); """); - } + } } diff --git a/openbas-api/src/main/java/io/openbas/migration/V2_18__Exercise_workflow.java b/openbas-api/src/main/java/io/openbas/migration/V2_18__Exercise_workflow.java index ddd87e5080..b9695f060b 100644 --- a/openbas-api/src/main/java/io/openbas/migration/V2_18__Exercise_workflow.java +++ b/openbas-api/src/main/java/io/openbas/migration/V2_18__Exercise_workflow.java @@ -1,22 +1,23 @@ package io.openbas.migration; +import java.sql.Statement; import org.flywaydb.core.api.migration.BaseJavaMigration; import org.flywaydb.core.api.migration.Context; import org.springframework.stereotype.Component; -import java.sql.Statement; - @Component public class V2_18__Exercise_workflow extends BaseJavaMigration { - @Override - public void migrate(Context context) throws Exception { - Statement select = context.getConnection().createStatement(); - // Exercise - select.execute("ALTER TABLE exercises ADD exercise_status varchar(255) not null default 'SCHEDULED';"); - select.execute("ALTER TABLE exercises ADD exercise_pause_date timestamp;"); - // Add pauses - select.execute(""" + @Override + public void migrate(Context context) throws Exception { + Statement select = context.getConnection().createStatement(); + // Exercise + select.execute( + "ALTER TABLE exercises ADD exercise_status varchar(255) not null default 'SCHEDULED';"); + select.execute("ALTER TABLE exercises ADD exercise_pause_date timestamp;"); + // Add pauses + select.execute( + """ create table pauses ( pause_id varchar(255) not null constraint pauses_pkey primary key, @@ -27,5 +28,5 @@ pause_date timestamp(0) with time zone not null, ); create index idx_pauses on pauses (pause_id); """); - } + } } diff --git a/openbas-api/src/main/java/io/openbas/migration/V2_19__Audience_tags_cascade.java b/openbas-api/src/main/java/io/openbas/migration/V2_19__Audience_tags_cascade.java index d525d82b7f..829611c9f4 100644 --- a/openbas-api/src/main/java/io/openbas/migration/V2_19__Audience_tags_cascade.java +++ b/openbas-api/src/main/java/io/openbas/migration/V2_19__Audience_tags_cascade.java @@ -1,27 +1,28 @@ package io.openbas.migration; +import java.sql.Statement; import org.flywaydb.core.api.migration.BaseJavaMigration; import org.flywaydb.core.api.migration.Context; import org.springframework.stereotype.Component; -import java.sql.Statement; - @Component public class V2_19__Audience_tags_cascade extends BaseJavaMigration { - @Override - public void migrate(Context context) throws Exception { - Statement select = context.getConnection().createStatement(); - // Fix audiences constraints - select.execute("ALTER TABLE audiences_tags DROP CONSTRAINT audience_id_fk;"); - select.execute("ALTER TABLE audiences_tags DROP CONSTRAINT tag_id_fk;"); - select.execute("ALTER TABLE audiences_tags " + - "ADD CONSTRAINT audience_id_fk " + - "FOREIGN KEY (audience_id) REFERENCES audiences(audience_id) " + - "ON DELETE CASCADE ;"); - select.execute("ALTER TABLE audiences_tags " + - "ADD CONSTRAINT tag_id_fk " + - "FOREIGN KEY (tag_id) REFERENCES tags(tag_id) " + - "ON DELETE CASCADE ;"); - } + @Override + public void migrate(Context context) throws Exception { + Statement select = context.getConnection().createStatement(); + // Fix audiences constraints + select.execute("ALTER TABLE audiences_tags DROP CONSTRAINT audience_id_fk;"); + select.execute("ALTER TABLE audiences_tags DROP CONSTRAINT tag_id_fk;"); + select.execute( + "ALTER TABLE audiences_tags " + + "ADD CONSTRAINT audience_id_fk " + + "FOREIGN KEY (audience_id) REFERENCES audiences(audience_id) " + + "ON DELETE CASCADE ;"); + select.execute( + "ALTER TABLE audiences_tags " + + "ADD CONSTRAINT tag_id_fk " + + "FOREIGN KEY (tag_id) REFERENCES tags(tag_id) " + + "ON DELETE CASCADE ;"); + } } diff --git a/openbas-api/src/main/java/io/openbas/migration/V2_1__Relative_inject.java b/openbas-api/src/main/java/io/openbas/migration/V2_1__Relative_inject.java index 014539f9c3..df84d82743 100644 --- a/openbas-api/src/main/java/io/openbas/migration/V2_1__Relative_inject.java +++ b/openbas-api/src/main/java/io/openbas/migration/V2_1__Relative_inject.java @@ -1,24 +1,25 @@ package io.openbas.migration; +import java.sql.Statement; import org.flywaydb.core.api.migration.BaseJavaMigration; import org.flywaydb.core.api.migration.Context; import org.springframework.stereotype.Component; -import java.sql.Statement; - @Component public class V2_1__Relative_inject extends BaseJavaMigration { - @Override - public void migrate(Context context) throws Exception { - Statement select = context.getConnection().createStatement(); - // Create the structure - select.execute("ALTER TABLE injects add inject_depends_duration bigint;"); - select.execute("ALTER TABLE injects add inject_depends_from_another varchar(255);"); - select.execute("ALTER TABLE injects add constraint fk_depends_from_another " + - "foreign key (inject_depends_from_another) references injects on delete cascade;"); - // Migration the data - select.executeUpdate(""" + @Override + public void migrate(Context context) throws Exception { + Statement select = context.getConnection().createStatement(); + // Create the structure + select.execute("ALTER TABLE injects add inject_depends_duration bigint;"); + select.execute("ALTER TABLE injects add inject_depends_from_another varchar(255);"); + select.execute( + "ALTER TABLE injects add constraint fk_depends_from_another " + + "foreign key (inject_depends_from_another) references injects on delete cascade;"); + // Migration the data + select.executeUpdate( + """ UPDATE injects SET inject_depends_duration=subquery.difference FROM (SELECT inject_id, inject_date, ex.exercise_start_date, @@ -30,5 +31,5 @@ public void migrate(Context context) throws Exception { ORDER BY inject_date) AS subquery WHERE injects.inject_id = subquery.inject_id; """); - } + } } diff --git a/openbas-api/src/main/java/io/openbas/migration/V2_20__Improve_user.java b/openbas-api/src/main/java/io/openbas/migration/V2_20__Improve_user.java index cf7e5bcd80..351965de18 100644 --- a/openbas-api/src/main/java/io/openbas/migration/V2_20__Improve_user.java +++ b/openbas-api/src/main/java/io/openbas/migration/V2_20__Improve_user.java @@ -1,18 +1,17 @@ package io.openbas.migration; +import java.sql.Statement; import org.flywaydb.core.api.migration.BaseJavaMigration; import org.flywaydb.core.api.migration.Context; import org.springframework.stereotype.Component; -import java.sql.Statement; - @Component public class V2_20__Improve_user extends BaseJavaMigration { - @Override - public void migrate(Context context) throws Exception { - Statement select = context.getConnection().createStatement(); - // User - select.execute("ALTER TABLE users ADD user_theme varchar(255);"); - } + @Override + public void migrate(Context context) throws Exception { + Statement select = context.getConnection().createStatement(); + // User + select.execute("ALTER TABLE users ADD user_theme varchar(255);"); + } } diff --git a/openbas-api/src/main/java/io/openbas/migration/V2_21__Comcheck_refactor.java b/openbas-api/src/main/java/io/openbas/migration/V2_21__Comcheck_refactor.java index cabac08050..9a8b7c7dfe 100644 --- a/openbas-api/src/main/java/io/openbas/migration/V2_21__Comcheck_refactor.java +++ b/openbas-api/src/main/java/io/openbas/migration/V2_21__Comcheck_refactor.java @@ -1,31 +1,32 @@ package io.openbas.migration; +import java.sql.Statement; import org.flywaydb.core.api.migration.BaseJavaMigration; import org.flywaydb.core.api.migration.Context; import org.springframework.stereotype.Component; -import java.sql.Statement; - @Component public class V2_21__Comcheck_refactor extends BaseJavaMigration { - @Override - public void migrate(Context context) throws Exception { - Statement select = context.getConnection().createStatement(); - // Comchecks - select.execute("ALTER TABLE comchecks DROP comcheck_audience;"); - select.execute("ALTER TABLE comchecks ADD comcheck_state varchar(256);"); - select.execute("ALTER TABLE comchecks ADD comcheck_subject varchar(256);"); - select.execute("ALTER TABLE comchecks ADD comcheck_message text;"); - select.execute("ALTER TABLE comchecks ADD comcheck_signature text;"); - // Comchecks statuses - select.execute("ALTER TABLE comchecks_statuses DROP status_state;"); - select.execute("ALTER TABLE comchecks_statuses DROP status_last_update;"); - select.execute("ALTER TABLE comchecks_statuses ADD status_sent_date timestamp;"); - select.execute("ALTER TABLE comchecks_statuses ADD status_receive_date timestamp;"); - select.execute("ALTER TABLE comchecks_statuses ADD status_sent_retry int;"); - // Inject and dry reporting - select.execute("ALTER TABLE injects_statuses RENAME COLUMN status_message TO status_reporting;"); - select.execute("ALTER TABLE dryinjects_statuses RENAME COLUMN status_message TO status_reporting;"); - } + @Override + public void migrate(Context context) throws Exception { + Statement select = context.getConnection().createStatement(); + // Comchecks + select.execute("ALTER TABLE comchecks DROP comcheck_audience;"); + select.execute("ALTER TABLE comchecks ADD comcheck_state varchar(256);"); + select.execute("ALTER TABLE comchecks ADD comcheck_subject varchar(256);"); + select.execute("ALTER TABLE comchecks ADD comcheck_message text;"); + select.execute("ALTER TABLE comchecks ADD comcheck_signature text;"); + // Comchecks statuses + select.execute("ALTER TABLE comchecks_statuses DROP status_state;"); + select.execute("ALTER TABLE comchecks_statuses DROP status_last_update;"); + select.execute("ALTER TABLE comchecks_statuses ADD status_sent_date timestamp;"); + select.execute("ALTER TABLE comchecks_statuses ADD status_receive_date timestamp;"); + select.execute("ALTER TABLE comchecks_statuses ADD status_sent_retry int;"); + // Inject and dry reporting + select.execute( + "ALTER TABLE injects_statuses RENAME COLUMN status_message TO status_reporting;"); + select.execute( + "ALTER TABLE dryinjects_statuses RENAME COLUMN status_message TO status_reporting;"); + } } diff --git a/openbas-api/src/main/java/io/openbas/migration/V2_22__Comcheck_template.java b/openbas-api/src/main/java/io/openbas/migration/V2_22__Comcheck_template.java index af08bddd84..34405a6c2b 100644 --- a/openbas-api/src/main/java/io/openbas/migration/V2_22__Comcheck_template.java +++ b/openbas-api/src/main/java/io/openbas/migration/V2_22__Comcheck_template.java @@ -1,18 +1,17 @@ package io.openbas.migration; +import java.sql.Statement; import org.flywaydb.core.api.migration.BaseJavaMigration; import org.flywaydb.core.api.migration.Context; import org.springframework.stereotype.Component; -import java.sql.Statement; - @Component public class V2_22__Comcheck_template extends BaseJavaMigration { - @Override - public void migrate(Context context) throws Exception { - Statement select = context.getConnection().createStatement(); - // Comchecks - select.execute("ALTER TABLE comchecks DROP comcheck_signature;"); - } + @Override + public void migrate(Context context) throws Exception { + Statement select = context.getConnection().createStatement(); + // Comchecks + select.execute("ALTER TABLE comchecks DROP comcheck_signature;"); + } } diff --git a/openbas-api/src/main/java/io/openbas/migration/V2_23__Tags_cascade.java b/openbas-api/src/main/java/io/openbas/migration/V2_23__Tags_cascade.java index b387ba88f5..8e0a0f4af9 100644 --- a/openbas-api/src/main/java/io/openbas/migration/V2_23__Tags_cascade.java +++ b/openbas-api/src/main/java/io/openbas/migration/V2_23__Tags_cascade.java @@ -1,52 +1,59 @@ package io.openbas.migration; +import java.sql.Statement; import org.flywaydb.core.api.migration.BaseJavaMigration; import org.flywaydb.core.api.migration.Context; import org.springframework.stereotype.Component; -import java.sql.Statement; - @Component public class V2_23__Tags_cascade extends BaseJavaMigration { - @Override - public void migrate(Context context) throws Exception { - Statement select = context.getConnection().createStatement(); - // Injects - select.execute("ALTER TABLE injects_tags DROP CONSTRAINT tag_id_fk;"); - select.execute("ALTER TABLE injects_tags DROP CONSTRAINT inject_id_fk;"); - select.execute("ALTER TABLE injects_tags " + - "ADD CONSTRAINT tag_id_fk FOREIGN KEY (tag_id) REFERENCES tags(tag_id) " + - "ON DELETE CASCADE;"); - select.execute("ALTER TABLE injects_tags " + - "ADD CONSTRAINT inject_id_fk FOREIGN KEY (inject_id) REFERENCES injects(inject_id) " + - "ON DELETE CASCADE;"); - // Exercises - select.execute("ALTER TABLE exercises_tags DROP CONSTRAINT tag_id_fk;"); - select.execute("ALTER TABLE exercises_tags DROP CONSTRAINT exercise_id_fk;"); - select.execute("ALTER TABLE exercises_tags " + - "ADD CONSTRAINT tag_id_fk FOREIGN KEY (tag_id) REFERENCES tags(tag_id) " + - "ON DELETE CASCADE;"); - select.execute("ALTER TABLE exercises_tags " + - "ADD CONSTRAINT exercise_id_fk FOREIGN KEY (exercise_id) REFERENCES exercises(exercise_id) " + - "ON DELETE CASCADE;"); - // Organizations - select.execute("ALTER TABLE organizations_tags DROP CONSTRAINT tag_id_fk;"); - select.execute("ALTER TABLE organizations_tags DROP CONSTRAINT organization_id_fk;"); - select.execute("ALTER TABLE organizations_tags " + - "ADD CONSTRAINT tag_id_fk FOREIGN KEY (tag_id) REFERENCES tags(tag_id) " + - "ON DELETE CASCADE;"); - select.execute("ALTER TABLE organizations_tags " + - "ADD CONSTRAINT organization_id_fk FOREIGN KEY (organization_id) REFERENCES organizations(organization_id) " + - "ON DELETE CASCADE;"); - // Users - select.execute("ALTER TABLE users_tags DROP CONSTRAINT tag_id_fk;"); - select.execute("ALTER TABLE users_tags DROP CONSTRAINT user_id_fk;"); - select.execute("ALTER TABLE users_tags " + - "ADD CONSTRAINT tag_id_fk FOREIGN KEY (tag_id) REFERENCES tags(tag_id) " + - "ON DELETE CASCADE;"); - select.execute("ALTER TABLE users_tags " + - "ADD CONSTRAINT user_id_fk FOREIGN KEY (user_id) REFERENCES users(user_id) " + - "ON DELETE CASCADE;"); - } + @Override + public void migrate(Context context) throws Exception { + Statement select = context.getConnection().createStatement(); + // Injects + select.execute("ALTER TABLE injects_tags DROP CONSTRAINT tag_id_fk;"); + select.execute("ALTER TABLE injects_tags DROP CONSTRAINT inject_id_fk;"); + select.execute( + "ALTER TABLE injects_tags " + + "ADD CONSTRAINT tag_id_fk FOREIGN KEY (tag_id) REFERENCES tags(tag_id) " + + "ON DELETE CASCADE;"); + select.execute( + "ALTER TABLE injects_tags " + + "ADD CONSTRAINT inject_id_fk FOREIGN KEY (inject_id) REFERENCES injects(inject_id) " + + "ON DELETE CASCADE;"); + // Exercises + select.execute("ALTER TABLE exercises_tags DROP CONSTRAINT tag_id_fk;"); + select.execute("ALTER TABLE exercises_tags DROP CONSTRAINT exercise_id_fk;"); + select.execute( + "ALTER TABLE exercises_tags " + + "ADD CONSTRAINT tag_id_fk FOREIGN KEY (tag_id) REFERENCES tags(tag_id) " + + "ON DELETE CASCADE;"); + select.execute( + "ALTER TABLE exercises_tags " + + "ADD CONSTRAINT exercise_id_fk FOREIGN KEY (exercise_id) REFERENCES exercises(exercise_id) " + + "ON DELETE CASCADE;"); + // Organizations + select.execute("ALTER TABLE organizations_tags DROP CONSTRAINT tag_id_fk;"); + select.execute("ALTER TABLE organizations_tags DROP CONSTRAINT organization_id_fk;"); + select.execute( + "ALTER TABLE organizations_tags " + + "ADD CONSTRAINT tag_id_fk FOREIGN KEY (tag_id) REFERENCES tags(tag_id) " + + "ON DELETE CASCADE;"); + select.execute( + "ALTER TABLE organizations_tags " + + "ADD CONSTRAINT organization_id_fk FOREIGN KEY (organization_id) REFERENCES organizations(organization_id) " + + "ON DELETE CASCADE;"); + // Users + select.execute("ALTER TABLE users_tags DROP CONSTRAINT tag_id_fk;"); + select.execute("ALTER TABLE users_tags DROP CONSTRAINT user_id_fk;"); + select.execute( + "ALTER TABLE users_tags " + + "ADD CONSTRAINT tag_id_fk FOREIGN KEY (tag_id) REFERENCES tags(tag_id) " + + "ON DELETE CASCADE;"); + select.execute( + "ALTER TABLE users_tags " + + "ADD CONSTRAINT user_id_fk FOREIGN KEY (user_id) REFERENCES users(user_id) " + + "ON DELETE CASCADE;"); + } } diff --git a/openbas-api/src/main/java/io/openbas/migration/V2_24__Improve_dryrun.java b/openbas-api/src/main/java/io/openbas/migration/V2_24__Improve_dryrun.java index d04dcb0b36..a82ec6deca 100644 --- a/openbas-api/src/main/java/io/openbas/migration/V2_24__Improve_dryrun.java +++ b/openbas-api/src/main/java/io/openbas/migration/V2_24__Improve_dryrun.java @@ -1,20 +1,20 @@ package io.openbas.migration; +import java.sql.Statement; import org.flywaydb.core.api.migration.BaseJavaMigration; import org.flywaydb.core.api.migration.Context; import org.springframework.stereotype.Component; -import java.sql.Statement; - @Component public class V2_24__Improve_dryrun extends BaseJavaMigration { - @Override - public void migrate(Context context) throws Exception { - Statement select = context.getConnection().createStatement(); - select.execute("ALTER TABLE dryruns DROP column dryrun_status;"); - // Add association table between organization and tag - select.execute(""" + @Override + public void migrate(Context context) throws Exception { + Statement select = context.getConnection().createStatement(); + select.execute("ALTER TABLE dryruns DROP column dryrun_status;"); + // Add association table between organization and tag + select.execute( + """ CREATE TABLE dryruns_users ( dryrun_id varchar(255) not null constraint dryrun_id_fk references dryruns on delete cascade, @@ -25,5 +25,5 @@ constraint dryruns_users_pkey primary key (user_id, dryrun_id) CREATE INDEX idx_dryruns_users_user on dryruns_users (user_id); CREATE INDEX idx_dryruns_users_dryrun on dryruns_users (dryrun_id); """); - } + } } diff --git a/openbas-api/src/main/java/io/openbas/migration/V2_25__Feedback_start.java b/openbas-api/src/main/java/io/openbas/migration/V2_25__Feedback_start.java index 630a7ffa5c..baf51ea407 100644 --- a/openbas-api/src/main/java/io/openbas/migration/V2_25__Feedback_start.java +++ b/openbas-api/src/main/java/io/openbas/migration/V2_25__Feedback_start.java @@ -1,21 +1,21 @@ package io.openbas.migration; +import java.sql.Statement; import org.flywaydb.core.api.migration.BaseJavaMigration; import org.flywaydb.core.api.migration.Context; import org.springframework.stereotype.Component; -import java.sql.Statement; - @Component public class V2_25__Feedback_start extends BaseJavaMigration { - @Override - public void migrate(Context context) throws Exception { - Statement select = context.getConnection().createStatement(); - // Drop unused table outcomes - select.execute("DROP TABLE IF EXISTS outcomes;"); - // Create evaluation table - select.execute(""" + @Override + public void migrate(Context context) throws Exception { + Statement select = context.getConnection().createStatement(); + // Drop unused table outcomes + select.execute("DROP TABLE IF EXISTS outcomes;"); + // Create evaluation table + select.execute( + """ create table evaluations ( evaluation_id varchar(255) not null constraint evaluations_pkey primary key, @@ -29,8 +29,9 @@ evaluation_updated_at timestamp not null default now() ); create index idx_evaluations on evaluations (evaluation_id); """); - // Create poll table - select.execute(""" + // Create poll table + select.execute( + """ create table polls ( poll_id varchar(255) not null constraint polls_pkey primary key, @@ -42,8 +43,9 @@ poll_updated_at timestamp not null default now() ); create index idx_polls on polls (poll_id); """); - //noinspection SqlResolve - select.execute(""" + //noinspection SqlResolve + select.execute( + """ create table answers ( answer_id varchar(255) not null constraint answers_pkey primary key, @@ -56,12 +58,13 @@ answer_updated_at timestamp not null default now() ); create index idx_answers on answers (answer_id); """); - // Replace log_date by log_created_at / log_updated_at for consistency - select.execute("ALTER TABLE logs ADD log_created_at timestamp not null default now();"); - select.execute("ALTER TABLE logs ADD log_updated_at timestamp not null default now();"); - select.execute("ALTER TABLE logs DROP column log_date;"); - // Implement "tags" on logs (log_tags table) - select.execute(""" + // Replace log_date by log_created_at / log_updated_at for consistency + select.execute("ALTER TABLE logs ADD log_created_at timestamp not null default now();"); + select.execute("ALTER TABLE logs ADD log_updated_at timestamp not null default now();"); + select.execute("ALTER TABLE logs DROP column log_date;"); + // Implement "tags" on logs (log_tags table) + select.execute( + """ CREATE TABLE logs_tags ( log_id varchar(255) not null constraint log_id_fk references logs on delete cascade, tag_id varchar(255) not null constraint tag_id_fk references tags on delete cascade, @@ -70,5 +73,5 @@ constraint logs_tags_pkey primary key (log_id, tag_id) CREATE INDEX idx_logs_tags_log on logs_tags (log_id); CREATE INDEX idx_logs_tags_tag on logs_tags (tag_id); """); - } + } } diff --git a/openbas-api/src/main/java/io/openbas/migration/V2_26__Improve_objective.java b/openbas-api/src/main/java/io/openbas/migration/V2_26__Improve_objective.java index f6f5a12c91..2c36f7533d 100644 --- a/openbas-api/src/main/java/io/openbas/migration/V2_26__Improve_objective.java +++ b/openbas-api/src/main/java/io/openbas/migration/V2_26__Improve_objective.java @@ -1,19 +1,20 @@ package io.openbas.migration; +import java.sql.Statement; import org.flywaydb.core.api.migration.BaseJavaMigration; import org.flywaydb.core.api.migration.Context; import org.springframework.stereotype.Component; -import java.sql.Statement; - @Component public class V2_26__Improve_objective extends BaseJavaMigration { - @Override - public void migrate(Context context) throws Exception { - Statement select = context.getConnection().createStatement(); - // created_at / updated_at - select.execute("ALTER TABLE objectives ADD objective_created_at timestamp not null default now();"); - select.execute("ALTER TABLE objectives ADD objective_updated_at timestamp not null default now();"); - } + @Override + public void migrate(Context context) throws Exception { + Statement select = context.getConnection().createStatement(); + // created_at / updated_at + select.execute( + "ALTER TABLE objectives ADD objective_created_at timestamp not null default now();"); + select.execute( + "ALTER TABLE objectives ADD objective_updated_at timestamp not null default now();"); + } } diff --git a/openbas-api/src/main/java/io/openbas/migration/V2_27__Document_refactor.java b/openbas-api/src/main/java/io/openbas/migration/V2_27__Document_refactor.java index ade963eac5..03b1c71b70 100644 --- a/openbas-api/src/main/java/io/openbas/migration/V2_27__Document_refactor.java +++ b/openbas-api/src/main/java/io/openbas/migration/V2_27__Document_refactor.java @@ -1,21 +1,21 @@ package io.openbas.migration; +import java.sql.Statement; import org.flywaydb.core.api.migration.BaseJavaMigration; import org.flywaydb.core.api.migration.Context; import org.springframework.stereotype.Component; -import java.sql.Statement; - @Component public class V2_27__Document_refactor extends BaseJavaMigration { - @Override - public void migrate(Context context) throws Exception { - Statement select = context.getConnection().createStatement(); - // Document can be private or public - select.execute("ALTER TABLE documents ADD document_public bool default true;"); - // Create inject_documents - select.execute(""" + @Override + public void migrate(Context context) throws Exception { + Statement select = context.getConnection().createStatement(); + // Document can be private or public + select.execute("ALTER TABLE documents ADD document_public bool default true;"); + // Create inject_documents + select.execute( + """ CREATE TABLE injects_documents ( inject_id varchar(255) not null constraint inject_id_fk references injects on delete cascade, document_id varchar(255) not null constraint document_id_fk references documents on delete cascade, @@ -25,5 +25,5 @@ constraint injects_documents_pkey primary key (inject_id, document_id) CREATE INDEX idx_injects_documents_inject on injects_documents (inject_id); CREATE INDEX idx_injects_documents_document on injects_documents (document_id); """); - } + } } diff --git a/openbas-api/src/main/java/io/openbas/migration/V2_28__Dryinject_link.java b/openbas-api/src/main/java/io/openbas/migration/V2_28__Dryinject_link.java index d719ce59ea..ae41e6fdcc 100644 --- a/openbas-api/src/main/java/io/openbas/migration/V2_28__Dryinject_link.java +++ b/openbas-api/src/main/java/io/openbas/migration/V2_28__Dryinject_link.java @@ -1,29 +1,29 @@ package io.openbas.migration; +import java.sql.Statement; import org.flywaydb.core.api.migration.BaseJavaMigration; import org.flywaydb.core.api.migration.Context; import org.springframework.stereotype.Component; -import java.sql.Statement; - @Component public class V2_28__Dryinject_link extends BaseJavaMigration { - @Override - public void migrate(Context context) throws Exception { - Statement select = context.getConnection().createStatement(); - // Cleanups - select.execute("DELETE FROM dryinjects_statuses;"); - select.execute("DELETE FROM dryinjects;"); - // Remove duplicated content - select.execute("ALTER TABLE dryinjects DROP column dryinject_title;"); - select.execute("ALTER TABLE dryinjects DROP column dryinject_content;"); - select.execute("ALTER TABLE dryinjects DROP column dryinject_type;"); - // Link dryinject to original inject - select.execute("ALTER TABLE dryinjects ADD dryinject_inject varchar(256);"); - select.execute("ALTER TABLE dryinjects " + - "ADD CONSTRAINT fk_dryinjects_injects " + - "FOREIGN KEY (dryinject_inject) REFERENCES injects(inject_id) " + - "ON DELETE SET NULL;"); - } + @Override + public void migrate(Context context) throws Exception { + Statement select = context.getConnection().createStatement(); + // Cleanups + select.execute("DELETE FROM dryinjects_statuses;"); + select.execute("DELETE FROM dryinjects;"); + // Remove duplicated content + select.execute("ALTER TABLE dryinjects DROP column dryinject_title;"); + select.execute("ALTER TABLE dryinjects DROP column dryinject_content;"); + select.execute("ALTER TABLE dryinjects DROP column dryinject_type;"); + // Link dryinject to original inject + select.execute("ALTER TABLE dryinjects ADD dryinject_inject varchar(256);"); + select.execute( + "ALTER TABLE dryinjects " + + "ADD CONSTRAINT fk_dryinjects_injects " + + "FOREIGN KEY (dryinject_inject) REFERENCES injects(inject_id) " + + "ON DELETE SET NULL;"); + } } diff --git a/openbas-api/src/main/java/io/openbas/migration/V2_29__Documents_exercise.java b/openbas-api/src/main/java/io/openbas/migration/V2_29__Documents_exercise.java index 029ff67529..2217f0285d 100644 --- a/openbas-api/src/main/java/io/openbas/migration/V2_29__Documents_exercise.java +++ b/openbas-api/src/main/java/io/openbas/migration/V2_29__Documents_exercise.java @@ -1,23 +1,23 @@ package io.openbas.migration; +import java.sql.Statement; import org.flywaydb.core.api.migration.BaseJavaMigration; import org.flywaydb.core.api.migration.Context; import org.springframework.stereotype.Component; -import java.sql.Statement; - @Component public class V2_29__Documents_exercise extends BaseJavaMigration { - @Override - public void migrate(Context context) throws Exception { - Statement select = context.getConnection().createStatement(); - // Document can be private or public - //noinspection SqlResolve - select.execute("ALTER TABLE documents DROP COLUMN document_public;"); - select.execute("ALTER TABLE documents DROP COLUMN document_path;"); - // Create inject_documents - select.execute(""" + @Override + public void migrate(Context context) throws Exception { + Statement select = context.getConnection().createStatement(); + // Document can be private or public + //noinspection SqlResolve + select.execute("ALTER TABLE documents DROP COLUMN document_public;"); + select.execute("ALTER TABLE documents DROP COLUMN document_path;"); + // Create inject_documents + select.execute( + """ CREATE TABLE exercises_documents ( exercise_id varchar(255) not null constraint exercise_id_fk references exercises on delete cascade, document_id varchar(255) not null constraint document_id_fk references documents on delete cascade, @@ -26,5 +26,5 @@ constraint exercises_documents_pkey primary key (exercise_id, document_id) CREATE INDEX idx_exercises_documents_inject on exercises_documents (exercise_id); CREATE INDEX idx_exercises_documents_document on exercises_documents (document_id); """); - } + } } diff --git a/openbas-api/src/main/java/io/openbas/migration/V2_2__Simplify_model.java b/openbas-api/src/main/java/io/openbas/migration/V2_2__Simplify_model.java index a5448ef960..fd9df25b25 100644 --- a/openbas-api/src/main/java/io/openbas/migration/V2_2__Simplify_model.java +++ b/openbas-api/src/main/java/io/openbas/migration/V2_2__Simplify_model.java @@ -1,33 +1,35 @@ package io.openbas.migration; +import java.sql.Statement; import org.flywaydb.core.api.migration.BaseJavaMigration; import org.flywaydb.core.api.migration.Context; import org.springframework.stereotype.Component; -import java.sql.Statement; - @Component public class V2_2__Simplify_model extends BaseJavaMigration { - @Override - public void migrate(Context context) throws Exception { - Statement select = context.getConnection().createStatement(); - select.execute("DROP TABLE IF EXISTS doctrine_migration_versions;"); - // 01. Outcome - clean the table, redirect to inject - //noinspection SqlWithoutWhere - select.execute("DELETE FROM outcomes;"); - select.execute("ALTER TABLE outcomes DROP COLUMN outcome_incident;"); - select.execute("ALTER TABLE outcomes ADD outcome_inject varchar(255);"); - select.execute("ALTER TABLE outcomes ADD constraint fk_outcome_inject " + - "foreign key (outcome_inject) references injects on delete cascade;"); + @Override + public void migrate(Context context) throws Exception { + Statement select = context.getConnection().createStatement(); + select.execute("DROP TABLE IF EXISTS doctrine_migration_versions;"); + // 01. Outcome - clean the table, redirect to inject + //noinspection SqlWithoutWhere + select.execute("DELETE FROM outcomes;"); + select.execute("ALTER TABLE outcomes DROP COLUMN outcome_incident;"); + select.execute("ALTER TABLE outcomes ADD outcome_inject varchar(255);"); + select.execute( + "ALTER TABLE outcomes ADD constraint fk_outcome_inject " + + "foreign key (outcome_inject) references injects on delete cascade;"); - // 02. Injects, redirect from incident to exercise - // 02.01 - Create the new reference - select.execute("ALTER TABLE injects ADD inject_exercise varchar(255);"); - select.execute("ALTER TABLE injects ADD constraint fk_inject_exercise " + - "foreign key (inject_exercise) references exercises on delete cascade;"); - // 02.02 - Migrate the injects. - select.executeUpdate(""" + // 02. Injects, redirect from incident to exercise + // 02.01 - Create the new reference + select.execute("ALTER TABLE injects ADD inject_exercise varchar(255);"); + select.execute( + "ALTER TABLE injects ADD constraint fk_inject_exercise " + + "foreign key (inject_exercise) references exercises on delete cascade;"); + // 02.02 - Migrate the injects. + select.executeUpdate( + """ UPDATE injects SET inject_exercise=subquery.event_exercise FROM (SELECT inject.inject_id, e.event_exercise @@ -36,25 +38,27 @@ public void migrate(Context context) throws Exception { RIGHT JOIN events e on inc.incident_event = e.event_id) AS subquery WHERE injects.inject_id = subquery.inject_id; """); - // 02.03 - Clean the table - select.execute("ALTER TABLE injects DROP COLUMN inject_incident;"); + // 02.03 - Clean the table + select.execute("ALTER TABLE injects DROP COLUMN inject_incident;"); - // 03. Drop incidents / events - select.execute("DROP TABLE planificateurs_events;"); - select.execute("DROP TABLE incidents_subobjectives;"); - select.execute("DROP TABLE subobjectives;"); - select.execute("DROP TABLE incidents;"); - select.execute("DROP TABLE incident_types;"); - select.execute("DROP TABLE events;"); + // 03. Drop incidents / events + select.execute("DROP TABLE planificateurs_events;"); + select.execute("DROP TABLE incidents_subobjectives;"); + select.execute("DROP TABLE subobjectives;"); + select.execute("DROP TABLE incidents;"); + select.execute("DROP TABLE incident_types;"); + select.execute("DROP TABLE events;"); - // 04. Drop audiences - // 04.01 - Redirect subaudiances to exercise - select.execute("ALTER TABLE subaudiences ADD audience_exercise varchar(255);"); - //noinspection SqlResolve - select.execute("ALTER TABLE subaudiences ADD constraint fk_audience_exercise " + - "foreign key (audience_exercise) references exercises on delete cascade;"); - //noinspection SqlResolve - select.executeUpdate(""" + // 04. Drop audiences + // 04.01 - Redirect subaudiances to exercise + select.execute("ALTER TABLE subaudiences ADD audience_exercise varchar(255);"); + //noinspection SqlResolve + select.execute( + "ALTER TABLE subaudiences ADD constraint fk_audience_exercise " + + "foreign key (audience_exercise) references exercises on delete cascade;"); + //noinspection SqlResolve + select.executeUpdate( + """ UPDATE subaudiences SET audience_exercise=subquery.audience_exercise FROM (SELECT sub.subaudience_id, au.audience_exercise @@ -63,34 +67,37 @@ public void migrate(Context context) throws Exception { ) AS subquery WHERE subaudiences.subaudience_id = subquery.subaudience_id; """); - select.execute("ALTER TABLE subaudiences DROP COLUMN subaudience_audience;"); - // 04.02 - Redirect comchecks - //noinspection SqlWithoutWhere - select.execute("DELETE FROM comchecks;"); - select.execute("ALTER TABLE comchecks DROP COLUMN comcheck_audience;"); - select.execute("ALTER TABLE comchecks ADD comcheck_audience varchar(255);"); - select.execute("ALTER TABLE comchecks ADD constraint fk_comcheck_audience " + - "foreign key (comcheck_audience) references subaudiences on delete cascade;"); - // 04.03 - Delete tables - select.execute("DROP TABLE planificateurs_audiences;"); - select.execute("DROP TABLE injects_audiences;"); - select.execute("DROP TABLE audiences;"); - // 04.04 - Rename subaudience - select.execute("ALTER TABLE subaudiences RENAME COLUMN subaudience_id TO audience_id;"); - select.execute("ALTER TABLE subaudiences RENAME COLUMN subaudience_name TO audience_name;"); - select.execute("ALTER TABLE subaudiences RENAME COLUMN subaudience_enabled TO audience_enabled;"); - select.execute("ALTER TABLE subaudiences RENAME TO audiences;"); - select.execute("ALTER TABLE injects_subaudiences RENAME COLUMN subaudience_id TO audience_id;"); - select.execute("ALTER TABLE injects_subaudiences RENAME TO injects_audiences;"); - select.execute("ALTER TABLE users_subaudiences RENAME COLUMN subaudience_id TO audience_id;"); - select.execute("ALTER TABLE users_subaudiences RENAME TO users_audiences;"); + select.execute("ALTER TABLE subaudiences DROP COLUMN subaudience_audience;"); + // 04.02 - Redirect comchecks + //noinspection SqlWithoutWhere + select.execute("DELETE FROM comchecks;"); + select.execute("ALTER TABLE comchecks DROP COLUMN comcheck_audience;"); + select.execute("ALTER TABLE comchecks ADD comcheck_audience varchar(255);"); + select.execute( + "ALTER TABLE comchecks ADD constraint fk_comcheck_audience " + + "foreign key (comcheck_audience) references subaudiences on delete cascade;"); + // 04.03 - Delete tables + select.execute("DROP TABLE planificateurs_audiences;"); + select.execute("DROP TABLE injects_audiences;"); + select.execute("DROP TABLE audiences;"); + // 04.04 - Rename subaudience + select.execute("ALTER TABLE subaudiences RENAME COLUMN subaudience_id TO audience_id;"); + select.execute("ALTER TABLE subaudiences RENAME COLUMN subaudience_name TO audience_name;"); + select.execute( + "ALTER TABLE subaudiences RENAME COLUMN subaudience_enabled TO audience_enabled;"); + select.execute("ALTER TABLE subaudiences RENAME TO audiences;"); + select.execute("ALTER TABLE injects_subaudiences RENAME COLUMN subaudience_id TO audience_id;"); + select.execute("ALTER TABLE injects_subaudiences RENAME TO injects_audiences;"); + select.execute("ALTER TABLE users_subaudiences RENAME COLUMN subaudience_id TO audience_id;"); + select.execute("ALTER TABLE users_subaudiences RENAME TO users_audiences;"); - // 04. Drop files - select.execute("ALTER TABLE exercises DROP COLUMN exercise_image;"); - select.execute("ALTER TABLE exercises ADD exercise_image varchar(255);"); - select.execute("ALTER TABLE exercises ADD constraint fk_exercise_image " + - "foreign key (exercise_image) references documents on delete cascade;"); - select.execute("DROP TABLE files;"); - select.execute("DROP TABLE documents_exercises;"); - } + // 04. Drop files + select.execute("ALTER TABLE exercises DROP COLUMN exercise_image;"); + select.execute("ALTER TABLE exercises ADD exercise_image varchar(255);"); + select.execute( + "ALTER TABLE exercises ADD constraint fk_exercise_image " + + "foreign key (exercise_image) references documents on delete cascade;"); + select.execute("DROP TABLE files;"); + select.execute("DROP TABLE documents_exercises;"); + } } diff --git a/openbas-api/src/main/java/io/openbas/migration/V2_30__Document_path.java b/openbas-api/src/main/java/io/openbas/migration/V2_30__Document_path.java index a4c8a53dda..870bdf948f 100644 --- a/openbas-api/src/main/java/io/openbas/migration/V2_30__Document_path.java +++ b/openbas-api/src/main/java/io/openbas/migration/V2_30__Document_path.java @@ -1,18 +1,17 @@ package io.openbas.migration; +import java.sql.Statement; import org.flywaydb.core.api.migration.BaseJavaMigration; import org.flywaydb.core.api.migration.Context; import org.springframework.stereotype.Component; -import java.sql.Statement; - @Component public class V2_30__Document_path extends BaseJavaMigration { - @Override - public void migrate(Context context) throws Exception { - Statement select = context.getConnection().createStatement(); - select.execute("ALTER TABLE documents ADD document_target text;"); - select.executeUpdate("UPDATE documents SET document_target=document_name;"); - } + @Override + public void migrate(Context context) throws Exception { + Statement select = context.getConnection().createStatement(); + select.execute("ALTER TABLE documents ADD document_target text;"); + select.executeUpdate("UPDATE documents SET document_target=document_name;"); + } } diff --git a/openbas-api/src/main/java/io/openbas/migration/V2_31__Controls_name.java b/openbas-api/src/main/java/io/openbas/migration/V2_31__Controls_name.java index 0499d6ba6c..d8933a91fc 100644 --- a/openbas-api/src/main/java/io/openbas/migration/V2_31__Controls_name.java +++ b/openbas-api/src/main/java/io/openbas/migration/V2_31__Controls_name.java @@ -1,20 +1,19 @@ package io.openbas.migration; +import java.sql.Statement; import org.flywaydb.core.api.migration.BaseJavaMigration; import org.flywaydb.core.api.migration.Context; import org.springframework.stereotype.Component; -import java.sql.Statement; - @Component public class V2_31__Controls_name extends BaseJavaMigration { - @Override - public void migrate(Context context) throws Exception { - Statement select = context.getConnection().createStatement(); - // Comchecks - select.execute("ALTER TABLE comchecks ADD comcheck_name varchar(256);"); - // Comchecks - select.execute("ALTER TABLE dryruns ADD dryrun_name varchar(256);"); - } + @Override + public void migrate(Context context) throws Exception { + Statement select = context.getConnection().createStatement(); + // Comchecks + select.execute("ALTER TABLE comchecks ADD comcheck_name varchar(256);"); + // Comchecks + select.execute("ALTER TABLE dryruns ADD dryrun_name varchar(256);"); + } } diff --git a/openbas-api/src/main/java/io/openbas/migration/V2_32__Inject_contract.java b/openbas-api/src/main/java/io/openbas/migration/V2_32__Inject_contract.java index dc295aef2c..450453822e 100644 --- a/openbas-api/src/main/java/io/openbas/migration/V2_32__Inject_contract.java +++ b/openbas-api/src/main/java/io/openbas/migration/V2_32__Inject_contract.java @@ -1,23 +1,26 @@ package io.openbas.migration; +import java.sql.Statement; import org.flywaydb.core.api.migration.BaseJavaMigration; import org.flywaydb.core.api.migration.Context; import org.springframework.stereotype.Component; -import java.sql.Statement; - @Component public class V2_32__Inject_contract extends BaseJavaMigration { - @Override - public void migrate(Context context) throws Exception { - Statement select = context.getConnection().createStatement(); - // Injects - select.execute("ALTER TABLE injects ADD inject_contract varchar(256);"); - // Update injects - select.executeUpdate("UPDATE injects SET inject_contract='138ad8f8-32f8-4a22-8114-aaa12322bd09' WHERE injects.inject_type = 'openex_email';"); - select.executeUpdate("UPDATE injects SET inject_contract='d02e9132-b9d0-4daa-b3b1-4b9871f8472c' WHERE injects.inject_type = 'openex_manual';"); - select.executeUpdate("UPDATE injects SET inject_contract='aeab9ed6-ae98-4b48-b8cc-2e91ac54f2f9' WHERE injects.inject_type = 'openex_mastodon';"); - select.executeUpdate("UPDATE injects SET inject_contract='e9e902bc-b03d-4223-89e1-fca093ac79dd' WHERE injects.inject_type = 'openex_ovh_sms';"); - } + @Override + public void migrate(Context context) throws Exception { + Statement select = context.getConnection().createStatement(); + // Injects + select.execute("ALTER TABLE injects ADD inject_contract varchar(256);"); + // Update injects + select.executeUpdate( + "UPDATE injects SET inject_contract='138ad8f8-32f8-4a22-8114-aaa12322bd09' WHERE injects.inject_type = 'openex_email';"); + select.executeUpdate( + "UPDATE injects SET inject_contract='d02e9132-b9d0-4daa-b3b1-4b9871f8472c' WHERE injects.inject_type = 'openex_manual';"); + select.executeUpdate( + "UPDATE injects SET inject_contract='aeab9ed6-ae98-4b48-b8cc-2e91ac54f2f9' WHERE injects.inject_type = 'openex_mastodon';"); + select.executeUpdate( + "UPDATE injects SET inject_contract='e9e902bc-b03d-4223-89e1-fca093ac79dd' WHERE injects.inject_type = 'openex_ovh_sms';"); + } } diff --git a/openbas-api/src/main/java/io/openbas/migration/V2_33__Inject_not_null.java b/openbas-api/src/main/java/io/openbas/migration/V2_33__Inject_not_null.java index 53ef1b5994..b0c1280cbe 100644 --- a/openbas-api/src/main/java/io/openbas/migration/V2_33__Inject_not_null.java +++ b/openbas-api/src/main/java/io/openbas/migration/V2_33__Inject_not_null.java @@ -1,19 +1,18 @@ package io.openbas.migration; +import java.sql.Statement; import org.flywaydb.core.api.migration.BaseJavaMigration; import org.flywaydb.core.api.migration.Context; import org.springframework.stereotype.Component; -import java.sql.Statement; - @Component public class V2_33__Inject_not_null extends BaseJavaMigration { - @Override - public void migrate(Context context) throws Exception { - Statement select = context.getConnection().createStatement(); - // Injects - select.execute("ALTER TABLE injects ALTER COLUMN inject_contract SET NOT NULL"); - select.execute("ALTER TABLE injects ALTER COLUMN inject_type SET NOT NULL"); - } + @Override + public void migrate(Context context) throws Exception { + Statement select = context.getConnection().createStatement(); + // Injects + select.execute("ALTER TABLE injects ALTER COLUMN inject_contract SET NOT NULL"); + select.execute("ALTER TABLE injects ALTER COLUMN inject_type SET NOT NULL"); + } } diff --git a/openbas-api/src/main/java/io/openbas/migration/V2_34__Inject_communication.java b/openbas-api/src/main/java/io/openbas/migration/V2_34__Inject_communication.java index 6a1aa195a0..4e57e86f86 100644 --- a/openbas-api/src/main/java/io/openbas/migration/V2_34__Inject_communication.java +++ b/openbas-api/src/main/java/io/openbas/migration/V2_34__Inject_communication.java @@ -1,19 +1,19 @@ package io.openbas.migration; +import java.sql.Statement; import org.flywaydb.core.api.migration.BaseJavaMigration; import org.flywaydb.core.api.migration.Context; import org.springframework.stereotype.Component; -import java.sql.Statement; - @Component public class V2_34__Inject_communication extends BaseJavaMigration { - @Override - public void migrate(Context context) throws Exception { - Statement select = context.getConnection().createStatement(); - // Injects - select.execute(""" + @Override + public void migrate(Context context) throws Exception { + Statement select = context.getConnection().createStatement(); + // Injects + select.execute( + """ create table communications ( communication_id varchar(255) not null constraint communications_pkey primary key, @@ -28,8 +28,9 @@ communication_inject varchar(255) create index idx_communication_subject on communications (communication_subject); create index idx_communications on communications (communication_id); """); - // Create communications_users - select.execute(""" + // Create communications_users + select.execute( + """ CREATE TABLE communications_users ( communication_id varchar(255) not null constraint communication_id_fk references communications on delete cascade, user_id varchar(255) not null constraint user_id_fk references users on delete cascade, @@ -38,5 +39,5 @@ constraint communications_users_pkey primary key (communication_id, user_id) CREATE INDEX idx_communications_users_communication on communications_users (communication_id); CREATE INDEX idx_communications_users_user on communications_users (user_id); """); - } + } } diff --git a/openbas-api/src/main/java/io/openbas/migration/V2_35__Inject_communication_ack.java b/openbas-api/src/main/java/io/openbas/migration/V2_35__Inject_communication_ack.java index 1dc63cf0f5..b0b045d393 100644 --- a/openbas-api/src/main/java/io/openbas/migration/V2_35__Inject_communication_ack.java +++ b/openbas-api/src/main/java/io/openbas/migration/V2_35__Inject_communication_ack.java @@ -1,17 +1,16 @@ package io.openbas.migration; +import java.sql.Statement; import org.flywaydb.core.api.migration.BaseJavaMigration; import org.flywaydb.core.api.migration.Context; import org.springframework.stereotype.Component; -import java.sql.Statement; - @Component public class V2_35__Inject_communication_ack extends BaseJavaMigration { - @Override - public void migrate(Context context) throws Exception { - Statement select = context.getConnection().createStatement(); - select.execute("ALTER TABLE communications ADD communication_ack bool default false;"); - } + @Override + public void migrate(Context context) throws Exception { + Statement select = context.getConnection().createStatement(); + select.execute("ALTER TABLE communications ADD communication_ack bool default false;"); + } } diff --git a/openbas-api/src/main/java/io/openbas/migration/V2_36__Inject_communication_animation.java b/openbas-api/src/main/java/io/openbas/migration/V2_36__Inject_communication_animation.java index 79f59b089f..925c2d7e3d 100644 --- a/openbas-api/src/main/java/io/openbas/migration/V2_36__Inject_communication_animation.java +++ b/openbas-api/src/main/java/io/openbas/migration/V2_36__Inject_communication_animation.java @@ -1,17 +1,16 @@ package io.openbas.migration; +import java.sql.Statement; import org.flywaydb.core.api.migration.BaseJavaMigration; import org.flywaydb.core.api.migration.Context; import org.springframework.stereotype.Component; -import java.sql.Statement; - @Component public class V2_36__Inject_communication_animation extends BaseJavaMigration { - @Override - public void migrate(Context context) throws Exception { - Statement select = context.getConnection().createStatement(); - select.execute("ALTER TABLE communications ADD communication_animation bool default false;"); - } + @Override + public void migrate(Context context) throws Exception { + Statement select = context.getConnection().createStatement(); + select.execute("ALTER TABLE communications ADD communication_animation bool default false;"); + } } diff --git a/openbas-api/src/main/java/io/openbas/migration/V2_37__Media_introduction.java b/openbas-api/src/main/java/io/openbas/migration/V2_37__Media_introduction.java index fede1a9149..ade0cb4537 100644 --- a/openbas-api/src/main/java/io/openbas/migration/V2_37__Media_introduction.java +++ b/openbas-api/src/main/java/io/openbas/migration/V2_37__Media_introduction.java @@ -1,20 +1,20 @@ package io.openbas.migration; +import java.sql.*; import org.flywaydb.core.api.migration.BaseJavaMigration; import org.flywaydb.core.api.migration.Context; import org.springframework.stereotype.Component; -import java.sql.*; - @Component public class V2_37__Media_introduction extends BaseJavaMigration { - @Override - public void migrate(Context context) throws Exception { - Connection connection = context.getConnection(); - Statement select = connection.createStatement(); - // Medias - select.execute(""" + @Override + public void migrate(Context context) throws Exception { + Connection connection = context.getConnection(); + Statement select = connection.createStatement(); + // Medias + select.execute( + """ CREATE TABLE medias ( media_id varchar(255) not null constraint medias_pkey primary key, @@ -26,8 +26,9 @@ media_color varchar(255), ); CREATE INDEX idx_medias on medias (media_id); """); - // Create articles - select.execute(""" + // Create articles + select.execute( + """ CREATE TABLE articles ( article_id varchar(255) not null constraint articles_pkey primary key, article_created_at timestamp not null default now(), @@ -45,8 +46,9 @@ article_exercise varchar(255) not null CREATE INDEX idx_articles on articles (article_id); CREATE INDEX idx_article_media_exercise on articles (article_media, article_exercise); """); - // Challenges - select.execute(""" + // Challenges + select.execute( + """ CREATE TABLE challenges ( challenge_id varchar(255) not null constraint challenges_pkey primary key, challenge_created_at timestamp not null default now(), @@ -57,8 +59,9 @@ challenge_updated_at timestamp not null default now(), ); CREATE INDEX idx_challenges on challenges (challenge_id); """); - // Expectations - select.execute(""" + // Expectations + select.execute( + """ CREATE TABLE injects_expectations ( inject_expectation_id varchar(255) not null constraint injects_expectations_pkey primary key, inject_expectation_type varchar(255) not null, @@ -71,8 +74,9 @@ challenge_id varchar(255) ); CREATE INDEX idx_injects_expectations on injects_expectations (inject_expectation_id); """); - // Inject user expectation - select.execute(""" + // Inject user expectation + select.execute( + """ CREATE TABLE injects_expectations_executions ( expectation_execution_id varchar(255) not null constraint expectations_pkey primary key, expectation_execution_created_at timestamp not null default now(), @@ -85,5 +89,5 @@ user_id varchar(255) not null ); CREATE INDEX idx_injects_expectations_executions on injects_expectations_executions (expectation_execution_id); """); - } + } } diff --git a/openbas-api/src/main/java/io/openbas/migration/V2_38__Challenge_flags.java b/openbas-api/src/main/java/io/openbas/migration/V2_38__Challenge_flags.java index de9fc87b79..bb257fb623 100644 --- a/openbas-api/src/main/java/io/openbas/migration/V2_38__Challenge_flags.java +++ b/openbas-api/src/main/java/io/openbas/migration/V2_38__Challenge_flags.java @@ -1,23 +1,23 @@ package io.openbas.migration; +import java.sql.Connection; +import java.sql.Statement; import org.flywaydb.core.api.migration.BaseJavaMigration; import org.flywaydb.core.api.migration.Context; import org.springframework.stereotype.Component; -import java.sql.Connection; -import java.sql.Statement; - @Component public class V2_38__Challenge_flags extends BaseJavaMigration { - @Override - public void migrate(Context context) throws Exception { - Connection connection = context.getConnection(); - Statement select = connection.createStatement(); - // Challenge - remove simple attribute flag - // select.execute("ALTER TABLE challenges DROP COLUMN challenge_flag;"); - // Challenges flags - select.execute(""" + @Override + public void migrate(Context context) throws Exception { + Connection connection = context.getConnection(); + Statement select = connection.createStatement(); + // Challenge - remove simple attribute flag + // select.execute("ALTER TABLE challenges DROP COLUMN challenge_flag;"); + // Challenges flags + select.execute( + """ CREATE TABLE challenges_flags ( flag_id varchar(255) not null constraint challenges_flags_pkey primary key, flag_created_at timestamp not null default now(), @@ -30,5 +30,5 @@ flag_challenge varchar(255) not null CREATE INDEX idx_flag_challenge on challenges_flags (flag_challenge); CREATE INDEX idx_challenges_flags on challenges_flags (flag_id); """); - } + } } diff --git a/openbas-api/src/main/java/io/openbas/migration/V2_39__Expectation_denorm.java b/openbas-api/src/main/java/io/openbas/migration/V2_39__Expectation_denorm.java index 5770101685..2659626de5 100644 --- a/openbas-api/src/main/java/io/openbas/migration/V2_39__Expectation_denorm.java +++ b/openbas-api/src/main/java/io/openbas/migration/V2_39__Expectation_denorm.java @@ -1,29 +1,32 @@ package io.openbas.migration; +import java.sql.Connection; +import java.sql.Statement; import org.flywaydb.core.api.migration.BaseJavaMigration; import org.flywaydb.core.api.migration.Context; import org.springframework.stereotype.Component; -import java.sql.Connection; -import java.sql.Statement; - @Component public class V2_39__Expectation_denorm extends BaseJavaMigration { - @Override - public void migrate(Context context) throws Exception { - Connection connection = context.getConnection(); - Statement select = connection.createStatement(); - // Add relations denormalization - select.execute("ALTER TABLE injects_expectations_executions ADD exercise_id varchar(256) NOT NULL;"); - select.execute("ALTER TABLE injects_expectations_executions " + - "ADD CONSTRAINT fk_expectation_exercise " + - "FOREIGN KEY (exercise_id) REFERENCES exercises(exercise_id) " + - "ON DELETE CASCADE ;"); - select.execute("ALTER TABLE injects_expectations_executions ADD inject_id varchar(256) NOT NULL;"); - select.execute("ALTER TABLE injects_expectations_executions " + - "ADD CONSTRAINT fk_expectation_inject " + - "FOREIGN KEY (inject_id) REFERENCES injects(inject_id) " + - "ON DELETE CASCADE ;"); - } + @Override + public void migrate(Context context) throws Exception { + Connection connection = context.getConnection(); + Statement select = connection.createStatement(); + // Add relations denormalization + select.execute( + "ALTER TABLE injects_expectations_executions ADD exercise_id varchar(256) NOT NULL;"); + select.execute( + "ALTER TABLE injects_expectations_executions " + + "ADD CONSTRAINT fk_expectation_exercise " + + "FOREIGN KEY (exercise_id) REFERENCES exercises(exercise_id) " + + "ON DELETE CASCADE ;"); + select.execute( + "ALTER TABLE injects_expectations_executions ADD inject_id varchar(256) NOT NULL;"); + select.execute( + "ALTER TABLE injects_expectations_executions " + + "ADD CONSTRAINT fk_expectation_inject " + + "FOREIGN KEY (inject_id) REFERENCES injects(inject_id) " + + "ON DELETE CASCADE ;"); + } } diff --git a/openbas-api/src/main/java/io/openbas/migration/V2_3__Nullable_exercise_dates.java b/openbas-api/src/main/java/io/openbas/migration/V2_3__Nullable_exercise_dates.java index 5d1d6321cd..249c4ebd66 100644 --- a/openbas-api/src/main/java/io/openbas/migration/V2_3__Nullable_exercise_dates.java +++ b/openbas-api/src/main/java/io/openbas/migration/V2_3__Nullable_exercise_dates.java @@ -1,19 +1,18 @@ package io.openbas.migration; +import java.sql.Statement; import org.flywaydb.core.api.migration.BaseJavaMigration; import org.flywaydb.core.api.migration.Context; import org.springframework.stereotype.Component; -import java.sql.Statement; - @Component public class V2_3__Nullable_exercise_dates extends BaseJavaMigration { - @Override - public void migrate(Context context) throws Exception { - Statement select = context.getConnection().createStatement(); - select.execute("ALTER TABLE injects DROP column inject_date;"); - select.execute("ALTER TABLE exercises ALTER COLUMN exercise_start_date DROP NOT NULL "); - select.execute("ALTER TABLE exercises ALTER COLUMN exercise_end_date DROP NOT NULL "); - } + @Override + public void migrate(Context context) throws Exception { + Statement select = context.getConnection().createStatement(); + select.execute("ALTER TABLE injects DROP column inject_date;"); + select.execute("ALTER TABLE exercises ALTER COLUMN exercise_start_date DROP NOT NULL "); + select.execute("ALTER TABLE exercises ALTER COLUMN exercise_end_date DROP NOT NULL "); + } } diff --git a/openbas-api/src/main/java/io/openbas/migration/V2_40__Expectation_doc_name.java b/openbas-api/src/main/java/io/openbas/migration/V2_40__Expectation_doc_name.java index 7c082e1c3c..2327e6bef6 100644 --- a/openbas-api/src/main/java/io/openbas/migration/V2_40__Expectation_doc_name.java +++ b/openbas-api/src/main/java/io/openbas/migration/V2_40__Expectation_doc_name.java @@ -1,20 +1,19 @@ package io.openbas.migration; +import java.sql.Connection; +import java.sql.Statement; import org.flywaydb.core.api.migration.BaseJavaMigration; import org.flywaydb.core.api.migration.Context; import org.springframework.stereotype.Component; -import java.sql.Connection; -import java.sql.Statement; - @Component public class V2_40__Expectation_doc_name extends BaseJavaMigration { - @Override - public void migrate(Context context) throws Exception { - Connection connection = context.getConnection(); - Statement select = connection.createStatement(); - // Add document_name in injects_expectations - select.execute("ALTER TABLE injects_expectations ADD inject_expectation_document text;"); - } + @Override + public void migrate(Context context) throws Exception { + Connection connection = context.getConnection(); + Statement select = connection.createStatement(); + // Add document_name in injects_expectations + select.execute("ALTER TABLE injects_expectations ADD inject_expectation_document text;"); + } } diff --git a/openbas-api/src/main/java/io/openbas/migration/V2_41__Cleanup_article.java b/openbas-api/src/main/java/io/openbas/migration/V2_41__Cleanup_article.java index a9dabd9136..2281f3fdc6 100644 --- a/openbas-api/src/main/java/io/openbas/migration/V2_41__Cleanup_article.java +++ b/openbas-api/src/main/java/io/openbas/migration/V2_41__Cleanup_article.java @@ -1,19 +1,18 @@ package io.openbas.migration; +import java.sql.Connection; +import java.sql.Statement; import org.flywaydb.core.api.migration.BaseJavaMigration; import org.flywaydb.core.api.migration.Context; import org.springframework.stereotype.Component; -import java.sql.Connection; -import java.sql.Statement; - @Component public class V2_41__Cleanup_article extends BaseJavaMigration { - @Override - public void migrate(Context context) throws Exception { - Connection connection = context.getConnection(); - Statement select = connection.createStatement(); - select.execute("ALTER TABLE articles DROP column article_published;"); - } + @Override + public void migrate(Context context) throws Exception { + Connection connection = context.getConnection(); + Statement select = connection.createStatement(); + select.execute("ALTER TABLE articles DROP column article_published;"); + } } diff --git a/openbas-api/src/main/java/io/openbas/migration/V2_42__Inject_communication_fields.java b/openbas-api/src/main/java/io/openbas/migration/V2_42__Inject_communication_fields.java index 72b78a961e..63667e6818 100644 --- a/openbas-api/src/main/java/io/openbas/migration/V2_42__Inject_communication_fields.java +++ b/openbas-api/src/main/java/io/openbas/migration/V2_42__Inject_communication_fields.java @@ -1,18 +1,17 @@ package io.openbas.migration; +import java.sql.Statement; import org.flywaydb.core.api.migration.BaseJavaMigration; import org.flywaydb.core.api.migration.Context; import org.springframework.stereotype.Component; -import java.sql.Statement; - @Component public class V2_42__Inject_communication_fields extends BaseJavaMigration { - @Override - public void migrate(Context context) throws Exception { - Statement select = context.getConnection().createStatement(); - select.execute("ALTER TABLE communications ADD communication_content_html text;"); - select.execute("ALTER TABLE communications ADD communication_from text NOT NULL;"); - } + @Override + public void migrate(Context context) throws Exception { + Statement select = context.getConnection().createStatement(); + select.execute("ALTER TABLE communications ADD communication_content_html text;"); + select.execute("ALTER TABLE communications ADD communication_from text NOT NULL;"); + } } diff --git a/openbas-api/src/main/java/io/openbas/migration/V2_43__Expectation_audience.java b/openbas-api/src/main/java/io/openbas/migration/V2_43__Expectation_audience.java index e06569e523..7b31a89380 100644 --- a/openbas-api/src/main/java/io/openbas/migration/V2_43__Expectation_audience.java +++ b/openbas-api/src/main/java/io/openbas/migration/V2_43__Expectation_audience.java @@ -1,24 +1,25 @@ package io.openbas.migration; +import java.sql.Statement; import org.flywaydb.core.api.migration.BaseJavaMigration; import org.flywaydb.core.api.migration.Context; import org.springframework.stereotype.Component; -import java.sql.Statement; - @Component public class V2_43__Expectation_audience extends BaseJavaMigration { - @Override - public void migrate(Context context) throws Exception { - Statement select = context.getConnection().createStatement(); - // Add audience relation - select.execute("ALTER TABLE injects_expectations_executions ADD audience_id varchar(256) NOT NULL;"); - select.execute("ALTER TABLE injects_expectations_executions " + - "ADD CONSTRAINT fk_expectations_audience " + - "FOREIGN KEY (audience_id) REFERENCES audiences(audience_id) " + - "ON DELETE CASCADE ;"); - // Make user relation nullable - select.execute("ALTER TABLE injects_expectations_executions ALTER user_id DROP NOT NULL;"); - } + @Override + public void migrate(Context context) throws Exception { + Statement select = context.getConnection().createStatement(); + // Add audience relation + select.execute( + "ALTER TABLE injects_expectations_executions ADD audience_id varchar(256) NOT NULL;"); + select.execute( + "ALTER TABLE injects_expectations_executions " + + "ADD CONSTRAINT fk_expectations_audience " + + "FOREIGN KEY (audience_id) REFERENCES audiences(audience_id) " + + "ON DELETE CASCADE ;"); + // Make user relation nullable + select.execute("ALTER TABLE injects_expectations_executions ALTER user_id DROP NOT NULL;"); + } } diff --git a/openbas-api/src/main/java/io/openbas/migration/V2_44__Inject_communication_fields.java b/openbas-api/src/main/java/io/openbas/migration/V2_44__Inject_communication_fields.java index 3601a46af4..405367f2ff 100644 --- a/openbas-api/src/main/java/io/openbas/migration/V2_44__Inject_communication_fields.java +++ b/openbas-api/src/main/java/io/openbas/migration/V2_44__Inject_communication_fields.java @@ -1,17 +1,16 @@ package io.openbas.migration; +import java.sql.Statement; import org.flywaydb.core.api.migration.BaseJavaMigration; import org.flywaydb.core.api.migration.Context; import org.springframework.stereotype.Component; -import java.sql.Statement; - @Component public class V2_44__Inject_communication_fields extends BaseJavaMigration { - @Override - public void migrate(Context context) throws Exception { - Statement select = context.getConnection().createStatement(); - select.execute("ALTER TABLE communications ADD communication_to text NOT NULL;"); - } + @Override + public void migrate(Context context) throws Exception { + Statement select = context.getConnection().createStatement(); + select.execute("ALTER TABLE communications ADD communication_to text NOT NULL;"); + } } diff --git a/openbas-api/src/main/java/io/openbas/migration/V2_45__Media_upgrade.java b/openbas-api/src/main/java/io/openbas/migration/V2_45__Media_upgrade.java index a756949896..e2ff868cab 100644 --- a/openbas-api/src/main/java/io/openbas/migration/V2_45__Media_upgrade.java +++ b/openbas-api/src/main/java/io/openbas/migration/V2_45__Media_upgrade.java @@ -1,35 +1,38 @@ package io.openbas.migration; +import java.sql.Statement; import org.flywaydb.core.api.migration.BaseJavaMigration; import org.flywaydb.core.api.migration.Context; import org.springframework.stereotype.Component; -import java.sql.Statement; - @Component public class V2_45__Media_upgrade extends BaseJavaMigration { - @Override - public void migrate(Context context) throws Exception { - Statement select = context.getConnection().createStatement(); - // Remove media and exercises fields - select.execute("ALTER TABLE medias DROP column media_color;"); - select.execute("ALTER TABLE medias DROP column media_published;"); - select.execute("ALTER TABLE exercises DROP column exercise_image;"); - // Add new required fields - select.execute("ALTER TABLE medias ADD media_type varchar(255);"); - select.execute("ALTER TABLE medias ADD media_description text;"); - select.execute("ALTER TABLE medias ADD media_logo_dark varchar(255);"); - select.execute("ALTER TABLE medias ADD media_logo_light varchar(255);"); - select.execute("ALTER TABLE medias ADD media_primary_color_dark varchar(255);"); - select.execute("ALTER TABLE medias ADD media_primary_color_light varchar(255);"); - select.execute("ALTER TABLE medias ADD media_secondary_color_dark varchar(255);"); - select.execute("ALTER TABLE medias ADD media_secondary_color_light varchar(255);"); - select.execute("ALTER TABLE exercises ADD exercise_logo_dark varchar(255);"); - select.execute("ALTER TABLE exercises ADD exercise_logo_light varchar(255);"); - select.execute("ALTER TABLE exercises ADD constraint fk_exercise_logo_dark foreign key (exercise_logo_dark) references documents on delete cascade;"); - select.execute("ALTER TABLE exercises ADD constraint fk_exercise_logo_light foreign key (exercise_logo_light) references documents on delete cascade;"); - select.execute("ALTER TABLE medias ADD constraint fk_media_logo_dark foreign key (media_logo_dark) references documents on delete cascade;"); - select.execute("ALTER TABLE medias ADD constraint fk_media_logo_light foreign key (media_logo_light) references documents on delete cascade;"); - } + @Override + public void migrate(Context context) throws Exception { + Statement select = context.getConnection().createStatement(); + // Remove media and exercises fields + select.execute("ALTER TABLE medias DROP column media_color;"); + select.execute("ALTER TABLE medias DROP column media_published;"); + select.execute("ALTER TABLE exercises DROP column exercise_image;"); + // Add new required fields + select.execute("ALTER TABLE medias ADD media_type varchar(255);"); + select.execute("ALTER TABLE medias ADD media_description text;"); + select.execute("ALTER TABLE medias ADD media_logo_dark varchar(255);"); + select.execute("ALTER TABLE medias ADD media_logo_light varchar(255);"); + select.execute("ALTER TABLE medias ADD media_primary_color_dark varchar(255);"); + select.execute("ALTER TABLE medias ADD media_primary_color_light varchar(255);"); + select.execute("ALTER TABLE medias ADD media_secondary_color_dark varchar(255);"); + select.execute("ALTER TABLE medias ADD media_secondary_color_light varchar(255);"); + select.execute("ALTER TABLE exercises ADD exercise_logo_dark varchar(255);"); + select.execute("ALTER TABLE exercises ADD exercise_logo_light varchar(255);"); + select.execute( + "ALTER TABLE exercises ADD constraint fk_exercise_logo_dark foreign key (exercise_logo_dark) references documents on delete cascade;"); + select.execute( + "ALTER TABLE exercises ADD constraint fk_exercise_logo_light foreign key (exercise_logo_light) references documents on delete cascade;"); + select.execute( + "ALTER TABLE medias ADD constraint fk_media_logo_dark foreign key (media_logo_dark) references documents on delete cascade;"); + select.execute( + "ALTER TABLE medias ADD constraint fk_media_logo_light foreign key (media_logo_light) references documents on delete cascade;"); + } } diff --git a/openbas-api/src/main/java/io/openbas/migration/V2_46__Expectation_upgrade.java b/openbas-api/src/main/java/io/openbas/migration/V2_46__Expectation_upgrade.java index b2375b978a..0186e904f5 100644 --- a/openbas-api/src/main/java/io/openbas/migration/V2_46__Expectation_upgrade.java +++ b/openbas-api/src/main/java/io/openbas/migration/V2_46__Expectation_upgrade.java @@ -1,36 +1,42 @@ package io.openbas.migration; +import java.sql.Statement; import org.flywaydb.core.api.migration.BaseJavaMigration; import org.flywaydb.core.api.migration.Context; import org.springframework.stereotype.Component; -import java.sql.Statement; - @Component public class V2_46__Expectation_upgrade extends BaseJavaMigration { - @Override - public void migrate(Context context) throws Exception { - Statement select = context.getConnection().createStatement(); - // drop unneeded - select.execute("ALTER TABLE injects_expectations_executions DROP inject_expectation_id;"); - // Rename old fields - select.execute("ALTER TABLE injects_expectations_executions RENAME COLUMN expectation_execution_id TO inject_expectation_id;"); - select.execute("ALTER TABLE injects_expectations_executions RENAME COLUMN expectation_execution_created_at TO inject_expectation_created_at;"); - select.execute("ALTER TABLE injects_expectations_executions RENAME COLUMN expectation_execution_updated_at TO inject_expectation_updated_at;"); - select.execute("ALTER TABLE injects_expectations_executions RENAME COLUMN expectation_execution_result TO inject_expectation_result;"); - // Add missing fields - select.execute("ALTER TABLE injects_expectations_executions ADD inject_expectation_type varchar(255) not null;"); - select.execute("ALTER TABLE injects_expectations_executions ADD inject_expectation_score int;"); - select.execute("ALTER TABLE injects_expectations_executions ADD article_id varchar(255);"); - select.execute("ALTER TABLE injects_expectations_executions ADD constraint fk_article foreign key (article_id) references articles on delete cascade;"); - select.execute("ALTER TABLE injects_expectations_executions ADD challenge_id varchar(255);"); - select.execute("ALTER TABLE injects_expectations_executions ADD constraint fk_challenge foreign key (challenge_id) references challenges on delete cascade;"); - // Drop old table - select.execute("DROP TABLE injects_expectations;"); - select.execute("DROP INDEX idx_injects_expectations_executions;"); + @Override + public void migrate(Context context) throws Exception { + Statement select = context.getConnection().createStatement(); + // drop unneeded + select.execute("ALTER TABLE injects_expectations_executions DROP inject_expectation_id;"); + // Rename old fields + select.execute( + "ALTER TABLE injects_expectations_executions RENAME COLUMN expectation_execution_id TO inject_expectation_id;"); + select.execute( + "ALTER TABLE injects_expectations_executions RENAME COLUMN expectation_execution_created_at TO inject_expectation_created_at;"); + select.execute( + "ALTER TABLE injects_expectations_executions RENAME COLUMN expectation_execution_updated_at TO inject_expectation_updated_at;"); + select.execute( + "ALTER TABLE injects_expectations_executions RENAME COLUMN expectation_execution_result TO inject_expectation_result;"); + // Add missing fields + select.execute( + "ALTER TABLE injects_expectations_executions ADD inject_expectation_type varchar(255) not null;"); + select.execute("ALTER TABLE injects_expectations_executions ADD inject_expectation_score int;"); + select.execute("ALTER TABLE injects_expectations_executions ADD article_id varchar(255);"); + select.execute( + "ALTER TABLE injects_expectations_executions ADD constraint fk_article foreign key (article_id) references articles on delete cascade;"); + select.execute("ALTER TABLE injects_expectations_executions ADD challenge_id varchar(255);"); + select.execute( + "ALTER TABLE injects_expectations_executions ADD constraint fk_challenge foreign key (challenge_id) references challenges on delete cascade;"); + // Drop old table + select.execute("DROP TABLE injects_expectations;"); + select.execute("DROP INDEX idx_injects_expectations_executions;"); - // Rename - select.execute("ALTER TABLE injects_expectations_executions RENAME TO injects_expectations;"); - } + // Rename + select.execute("ALTER TABLE injects_expectations_executions RENAME TO injects_expectations;"); + } } diff --git a/openbas-api/src/main/java/io/openbas/migration/V2_47__Media_upgrade.java b/openbas-api/src/main/java/io/openbas/migration/V2_47__Media_upgrade.java index 1e31e93b35..ea23b2f3c3 100644 --- a/openbas-api/src/main/java/io/openbas/migration/V2_47__Media_upgrade.java +++ b/openbas-api/src/main/java/io/openbas/migration/V2_47__Media_upgrade.java @@ -1,18 +1,17 @@ package io.openbas.migration; +import java.sql.Statement; import org.flywaydb.core.api.migration.BaseJavaMigration; import org.flywaydb.core.api.migration.Context; import org.springframework.stereotype.Component; -import java.sql.Statement; - @Component public class V2_47__Media_upgrade extends BaseJavaMigration { - @Override - public void migrate(Context context) throws Exception { - Statement select = context.getConnection().createStatement(); - // Add new required fields - select.execute("ALTER TABLE medias ADD media_mode varchar(255);"); - } + @Override + public void migrate(Context context) throws Exception { + Statement select = context.getConnection().createStatement(); + // Add new required fields + select.execute("ALTER TABLE medias ADD media_mode varchar(255);"); + } } diff --git a/openbas-api/src/main/java/io/openbas/migration/V2_48__Media_upgrade.java b/openbas-api/src/main/java/io/openbas/migration/V2_48__Media_upgrade.java index e969a6b433..f091a8f646 100644 --- a/openbas-api/src/main/java/io/openbas/migration/V2_48__Media_upgrade.java +++ b/openbas-api/src/main/java/io/openbas/migration/V2_48__Media_upgrade.java @@ -1,26 +1,26 @@ package io.openbas.migration; +import java.sql.Statement; import org.flywaydb.core.api.migration.BaseJavaMigration; import org.flywaydb.core.api.migration.Context; import org.springframework.stereotype.Component; -import java.sql.Statement; - @Component public class V2_48__Media_upgrade extends BaseJavaMigration { - @Override - public void migrate(Context context) throws Exception { - Statement select = context.getConnection().createStatement(); - // Article table upgrade - select.execute("ALTER TABLE articles DROP column article_header;"); - select.execute("ALTER TABLE articles DROP column article_footer;"); - select.execute("ALTER TABLE articles ADD article_author text;"); - select.execute("ALTER TABLE articles ADD article_shares int;"); - select.execute("ALTER TABLE articles ADD article_likes int;"); - select.execute("ALTER TABLE articles ADD article_comments int;"); - // Create article_documents - select.execute(""" + @Override + public void migrate(Context context) throws Exception { + Statement select = context.getConnection().createStatement(); + // Article table upgrade + select.execute("ALTER TABLE articles DROP column article_header;"); + select.execute("ALTER TABLE articles DROP column article_footer;"); + select.execute("ALTER TABLE articles ADD article_author text;"); + select.execute("ALTER TABLE articles ADD article_shares int;"); + select.execute("ALTER TABLE articles ADD article_likes int;"); + select.execute("ALTER TABLE articles ADD article_comments int;"); + // Create article_documents + select.execute( + """ CREATE TABLE articles_documents ( article_id varchar(255) not null constraint article_id_fk references articles on delete cascade, document_id varchar(255) not null constraint document_id_fk references documents on delete cascade, @@ -29,5 +29,5 @@ constraint articles_documents_pkey primary key (article_id, document_id) CREATE INDEX idx_articles_documents_article on articles_documents (article_id); CREATE INDEX idx_articles_documents_document on articles_documents (document_id); """); - } + } } diff --git a/openbas-api/src/main/java/io/openbas/migration/V2_49__Change_foreign_key_document.java b/openbas-api/src/main/java/io/openbas/migration/V2_49__Change_foreign_key_document.java index 4bc95a3108..743c37ee1e 100644 --- a/openbas-api/src/main/java/io/openbas/migration/V2_49__Change_foreign_key_document.java +++ b/openbas-api/src/main/java/io/openbas/migration/V2_49__Change_foreign_key_document.java @@ -1,28 +1,31 @@ package io.openbas.migration; +import java.sql.Statement; import org.flywaydb.core.api.migration.BaseJavaMigration; import org.flywaydb.core.api.migration.Context; import org.springframework.stereotype.Component; -import java.sql.Statement; - @Component public class V2_49__Change_foreign_key_document extends BaseJavaMigration { - @Override - public void migrate(Context context) throws Exception { - Statement select = context.getConnection().createStatement(); - // Adapt user column - select.execute("ALTER TABLE exercises DROP CONSTRAINT fk_exercise_logo_dark;"); - select.execute("ALTER TABLE exercises DROP CONSTRAINT fk_exercise_logo_light;"); + @Override + public void migrate(Context context) throws Exception { + Statement select = context.getConnection().createStatement(); + // Adapt user column + select.execute("ALTER TABLE exercises DROP CONSTRAINT fk_exercise_logo_dark;"); + select.execute("ALTER TABLE exercises DROP CONSTRAINT fk_exercise_logo_light;"); - select.execute("ALTER TABLE medias DROP CONSTRAINT fk_media_logo_dark;"); - select.execute("ALTER TABLE medias DROP CONSTRAINT fk_media_logo_light;"); + select.execute("ALTER TABLE medias DROP CONSTRAINT fk_media_logo_dark;"); + select.execute("ALTER TABLE medias DROP CONSTRAINT fk_media_logo_light;"); - select.execute("ALTER TABLE exercises ADD constraint fk_exercise_logo_dark foreign key (exercise_logo_dark) references documents on delete set null;"); - select.execute("ALTER TABLE exercises ADD constraint fk_exercise_logo_light foreign key (exercise_logo_light) references documents on delete set null;"); + select.execute( + "ALTER TABLE exercises ADD constraint fk_exercise_logo_dark foreign key (exercise_logo_dark) references documents on delete set null;"); + select.execute( + "ALTER TABLE exercises ADD constraint fk_exercise_logo_light foreign key (exercise_logo_light) references documents on delete set null;"); - select.execute("ALTER TABLE medias ADD constraint fk_media_logo_dark foreign key (media_logo_dark) references documents on delete set null;"); - select.execute("ALTER TABLE medias ADD constraint fk_media_logo_light foreign key (media_logo_light) references documents on delete set null;"); - } + select.execute( + "ALTER TABLE medias ADD constraint fk_media_logo_dark foreign key (media_logo_dark) references documents on delete set null;"); + select.execute( + "ALTER TABLE medias ADD constraint fk_media_logo_light foreign key (media_logo_light) references documents on delete set null;"); + } } diff --git a/openbas-api/src/main/java/io/openbas/migration/V2_4__Creation_update_cleanup.java b/openbas-api/src/main/java/io/openbas/migration/V2_4__Creation_update_cleanup.java index 9c4252f2e7..24f2212d4e 100644 --- a/openbas-api/src/main/java/io/openbas/migration/V2_4__Creation_update_cleanup.java +++ b/openbas-api/src/main/java/io/openbas/migration/V2_4__Creation_update_cleanup.java @@ -1,25 +1,25 @@ package io.openbas.migration; +import java.sql.Statement; import org.flywaydb.core.api.migration.BaseJavaMigration; import org.flywaydb.core.api.migration.Context; import org.springframework.stereotype.Component; -import java.sql.Statement; - @Component public class V2_4__Creation_update_cleanup extends BaseJavaMigration { - @Override - public void migrate(Context context) throws Exception { - Statement select = context.getConnection().createStatement(); - // Cleanup - select.execute("ALTER TABLE users DROP column user_planificateur;"); - select.execute("ALTER TABLE users DROP column user_phone3;"); - select.execute("ALTER TABLE users DROP column user_email2;"); - // Add color to tag - select.execute("ALTER TABLE tags ADD tag_color varchar(255) default '#01478DFF';"); - // Add association table between exercise and tag - select.execute(""" + @Override + public void migrate(Context context) throws Exception { + Statement select = context.getConnection().createStatement(); + // Cleanup + select.execute("ALTER TABLE users DROP column user_planificateur;"); + select.execute("ALTER TABLE users DROP column user_phone3;"); + select.execute("ALTER TABLE users DROP column user_email2;"); + // Add color to tag + select.execute("ALTER TABLE tags ADD tag_color varchar(255) default '#01478DFF';"); + // Add association table between exercise and tag + select.execute( + """ CREATE TABLE exercises_tags ( exercise_id varchar(255) not null constraint exercise_id_fk references exercises, tag_id varchar(255) not null constraint tag_id_fk references tags, @@ -28,15 +28,17 @@ constraint exercises_tags_pkey primary key (exercise_id, tag_id) CREATE INDEX idx_exercises_tags_exercise on exercises_tags (exercise_id); CREATE INDEX idx_exercises_tags_exercise_tag on exercises_tags (tag_id); """); - // created_at / updated_at - // exercise - select.execute("ALTER TABLE exercises ADD exercise_created_at timestamp not null default now();"); - select.execute("ALTER TABLE exercises ADD exercise_updated_at timestamp not null default now();"); - // user - select.execute("ALTER TABLE users ADD user_created_at timestamp not null default now();"); - select.execute("ALTER TABLE users ADD user_updated_at timestamp not null default now();"); - // inject - select.execute("ALTER TABLE injects ADD inject_created_at timestamp not null default now();"); - select.execute("ALTER TABLE injects ADD inject_updated_at timestamp not null default now();"); - } + // created_at / updated_at + // exercise + select.execute( + "ALTER TABLE exercises ADD exercise_created_at timestamp not null default now();"); + select.execute( + "ALTER TABLE exercises ADD exercise_updated_at timestamp not null default now();"); + // user + select.execute("ALTER TABLE users ADD user_created_at timestamp not null default now();"); + select.execute("ALTER TABLE users ADD user_updated_at timestamp not null default now();"); + // inject + select.execute("ALTER TABLE injects ADD inject_created_at timestamp not null default now();"); + select.execute("ALTER TABLE injects ADD inject_updated_at timestamp not null default now();"); + } } diff --git a/openbas-api/src/main/java/io/openbas/migration/V2_50__Challenges.java b/openbas-api/src/main/java/io/openbas/migration/V2_50__Challenges.java index 5c358ceb79..321feb2822 100644 --- a/openbas-api/src/main/java/io/openbas/migration/V2_50__Challenges.java +++ b/openbas-api/src/main/java/io/openbas/migration/V2_50__Challenges.java @@ -1,19 +1,19 @@ package io.openbas.migration; +import java.sql.Statement; import org.flywaydb.core.api.migration.BaseJavaMigration; import org.flywaydb.core.api.migration.Context; import org.springframework.stereotype.Component; -import java.sql.Statement; - @Component public class V2_50__Challenges extends BaseJavaMigration { - @Override - public void migrate(Context context) throws Exception { - Statement select = context.getConnection().createStatement(); - // Add association table between challenge and tag - select.execute(""" + @Override + public void migrate(Context context) throws Exception { + Statement select = context.getConnection().createStatement(); + // Add association table between challenge and tag + select.execute( + """ CREATE TABLE challenges_tags ( challenge_id varchar(255) not null constraint challenge_id_fk references challenges, tag_id varchar(255) not null constraint tag_id_fk references tags, @@ -22,10 +22,10 @@ constraint challenges_tags_pkey primary key (challenge_id, tag_id) CREATE INDEX idx_challenge_tags_challenge on challenges_tags (challenge_id); CREATE INDEX idx_challenge_tags_tag on challenges_tags (tag_id); """); - select.execute("ALTER TABLE challenges DROP column challenge_description;"); - select.execute("ALTER TABLE challenges ADD challenge_category varchar(255);"); - select.execute("ALTER TABLE challenges ADD challenge_content text;"); - select.execute("ALTER TABLE challenges ADD challenge_score int;"); - select.execute("ALTER TABLE challenges ADD challenge_max_attempts int;"); - } + select.execute("ALTER TABLE challenges DROP column challenge_description;"); + select.execute("ALTER TABLE challenges ADD challenge_category varchar(255);"); + select.execute("ALTER TABLE challenges ADD challenge_content text;"); + select.execute("ALTER TABLE challenges ADD challenge_score int;"); + select.execute("ALTER TABLE challenges ADD challenge_max_attempts int;"); + } } diff --git a/openbas-api/src/main/java/io/openbas/migration/V2_51__Challenges_documents.java b/openbas-api/src/main/java/io/openbas/migration/V2_51__Challenges_documents.java index 59da5d5311..410a2da308 100644 --- a/openbas-api/src/main/java/io/openbas/migration/V2_51__Challenges_documents.java +++ b/openbas-api/src/main/java/io/openbas/migration/V2_51__Challenges_documents.java @@ -1,19 +1,19 @@ package io.openbas.migration; +import java.sql.Statement; import org.flywaydb.core.api.migration.BaseJavaMigration; import org.flywaydb.core.api.migration.Context; import org.springframework.stereotype.Component; -import java.sql.Statement; - @Component public class V2_51__Challenges_documents extends BaseJavaMigration { - @Override - public void migrate(Context context) throws Exception { - Statement select = context.getConnection().createStatement(); - // Add association table between challenge and tag - select.execute(""" + @Override + public void migrate(Context context) throws Exception { + Statement select = context.getConnection().createStatement(); + // Add association table between challenge and tag + select.execute( + """ CREATE TABLE challenges_documents ( challenge_id varchar(255) not null constraint challenge_id_fk references challenges, document_id varchar(255) not null constraint document_id_fk references documents, @@ -22,5 +22,5 @@ constraint challenges_documents_pkey primary key (challenge_id, document_id) CREATE INDEX idx_challenge_documents_challenge on challenges_documents (challenge_id); CREATE INDEX idx_challenge_documents_document on challenges_documents (document_id); """); - } + } } diff --git a/openbas-api/src/main/java/io/openbas/migration/V2_52__Challenges_documents.java b/openbas-api/src/main/java/io/openbas/migration/V2_52__Challenges_documents.java index 1293e28ce0..c37b4b5174 100644 --- a/openbas-api/src/main/java/io/openbas/migration/V2_52__Challenges_documents.java +++ b/openbas-api/src/main/java/io/openbas/migration/V2_52__Challenges_documents.java @@ -1,18 +1,17 @@ package io.openbas.migration; +import java.sql.Statement; import org.flywaydb.core.api.migration.BaseJavaMigration; import org.flywaydb.core.api.migration.Context; import org.springframework.stereotype.Component; -import java.sql.Statement; - @Component public class V2_52__Challenges_documents extends BaseJavaMigration { - @Override - public void migrate(Context context) throws Exception { - Statement select = context.getConnection().createStatement(); - // Add association table between challenge and tag - select.execute("ALTER TABLE injects_expectations ADD inject_expectation_expected_score int;"); - } + @Override + public void migrate(Context context) throws Exception { + Statement select = context.getConnection().createStatement(); + // Add association table between challenge and tag + select.execute("ALTER TABLE injects_expectations ADD inject_expectation_expected_score int;"); + } } diff --git a/openbas-api/src/main/java/io/openbas/migration/V2_53__Inject_status_upgrade.java b/openbas-api/src/main/java/io/openbas/migration/V2_53__Inject_status_upgrade.java index de327821e8..d3d9652d91 100644 --- a/openbas-api/src/main/java/io/openbas/migration/V2_53__Inject_status_upgrade.java +++ b/openbas-api/src/main/java/io/openbas/migration/V2_53__Inject_status_upgrade.java @@ -1,18 +1,17 @@ package io.openbas.migration; +import java.sql.Statement; import org.flywaydb.core.api.migration.BaseJavaMigration; import org.flywaydb.core.api.migration.Context; import org.springframework.stereotype.Component; -import java.sql.Statement; - @Component public class V2_53__Inject_status_upgrade extends BaseJavaMigration { - @Override - public void migrate(Context context) throws Exception { - Statement select = context.getConnection().createStatement(); - // Add new required fields - select.execute("ALTER TABLE injects_statuses ADD status_async_id varchar(255);"); - } + @Override + public void migrate(Context context) throws Exception { + Statement select = context.getConnection().createStatement(); + // Add new required fields + select.execute("ALTER TABLE injects_statuses ADD status_async_id varchar(255);"); + } } diff --git a/openbas-api/src/main/java/io/openbas/migration/V2_54__LessonsLearned.java b/openbas-api/src/main/java/io/openbas/migration/V2_54__LessonsLearned.java index 23dc186e28..2151c058db 100644 --- a/openbas-api/src/main/java/io/openbas/migration/V2_54__LessonsLearned.java +++ b/openbas-api/src/main/java/io/openbas/migration/V2_54__LessonsLearned.java @@ -1,22 +1,22 @@ package io.openbas.migration; +import java.sql.Connection; +import java.sql.Statement; import org.flywaydb.core.api.migration.BaseJavaMigration; import org.flywaydb.core.api.migration.Context; import org.springframework.stereotype.Component; -import java.sql.Connection; -import java.sql.Statement; - @Component public class V2_54__LessonsLearned extends BaseJavaMigration { - @Override - public void migrate(Context context) throws Exception { - Connection connection = context.getConnection(); - Statement select = connection.createStatement(); - select.execute("DROP TABLE IF EXISTS answers;"); - select.execute("DROP TABLE IF EXISTS polls;"); - select.execute(""" + @Override + public void migrate(Context context) throws Exception { + Connection connection = context.getConnection(); + Statement select = connection.createStatement(); + select.execute("DROP TABLE IF EXISTS answers;"); + select.execute("DROP TABLE IF EXISTS polls;"); + select.execute( + """ CREATE TABLE lessons_templates ( lessons_template_id varchar(255) not null constraint lessons_templates_pkey primary key, lessons_template_created_at timestamp not null default now(), @@ -48,7 +48,8 @@ lessons_template_question_category varchar(255) not null constraint fk_lessons_t CREATE INDEX idx_lessons_template_questions on lessons_template_questions (lessons_template_question_id); CREATE INDEX idx_lessons_template_question_category on lessons_template_questions (lessons_template_question_category); """); - select.execute(""" + select.execute( + """ CREATE TABLE lessons_categories ( lessons_category_id varchar(255) not null constraint lessons_categories_pkey primary key, lessons_category_created_at timestamp not null default now(), @@ -79,7 +80,8 @@ constraint lessons_questions_audiences_pkey primary key (audience_id, lessons_qu CREATE INDEX idx_lessons_questions_audiences_question on lessons_questions_audiences (lessons_question_id); CREATE INDEX idx_lessons_questions_audiences_audience on lessons_questions_audiences (audience_id); """); - select.execute(""" + select.execute( + """ CREATE TABLE lessons_answers ( lessons_answer_id varchar(255) not null constraint lessons_answers_pkey primary key, lessons_answer_created_at timestamp not null default now(), @@ -94,5 +96,5 @@ lessons_answer_user varchar(255) constraint fk_lessons_answer_user references us CREATE INDEX idx_lessons_answer_question on lessons_answers (lessons_answer_question); CREATE INDEX idx_lessons_answer_user on lessons_answers (lessons_answer_user); """); - } + } } diff --git a/openbas-api/src/main/java/io/openbas/migration/V2_55__Update_communication.java b/openbas-api/src/main/java/io/openbas/migration/V2_55__Update_communication.java index 5596fc5fc0..2c4433f6b9 100644 --- a/openbas-api/src/main/java/io/openbas/migration/V2_55__Update_communication.java +++ b/openbas-api/src/main/java/io/openbas/migration/V2_55__Update_communication.java @@ -1,18 +1,17 @@ package io.openbas.migration; +import java.sql.Statement; import org.flywaydb.core.api.migration.BaseJavaMigration; import org.flywaydb.core.api.migration.Context; import org.springframework.stereotype.Component; -import java.sql.Statement; - @Component public class V2_55__Update_communication extends BaseJavaMigration { - @Override - public void migrate(Context context) throws Exception { - Statement select = context.getConnection().createStatement(); - // Add new required fields - select.execute("ALTER TABLE communications ADD communication_attachments text[];"); - } + @Override + public void migrate(Context context) throws Exception { + Statement select = context.getConnection().createStatement(); + // Add new required fields + select.execute("ALTER TABLE communications ADD communication_attachments text[];"); + } } diff --git a/openbas-api/src/main/java/io/openbas/migration/V2_56__ModifyLessonsLearned.java b/openbas-api/src/main/java/io/openbas/migration/V2_56__ModifyLessonsLearned.java index 1bbe5c84d2..fb7ec08389 100644 --- a/openbas-api/src/main/java/io/openbas/migration/V2_56__ModifyLessonsLearned.java +++ b/openbas-api/src/main/java/io/openbas/migration/V2_56__ModifyLessonsLearned.java @@ -1,21 +1,21 @@ package io.openbas.migration; +import java.sql.Connection; +import java.sql.Statement; import org.flywaydb.core.api.migration.BaseJavaMigration; import org.flywaydb.core.api.migration.Context; import org.springframework.stereotype.Component; -import java.sql.Connection; -import java.sql.Statement; - @Component public class V2_56__ModifyLessonsLearned extends BaseJavaMigration { - @Override - public void migrate(Context context) throws Exception { - Connection connection = context.getConnection(); - Statement select = connection.createStatement(); - select.execute("DROP TABLE IF EXISTS lessons_questions_audiences;"); - select.execute(""" + @Override + public void migrate(Context context) throws Exception { + Connection connection = context.getConnection(); + Statement select = connection.createStatement(); + select.execute("DROP TABLE IF EXISTS lessons_questions_audiences;"); + select.execute( + """ CREATE TABLE lessons_categories_audiences ( audience_id varchar(255) not null constraint audience_id_fk references audiences on delete cascade, lessons_category_id varchar(255) not null constraint lessons_category_id_fk references lessons_categories on delete cascade, @@ -24,6 +24,6 @@ constraint lessons_categories_audiences_pkey primary key (audience_id, lessons_c CREATE INDEX idx_lessons_categories_audiences_category on lessons_categories_audiences (lessons_category_id); CREATE INDEX idx_lessons_categories_audiences_audience on lessons_categories_audiences (audience_id); """); - select.execute("ALTER TABLE exercises ADD exercise_lessons_anonymized bool default false;"); - } + select.execute("ALTER TABLE exercises ADD exercise_lessons_anonymized bool default false;"); + } } diff --git a/openbas-api/src/main/java/io/openbas/migration/V2_57__Group_organizations.java b/openbas-api/src/main/java/io/openbas/migration/V2_57__Group_organizations.java index b1ddc9079b..11af12a242 100644 --- a/openbas-api/src/main/java/io/openbas/migration/V2_57__Group_organizations.java +++ b/openbas-api/src/main/java/io/openbas/migration/V2_57__Group_organizations.java @@ -1,19 +1,19 @@ package io.openbas.migration; +import java.sql.Statement; import org.flywaydb.core.api.migration.BaseJavaMigration; import org.flywaydb.core.api.migration.Context; import org.springframework.stereotype.Component; -import java.sql.Statement; - @Component public class V2_57__Group_organizations extends BaseJavaMigration { - @Override - public void migrate(Context context) throws Exception { - Statement select = context.getConnection().createStatement(); - // Create groups_organizations - select.execute(""" + @Override + public void migrate(Context context) throws Exception { + Statement select = context.getConnection().createStatement(); + // Create groups_organizations + select.execute( + """ CREATE TABLE groups_organizations ( group_id varchar(255) not null constraint group_id_fk references groups on delete cascade, organization_id varchar(255) not null constraint organization_id_fk references organizations on delete cascade, @@ -22,5 +22,5 @@ constraint groups_organizations_pkey primary key (group_id, organization_id) CREATE INDEX idx_groups_organizations_group on groups_organizations (group_id); CREATE INDEX idx_groups_organizations_organization on groups_organizations (organization_id); """); - } + } } diff --git a/openbas-api/src/main/java/io/openbas/migration/V2_58__Reports.java b/openbas-api/src/main/java/io/openbas/migration/V2_58__Reports.java index 6b860f8993..06e4a1fcec 100644 --- a/openbas-api/src/main/java/io/openbas/migration/V2_58__Reports.java +++ b/openbas-api/src/main/java/io/openbas/migration/V2_58__Reports.java @@ -1,20 +1,20 @@ package io.openbas.migration; +import java.sql.Connection; +import java.sql.Statement; import org.flywaydb.core.api.migration.BaseJavaMigration; import org.flywaydb.core.api.migration.Context; import org.springframework.stereotype.Component; -import java.sql.Connection; -import java.sql.Statement; - @Component public class V2_58__Reports extends BaseJavaMigration { - @Override - public void migrate(Context context) throws Exception { - Connection connection = context.getConnection(); - Statement select = connection.createStatement(); - select.execute(""" + @Override + public void migrate(Context context) throws Exception { + Connection connection = context.getConnection(); + Statement select = connection.createStatement(); + select.execute( + """ CREATE TABLE reports ( report_id varchar(255) not null constraint reports_pkey primary key, report_created_at timestamp not null default now(), @@ -32,5 +32,5 @@ report_exercise varchar(255) not null constraint fk_report_exercise references e CREATE INDEX idx_reports on reports (report_id); CREATE INDEX idx_report_exercise on reports (report_exercise); """); - } + } } diff --git a/openbas-api/src/main/java/io/openbas/migration/V2_59__ModifyReport.java b/openbas-api/src/main/java/io/openbas/migration/V2_59__ModifyReport.java index b335560569..eec3ca4e83 100644 --- a/openbas-api/src/main/java/io/openbas/migration/V2_59__ModifyReport.java +++ b/openbas-api/src/main/java/io/openbas/migration/V2_59__ModifyReport.java @@ -1,20 +1,20 @@ package io.openbas.migration; +import java.sql.Connection; +import java.sql.Statement; import org.flywaydb.core.api.migration.BaseJavaMigration; import org.flywaydb.core.api.migration.Context; import org.springframework.stereotype.Component; -import java.sql.Connection; -import java.sql.Statement; - @Component public class V2_59__ModifyReport extends BaseJavaMigration { - @Override - public void migrate(Context context) throws Exception { - Connection connection = context.getConnection(); - Statement select = connection.createStatement(); - select.execute("ALTER TABLE reports ADD report_description text;"); - select.execute("ALTER TABLE reports ADD report_general_information bool not null default true;"); - } + @Override + public void migrate(Context context) throws Exception { + Connection connection = context.getConnection(); + Statement select = connection.createStatement(); + select.execute("ALTER TABLE reports ADD report_description text;"); + select.execute( + "ALTER TABLE reports ADD report_general_information bool not null default true;"); + } } diff --git a/openbas-api/src/main/java/io/openbas/migration/V2_5__Organization_tags.java b/openbas-api/src/main/java/io/openbas/migration/V2_5__Organization_tags.java index 7831c8881d..7659c47495 100644 --- a/openbas-api/src/main/java/io/openbas/migration/V2_5__Organization_tags.java +++ b/openbas-api/src/main/java/io/openbas/migration/V2_5__Organization_tags.java @@ -1,19 +1,19 @@ package io.openbas.migration; +import java.sql.Statement; import org.flywaydb.core.api.migration.BaseJavaMigration; import org.flywaydb.core.api.migration.Context; import org.springframework.stereotype.Component; -import java.sql.Statement; - @Component public class V2_5__Organization_tags extends BaseJavaMigration { - @Override - public void migrate(Context context) throws Exception { - Statement select = context.getConnection().createStatement(); - // Add association table between organization and tag - select.execute(""" + @Override + public void migrate(Context context) throws Exception { + Statement select = context.getConnection().createStatement(); + // Add association table between organization and tag + select.execute( + """ CREATE TABLE organizations_tags ( organization_id varchar(255) not null constraint organization_id_fk references organizations, tag_id varchar(255) not null constraint tag_id_fk references tags, @@ -22,8 +22,10 @@ constraint organizations_tags_pkey primary key (organization_id, tag_id) CREATE INDEX idx_organization_tags_organization on organizations_tags (organization_id); CREATE INDEX idx_organization_tags_tag on organizations_tags (tag_id); """); - // created_at / updated_at - select.execute("ALTER TABLE organizations ADD organization_created_at timestamp not null default now();"); - select.execute("ALTER TABLE organizations ADD organization_updated_at timestamp not null default now();"); - } + // created_at / updated_at + select.execute( + "ALTER TABLE organizations ADD organization_created_at timestamp not null default now();"); + select.execute( + "ALTER TABLE organizations ADD organization_updated_at timestamp not null default now();"); + } } diff --git a/openbas-api/src/main/java/io/openbas/migration/V2_60__Delete_fk_users_injects.java b/openbas-api/src/main/java/io/openbas/migration/V2_60__Delete_fk_users_injects.java index b6da5a61fd..d97dfcaf5e 100644 --- a/openbas-api/src/main/java/io/openbas/migration/V2_60__Delete_fk_users_injects.java +++ b/openbas-api/src/main/java/io/openbas/migration/V2_60__Delete_fk_users_injects.java @@ -1,20 +1,20 @@ package io.openbas.migration; +import java.sql.Connection; +import java.sql.Statement; import org.flywaydb.core.api.migration.BaseJavaMigration; import org.flywaydb.core.api.migration.Context; import org.springframework.stereotype.Component; -import java.sql.Connection; -import java.sql.Statement; - @Component public class V2_60__Delete_fk_users_injects extends BaseJavaMigration { - @Override - public void migrate(Context context) throws Exception { - Connection connection = context.getConnection(); - Statement select = connection.createStatement(); - select.execute(""" + @Override + public void migrate(Context context) throws Exception { + Connection connection = context.getConnection(); + Statement select = connection.createStatement(); + select.execute( + """ ALTER TABLE injects DROP CONSTRAINT fk_a60839b2e20fc097, ADD CONSTRAINT fk_injects_user_id @@ -22,5 +22,5 @@ public void migrate(Context context) throws Exception { references users(user_id) on delete set null; """); - } + } } diff --git a/openbas-api/src/main/java/io/openbas/migration/V2_61__Inject_not_null_depends_duration.java b/openbas-api/src/main/java/io/openbas/migration/V2_61__Inject_not_null_depends_duration.java index a78fc88f22..1f58cd7a76 100644 --- a/openbas-api/src/main/java/io/openbas/migration/V2_61__Inject_not_null_depends_duration.java +++ b/openbas-api/src/main/java/io/openbas/migration/V2_61__Inject_not_null_depends_duration.java @@ -1,27 +1,28 @@ package io.openbas.migration; +import java.sql.Connection; +import java.sql.Statement; import org.flywaydb.core.api.migration.BaseJavaMigration; import org.flywaydb.core.api.migration.Context; import org.springframework.stereotype.Component; -import java.sql.Connection; -import java.sql.Statement; - @Component public class V2_61__Inject_not_null_depends_duration extends BaseJavaMigration { - @Override - public void migrate(Context context) throws Exception { - Connection connection = context.getConnection(); - Statement select = connection.createStatement(); - select.execute(""" + @Override + public void migrate(Context context) throws Exception { + Connection connection = context.getConnection(); + Statement select = connection.createStatement(); + select.execute( + """ UPDATE injects SET inject_depends_duration = 0 WHERE inject_depends_duration IS NULL; """); - select.execute(""" + select.execute( + """ ALTER TABLE injects ALTER COLUMN inject_depends_duration SET NOT NULL; """); - } + } } diff --git a/openbas-api/src/main/java/io/openbas/migration/V2_62__Variables_Variable_tags.java b/openbas-api/src/main/java/io/openbas/migration/V2_62__Variables_Variable_tags.java index b2142ceb21..2d8bfdc0dd 100644 --- a/openbas-api/src/main/java/io/openbas/migration/V2_62__Variables_Variable_tags.java +++ b/openbas-api/src/main/java/io/openbas/migration/V2_62__Variables_Variable_tags.java @@ -1,12 +1,11 @@ package io.openbas.migration; +import java.sql.Connection; +import java.sql.Statement; import org.flywaydb.core.api.migration.BaseJavaMigration; import org.flywaydb.core.api.migration.Context; import org.springframework.stereotype.Component; -import java.sql.Connection; -import java.sql.Statement; - @Component public class V2_62__Variables_Variable_tags extends BaseJavaMigration { @@ -15,7 +14,8 @@ public void migrate(Context context) throws Exception { Connection connection = context.getConnection(); Statement select = connection.createStatement(); // Add Variable table - select.execute(""" + select.execute( + """ CREATE TABLE IF NOT EXISTS variables ( variable_id varchar(255) not null constraint variables_pkey primary key, variable_key varchar(255) not null, diff --git a/openbas-api/src/main/java/io/openbas/migration/V2_63__InjectExpectation_upgrade.java b/openbas-api/src/main/java/io/openbas/migration/V2_63__InjectExpectation_upgrade.java index c31584f4d3..172bbabe5e 100644 --- a/openbas-api/src/main/java/io/openbas/migration/V2_63__InjectExpectation_upgrade.java +++ b/openbas-api/src/main/java/io/openbas/migration/V2_63__InjectExpectation_upgrade.java @@ -1,29 +1,29 @@ package io.openbas.migration; +import static io.openbas.database.model.InjectExpectation.EXPECTATION_TYPE.ARTICLE; +import static io.openbas.database.model.InjectExpectation.EXPECTATION_TYPE.MANUAL; + import com.fasterxml.jackson.databind.ObjectMapper; -import io.openbas.injectors.email.model.EmailContent; import io.openbas.injectors.channel.model.ChannelContent; +import io.openbas.injectors.email.model.EmailContent; import io.openbas.model.inject.form.Expectation; -import lombok.Data; -import lombok.EqualsAndHashCode; -import org.flywaydb.core.api.migration.BaseJavaMigration; -import org.flywaydb.core.api.migration.Context; -import org.springframework.stereotype.Component; - import java.sql.Connection; import java.sql.PreparedStatement; import java.sql.ResultSet; import java.sql.Statement; import java.util.List; import java.util.Objects; - -import static io.openbas.database.model.InjectExpectation.EXPECTATION_TYPE.ARTICLE; -import static io.openbas.database.model.InjectExpectation.EXPECTATION_TYPE.MANUAL; +import lombok.Data; +import lombok.EqualsAndHashCode; +import org.flywaydb.core.api.migration.BaseJavaMigration; +import org.flywaydb.core.api.migration.Context; +import org.springframework.stereotype.Component; @Component public class V2_63__InjectExpectation_upgrade extends BaseJavaMigration { - public static final String EXPECTATION_MANUAL_NAME = "The animation team can validate the audience reaction"; + public static final String EXPECTATION_MANUAL_NAME = + "The animation team can validate the audience reaction"; public static final String EXPECTATION_ARTICLE_NAME = "Expect audiences to read the article(s)"; @Override @@ -31,19 +31,21 @@ public void migrate(Context context) throws Exception { Connection connection = context.getConnection(); Statement select = connection.createStatement(); // Upgrade Inject Expectation table - select.execute(""" + select.execute( + """ ALTER TABLE injects_expectations ADD inject_expectation_name varchar(255); ALTER TABLE injects_expectations ADD inject_expectation_description text; """); // Migration datas ObjectMapper mapper = new ObjectMapper(); - ResultSet results = select.executeQuery(""" + ResultSet results = + select.executeQuery( + """ SELECT * FROM injects WHERE inject_type = 'openex_email' OR inject_type = 'openex_ovh_sms' OR inject_type = 'openex_media' """); - PreparedStatement statement = connection.prepareStatement( - "UPDATE injects SET inject_content = ? WHERE inject_id = ?" - ); + PreparedStatement statement = + connection.prepareStatement("UPDATE injects SET inject_content = ? WHERE inject_id = ?"); while (results.next()) { String content = results.getString("inject_content"); if (!content.equals("null")) { @@ -85,6 +87,7 @@ OvhSmsContentNew toNewContent() { return content; } } + @Data public static class OvhSmsContentNew { private String message; diff --git a/openbas-api/src/main/java/io/openbas/migration/V2_64__Audiences_detach_exercises.java b/openbas-api/src/main/java/io/openbas/migration/V2_64__Audiences_detach_exercises.java index 05cba92224..1b6457050c 100644 --- a/openbas-api/src/main/java/io/openbas/migration/V2_64__Audiences_detach_exercises.java +++ b/openbas-api/src/main/java/io/openbas/migration/V2_64__Audiences_detach_exercises.java @@ -1,12 +1,11 @@ package io.openbas.migration; +import java.sql.Connection; +import java.sql.Statement; import org.flywaydb.core.api.migration.BaseJavaMigration; import org.flywaydb.core.api.migration.Context; import org.springframework.stereotype.Component; -import java.sql.Connection; -import java.sql.Statement; - @Component public class V2_64__Audiences_detach_exercises extends BaseJavaMigration { @@ -15,7 +14,8 @@ public void migrate(Context context) throws Exception { Connection connection = context.getConnection(); Statement select = connection.createStatement(); // Add Variable table - select.execute(""" + select.execute( + """ ALTER TABLE audiences RENAME CONSTRAINT subaudiences_pkey TO team_pkey; ALTER TABLE audiences DROP CONSTRAINT fk_audience_exercise; ALTER TABLE audiences DROP column audience_enabled; @@ -27,11 +27,13 @@ public void migrate(Context context) throws Exception { ALTER TABLE audiences RENAME COLUMN audience_updated_at TO team_updated_at; ALTER TABLE audiences RENAME TO teams; """); - select.execute(""" + select.execute( + """ ALTER TABLE teams ADD COLUMN team_organization varchar(255); ALTER TABLE teams ADD CONSTRAINT fk_teams_organizations FOREIGN KEY (team_organization) REFERENCES organizations(organization_id) ON DELETE SET NULL; """); - select.execute(""" + select.execute( + """ CREATE TABLE exercises_teams ( exercise_id varchar(255) not null constraint exercise_id_fk @@ -46,7 +48,8 @@ primary key (exercise_id, team_id) CREATE INDEX idx_exercises_teams_exercise on exercises_teams (exercise_id); CREATE INDEX idx_exercises_teams_team on exercises_teams (team_id); """); - select.execute(""" + select.execute( + """ CREATE TABLE exercises_teams_users ( exercise_id varchar(255) not null constraint exercise_id_fk @@ -66,29 +69,34 @@ primary key (exercise_id, team_id, user_id) CREATE INDEX idx_exercises_teams_users_team on exercises_teams_users (team_id); CREATE INDEX idx_exercises_teams_users_user on exercises_teams_users (user_id); """); - select.execute(""" + select.execute( + """ ALTER TABLE users_audiences RENAME CONSTRAINT users_subaudiences_pkey TO users_teams_pkey; ALTER TABLE users_audiences RENAME COLUMN audience_id TO team_id; ALTER TABLE users_audiences RENAME to users_teams; """); - select.execute(""" + select.execute( + """ ALTER TABLE audiences_tags RENAME CONSTRAINT audiences_tags_pkey TO teams_tags_pkey; ALTER TABLE audiences_tags RENAME CONSTRAINT audience_id_fk TO team_id_fk; ALTER TABLE audiences_tags RENAME COLUMN audience_id TO team_id; ALTER TABLE audiences_tags RENAME to teams_tags; """); - select.execute(""" + select.execute( + """ ALTER TABLE injects_audiences RENAME CONSTRAINT injects_subaudiences_pkey TO injects_teams_pkey; ALTER TABLE injects_audiences RENAME COLUMN audience_id TO team_id; ALTER TABLE injects_audiences RENAME to injects_teams; """); - select.execute(""" + select.execute( + """ ALTER TABLE lessons_categories_audiences RENAME CONSTRAINT lessons_categories_audiences_pkey TO lessons_categories_teams_pkey; ALTER TABLE lessons_categories_audiences RENAME CONSTRAINT audience_id_fk TO team_id_fk; ALTER TABLE lessons_categories_audiences RENAME COLUMN audience_id TO team_id; ALTER TABLE lessons_categories_audiences RENAME to lessons_categories_teams; """); - select.execute(""" + select.execute( + """ ALTER TABLE injects RENAME COLUMN inject_all_audiences TO inject_all_teams; ALTER TABLE injects_expectations RENAME COLUMN audience_id TO team_id; ALTER TABLE injects_expectations RENAME CONSTRAINT fk_expectations_audience TO fk_expectations_team; diff --git a/openbas-api/src/main/java/io/openbas/migration/V2_65__Audiences_follow_and_media.java b/openbas-api/src/main/java/io/openbas/migration/V2_65__Audiences_follow_and_media.java index aec7263fd4..88a44cb0ad 100644 --- a/openbas-api/src/main/java/io/openbas/migration/V2_65__Audiences_follow_and_media.java +++ b/openbas-api/src/main/java/io/openbas/migration/V2_65__Audiences_follow_and_media.java @@ -1,15 +1,13 @@ package io.openbas.migration; import com.fasterxml.jackson.databind.ObjectMapper; -import org.flywaydb.core.api.migration.BaseJavaMigration; -import org.flywaydb.core.api.migration.Context; -import org.springframework.stereotype.Component; - import java.sql.Connection; import java.sql.PreparedStatement; import java.sql.ResultSet; import java.sql.Statement; -import java.util.Objects; +import org.flywaydb.core.api.migration.BaseJavaMigration; +import org.flywaydb.core.api.migration.Context; +import org.springframework.stereotype.Component; @Component public class V2_65__Audiences_follow_and_media extends BaseJavaMigration { @@ -19,7 +17,8 @@ public void migrate(Context context) throws Exception { Connection connection = context.getConnection(); Statement select = connection.createStatement(); // Medias - select.execute(""" + select.execute( + """ ALTER TABLE teams RENAME CONSTRAINT team_pkey TO teams_pkey; ALTER TABLE medias RENAME CONSTRAINT medias_pkey TO channels_pkey; ALTER TABLE medias RENAME COLUMN media_id TO channel_id; @@ -37,18 +36,24 @@ public void migrate(Context context) throws Exception { ALTER TABLE medias RENAME COLUMN media_updated_at TO channel_updated_at; ALTER TABLE medias RENAME TO channels; """); - select.execute(""" + select.execute( + """ ALTER TABLE articles RENAME CONSTRAINT fk_article_media TO fk_article_channel; ALTER TABLE articles RENAME COLUMN article_media TO article_channel; """); // Add Variable table - select.execute(""" + select.execute( + """ ALTER TABLE teams ADD team_contextual bool default false; """); // Migration the data ObjectMapper mapper = new ObjectMapper(); - ResultSet results = select.executeQuery("SELECT * FROM injects_teams it LEFT JOIN injects as inject ON it.inject_id = inject.inject_id"); - PreparedStatement statement = connection.prepareStatement("INSERT INTO exercises_teams (exercise_id, team_id) SELECT ?, ? WHERE NOT EXISTS (SELECT exercise_id FROM exercises_teams WHERE exercise_id = ? and team_id = ?)"); + ResultSet results = + select.executeQuery( + "SELECT * FROM injects_teams it LEFT JOIN injects as inject ON it.inject_id = inject.inject_id"); + PreparedStatement statement = + connection.prepareStatement( + "INSERT INTO exercises_teams (exercise_id, team_id) SELECT ?, ? WHERE NOT EXISTS (SELECT exercise_id FROM exercises_teams WHERE exercise_id = ? and team_id = ?)"); while (results.next()) { String exerciseId = results.getString("inject_exercise"); String teamId = results.getString("team_id"); diff --git a/openbas-api/src/main/java/io/openbas/migration/V2_66__Attack_patterns.java b/openbas-api/src/main/java/io/openbas/migration/V2_66__Attack_patterns.java index a795240622..f37560d78e 100644 --- a/openbas-api/src/main/java/io/openbas/migration/V2_66__Attack_patterns.java +++ b/openbas-api/src/main/java/io/openbas/migration/V2_66__Attack_patterns.java @@ -1,15 +1,11 @@ package io.openbas.migration; -import com.fasterxml.jackson.databind.ObjectMapper; +import java.sql.Connection; +import java.sql.Statement; import org.flywaydb.core.api.migration.BaseJavaMigration; import org.flywaydb.core.api.migration.Context; import org.springframework.stereotype.Component; -import java.sql.Connection; -import java.sql.PreparedStatement; -import java.sql.ResultSet; -import java.sql.Statement; - @Component public class V2_66__Attack_patterns extends BaseJavaMigration { @@ -18,7 +14,8 @@ public void migrate(Context context) throws Exception { Connection connection = context.getConnection(); Statement select = connection.createStatement(); // Kill chain phases - select.execute(""" + select.execute( + """ CREATE TABLE kill_chain_phases ( phase_id varchar(255) not null constraint kill_chain_phases_pkey primary key, phase_created_at timestamp not null default now(), @@ -31,7 +28,8 @@ phase_kill_chain_name varchar(255) not null, CREATE UNIQUE INDEX kill_chain_phases_unique on kill_chain_phases (phase_name, phase_kill_chain_name); """); // Attack patterns - select.execute(""" + select.execute( + """ CREATE TABLE attack_patterns ( attack_pattern_id varchar(255) not null constraint attack_patterns_pkey primary key, attack_pattern_created_at timestamp not null default now(), @@ -49,7 +47,8 @@ attack_pattern_parent varchar(255) CREATE INDEX idx_attack_patterns on attack_patterns (attack_pattern_id); CREATE UNIQUE INDEX attack_patterns_unique on attack_patterns (attack_pattern_external_id); """); - select.execute(""" + select.execute( + """ CREATE TABLE attack_patterns_kill_chain_phases ( attack_pattern_id varchar(255) not null constraint attack_pattern_id_fk @@ -65,7 +64,8 @@ primary key (attack_pattern_id, phase_id) CREATE INDEX idx_attack_patterns_kill_chain_phases_kill_chain_phase on attack_patterns_kill_chain_phases (phase_id); """); // Cleanup a bit indexes - select.execute(""" + select.execute( + """ CREATE INDEX idx_teams on teams (team_id); ALTER INDEX idx_medias RENAME TO idx_channels; ALTER INDEX idx_4e039727729413d0 RENAME TO idx_comchecks; diff --git a/openbas-api/src/main/java/io/openbas/migration/V2_67__Variables_Enum.java b/openbas-api/src/main/java/io/openbas/migration/V2_67__Variables_Enum.java index 1ffe50fb3f..f63f2d2dea 100644 --- a/openbas-api/src/main/java/io/openbas/migration/V2_67__Variables_Enum.java +++ b/openbas-api/src/main/java/io/openbas/migration/V2_67__Variables_Enum.java @@ -1,14 +1,13 @@ package io.openbas.migration; import io.openbas.database.model.Variable; -import org.flywaydb.core.api.migration.BaseJavaMigration; -import org.flywaydb.core.api.migration.Context; -import org.springframework.stereotype.Component; - import java.sql.Connection; import java.sql.PreparedStatement; import java.sql.ResultSet; import java.sql.Statement; +import org.flywaydb.core.api.migration.BaseJavaMigration; +import org.flywaydb.core.api.migration.Context; +import org.springframework.stereotype.Component; @Component public class V2_67__Variables_Enum extends BaseJavaMigration { @@ -21,9 +20,8 @@ public void migrate(Context context) throws Exception { select.execute("ALTER TABLE variables ALTER COLUMN variable_type TYPE varchar(255)"); // Migration datas ResultSet results = select.executeQuery("SELECT * FROM variables"); - PreparedStatement statement = connection.prepareStatement( - "UPDATE variables SET variable_type = ? WHERE variable_id = ?" - ); + PreparedStatement statement = + connection.prepareStatement("UPDATE variables SET variable_type = ? WHERE variable_id = ?"); while (results.next()) { String id = results.getString("variable_id"); int type = results.getInt("variable_type"); diff --git a/openbas-api/src/main/java/io/openbas/migration/V2_68__Assets_Asset_Groups.java b/openbas-api/src/main/java/io/openbas/migration/V2_68__Assets_Asset_Groups.java index c9d6fe545e..ff254f5085 100644 --- a/openbas-api/src/main/java/io/openbas/migration/V2_68__Assets_Asset_Groups.java +++ b/openbas-api/src/main/java/io/openbas/migration/V2_68__Assets_Asset_Groups.java @@ -1,12 +1,11 @@ package io.openbas.migration; +import java.sql.Connection; +import java.sql.Statement; import org.flywaydb.core.api.migration.BaseJavaMigration; import org.flywaydb.core.api.migration.Context; import org.springframework.stereotype.Component; -import java.sql.Connection; -import java.sql.Statement; - @Component public class V2_68__Assets_Asset_Groups extends BaseJavaMigration { @@ -15,11 +14,13 @@ public void migrate(Context context) throws Exception { Connection connection = context.getConnection(); Statement select = connection.createStatement(); // Add extension - select.execute(""" + select.execute( + """ CREATE EXTENSION IF NOT EXISTS hstore; """); // Create table asset - select.execute(""" + select.execute( + """ CREATE TABLE IF NOT EXISTS assets ( asset_id varchar(255) not null constraint assets_pkey primary key, asset_type varchar(255) not null, @@ -34,14 +35,16 @@ asset_updated_at timestamp not null default now() CREATE INDEX IF NOT EXISTS idx_assets on assets (asset_id); """); // Add column for endpoint type - select.execute(""" + select.execute( + """ ALTER TABLE assets ADD COLUMN endpoint_ips text[]; ALTER TABLE assets ADD COLUMN endpoint_hostname varchar(255); ALTER TABLE assets ADD COLUMN endpoint_platform varchar(255) not null; ALTER TABLE assets ADD COLUMN endpoint_mac_addresses text[]; """); // Add association table between asset and tag - select.execute(""" + select.execute( + """ CREATE TABLE assets_tags ( asset_id varchar(255) not null constraint asset_id_fk references assets, tag_id varchar(255) not null constraint tag_id_fk references tags, @@ -51,7 +54,8 @@ constraint assets_tags_pkey primary key (asset_id, tag_id) CREATE INDEX idx_assets_tags_tag on assets_tags (tag_id); """); // Create table asset groups - select.execute(""" + select.execute( + """ CREATE TABLE IF NOT EXISTS asset_groups ( asset_group_id varchar(255) not null constraint asset_groups_pkey primary key, asset_group_name varchar(255) not null, @@ -62,7 +66,8 @@ asset_group_updated_at timestamp not null default now() CREATE INDEX IF NOT EXISTS idx_asset_groups on asset_groups (asset_group_id); """); // Add association table between asset group and tag - select.execute(""" + select.execute( + """ CREATE TABLE asset_groups_tags ( asset_group_id varchar(255) not null constraint asset_group_id_fk references asset_groups on delete cascade, tag_id varchar(255) not null constraint tag_id_fk references tags on delete cascade, @@ -72,7 +77,8 @@ constraint asset_groups_tags_pkey primary key (asset_group_id, tag_id) CREATE INDEX idx_asset_groups_tags_tag on asset_groups_tags (tag_id); """); // Add association table between asset and asset groups - select.execute(""" + select.execute( + """ CREATE TABLE IF NOT EXISTS asset_groups_assets ( asset_group_id varchar(255) not null constraint asset_group_id_fk references asset_groups on delete cascade, asset_id varchar(255) not null constraint asset_id_fk references assets on delete cascade, diff --git a/openbas-api/src/main/java/io/openbas/migration/V2_69__Modify_Inject_async_ids.java b/openbas-api/src/main/java/io/openbas/migration/V2_69__Modify_Inject_async_ids.java index c854a1aa65..7108affc33 100644 --- a/openbas-api/src/main/java/io/openbas/migration/V2_69__Modify_Inject_async_ids.java +++ b/openbas-api/src/main/java/io/openbas/migration/V2_69__Modify_Inject_async_ids.java @@ -1,12 +1,11 @@ package io.openbas.migration; +import java.sql.Connection; +import java.sql.Statement; import org.flywaydb.core.api.migration.BaseJavaMigration; import org.flywaydb.core.api.migration.Context; import org.springframework.stereotype.Component; -import java.sql.Connection; -import java.sql.Statement; - @Component public class V2_69__Modify_Inject_async_ids extends BaseJavaMigration { @@ -15,7 +14,8 @@ public void migrate(Context context) throws Exception { Connection connection = context.getConnection(); Statement select = connection.createStatement(); // Modify inject async ids property - select.execute(""" + select.execute( + """ ALTER TABLE injects_statuses ADD COLUMN status_async_ids text[]; UPDATE injects_statuses SET status_async_ids = ARRAY[status_async_id]; ALTER TABLE injects_statuses DROP COLUMN status_async_id; diff --git a/openbas-api/src/main/java/io/openbas/migration/V2_6__User_tags.java b/openbas-api/src/main/java/io/openbas/migration/V2_6__User_tags.java index 99204ea01d..5d16875866 100644 --- a/openbas-api/src/main/java/io/openbas/migration/V2_6__User_tags.java +++ b/openbas-api/src/main/java/io/openbas/migration/V2_6__User_tags.java @@ -1,19 +1,19 @@ package io.openbas.migration; +import java.sql.Statement; import org.flywaydb.core.api.migration.BaseJavaMigration; import org.flywaydb.core.api.migration.Context; import org.springframework.stereotype.Component; -import java.sql.Statement; - @Component public class V2_6__User_tags extends BaseJavaMigration { - @Override - public void migrate(Context context) throws Exception { - Statement select = context.getConnection().createStatement(); - // Add association table between organization and tag - select.execute(""" + @Override + public void migrate(Context context) throws Exception { + Statement select = context.getConnection().createStatement(); + // Add association table between organization and tag + select.execute( + """ CREATE TABLE users_tags ( user_id varchar(255) not null constraint user_id_fk references users, tag_id varchar(255) not null constraint tag_id_fk references tags, @@ -22,5 +22,5 @@ constraint users_tags_pkey primary key (user_id, tag_id) CREATE INDEX idx_users_tags_user on users_tags (user_id); CREATE INDEX idx_users_tags_tag on users_tags (tag_id); """); - } + } } diff --git a/openbas-api/src/main/java/io/openbas/migration/V2_70__Enhance_attack_patterns.java b/openbas-api/src/main/java/io/openbas/migration/V2_70__Enhance_attack_patterns.java index 8354c2dba9..f968440fe2 100644 --- a/openbas-api/src/main/java/io/openbas/migration/V2_70__Enhance_attack_patterns.java +++ b/openbas-api/src/main/java/io/openbas/migration/V2_70__Enhance_attack_patterns.java @@ -1,12 +1,11 @@ package io.openbas.migration; +import java.sql.Connection; +import java.sql.Statement; import org.flywaydb.core.api.migration.BaseJavaMigration; import org.flywaydb.core.api.migration.Context; import org.springframework.stereotype.Component; -import java.sql.Connection; -import java.sql.Statement; - @Component public class V2_70__Enhance_attack_patterns extends BaseJavaMigration { @@ -15,7 +14,8 @@ public void migrate(Context context) throws Exception { Connection connection = context.getConnection(); Statement select = connection.createStatement(); // Cleanup a bit indexes - select.execute(""" + select.execute( + """ ALTER TABLE users_teams RENAME CONSTRAINT fk_cfb417fca76ed395 TO fk_user_id; ALTER TABLE users_teams RENAME CONSTRAINT fk_cfb417fccb0ca5a3 TO fk_team_id; ALTER TABLE injects_tags RENAME CONSTRAINT tag_id_fk TO fk_tag_id; @@ -41,7 +41,8 @@ public void migrate(Context context) throws Exception { ALTER INDEX attack_patterns_kill_chain_phases_pkey RENAME TO pkey_attack_patterns_kill_chain_phases; """); // Add column for endpoint type - select.execute(""" + select.execute( + """ ALTER TABLE kill_chain_phases ADD COLUMN phase_description text; ALTER TABLE kill_chain_phases ADD COLUMN phase_shortname varchar(255) not null; ALTER TABLE kill_chain_phases ADD COLUMN phase_external_id varchar(255) not null; diff --git a/openbas-api/src/main/java/io/openbas/migration/V2_71__Modify_inject.java b/openbas-api/src/main/java/io/openbas/migration/V2_71__Modify_inject.java index 4dda66a2b0..46fc490785 100644 --- a/openbas-api/src/main/java/io/openbas/migration/V2_71__Modify_inject.java +++ b/openbas-api/src/main/java/io/openbas/migration/V2_71__Modify_inject.java @@ -1,12 +1,11 @@ package io.openbas.migration; +import java.sql.Connection; +import java.sql.Statement; import org.flywaydb.core.api.migration.BaseJavaMigration; import org.flywaydb.core.api.migration.Context; import org.springframework.stereotype.Component; -import java.sql.Connection; -import java.sql.Statement; - @Component public class V2_71__Modify_inject extends BaseJavaMigration { @@ -15,12 +14,14 @@ public void migrate(Context context) throws Exception { Connection connection = context.getConnection(); Statement select = connection.createStatement(); // Add table link asset to inject - select.execute(""" + select.execute( + """ ALTER TABLE injects ADD COLUMN inject_assets varchar(256); ALTER TABLE injects ADD COLUMN injects_asset_groups varchar(256); """); // Add association table between asset and inject - select.execute(""" + select.execute( + """ CREATE TABLE injects_assets ( inject_id varchar(255) not null constraint inject_id_fk references injects on delete cascade, asset_id varchar(255) not null constraint asset_id_fk references assets on delete cascade, @@ -30,7 +31,8 @@ constraint injects_assets_pkey primary key (inject_id, asset_id) CREATE INDEX idx_injects_assets_asset on injects_assets (asset_id); """); // Add association table between asset group and inject - select.execute(""" + select.execute( + """ CREATE TABLE injects_asset_groups ( inject_id varchar(255) not null constraint inject_id_fk references injects on delete cascade, asset_group_id varchar(255) not null constraint asset_group_id_fk references asset_groups on delete cascade, @@ -40,7 +42,8 @@ constraint injects_asset_groups_pkey primary key (inject_id, asset_group_id) CREATE INDEX idx_injects_asset_groups_asset_groups on injects_asset_groups (asset_group_id); """); // Add asset to inject expectation - select.execute(""" + select.execute( + """ ALTER TABLE injects_expectations ADD COLUMN inject_expectation_group bool default false; ALTER TABLE injects_expectations ADD COLUMN asset_id varchar(256) constraint fk_asset references assets on delete cascade; ALTER TABLE injects_expectations ADD COLUMN asset_group_id varchar(256) constraint fk_asset_group references asset_groups on delete cascade; diff --git a/openbas-api/src/main/java/io/openbas/migration/V2_72__Add_index_user_email_lower_case.java b/openbas-api/src/main/java/io/openbas/migration/V2_72__Add_index_user_email_lower_case.java index 3591885e61..5526aa786c 100644 --- a/openbas-api/src/main/java/io/openbas/migration/V2_72__Add_index_user_email_lower_case.java +++ b/openbas-api/src/main/java/io/openbas/migration/V2_72__Add_index_user_email_lower_case.java @@ -1,12 +1,11 @@ package io.openbas.migration; +import java.sql.Connection; +import java.sql.Statement; import org.flywaydb.core.api.migration.BaseJavaMigration; import org.flywaydb.core.api.migration.Context; import org.springframework.stereotype.Component; -import java.sql.Connection; -import java.sql.Statement; - @Component public class V2_72__Add_index_user_email_lower_case extends BaseJavaMigration { @@ -15,7 +14,8 @@ public void migrate(Context context) throws Exception { Connection connection = context.getConnection(); Statement select = connection.createStatement(); // Add index on user.email with - select.execute(""" + select.execute( + """ CREATE INDEX idx_users_user_email_lower_case on users (lower(user_email)); """); } diff --git a/openbas-api/src/main/java/io/openbas/migration/V2_73__Scenarios.java b/openbas-api/src/main/java/io/openbas/migration/V2_73__Scenarios.java index de1ae0e47a..1a0669c5e5 100644 --- a/openbas-api/src/main/java/io/openbas/migration/V2_73__Scenarios.java +++ b/openbas-api/src/main/java/io/openbas/migration/V2_73__Scenarios.java @@ -1,12 +1,11 @@ package io.openbas.migration; +import java.sql.Connection; +import java.sql.Statement; import org.flywaydb.core.api.migration.BaseJavaMigration; import org.flywaydb.core.api.migration.Context; import org.springframework.stereotype.Component; -import java.sql.Connection; -import java.sql.Statement; - @Component public class V2_73__Scenarios extends BaseJavaMigration { @@ -15,7 +14,8 @@ public void migrate(Context context) throws Exception { Connection connection = context.getConnection(); Statement select = connection.createStatement(); // Create scenario table - select.execute(""" + select.execute( + """ CREATE TABLE IF NOT EXISTS scenarios ( scenario_id varchar(255) not null constraint scenarios_pkey primary key, scenario_name varchar(255) not null, @@ -30,7 +30,8 @@ scenario_updated_at timestamp not null default now() CREATE INDEX IF NOT EXISTS idx_assets on assets (asset_id); """); // Add association table between scenario and team and player - select.execute(""" + select.execute( + """ CREATE TABLE scenarios_teams_users ( scenario_id varchar(255) not null constraint scenario_id_fk references scenarios on delete cascade, team_id varchar(255) not null constraint team_id_fk references teams on delete cascade, @@ -42,15 +43,18 @@ primary key (scenario_id, team_id, user_id) CREATE INDEX idx_scenarios_teams_users_user on scenarios_teams_users (user_id); """); // Add scenario to grant - select.execute(""" + select.execute( + """ ALTER TABLE grants ADD COLUMN grant_scenario varchar(255) constraint scenario_fk references scenarios on delete cascade ; """); // Add scenario to inject - select.execute(""" + select.execute( + """ ALTER TABLE injects ADD COLUMN inject_scenario varchar(255) constraint scenario_fk references scenarios on delete cascade ; """); // Add association table between scenario and team - select.execute(""" + select.execute( + """ CREATE TABLE scenarios_teams ( scenario_id varchar(255) not null constraint scenario_id_fk references scenarios, team_id varchar(255) not null constraint team_id_fk references teams, @@ -60,11 +64,13 @@ constraint scenarios_teams_pkey primary key (scenario_id, team_id) CREATE INDEX idx_scenarios_teams_team on scenarios_teams (team_id); """); // Add scenario to objective - select.execute(""" + select.execute( + """ ALTER TABLE objectives ADD COLUMN objective_scenario varchar(255) constraint scenario_fk references scenarios on delete cascade ; """); // Add association table between scenario and tag - select.execute(""" + select.execute( + """ CREATE TABLE scenarios_tags ( scenario_id varchar(255) not null constraint scenario_id_fk references scenarios, tag_id varchar(255) not null constraint tag_id_fk references tags, @@ -74,7 +80,8 @@ constraint scenarios_tags_pkey primary key (scenario_id, tag_id) CREATE INDEX idx_scenarios_tags_tag on scenarios_tags (tag_id); """); // Add association table between scenario and tag - select.execute(""" + select.execute( + """ CREATE TABLE scenarios_documents ( scenario_id varchar(255) not null constraint scenario_id_fk references scenarios, document_id varchar(255) not null constraint document_id_fk references documents, @@ -84,24 +91,28 @@ constraint scenarios_documents_pkey primary key (scenario_id, document_id) CREATE INDEX idx_scenarios_documents_document on scenarios_documents (document_id); """); // Add scenario to article - select.execute(""" + select.execute( + """ ALTER TABLE articles ALTER COLUMN article_exercise DROP NOT NULL ; ALTER TABLE articles ADD COLUMN article_scenario varchar(255) constraint scenario_fk references scenarios on delete cascade ; """); // Add scenario to lessons categories - select.execute(""" + select.execute( + """ ALTER TABLE lessons_categories ALTER COLUMN lessons_category_exercise DROP NOT NULL ; ALTER TABLE lessons_categories ADD COLUMN lessons_category_scenario varchar(255) constraint scenario_fk references scenarios on delete cascade ; """); // Add scenario to group - select.execute(""" + select.execute( + """ create table groups_scenarios_default_grants ( group_id varchar(255) not null constraint group_id_fk references groups, scenarios_default_grants varchar(255) ); """); // Add scenario to variables - select.execute(""" + select.execute( + """ ALTER TABLE variables ADD COLUMN variable_scenario varchar(255) default NULL::character varying constraint scenario_id_fk references scenarios on delete cascade; CREATE INDEX IF NOT EXISTS idx_variable_scenario on variables (variable_scenario); """); diff --git a/openbas-api/src/main/java/io/openbas/migration/V2_74__OpenBAS.java b/openbas-api/src/main/java/io/openbas/migration/V2_74__OpenBAS.java index d383295e86..c9a6df5eda 100644 --- a/openbas-api/src/main/java/io/openbas/migration/V2_74__OpenBAS.java +++ b/openbas-api/src/main/java/io/openbas/migration/V2_74__OpenBAS.java @@ -1,12 +1,11 @@ package io.openbas.migration; +import java.sql.Connection; +import java.sql.Statement; import org.flywaydb.core.api.migration.BaseJavaMigration; import org.flywaydb.core.api.migration.Context; import org.springframework.stereotype.Component; -import java.sql.Connection; -import java.sql.Statement; - @Component public class V2_74__OpenBAS extends BaseJavaMigration { @@ -15,7 +14,8 @@ public void migrate(Context context) throws Exception { Connection connection = context.getConnection(); Statement select = connection.createStatement(); // Migration the data - select.executeUpdate(""" + select.executeUpdate( + """ UPDATE injects SET inject_type = REPLACE(inject_type, 'openex_', 'openbas_') WHERE inject_type LIKE 'openex_%'; diff --git a/openbas-api/src/main/java/io/openbas/migration/V2_75__Inject_expectation_result.java b/openbas-api/src/main/java/io/openbas/migration/V2_75__Inject_expectation_result.java index 67b0dedd2b..30bf3b9625 100644 --- a/openbas-api/src/main/java/io/openbas/migration/V2_75__Inject_expectation_result.java +++ b/openbas-api/src/main/java/io/openbas/migration/V2_75__Inject_expectation_result.java @@ -1,12 +1,11 @@ package io.openbas.migration; +import java.sql.Connection; +import java.sql.Statement; import org.flywaydb.core.api.migration.BaseJavaMigration; import org.flywaydb.core.api.migration.Context; import org.springframework.stereotype.Component; -import java.sql.Connection; -import java.sql.Statement; - @Component public class V2_75__Inject_expectation_result extends BaseJavaMigration { @@ -15,11 +14,12 @@ public void migrate(Context context) throws Exception { Connection connection = context.getConnection(); Statement select = connection.createStatement(); // Migration the data - select.execute(""" + select.execute( + """ ALTER TABLE injects_expectations ADD COLUMN inject_expectation_results json; UPDATE injects_expectations SET inject_expectation_results = json_build_array(json_build_object('result', inject_expectation_result)); ALTER TABLE injects_expectations DROP COLUMN inject_expectation_result; - + UPDATE injects_expectations SET inject_expectation_type = 'PREVENTION' WHERE inject_expectation_type = 'TECHNICAL'; diff --git a/openbas-api/src/main/java/io/openbas/migration/V2_76__Add_reply_to_scenarios_and_exercises.java b/openbas-api/src/main/java/io/openbas/migration/V2_76__Add_reply_to_scenarios_and_exercises.java index ff1fd29c7e..28dd446dee 100644 --- a/openbas-api/src/main/java/io/openbas/migration/V2_76__Add_reply_to_scenarios_and_exercises.java +++ b/openbas-api/src/main/java/io/openbas/migration/V2_76__Add_reply_to_scenarios_and_exercises.java @@ -1,21 +1,21 @@ package io.openbas.migration; +import java.sql.Connection; +import java.sql.Statement; import org.flywaydb.core.api.migration.BaseJavaMigration; import org.flywaydb.core.api.migration.Context; import org.springframework.stereotype.Component; -import java.sql.Connection; -import java.sql.Statement; - @Component public class V2_76__Add_reply_to_scenarios_and_exercises extends BaseJavaMigration { - @Override - public void migrate(Context context) throws Exception { - Connection connection = context.getConnection(); - Statement select = connection.createStatement(); - // Scenario - select.execute(""" + @Override + public void migrate(Context context) throws Exception { + Connection connection = context.getConnection(); + Statement select = connection.createStatement(); + // Scenario + select.execute( + """ create table scenario_mails_reply_to ( scenario_id varchar(255) not null @@ -24,8 +24,9 @@ scenario_id varchar(255) not null scenario_reply_to varchar(255) ); """); - // Exercise - select.execute(""" + // Exercise + select.execute( + """ create table exercise_mails_reply_to ( exercise_id varchar(255) not null @@ -34,5 +35,5 @@ exercise_id varchar(255) not null exercise_reply_to varchar(255) ); """); - } + } } diff --git a/openbas-api/src/main/java/io/openbas/migration/V2_77__Asset_group_dynamic_filter.java b/openbas-api/src/main/java/io/openbas/migration/V2_77__Asset_group_dynamic_filter.java index 2837817544..84232c5a7c 100644 --- a/openbas-api/src/main/java/io/openbas/migration/V2_77__Asset_group_dynamic_filter.java +++ b/openbas-api/src/main/java/io/openbas/migration/V2_77__Asset_group_dynamic_filter.java @@ -1,12 +1,11 @@ package io.openbas.migration; +import java.sql.Connection; +import java.sql.Statement; import org.flywaydb.core.api.migration.BaseJavaMigration; import org.flywaydb.core.api.migration.Context; import org.springframework.stereotype.Component; -import java.sql.Connection; -import java.sql.Statement; - @Component public class V2_77__Asset_group_dynamic_filter extends BaseJavaMigration { @@ -15,7 +14,8 @@ public void migrate(Context context) throws Exception { Connection connection = context.getConnection(); Statement select = connection.createStatement(); // Migration the data - select.executeUpdate(""" + select.executeUpdate( + """ ALTER TABLE asset_groups ADD COLUMN asset_group_dynamic_filter json; """); } diff --git a/openbas-api/src/main/java/io/openbas/migration/V2_78__Add_tag_unique_index.java b/openbas-api/src/main/java/io/openbas/migration/V2_78__Add_tag_unique_index.java index 34720828dd..da078110fc 100644 --- a/openbas-api/src/main/java/io/openbas/migration/V2_78__Add_tag_unique_index.java +++ b/openbas-api/src/main/java/io/openbas/migration/V2_78__Add_tag_unique_index.java @@ -1,11 +1,10 @@ package io.openbas.migration; -import org.flywaydb.core.api.migration.BaseJavaMigration; -import org.flywaydb.core.api.migration.Context; - import java.sql.Connection; import java.sql.SQLException; import java.sql.Statement; +import org.flywaydb.core.api.migration.BaseJavaMigration; +import org.flywaydb.core.api.migration.Context; public class V2_78__Add_tag_unique_index extends BaseJavaMigration { @@ -14,7 +13,8 @@ public void migrate(Context context) throws Exception { Connection connection = context.getConnection(); try (Statement statement = connection.createStatement()) { // Create temporary table for uniq tags - statement.executeUpdate(""" + statement.executeUpdate( + """ CREATE TABLE uniq_tags AS SELECT MIN(tag_id) AS uniq_id, tag_name FROM tags @@ -36,7 +36,8 @@ SELECT MIN(tag_id) AS uniq_id, tag_name deduplicateInTable(statement, "users_tags", "users_tags_pkey"); // Remove duplicate tags in tags table - statement.executeUpdate(""" + statement.executeUpdate( + """ DELETE FROM tags WHERE tags.tag_name IN (SELECT uniq_tags.tag_name FROM uniq_tags) AND NOT EXISTS ( @@ -47,39 +48,53 @@ AND NOT EXISTS ( """); // Recreate primary constraint - recreatePrimaryConstraint(statement, "asset_groups_tags", "asset_groups_tags_pkey", "asset_group_id"); + recreatePrimaryConstraint( + statement, "asset_groups_tags", "asset_groups_tags_pkey", "asset_group_id"); recreatePrimaryConstraint(statement, "assets_tags", "assets_tags_pkey", "asset_id"); - recreatePrimaryConstraint(statement, "challenges_tags", "challenges_tags_pkey", "challenge_id"); + recreatePrimaryConstraint( + statement, "challenges_tags", "challenges_tags_pkey", "challenge_id"); recreatePrimaryConstraint(statement, "documents_tags", "documents_tags_pkey", "document_id"); recreatePrimaryConstraint(statement, "exercises_tags", "exercises_tags_pkey", "exercise_id"); recreatePrimaryConstraint(statement, "injects_tags", "injects_tags_pkey", "inject_id"); recreatePrimaryConstraint(statement, "logs_tags", "logs_tags_pkey", "log_id"); - recreatePrimaryConstraint(statement, "organizations_tags", "organizations_tags_pkey", "organization_id"); + recreatePrimaryConstraint( + statement, "organizations_tags", "organizations_tags_pkey", "organization_id"); recreatePrimaryConstraint(statement, "scenarios_tags", "scenarios_tags_pkey", "scenario_id"); recreatePrimaryConstraint(statement, "teams_tags", "teams_tags_pkey", "team_id"); recreatePrimaryConstraint(statement, "users_tags", "users_tags_pkey", "user_id"); // Add unicity - statement.executeUpdate(""" + statement.executeUpdate( + """ CREATE UNIQUE INDEX IF NOT EXISTS tag_name_unique ON tags (tag_name); """); // Remove temporary table - statement.executeUpdate(""" + statement.executeUpdate( + """ DROP TABLE IF EXISTS uniq_tags; """); } } - private static void deduplicateInTable(Statement statement, String table, String constraintKey) throws SQLException { + private static void deduplicateInTable(Statement statement, String table, String constraintKey) + throws SQLException { // Remove primary key - statement.executeUpdate(""" - ALTER TABLE """ + " ".concat(table).concat(" ") + """ - DROP CONSTRAINT """ + " ".concat(constraintKey).concat(" ") + """ + statement.executeUpdate( + """ + ALTER TABLE """ + + " ".concat(table).concat(" ") + + """ + DROP CONSTRAINT """ + + " ".concat(constraintKey).concat(" ") + + """ """); // Set uniq tag - statement.executeUpdate(""" - UPDATE """ + " ".concat(table).concat(" ") + """ + statement.executeUpdate( + """ + UPDATE """ + + " ".concat(table).concat(" ") + + """ tableName SET tag_id = uniq_tag.uniq_id FROM uniq_tags uniq_tag @@ -87,32 +102,51 @@ private static void deduplicateInTable(Statement statement, String table, String WHERE tableName.tag_id = t.tag_id; """); // Remove duplicate line by create a new table with distinct - statement.executeUpdate(""" - CREATE TABLE """ + " ".concat(table).concat("_temp") + """ + statement.executeUpdate( + """ + CREATE TABLE """ + + " ".concat(table).concat("_temp") + + """ AS - SELECT DISTINCT * FROM """ + " ".concat(table).concat(" ") + """ + SELECT DISTINCT * FROM """ + + " ".concat(table).concat(" ") + + """ """); - statement.executeUpdate(""" - DROP TABLE """ + " ".concat(table).concat(" ") + """ + statement.executeUpdate( + """ + DROP TABLE """ + + " ".concat(table).concat(" ") + + """ """); - statement.executeUpdate(""" - ALTER TABLE """ + " ".concat(table).concat("_temp") + """ + statement.executeUpdate( + """ + ALTER TABLE """ + + " ".concat(table).concat("_temp") + + """ RENAME - TO """ + " ".concat(table).concat(" ") + """ + TO """ + + " ".concat(table).concat(" ") + + """ """); } - private static void recreatePrimaryConstraint(Statement statement, String table, String constraintKey, String key) - throws SQLException { + private static void recreatePrimaryConstraint( + Statement statement, String table, String constraintKey, String key) throws SQLException { // Add primary key - statement.executeUpdate(""" - ALTER TABLE """ + " ".concat(table).concat(" ") + """ - ADD CONSTRAINT """ + " ".concat(constraintKey).concat(" ") + """ + statement.executeUpdate( + """ + ALTER TABLE """ + + " ".concat(table).concat(" ") + + """ + ADD CONSTRAINT """ + + " ".concat(constraintKey).concat(" ") + + """ PRIMARY KEY ( - """ + " ".concat(key).concat(" ") + """ + """ + + " ".concat(key).concat(" ") + + """ , tag_id ); """); } - } diff --git a/openbas-api/src/main/java/io/openbas/migration/V2_79__Injectors.java b/openbas-api/src/main/java/io/openbas/migration/V2_79__Injectors.java index e723913716..2c95396587 100644 --- a/openbas-api/src/main/java/io/openbas/migration/V2_79__Injectors.java +++ b/openbas-api/src/main/java/io/openbas/migration/V2_79__Injectors.java @@ -1,12 +1,11 @@ package io.openbas.migration; +import java.sql.Connection; +import java.sql.Statement; import org.flywaydb.core.api.migration.BaseJavaMigration; import org.flywaydb.core.api.migration.Context; import org.springframework.stereotype.Component; -import java.sql.Connection; -import java.sql.Statement; - @Component public class V2_79__Injectors extends BaseJavaMigration { @@ -15,7 +14,8 @@ public void migrate(Context context) throws Exception { Connection connection = context.getConnection(); Statement select = connection.createStatement(); // Create table - select.execute(""" + select.execute( + """ CREATE TABLE injectors ( injector_id varchar(255) not null constraint injector_pkey primary key, injector_created_at timestamp not null default now(), diff --git a/openbas-api/src/main/java/io/openbas/migration/V2_7__Model_adaptation.java b/openbas-api/src/main/java/io/openbas/migration/V2_7__Model_adaptation.java index bfaf173cb9..0b5d7ce674 100644 --- a/openbas-api/src/main/java/io/openbas/migration/V2_7__Model_adaptation.java +++ b/openbas-api/src/main/java/io/openbas/migration/V2_7__Model_adaptation.java @@ -1,23 +1,22 @@ package io.openbas.migration; +import java.sql.Statement; import org.flywaydb.core.api.migration.BaseJavaMigration; import org.flywaydb.core.api.migration.Context; import org.springframework.stereotype.Component; -import java.sql.Statement; - @Component public class V2_7__Model_adaptation extends BaseJavaMigration { - @Override - public void migrate(Context context) throws Exception { - Statement select = context.getConnection().createStatement(); - // Exercise - select.execute("ALTER TABLE exercises ALTER COLUMN exercise_description DROP NOT NULL "); - // User - select.execute("ALTER TABLE users ALTER COLUMN user_firstname DROP NOT NULL "); - select.execute("ALTER TABLE users ALTER COLUMN user_lastname DROP NOT NULL "); - // Group - select.execute("ALTER TABLE groups ADD group_description text;"); - } + @Override + public void migrate(Context context) throws Exception { + Statement select = context.getConnection().createStatement(); + // Exercise + select.execute("ALTER TABLE exercises ALTER COLUMN exercise_description DROP NOT NULL "); + // User + select.execute("ALTER TABLE users ALTER COLUMN user_firstname DROP NOT NULL "); + select.execute("ALTER TABLE users ALTER COLUMN user_lastname DROP NOT NULL "); + // Group + select.execute("ALTER TABLE groups ADD group_description text;"); + } } diff --git a/openbas-api/src/main/java/io/openbas/migration/V2_80__Inject_status.java b/openbas-api/src/main/java/io/openbas/migration/V2_80__Inject_status.java index 76a527acf7..88627dec96 100644 --- a/openbas-api/src/main/java/io/openbas/migration/V2_80__Inject_status.java +++ b/openbas-api/src/main/java/io/openbas/migration/V2_80__Inject_status.java @@ -1,12 +1,11 @@ package io.openbas.migration; +import java.sql.Connection; +import java.sql.Statement; import org.flywaydb.core.api.migration.BaseJavaMigration; import org.flywaydb.core.api.migration.Context; import org.springframework.stereotype.Component; -import java.sql.Connection; -import java.sql.Statement; - @Component public class V2_80__Inject_status extends BaseJavaMigration { @@ -17,8 +16,10 @@ public void migrate(Context context) throws Exception { // Inject statuses select.execute("ALTER TABLE injects_statuses DROP status_async_ids"); select.execute("ALTER TABLE injects_statuses RENAME status_date TO tracking_sent_date"); - select.execute("ALTER TABLE injects_statuses RENAME status_execution TO tracking_total_execution_time"); - select.execute("ALTER TABLE injects_statuses ALTER column tracking_total_execution_time type bigint"); + select.execute( + "ALTER TABLE injects_statuses RENAME status_execution TO tracking_total_execution_time"); + select.execute( + "ALTER TABLE injects_statuses ALTER column tracking_total_execution_time type bigint"); select.execute("ALTER TABLE injects_statuses ADD status_executions text;"); select.execute("ALTER TABLE injects_statuses ADD tracking_ack_date timestamp;"); select.execute("ALTER TABLE injects_statuses ADD tracking_end_date timestamp;"); @@ -27,8 +28,10 @@ public void migrate(Context context) throws Exception { select.execute("ALTER TABLE injects_statuses ADD tracking_total_success int;"); // Dry Inject statuses select.execute("ALTER TABLE dryinjects_statuses RENAME status_date TO tracking_sent_date"); - select.execute("ALTER TABLE dryinjects_statuses RENAME status_execution TO tracking_total_execution_time"); - select.execute("ALTER TABLE dryinjects_statuses ALTER column tracking_total_execution_time type bigint"); + select.execute( + "ALTER TABLE dryinjects_statuses RENAME status_execution TO tracking_total_execution_time"); + select.execute( + "ALTER TABLE dryinjects_statuses ALTER column tracking_total_execution_time type bigint"); select.execute("ALTER TABLE dryinjects_statuses ADD status_executions text;"); select.execute("ALTER TABLE dryinjects_statuses ADD tracking_ack_date timestamp;"); select.execute("ALTER TABLE dryinjects_statuses ADD tracking_end_date timestamp;"); diff --git a/openbas-api/src/main/java/io/openbas/migration/V2_81__Contracts.java b/openbas-api/src/main/java/io/openbas/migration/V2_81__Contracts.java index 09eb243604..3c3cde8822 100644 --- a/openbas-api/src/main/java/io/openbas/migration/V2_81__Contracts.java +++ b/openbas-api/src/main/java/io/openbas/migration/V2_81__Contracts.java @@ -1,12 +1,11 @@ package io.openbas.migration; +import java.sql.Connection; +import java.sql.Statement; import org.flywaydb.core.api.migration.BaseJavaMigration; import org.flywaydb.core.api.migration.Context; import org.springframework.stereotype.Component; -import java.sql.Connection; -import java.sql.Statement; - @Component public class V2_81__Contracts extends BaseJavaMigration { @@ -17,7 +16,8 @@ public void migrate(Context context) throws Exception { // Cleanup injectors select.execute("ALTER TABLE injectors DROP column injector_contracts;"); // Create injectors_contracts table - select.execute(""" + select.execute( + """ CREATE TABLE injectors_contracts ( injector_contract_id varchar(255) not null constraint injector_contract_pkey primary key, injector_contract_created_at timestamp not null default now(), @@ -33,7 +33,8 @@ injector_id varchar(255) not null CREATE INDEX idx_injectors_contracts on injectors_contracts (injector_contract_id); """); // Create relations between contracts and attack_patterns - select.execute(""" + select.execute( + """ CREATE TABLE injectors_contracts_attack_patterns ( attack_pattern_id varchar(255) not null constraint attack_pattern_id_fk diff --git a/openbas-api/src/main/java/io/openbas/migration/V2_82__Collectors.java b/openbas-api/src/main/java/io/openbas/migration/V2_82__Collectors.java index 879afd97f9..6114e716a9 100644 --- a/openbas-api/src/main/java/io/openbas/migration/V2_82__Collectors.java +++ b/openbas-api/src/main/java/io/openbas/migration/V2_82__Collectors.java @@ -1,12 +1,11 @@ package io.openbas.migration; +import java.sql.Connection; +import java.sql.Statement; import org.flywaydb.core.api.migration.BaseJavaMigration; import org.flywaydb.core.api.migration.Context; import org.springframework.stereotype.Component; -import java.sql.Connection; -import java.sql.Statement; - @Component public class V2_82__Collectors extends BaseJavaMigration { @@ -15,7 +14,8 @@ public void migrate(Context context) throws Exception { Connection connection = context.getConnection(); Statement select = connection.createStatement(); // Create table - select.execute(""" + select.execute( + """ CREATE TABLE collectors ( collector_id varchar(255) not null constraint collector_pkey primary key, collector_created_at timestamp not null default now(), diff --git a/openbas-api/src/main/java/io/openbas/migration/V2_83__Scenario_recurrence.java b/openbas-api/src/main/java/io/openbas/migration/V2_83__Scenario_recurrence.java index 96ea8ced81..9c00cee7a9 100644 --- a/openbas-api/src/main/java/io/openbas/migration/V2_83__Scenario_recurrence.java +++ b/openbas-api/src/main/java/io/openbas/migration/V2_83__Scenario_recurrence.java @@ -1,12 +1,11 @@ package io.openbas.migration; +import java.sql.Connection; +import java.sql.Statement; import org.flywaydb.core.api.migration.BaseJavaMigration; import org.flywaydb.core.api.migration.Context; import org.springframework.stereotype.Component; -import java.sql.Connection; -import java.sql.Statement; - @Component public class V2_83__Scenario_recurrence extends BaseJavaMigration { @@ -15,12 +14,14 @@ public void migrate(Context context) throws Exception { Connection connection = context.getConnection(); Statement select = connection.createStatement(); // Add recurrence to scenario - select.executeUpdate(""" + select.executeUpdate( + """ ALTER TABLE scenarios ADD COLUMN scenario_recurrence varchar(256); ALTER TABLE scenarios ADD COLUMN scenario_recurrence_start timestamp; """); // Add association table between scenario and exercise - select.execute(""" + select.execute( + """ CREATE TABLE scenario_exercise ( scenario_id varchar(255) not null constraint scenario_id_fk references scenarios on delete cascade, exercise_id varchar(255) not null constraint exercise_id_fk references exercises on delete cascade, diff --git a/openbas-api/src/main/java/io/openbas/migration/V2_84__Scenario_recurrence_end_date.java b/openbas-api/src/main/java/io/openbas/migration/V2_84__Scenario_recurrence_end_date.java index 3e828680c9..db16199305 100644 --- a/openbas-api/src/main/java/io/openbas/migration/V2_84__Scenario_recurrence_end_date.java +++ b/openbas-api/src/main/java/io/openbas/migration/V2_84__Scenario_recurrence_end_date.java @@ -1,12 +1,11 @@ package io.openbas.migration; +import java.sql.Connection; +import java.sql.Statement; import org.flywaydb.core.api.migration.BaseJavaMigration; import org.flywaydb.core.api.migration.Context; import org.springframework.stereotype.Component; -import java.sql.Connection; -import java.sql.Statement; - @Component public class V2_84__Scenario_recurrence_end_date extends BaseJavaMigration { @@ -15,7 +14,8 @@ public void migrate(Context context) throws Exception { Connection connection = context.getConnection(); Statement select = connection.createStatement(); // Add end date recurrence to scenario - select.executeUpdate(""" + select.executeUpdate( + """ ALTER TABLE scenarios ADD COLUMN scenario_recurrence_end timestamp; """); } diff --git a/openbas-api/src/main/java/io/openbas/migration/V2_85__Full_text_search.java b/openbas-api/src/main/java/io/openbas/migration/V2_85__Full_text_search.java index a0efc09f9c..d290d06985 100644 --- a/openbas-api/src/main/java/io/openbas/migration/V2_85__Full_text_search.java +++ b/openbas-api/src/main/java/io/openbas/migration/V2_85__Full_text_search.java @@ -1,12 +1,11 @@ package io.openbas.migration; +import java.sql.Connection; +import java.sql.Statement; import org.flywaydb.core.api.migration.BaseJavaMigration; import org.flywaydb.core.api.migration.Context; import org.springframework.stereotype.Component; -import java.sql.Connection; -import java.sql.Statement; - @Component public class V2_85__Full_text_search extends BaseJavaMigration { @@ -15,9 +14,10 @@ public void migrate(Context context) throws Exception { Connection connection = context.getConnection(); Statement select = connection.createStatement(); // Add full text search index on assets, assets groups, players, teams, organizations - select.execute(""" + select.execute( + """ CREATE EXTENSION IF NOT EXISTS pg_trgm; - + CREATE INDEX idx_pg_trgm_assets_asset_name ON assets USING gin(to_tsvector('simple', asset_name)); CREATE INDEX idx_pg_trgm_asset_groups_asset_group_name ON asset_groups USING gin(to_tsvector('simple', asset_group_name)); CREATE INDEX idx_pg_trgm_users_user_email ON users USING gin(to_tsvector('simple', user_email)); diff --git a/openbas-api/src/main/java/io/openbas/migration/V2_86__Add_column_atomic_testing_to_injectors_contracts.java b/openbas-api/src/main/java/io/openbas/migration/V2_86__Add_column_atomic_testing_to_injectors_contracts.java index 76c5487564..2f8dabd44f 100644 --- a/openbas-api/src/main/java/io/openbas/migration/V2_86__Add_column_atomic_testing_to_injectors_contracts.java +++ b/openbas-api/src/main/java/io/openbas/migration/V2_86__Add_column_atomic_testing_to_injectors_contracts.java @@ -13,12 +13,16 @@ public class V2_86__Add_column_atomic_testing_to_injectors_contracts extends Bas public void migrate(Context context) throws Exception { Connection connection = context.getConnection(); Statement select = connection.createStatement(); - select.execute(""" + select.execute( + """ ALTER TABLE injectors_contracts ADD COLUMN injector_contract_atomic_testing bool not null default true; """); // Update injects contracts - select.executeUpdate("UPDATE injectors_contracts SET injector_contract_atomic_testing='false' WHERE injectors_contracts.injector_contract_id = 'd02e9132-b9d0-4daa-b3b1-4b9871f8472c';"); - select.executeUpdate("UPDATE injectors_contracts SET injector_contract_atomic_testing='false' WHERE injectors_contracts.injector_contract_id = 'fb5e49a2-6366-4492-b69a-f9b9f39a533e';"); - select.executeUpdate("UPDATE injectors_contracts SET injector_contract_atomic_testing='false' WHERE injectors_contracts.injector_contract_id = 'f8e70b27-a69c-4b9f-a2df-e217c36b3981';"); + select.executeUpdate( + "UPDATE injectors_contracts SET injector_contract_atomic_testing='false' WHERE injectors_contracts.injector_contract_id = 'd02e9132-b9d0-4daa-b3b1-4b9871f8472c';"); + select.executeUpdate( + "UPDATE injectors_contracts SET injector_contract_atomic_testing='false' WHERE injectors_contracts.injector_contract_id = 'fb5e49a2-6366-4492-b69a-f9b9f39a533e';"); + select.executeUpdate( + "UPDATE injectors_contracts SET injector_contract_atomic_testing='false' WHERE injectors_contracts.injector_contract_id = 'f8e70b27-a69c-4b9f-a2df-e217c36b3981';"); } } diff --git a/openbas-api/src/main/java/io/openbas/migration/V2_87__Delete_constraint_not_null_inject_expectations_exercise.java b/openbas-api/src/main/java/io/openbas/migration/V2_87__Delete_constraint_not_null_inject_expectations_exercise.java index cf22bfb19a..65a2d7f1c3 100644 --- a/openbas-api/src/main/java/io/openbas/migration/V2_87__Delete_constraint_not_null_inject_expectations_exercise.java +++ b/openbas-api/src/main/java/io/openbas/migration/V2_87__Delete_constraint_not_null_inject_expectations_exercise.java @@ -6,7 +6,8 @@ import org.springframework.stereotype.Component; @Component -public class V2_87__Delete_constraint_not_null_inject_expectations_exercise extends BaseJavaMigration { +public class V2_87__Delete_constraint_not_null_inject_expectations_exercise + extends BaseJavaMigration { @Override public void migrate(Context context) throws Exception { diff --git a/openbas-api/src/main/java/io/openbas/migration/V2_88__Truncate_injector_collector.java b/openbas-api/src/main/java/io/openbas/migration/V2_88__Truncate_injector_collector.java index 896acae4b5..d64f86d32f 100644 --- a/openbas-api/src/main/java/io/openbas/migration/V2_88__Truncate_injector_collector.java +++ b/openbas-api/src/main/java/io/openbas/migration/V2_88__Truncate_injector_collector.java @@ -1,11 +1,10 @@ package io.openbas.migration; +import java.sql.Statement; import org.flywaydb.core.api.migration.BaseJavaMigration; import org.flywaydb.core.api.migration.Context; import org.springframework.stereotype.Component; -import java.sql.Statement; - @Component public class V2_88__Truncate_injector_collector extends BaseJavaMigration { diff --git a/openbas-api/src/main/java/io/openbas/migration/V2_89__Add_foreign_key_injector_contract_to_inject.java b/openbas-api/src/main/java/io/openbas/migration/V2_89__Add_foreign_key_injector_contract_to_inject.java index 3e7d8542d7..b284f56a24 100644 --- a/openbas-api/src/main/java/io/openbas/migration/V2_89__Add_foreign_key_injector_contract_to_inject.java +++ b/openbas-api/src/main/java/io/openbas/migration/V2_89__Add_foreign_key_injector_contract_to_inject.java @@ -7,8 +7,8 @@ @Component public class V2_89__Add_foreign_key_injector_contract_to_inject extends BaseJavaMigration { - @Override - public void migrate(Context context) throws Exception { - // DO NOTHING - } + @Override + public void migrate(Context context) throws Exception { + // DO NOTHING + } } diff --git a/openbas-api/src/main/java/io/openbas/migration/V2_8__Cleanup_model.java b/openbas-api/src/main/java/io/openbas/migration/V2_8__Cleanup_model.java index f16a5da658..c0855f84d9 100644 --- a/openbas-api/src/main/java/io/openbas/migration/V2_8__Cleanup_model.java +++ b/openbas-api/src/main/java/io/openbas/migration/V2_8__Cleanup_model.java @@ -1,23 +1,23 @@ package io.openbas.migration; +import java.sql.Statement; import org.flywaydb.core.api.migration.BaseJavaMigration; import org.flywaydb.core.api.migration.Context; import org.springframework.stereotype.Component; -import java.sql.Statement; - @Component public class V2_8__Cleanup_model extends BaseJavaMigration { - @Override - public void migrate(Context context) throws Exception { - Statement select = context.getConnection().createStatement(); - // User - select.execute("ALTER TABLE users DROP column user_login;"); - // Exercise - select.execute("ALTER TABLE exercises DROP column exercise_latitude;"); - select.execute("ALTER TABLE exercises DROP column exercise_longitude;"); - select.execute("ALTER TABLE exercises DROP column exercise_type;"); - select.execute("ALTER TABLE exercises RENAME COLUMN exercise_mail_expediteur TO exercise_mail_from;"); - } + @Override + public void migrate(Context context) throws Exception { + Statement select = context.getConnection().createStatement(); + // User + select.execute("ALTER TABLE users DROP column user_login;"); + // Exercise + select.execute("ALTER TABLE exercises DROP column exercise_latitude;"); + select.execute("ALTER TABLE exercises DROP column exercise_longitude;"); + select.execute("ALTER TABLE exercises DROP column exercise_type;"); + select.execute( + "ALTER TABLE exercises RENAME COLUMN exercise_mail_expediteur TO exercise_mail_from;"); + } } diff --git a/openbas-api/src/main/java/io/openbas/migration/V2_90__Custom_injectors.java b/openbas-api/src/main/java/io/openbas/migration/V2_90__Custom_injectors.java index 160b62f5b2..f11a494ec5 100644 --- a/openbas-api/src/main/java/io/openbas/migration/V2_90__Custom_injectors.java +++ b/openbas-api/src/main/java/io/openbas/migration/V2_90__Custom_injectors.java @@ -1,18 +1,17 @@ package io.openbas.migration; +import java.sql.Statement; import org.flywaydb.core.api.migration.BaseJavaMigration; import org.flywaydb.core.api.migration.Context; import org.springframework.stereotype.Component; -import java.sql.Statement; - @Component public class V2_90__Custom_injectors extends BaseJavaMigration { - @Override - public void migrate(Context context) throws Exception { - Statement select = context.getConnection().createStatement(); - select.execute("ALTER TABLE injectors ADD injector_custom_contracts bool default false;"); - select.execute("ALTER TABLE injectors ADD injector_contract_template text;"); - } + @Override + public void migrate(Context context) throws Exception { + Statement select = context.getConnection().createStatement(); + select.execute("ALTER TABLE injectors ADD injector_custom_contracts bool default false;"); + select.execute("ALTER TABLE injectors ADD injector_contract_template text;"); + } } diff --git a/openbas-api/src/main/java/io/openbas/migration/V2_91__Custom_inject_contracts.java b/openbas-api/src/main/java/io/openbas/migration/V2_91__Custom_inject_contracts.java index d61908d7cc..bc5b523ed6 100644 --- a/openbas-api/src/main/java/io/openbas/migration/V2_91__Custom_inject_contracts.java +++ b/openbas-api/src/main/java/io/openbas/migration/V2_91__Custom_inject_contracts.java @@ -1,18 +1,18 @@ package io.openbas.migration; +import java.sql.Statement; import org.flywaydb.core.api.migration.BaseJavaMigration; import org.flywaydb.core.api.migration.Context; import org.springframework.stereotype.Component; -import java.sql.Statement; - @Component public class V2_91__Custom_inject_contracts extends BaseJavaMigration { - @Override - public void migrate(Context context) throws Exception { - Statement select = context.getConnection().createStatement(); - select.execute("ALTER TABLE injectors_contracts ADD injector_contract_custom bool default false;"); - select.execute("ALTER TABLE injectors DROP injector_contract_template;"); - } + @Override + public void migrate(Context context) throws Exception { + Statement select = context.getConnection().createStatement(); + select.execute( + "ALTER TABLE injectors_contracts ADD injector_contract_custom bool default false;"); + select.execute("ALTER TABLE injectors DROP injector_contract_template;"); + } } diff --git a/openbas-api/src/main/java/io/openbas/migration/V2_92__Collectors_external.java b/openbas-api/src/main/java/io/openbas/migration/V2_92__Collectors_external.java index 1336ad0c3b..c79f581dd2 100644 --- a/openbas-api/src/main/java/io/openbas/migration/V2_92__Collectors_external.java +++ b/openbas-api/src/main/java/io/openbas/migration/V2_92__Collectors_external.java @@ -1,17 +1,16 @@ package io.openbas.migration; +import java.sql.Statement; import org.flywaydb.core.api.migration.BaseJavaMigration; import org.flywaydb.core.api.migration.Context; import org.springframework.stereotype.Component; -import java.sql.Statement; - @Component public class V2_92__Collectors_external extends BaseJavaMigration { - @Override - public void migrate(Context context) throws Exception { - Statement select = context.getConnection().createStatement(); - select.execute("ALTER TABLE collectors ADD collector_external bool default false not null;"); - } + @Override + public void migrate(Context context) throws Exception { + Statement select = context.getConnection().createStatement(); + select.execute("ALTER TABLE collectors ADD collector_external bool default false not null;"); + } } diff --git a/openbas-api/src/main/java/io/openbas/migration/V2_93__Payloads.java b/openbas-api/src/main/java/io/openbas/migration/V2_93__Payloads.java index 6201593935..020b253399 100644 --- a/openbas-api/src/main/java/io/openbas/migration/V2_93__Payloads.java +++ b/openbas-api/src/main/java/io/openbas/migration/V2_93__Payloads.java @@ -1,12 +1,11 @@ package io.openbas.migration; +import java.sql.Connection; +import java.sql.Statement; import org.flywaydb.core.api.migration.BaseJavaMigration; import org.flywaydb.core.api.migration.Context; import org.springframework.stereotype.Component; -import java.sql.Connection; -import java.sql.Statement; - @Component public class V2_93__Payloads extends BaseJavaMigration { @@ -19,7 +18,8 @@ public void migrate(Context context) throws Exception { select.execute("TRUNCATE kill_chain_phases CASCADE;"); // Create table payloads - select.execute(""" + select.execute( + """ CREATE TABLE IF NOT EXISTS payloads ( payload_id varchar(255) not null constraint payloads_pkey primary key, payload_type varchar(255) not null, @@ -32,7 +32,8 @@ payload_updated_at timestamp not null default now() CREATE INDEX IF NOT EXISTS idx_payloads on payloads (payload_id); """); // Add association table between payload and tag - select.execute(""" + select.execute( + """ CREATE TABLE payloads_tags ( payload_id varchar(255) not null constraint payload_id_fk references payloads, tag_id varchar(255) not null constraint tag_id_fk references tags, @@ -42,7 +43,8 @@ constraint payloads_tags_pkey primary key (payload_id, tag_id) CREATE INDEX idx_payloads_tags_tag on payloads_tags (tag_id); """); // Add association table between payload and inject - select.execute(""" + select.execute( + """ CREATE TABLE injects_payloads ( inject_id varchar(255) not null constraint inject_id_fk references injects on delete cascade, payload_id varchar(255) not null constraint payload_id_fk references payloads on delete cascade, diff --git a/openbas-api/src/main/java/io/openbas/migration/V2_94__Remove_foreign_key_injector_contract_to_inject.java b/openbas-api/src/main/java/io/openbas/migration/V2_94__Remove_foreign_key_injector_contract_to_inject.java index 61ec0bceeb..9adfa35c70 100644 --- a/openbas-api/src/main/java/io/openbas/migration/V2_94__Remove_foreign_key_injector_contract_to_inject.java +++ b/openbas-api/src/main/java/io/openbas/migration/V2_94__Remove_foreign_key_injector_contract_to_inject.java @@ -1,12 +1,11 @@ package io.openbas.migration; +import java.sql.Connection; +import java.sql.Statement; import org.flywaydb.core.api.migration.BaseJavaMigration; import org.flywaydb.core.api.migration.Context; import org.springframework.stereotype.Component; -import java.sql.Connection; -import java.sql.Statement; - @Component public class V2_94__Remove_foreign_key_injector_contract_to_inject extends BaseJavaMigration { @@ -14,8 +13,6 @@ public class V2_94__Remove_foreign_key_injector_contract_to_inject extends BaseJ public void migrate(Context context) throws Exception { Connection connection = context.getConnection(); Statement select = connection.createStatement(); - select.execute( - "ALTER TABLE injects DROP CONSTRAINT IF EXISTS injector_contract_fk" - ); + select.execute("ALTER TABLE injects DROP CONSTRAINT IF EXISTS injector_contract_fk"); } } diff --git a/openbas-api/src/main/java/io/openbas/migration/V2_95__Truncate_assets.java b/openbas-api/src/main/java/io/openbas/migration/V2_95__Truncate_assets.java index bca49f8adb..1825fd95e4 100644 --- a/openbas-api/src/main/java/io/openbas/migration/V2_95__Truncate_assets.java +++ b/openbas-api/src/main/java/io/openbas/migration/V2_95__Truncate_assets.java @@ -1,12 +1,11 @@ package io.openbas.migration; +import java.sql.Connection; +import java.sql.Statement; import org.flywaydb.core.api.migration.BaseJavaMigration; import org.flywaydb.core.api.migration.Context; import org.springframework.stereotype.Component; -import java.sql.Connection; -import java.sql.Statement; - @Component public class V2_95__Truncate_assets extends BaseJavaMigration { diff --git a/openbas-api/src/main/java/io/openbas/migration/V2_96__Mitigations.java b/openbas-api/src/main/java/io/openbas/migration/V2_96__Mitigations.java index 973b3c9d94..bc55b07a87 100644 --- a/openbas-api/src/main/java/io/openbas/migration/V2_96__Mitigations.java +++ b/openbas-api/src/main/java/io/openbas/migration/V2_96__Mitigations.java @@ -1,12 +1,11 @@ package io.openbas.migration; +import java.sql.Connection; +import java.sql.Statement; import org.flywaydb.core.api.migration.BaseJavaMigration; import org.flywaydb.core.api.migration.Context; import org.springframework.stereotype.Component; -import java.sql.Connection; -import java.sql.Statement; - @Component public class V2_96__Mitigations extends BaseJavaMigration { @@ -15,7 +14,8 @@ public void migrate(Context context) throws Exception { Connection connection = context.getConnection(); Statement select = connection.createStatement(); // Mitigations - select.execute(""" + select.execute( + """ CREATE TABLE mitigations ( mitigation_id varchar(255) not null constraint mitigations_pkey primary key, mitigation_created_at timestamp not null default now(), @@ -30,7 +30,8 @@ mitigation_stix_id varchar(255) not null, CREATE INDEX idx_mitigations on mitigations (mitigation_id); CREATE UNIQUE INDEX mitigations_unique on mitigations (mitigation_external_id); """); - select.execute(""" + select.execute( + """ CREATE TABLE mitigations_attack_patterns ( mitigation_id varchar(255) not null constraint mitigation_id_fk diff --git a/openbas-api/src/main/java/io/openbas/migration/V2_97__Injector_agents.java b/openbas-api/src/main/java/io/openbas/migration/V2_97__Injector_agents.java index a8ec814fd4..dbc1f95ccf 100644 --- a/openbas-api/src/main/java/io/openbas/migration/V2_97__Injector_agents.java +++ b/openbas-api/src/main/java/io/openbas/migration/V2_97__Injector_agents.java @@ -1,12 +1,10 @@ package io.openbas.migration; +import java.sql.Statement; import org.flywaydb.core.api.migration.BaseJavaMigration; import org.flywaydb.core.api.migration.Context; import org.springframework.stereotype.Component; -import java.sql.Connection; -import java.sql.Statement; - @Component public class V2_97__Injector_agents extends BaseJavaMigration { diff --git a/openbas-api/src/main/java/io/openbas/migration/V2_98__Scenario_enhancement.java b/openbas-api/src/main/java/io/openbas/migration/V2_98__Scenario_enhancement.java index 94860fd644..d9b7e30f64 100644 --- a/openbas-api/src/main/java/io/openbas/migration/V2_98__Scenario_enhancement.java +++ b/openbas-api/src/main/java/io/openbas/migration/V2_98__Scenario_enhancement.java @@ -1,11 +1,10 @@ package io.openbas.migration; +import java.sql.Statement; import org.flywaydb.core.api.migration.BaseJavaMigration; import org.flywaydb.core.api.migration.Context; import org.springframework.stereotype.Component; -import java.sql.Statement; - @Component public class V2_98__Scenario_enhancement extends BaseJavaMigration { diff --git a/openbas-api/src/main/java/io/openbas/migration/V2_99__Injector_contracts_platforms.java b/openbas-api/src/main/java/io/openbas/migration/V2_99__Injector_contracts_platforms.java index 08c07857de..8e4dfa2bcf 100644 --- a/openbas-api/src/main/java/io/openbas/migration/V2_99__Injector_contracts_platforms.java +++ b/openbas-api/src/main/java/io/openbas/migration/V2_99__Injector_contracts_platforms.java @@ -1,11 +1,10 @@ package io.openbas.migration; +import java.sql.Statement; import org.flywaydb.core.api.migration.BaseJavaMigration; import org.flywaydb.core.api.migration.Context; import org.springframework.stereotype.Component; -import java.sql.Statement; - @Component public class V2_99__Injector_contracts_platforms extends BaseJavaMigration { diff --git a/openbas-api/src/main/java/io/openbas/migration/V2_9__Improve_model.java b/openbas-api/src/main/java/io/openbas/migration/V2_9__Improve_model.java index 0ed44ca814..c9f6656b11 100644 --- a/openbas-api/src/main/java/io/openbas/migration/V2_9__Improve_model.java +++ b/openbas-api/src/main/java/io/openbas/migration/V2_9__Improve_model.java @@ -1,26 +1,25 @@ package io.openbas.migration; +import java.sql.Statement; import org.flywaydb.core.api.migration.BaseJavaMigration; import org.flywaydb.core.api.migration.Context; import org.springframework.stereotype.Component; -import java.sql.Statement; - @Component public class V2_9__Improve_model extends BaseJavaMigration { - @Override - public void migrate(Context context) throws Exception { - Statement select = context.getConnection().createStatement(); - // User - select.execute("ALTER TABLE users DROP column user_latitude;"); - select.execute("ALTER TABLE users DROP column user_longitude;"); - select.execute("ALTER TABLE users ADD user_country varchar(255);"); - select.execute("ALTER TABLE users ADD user_city varchar(255);"); - // Inject - select.execute("ALTER TABLE injects DROP column inject_latitude;"); - select.execute("ALTER TABLE injects DROP column inject_longitude;"); - select.execute("ALTER TABLE injects ADD inject_country varchar(255);"); - select.execute("ALTER TABLE injects ADD inject_city varchar(255);"); - } + @Override + public void migrate(Context context) throws Exception { + Statement select = context.getConnection().createStatement(); + // User + select.execute("ALTER TABLE users DROP column user_latitude;"); + select.execute("ALTER TABLE users DROP column user_longitude;"); + select.execute("ALTER TABLE users ADD user_country varchar(255);"); + select.execute("ALTER TABLE users ADD user_city varchar(255);"); + // Inject + select.execute("ALTER TABLE injects DROP column inject_latitude;"); + select.execute("ALTER TABLE injects DROP column inject_longitude;"); + select.execute("ALTER TABLE injects ADD inject_country varchar(255);"); + select.execute("ALTER TABLE injects ADD inject_city varchar(255);"); + } } diff --git a/openbas-api/src/main/java/io/openbas/migration/V3_01__Link_injects_contracts.java b/openbas-api/src/main/java/io/openbas/migration/V3_01__Link_injects_contracts.java index 550a5e3ccc..1c378739f2 100644 --- a/openbas-api/src/main/java/io/openbas/migration/V3_01__Link_injects_contracts.java +++ b/openbas-api/src/main/java/io/openbas/migration/V3_01__Link_injects_contracts.java @@ -1,64 +1,82 @@ package io.openbas.migration; import com.fasterxml.jackson.databind.ObjectMapper; -import org.flywaydb.core.api.migration.BaseJavaMigration; -import org.flywaydb.core.api.migration.Context; -import org.springframework.stereotype.Component; - import java.sql.Connection; import java.sql.PreparedStatement; import java.sql.ResultSet; import java.sql.Statement; -import java.util.Objects; +import org.flywaydb.core.api.migration.BaseJavaMigration; +import org.flywaydb.core.api.migration.Context; +import org.springframework.stereotype.Component; @Component public class V3_01__Link_injects_contracts extends BaseJavaMigration { - @Override - public void migrate(Context context) throws Exception { - Connection connection = context.getConnection(); - Statement statement = connection.createStatement(); + @Override + public void migrate(Context context) throws Exception { + Connection connection = context.getConnection(); + Statement statement = connection.createStatement(); - // Migration datas - ObjectMapper mapper = new ObjectMapper(); - ResultSet resultsInjects = statement.executeQuery("SELECT * FROM injects"); + // Migration datas + ObjectMapper mapper = new ObjectMapper(); + ResultSet resultsInjects = statement.executeQuery("SELECT * FROM injects"); - PreparedStatement statementInjectors = connection.prepareStatement("INSERT INTO injectors (injector_id, injector_name, injector_type) VALUES (?, ?, ?) ON CONFLICT DO NOTHING"); - PreparedStatement statementInjectorsContracts = connection.prepareStatement("INSERT INTO injectors_contracts (injector_contract_id, injector_id, injector_contract_labels, injector_contract_content) VALUES (?, ?, ?, '{}') ON CONFLICT DO NOTHING"); - while (resultsInjects.next()) { - Statement statement2 = connection.createStatement(); - String injectType = resultsInjects.getString("inject_type"); - String injectContract = resultsInjects.getString("inject_contract"); - String injectorId = injectType; - switch (injectType ){ - case "openex_email": - case "openbas_email": - injectorId = "41b4dd55-5bd1-4614-98cd-9e3770753306"; - break; - case "openex_manual": - case "openbas_manual": - injectorId = "6981a39d-e219-4016-a235-cf7747994abc"; - break; - case "openex_mastodon": - case "openbas_mastodon": - injectorId = "37cd1743-8975-43c0-837c-f99970142e72"; - break; - case "openex_ovh_sms": - case "openbas_ovh_sms": - injectorId = "e5aefbca-cf8f-4a57-9384-0503a8ffc22f"; - break; - case "openex_lade": - case "openbas_lade": - injectorId = "0097265b-0515-48a5-9bff-71d0f375fcc4"; - break; - } - statement2.executeUpdate("INSERT INTO injectors (injector_id, injector_name, injector_type) VALUES ('" + injectorId + "', '" + injectType + "','" + injectType + "') ON CONFLICT DO NOTHING"); - if( injectorId == null ) { - throw new Exception("An error occurred"); - } - statement2.executeUpdate("INSERT INTO injectors_contracts (injector_contract_id, injector_id, injector_contract_labels, injector_contract_content) VALUES ('" + injectContract + "', '" + injectorId + "','{\"en=>" + injectType + "\"}', '{}') ON CONFLICT DO NOTHING"); - statement2.close(); - } - statement.execute("ALTER TABLE injects RENAME COLUMN inject_contract TO inject_injector_contract;"); - statement.execute("ALTER TABLE injects ADD CONSTRAINT injector_contract_fk FOREIGN KEY (inject_injector_contract) REFERENCES injectors_contracts(injector_contract_id) ON DELETE SET NULL;"); + PreparedStatement statementInjectors = + connection.prepareStatement( + "INSERT INTO injectors (injector_id, injector_name, injector_type) VALUES (?, ?, ?) ON CONFLICT DO NOTHING"); + PreparedStatement statementInjectorsContracts = + connection.prepareStatement( + "INSERT INTO injectors_contracts (injector_contract_id, injector_id, injector_contract_labels, injector_contract_content) VALUES (?, ?, ?, '{}') ON CONFLICT DO NOTHING"); + while (resultsInjects.next()) { + Statement statement2 = connection.createStatement(); + String injectType = resultsInjects.getString("inject_type"); + String injectContract = resultsInjects.getString("inject_contract"); + String injectorId = injectType; + switch (injectType) { + case "openex_email": + case "openbas_email": + injectorId = "41b4dd55-5bd1-4614-98cd-9e3770753306"; + break; + case "openex_manual": + case "openbas_manual": + injectorId = "6981a39d-e219-4016-a235-cf7747994abc"; + break; + case "openex_mastodon": + case "openbas_mastodon": + injectorId = "37cd1743-8975-43c0-837c-f99970142e72"; + break; + case "openex_ovh_sms": + case "openbas_ovh_sms": + injectorId = "e5aefbca-cf8f-4a57-9384-0503a8ffc22f"; + break; + case "openex_lade": + case "openbas_lade": + injectorId = "0097265b-0515-48a5-9bff-71d0f375fcc4"; + break; + } + statement2.executeUpdate( + "INSERT INTO injectors (injector_id, injector_name, injector_type) VALUES ('" + + injectorId + + "', '" + + injectType + + "','" + + injectType + + "') ON CONFLICT DO NOTHING"); + if (injectorId == null) { + throw new Exception("An error occurred"); + } + statement2.executeUpdate( + "INSERT INTO injectors_contracts (injector_contract_id, injector_id, injector_contract_labels, injector_contract_content) VALUES ('" + + injectContract + + "', '" + + injectorId + + "','{\"en=>" + + injectType + + "\"}', '{}') ON CONFLICT DO NOTHING"); + statement2.close(); } + statement.execute( + "ALTER TABLE injects RENAME COLUMN inject_contract TO inject_injector_contract;"); + statement.execute( + "ALTER TABLE injects ADD CONSTRAINT injector_contract_fk FOREIGN KEY (inject_injector_contract) REFERENCES injectors_contracts(injector_contract_id) ON DELETE SET NULL;"); + } } diff --git a/openbas-api/src/main/java/io/openbas/migration/V3_02__Exercise_enhancement.java b/openbas-api/src/main/java/io/openbas/migration/V3_02__Exercise_enhancement.java index 9a07c2fa6f..751b3414de 100644 --- a/openbas-api/src/main/java/io/openbas/migration/V3_02__Exercise_enhancement.java +++ b/openbas-api/src/main/java/io/openbas/migration/V3_02__Exercise_enhancement.java @@ -1,11 +1,10 @@ package io.openbas.migration; +import java.sql.Statement; import org.flywaydb.core.api.migration.BaseJavaMigration; import org.flywaydb.core.api.migration.Context; import org.springframework.stereotype.Component; -import java.sql.Statement; - @Component public class V3_02__Exercise_enhancement extends BaseJavaMigration { diff --git a/openbas-api/src/main/java/io/openbas/migration/V3_03__Executors.java b/openbas-api/src/main/java/io/openbas/migration/V3_03__Executors.java index 76aeed2b31..50cdad72ba 100644 --- a/openbas-api/src/main/java/io/openbas/migration/V3_03__Executors.java +++ b/openbas-api/src/main/java/io/openbas/migration/V3_03__Executors.java @@ -1,12 +1,11 @@ package io.openbas.migration; +import java.sql.Connection; +import java.sql.Statement; import org.flywaydb.core.api.migration.BaseJavaMigration; import org.flywaydb.core.api.migration.Context; import org.springframework.stereotype.Component; -import java.sql.Connection; -import java.sql.Statement; - @Component public class V3_03__Executors extends BaseJavaMigration { @@ -15,7 +14,8 @@ public void migrate(Context context) throws Exception { Connection connection = context.getConnection(); Statement select = connection.createStatement(); // Create table - select.execute(""" + select.execute( + """ CREATE TABLE executors ( executor_id varchar(255) not null constraint executor_pkey primary key, executor_created_at timestamp not null default now(), @@ -31,7 +31,8 @@ executor_type varchar(255) not null, select.execute("ALTER TABLE injectors DROP column injector_simulation_agent;"); select.execute("ALTER TABLE injectors DROP column injector_simulation_agent_platforms;"); select.execute("ALTER TABLE injectors DROP column injector_simulation_agent_doc;"); - select.execute("ALTER TABLE injectors_contracts ADD injector_contract_needs_executor bool default false;"); + select.execute( + "ALTER TABLE injectors_contracts ADD injector_contract_needs_executor bool default false;"); select.execute("DELETE FROM collectors WHERE collector_type = 'openbas_caldera'"); } } diff --git a/openbas-api/src/main/java/io/openbas/migration/V3_04__Assets.java b/openbas-api/src/main/java/io/openbas/migration/V3_04__Assets.java index f3bf5a8d7a..8629dfec24 100644 --- a/openbas-api/src/main/java/io/openbas/migration/V3_04__Assets.java +++ b/openbas-api/src/main/java/io/openbas/migration/V3_04__Assets.java @@ -1,12 +1,11 @@ package io.openbas.migration; +import java.sql.Connection; +import java.sql.Statement; import org.flywaydb.core.api.migration.BaseJavaMigration; import org.flywaydb.core.api.migration.Context; import org.springframework.stereotype.Component; -import java.sql.Connection; -import java.sql.Statement; - @Component public class V3_04__Assets extends BaseJavaMigration { @@ -20,7 +19,8 @@ public void migrate(Context context) throws Exception { select.execute("ALTER TABLE assets ADD asset_executor varchar(255);"); select.execute("ALTER TABLE assets ADD asset_external_reference varchar(255);"); select.execute("ALTER TABLE assets ADD asset_temporary_execution bool default false;"); - select.execute("ALTER TABLE assets ADD CONSTRAINT executor_fk FOREIGN KEY (asset_executor) REFERENCES executors(executor_id) ON DELETE SET NULL;"); + select.execute( + "ALTER TABLE assets ADD CONSTRAINT executor_fk FOREIGN KEY (asset_executor) REFERENCES executors(executor_id) ON DELETE SET NULL;"); select.execute("ALTER TABLE injectors ADD injector_executor_commands hstore;"); } -} \ No newline at end of file +} diff --git a/openbas-api/src/main/java/io/openbas/migration/V3_05__Inject_type.java b/openbas-api/src/main/java/io/openbas/migration/V3_05__Inject_type.java index 68db20d272..5384ef9df7 100644 --- a/openbas-api/src/main/java/io/openbas/migration/V3_05__Inject_type.java +++ b/openbas-api/src/main/java/io/openbas/migration/V3_05__Inject_type.java @@ -1,12 +1,11 @@ package io.openbas.migration; +import java.sql.Connection; +import java.sql.Statement; import org.flywaydb.core.api.migration.BaseJavaMigration; import org.flywaydb.core.api.migration.Context; import org.springframework.stereotype.Component; -import java.sql.Connection; -import java.sql.Statement; - @Component public class V3_05__Inject_type extends BaseJavaMigration { @@ -16,4 +15,4 @@ public void migrate(Context context) throws Exception { Statement select = connection.createStatement(); select.execute("ALTER TABLE injects DROP column inject_type;"); } -} \ No newline at end of file +} diff --git a/openbas-api/src/main/java/io/openbas/migration/V3_06__Assets.java b/openbas-api/src/main/java/io/openbas/migration/V3_06__Assets.java index 847c2ff631..9f7733ea96 100644 --- a/openbas-api/src/main/java/io/openbas/migration/V3_06__Assets.java +++ b/openbas-api/src/main/java/io/openbas/migration/V3_06__Assets.java @@ -1,12 +1,11 @@ package io.openbas.migration; +import java.sql.Connection; +import java.sql.Statement; import org.flywaydb.core.api.migration.BaseJavaMigration; import org.flywaydb.core.api.migration.Context; import org.springframework.stereotype.Component; -import java.sql.Connection; -import java.sql.Statement; - @Component public class V3_06__Assets extends BaseJavaMigration { @@ -15,8 +14,10 @@ public void migrate(Context context) throws Exception { Connection connection = context.getConnection(); Statement select = connection.createStatement(); select.execute("ALTER TABLE assets DROP column asset_temporary_execution;"); - select.execute("ALTER TABLE assets ADD column asset_parent varchar(255) constraint asset_parent_fk references assets on delete cascade;"); - select.execute("ALTER TABLE assets ADD column asset_inject varchar(255) constraint asset_inject_fk references injects on delete cascade;"); + select.execute( + "ALTER TABLE assets ADD column asset_parent varchar(255) constraint asset_parent_fk references assets on delete cascade;"); + select.execute( + "ALTER TABLE assets ADD column asset_inject varchar(255) constraint asset_inject_fk references injects on delete cascade;"); select.execute("CREATE UNIQUE INDEX assets_unique on assets (asset_external_reference);"); } -} \ No newline at end of file +} diff --git a/openbas-api/src/main/java/io/openbas/migration/V3_07__Scenarios.java b/openbas-api/src/main/java/io/openbas/migration/V3_07__Scenarios.java index ed7538798d..6deef085f7 100644 --- a/openbas-api/src/main/java/io/openbas/migration/V3_07__Scenarios.java +++ b/openbas-api/src/main/java/io/openbas/migration/V3_07__Scenarios.java @@ -1,11 +1,10 @@ package io.openbas.migration; +import java.sql.Statement; import org.flywaydb.core.api.migration.BaseJavaMigration; import org.flywaydb.core.api.migration.Context; import org.springframework.stereotype.Component; -import java.sql.Statement; - @Component public class V3_07__Scenarios extends BaseJavaMigration { diff --git a/openbas-api/src/main/java/io/openbas/migration/V3_08__Injectors.java b/openbas-api/src/main/java/io/openbas/migration/V3_08__Injectors.java index a3157bc959..e4e8731d40 100644 --- a/openbas-api/src/main/java/io/openbas/migration/V3_08__Injectors.java +++ b/openbas-api/src/main/java/io/openbas/migration/V3_08__Injectors.java @@ -1,12 +1,11 @@ package io.openbas.migration; +import java.sql.Connection; +import java.sql.Statement; import org.flywaydb.core.api.migration.BaseJavaMigration; import org.flywaydb.core.api.migration.Context; import org.springframework.stereotype.Component; -import java.sql.Connection; -import java.sql.Statement; - @Component public class V3_08__Injectors extends BaseJavaMigration { @@ -16,4 +15,4 @@ public void migrate(Context context) throws Exception { Statement select = connection.createStatement(); select.execute("ALTER TABLE injectors ADD injector_executor_clear_commands hstore;"); } -} \ No newline at end of file +} diff --git a/openbas-api/src/main/java/io/openbas/migration/V3_09__Assets.java b/openbas-api/src/main/java/io/openbas/migration/V3_09__Assets.java index 74cc0f8c72..044d8a4829 100644 --- a/openbas-api/src/main/java/io/openbas/migration/V3_09__Assets.java +++ b/openbas-api/src/main/java/io/openbas/migration/V3_09__Assets.java @@ -1,12 +1,11 @@ package io.openbas.migration; +import java.sql.Connection; +import java.sql.Statement; import org.flywaydb.core.api.migration.BaseJavaMigration; import org.flywaydb.core.api.migration.Context; import org.springframework.stereotype.Component; -import java.sql.Connection; -import java.sql.Statement; - @Component public class V3_09__Assets extends BaseJavaMigration { @@ -16,4 +15,4 @@ public void migrate(Context context) throws Exception { Statement select = connection.createStatement(); select.execute("ALTER TABLE assets ADD column asset_cleared_at timestamp default now();"); } -} \ No newline at end of file +} diff --git a/openbas-api/src/main/java/io/openbas/migration/V3_10__Inject_expectation_signatures.java b/openbas-api/src/main/java/io/openbas/migration/V3_10__Inject_expectation_signatures.java index eda052af92..3a375b7eb3 100644 --- a/openbas-api/src/main/java/io/openbas/migration/V3_10__Inject_expectation_signatures.java +++ b/openbas-api/src/main/java/io/openbas/migration/V3_10__Inject_expectation_signatures.java @@ -1,12 +1,11 @@ package io.openbas.migration; +import java.sql.Connection; +import java.sql.Statement; import org.flywaydb.core.api.migration.BaseJavaMigration; import org.flywaydb.core.api.migration.Context; import org.springframework.stereotype.Component; -import java.sql.Connection; -import java.sql.Statement; - @Component public class V3_10__Inject_expectation_signatures extends BaseJavaMigration { @@ -15,6 +14,7 @@ public void migrate(Context context) throws Exception { Connection connection = context.getConnection(); Statement select = connection.createStatement(); // Migration the data - select.execute("ALTER TABLE injects_expectations ADD COLUMN inject_expectation_signatures json;"); + select.execute( + "ALTER TABLE injects_expectations ADD COLUMN inject_expectation_signatures json;"); } } diff --git a/openbas-api/src/main/java/io/openbas/migration/V3_11__Assets.java b/openbas-api/src/main/java/io/openbas/migration/V3_11__Assets.java index c9c264e911..a85d8baf61 100644 --- a/openbas-api/src/main/java/io/openbas/migration/V3_11__Assets.java +++ b/openbas-api/src/main/java/io/openbas/migration/V3_11__Assets.java @@ -1,19 +1,18 @@ package io.openbas.migration; +import java.sql.Connection; +import java.sql.Statement; import org.flywaydb.core.api.migration.BaseJavaMigration; import org.flywaydb.core.api.migration.Context; import org.springframework.stereotype.Component; -import java.sql.Connection; -import java.sql.Statement; - @Component public class V3_11__Assets extends BaseJavaMigration { - @Override - public void migrate(Context context) throws Exception { - Connection connection = context.getConnection(); - Statement select = connection.createStatement(); - select.execute("ALTER TABLE assets ADD column asset_process_name varchar(255);"); - } -} \ No newline at end of file + @Override + public void migrate(Context context) throws Exception { + Connection connection = context.getConnection(); + Statement select = connection.createStatement(); + select.execute("ALTER TABLE assets ADD column asset_process_name varchar(255);"); + } +} diff --git a/openbas-api/src/main/java/io/openbas/migration/V3_12__Payloads.java b/openbas-api/src/main/java/io/openbas/migration/V3_12__Payloads.java index 548e36182e..f17ca921d2 100644 --- a/openbas-api/src/main/java/io/openbas/migration/V3_12__Payloads.java +++ b/openbas-api/src/main/java/io/openbas/migration/V3_12__Payloads.java @@ -1,32 +1,33 @@ package io.openbas.migration; +import java.sql.Connection; +import java.sql.Statement; import org.flywaydb.core.api.migration.BaseJavaMigration; import org.flywaydb.core.api.migration.Context; import org.springframework.stereotype.Component; -import java.sql.Connection; -import java.sql.Statement; - @Component public class V3_12__Payloads extends BaseJavaMigration { - @Override - public void migrate(Context context) throws Exception { - Connection connection = context.getConnection(); - Statement select = connection.createStatement(); - // Purge - select.execute("TRUNCATE payloads CASCADE;"); - select.execute("ALTER TABLE payloads DROP column payload_content;"); - select.execute("ALTER TABLE payloads ADD column payload_platforms text[];"); - select.execute("ALTER TABLE payloads ADD column command_executor varchar(255);"); - select.execute("ALTER TABLE payloads ADD column command_content text;"); - select.execute("ALTER TABLE payloads ADD column executable_file varchar(255) constraint executable_file_fk references documents on delete cascade;"); - select.execute("ALTER TABLE payloads ADD column file_drop_file varchar(255) constraint file_drop_file_fk references documents on delete cascade;"); - select.execute("ALTER TABLE payloads ADD column dns_resolution_hostname text;"); - select.execute("ALTER TABLE payloads ADD column network_traffic_ip text;"); - select.execute("ALTER TABLE payloads ADD column payload_cleanup_executor varchar(255);"); - select.execute("ALTER TABLE payloads ADD column payload_cleanup_command text;"); - select.execute("ALTER TABLE payloads ADD column payload_arguments json;"); - select.execute("ALTER TABLE payloads ADD column payload_prerequisites json;"); - } + @Override + public void migrate(Context context) throws Exception { + Connection connection = context.getConnection(); + Statement select = connection.createStatement(); + // Purge + select.execute("TRUNCATE payloads CASCADE;"); + select.execute("ALTER TABLE payloads DROP column payload_content;"); + select.execute("ALTER TABLE payloads ADD column payload_platforms text[];"); + select.execute("ALTER TABLE payloads ADD column command_executor varchar(255);"); + select.execute("ALTER TABLE payloads ADD column command_content text;"); + select.execute( + "ALTER TABLE payloads ADD column executable_file varchar(255) constraint executable_file_fk references documents on delete cascade;"); + select.execute( + "ALTER TABLE payloads ADD column file_drop_file varchar(255) constraint file_drop_file_fk references documents on delete cascade;"); + select.execute("ALTER TABLE payloads ADD column dns_resolution_hostname text;"); + select.execute("ALTER TABLE payloads ADD column network_traffic_ip text;"); + select.execute("ALTER TABLE payloads ADD column payload_cleanup_executor varchar(255);"); + select.execute("ALTER TABLE payloads ADD column payload_cleanup_command text;"); + select.execute("ALTER TABLE payloads ADD column payload_arguments json;"); + select.execute("ALTER TABLE payloads ADD column payload_prerequisites json;"); + } } diff --git a/openbas-api/src/main/java/io/openbas/migration/V3_13__Payloads_Attack_Patterns.java b/openbas-api/src/main/java/io/openbas/migration/V3_13__Payloads_Attack_Patterns.java index 21780224fe..9bfbe77717 100644 --- a/openbas-api/src/main/java/io/openbas/migration/V3_13__Payloads_Attack_Patterns.java +++ b/openbas-api/src/main/java/io/openbas/migration/V3_13__Payloads_Attack_Patterns.java @@ -1,12 +1,11 @@ package io.openbas.migration; +import java.sql.Connection; +import java.sql.Statement; import org.flywaydb.core.api.migration.BaseJavaMigration; import org.flywaydb.core.api.migration.Context; import org.springframework.stereotype.Component; -import java.sql.Connection; -import java.sql.Statement; - @Component public class V3_13__Payloads_Attack_Patterns extends BaseJavaMigration { @@ -15,7 +14,8 @@ public void migrate(Context context) throws Exception { Connection connection = context.getConnection(); Statement select = connection.createStatement(); // Create relations between contracts and attack_patterns - select.execute(""" + select.execute( + """ CREATE TABLE payloads_attack_patterns ( attack_pattern_id varchar(255) not null constraint attack_pattern_id_fk diff --git a/openbas-api/src/main/java/io/openbas/migration/V3_14__Injectors_payload.java b/openbas-api/src/main/java/io/openbas/migration/V3_14__Injectors_payload.java index 09e32b9188..62248ee2f6 100644 --- a/openbas-api/src/main/java/io/openbas/migration/V3_14__Injectors_payload.java +++ b/openbas-api/src/main/java/io/openbas/migration/V3_14__Injectors_payload.java @@ -1,17 +1,16 @@ package io.openbas.migration; +import java.sql.Statement; import org.flywaydb.core.api.migration.BaseJavaMigration; import org.flywaydb.core.api.migration.Context; import org.springframework.stereotype.Component; -import java.sql.Statement; - @Component public class V3_14__Injectors_payload extends BaseJavaMigration { - @Override - public void migrate(Context context) throws Exception { - Statement select = context.getConnection().createStatement(); - select.execute("ALTER TABLE injectors ADD injector_payloads bool default false;"); - } + @Override + public void migrate(Context context) throws Exception { + Statement select = context.getConnection().createStatement(); + select.execute("ALTER TABLE injectors ADD injector_payloads bool default false;"); + } } diff --git a/openbas-api/src/main/java/io/openbas/migration/V3_15__Injector_contracts_Payloads.java b/openbas-api/src/main/java/io/openbas/migration/V3_15__Injector_contracts_Payloads.java index c41a27a0f7..70c7308bcf 100644 --- a/openbas-api/src/main/java/io/openbas/migration/V3_15__Injector_contracts_Payloads.java +++ b/openbas-api/src/main/java/io/openbas/migration/V3_15__Injector_contracts_Payloads.java @@ -1,21 +1,22 @@ package io.openbas.migration; +import java.sql.Connection; +import java.sql.Statement; import org.flywaydb.core.api.migration.BaseJavaMigration; import org.flywaydb.core.api.migration.Context; import org.springframework.stereotype.Component; -import java.sql.Connection; -import java.sql.Statement; - @Component public class V3_15__Injector_contracts_Payloads extends BaseJavaMigration { - @Override - public void migrate(Context context) throws Exception { - Connection connection = context.getConnection(); - Statement select = connection.createStatement(); - // Purge - select.execute("ALTER TABLE injectors_contracts ADD column injector_contract_payload varchar(255) constraint injector_contract_payload_fk references payloads on delete cascade;"); - select.execute("CREATE UNIQUE INDEX injector_contract_payload_unique on injectors_contracts (injector_contract_payload, injector_id);"); - } + @Override + public void migrate(Context context) throws Exception { + Connection connection = context.getConnection(); + Statement select = connection.createStatement(); + // Purge + select.execute( + "ALTER TABLE injectors_contracts ADD column injector_contract_payload varchar(255) constraint injector_contract_payload_fk references payloads on delete cascade;"); + select.execute( + "CREATE UNIQUE INDEX injector_contract_payload_unique on injectors_contracts (injector_contract_payload, injector_id);"); + } } diff --git a/openbas-api/src/main/java/io/openbas/migration/V3_16__Add_array_union_agg_method.java b/openbas-api/src/main/java/io/openbas/migration/V3_16__Add_array_union_agg_method.java index 682c668d31..f6050fe3ba 100644 --- a/openbas-api/src/main/java/io/openbas/migration/V3_16__Add_array_union_agg_method.java +++ b/openbas-api/src/main/java/io/openbas/migration/V3_16__Add_array_union_agg_method.java @@ -1,14 +1,13 @@ package io.openbas.migration; +import java.sql.Connection; +import java.sql.ResultSet; +import java.sql.Statement; import lombok.extern.java.Log; import org.flywaydb.core.api.migration.BaseJavaMigration; import org.flywaydb.core.api.migration.Context; import org.springframework.stereotype.Component; -import java.sql.Connection; -import java.sql.ResultSet; -import java.sql.Statement; - @Log @Component public class V3_16__Add_array_union_agg_method extends BaseJavaMigration { @@ -17,28 +16,30 @@ public class V3_16__Add_array_union_agg_method extends BaseJavaMigration { public void migrate(Context context) throws Exception { Connection connection = context.getConnection(); try (Statement statement = connection.createStatement()) { - ResultSet rs = statement.executeQuery( - "SELECT EXISTS (SELECT 1 FROM pg_proc WHERE proname = 'array_union');"); + ResultSet rs = + statement.executeQuery( + "SELECT EXISTS (SELECT 1 FROM pg_proc WHERE proname = 'array_union');"); boolean functionExists = false; if (rs.next()) { functionExists = rs.getBoolean(1); } if (!functionExists) { - statement.execute("CREATE FUNCTION array_union(a ANYARRAY, b ANYARRAY)" - + " RETURNS ANYARRAY AS" - + " $$" - + "SELECT array_agg(DISTINCT x)" - + "FROM (" - + " SELECT unnest(a) x" - + " UNION ALL SELECT unnest(b)" - + " ) AS u" - + " $$ LANGUAGE SQL;" - + "CREATE AGGREGATE array_union_agg(ANYARRAY) (" - + " SFUNC = array_union," - + " STYPE = ANYARRAY," - + " INITCOND = '{}'" - + ");"); + statement.execute( + "CREATE FUNCTION array_union(a ANYARRAY, b ANYARRAY)" + + " RETURNS ANYARRAY AS" + + " $$" + + "SELECT array_agg(DISTINCT x)" + + "FROM (" + + " SELECT unnest(a) x" + + " UNION ALL SELECT unnest(b)" + + " ) AS u" + + " $$ LANGUAGE SQL;" + + "CREATE AGGREGATE array_union_agg(ANYARRAY) (" + + " SFUNC = array_union," + + " STYPE = ANYARRAY," + + " INITCOND = '{}'" + + ");"); } } } diff --git a/openbas-api/src/main/java/io/openbas/migration/V3_17__Payloads.java b/openbas-api/src/main/java/io/openbas/migration/V3_17__Payloads.java index e89cd8ec5c..3df2a08781 100644 --- a/openbas-api/src/main/java/io/openbas/migration/V3_17__Payloads.java +++ b/openbas-api/src/main/java/io/openbas/migration/V3_17__Payloads.java @@ -1,23 +1,23 @@ package io.openbas.migration; +import java.sql.Connection; +import java.sql.Statement; import org.flywaydb.core.api.migration.BaseJavaMigration; import org.flywaydb.core.api.migration.Context; import org.springframework.stereotype.Component; -import java.sql.Connection; -import java.sql.Statement; - @Component public class V3_17__Payloads extends BaseJavaMigration { - @Override - public void migrate(Context context) throws Exception { - Connection connection = context.getConnection(); - Statement select = connection.createStatement(); - select.execute("ALTER TABLE payloads RENAME COLUMN network_traffic_ip TO network_traffic_ip_src;"); - select.execute("ALTER TABLE payloads ADD column network_traffic_ip_dst text;"); - select.execute("ALTER TABLE payloads ADD column network_traffic_port_src int;"); - select.execute("ALTER TABLE payloads ADD column network_traffic_port_dst int;"); - select.execute("ALTER TABLE payloads ADD column network_traffic_protocol varchar(255);"); - } + @Override + public void migrate(Context context) throws Exception { + Connection connection = context.getConnection(); + Statement select = connection.createStatement(); + select.execute( + "ALTER TABLE payloads RENAME COLUMN network_traffic_ip TO network_traffic_ip_src;"); + select.execute("ALTER TABLE payloads ADD column network_traffic_ip_dst text;"); + select.execute("ALTER TABLE payloads ADD column network_traffic_port_src int;"); + select.execute("ALTER TABLE payloads ADD column network_traffic_port_dst int;"); + select.execute("ALTER TABLE payloads ADD column network_traffic_protocol varchar(255);"); + } } diff --git a/openbas-api/src/main/java/io/openbas/migration/V3_18__Injects_contract_null.java b/openbas-api/src/main/java/io/openbas/migration/V3_18__Injects_contract_null.java index 9a479e5ec0..b92aed5edb 100644 --- a/openbas-api/src/main/java/io/openbas/migration/V3_18__Injects_contract_null.java +++ b/openbas-api/src/main/java/io/openbas/migration/V3_18__Injects_contract_null.java @@ -1,19 +1,18 @@ package io.openbas.migration; +import java.sql.Connection; +import java.sql.Statement; import org.flywaydb.core.api.migration.BaseJavaMigration; import org.flywaydb.core.api.migration.Context; import org.springframework.stereotype.Component; -import java.sql.Connection; -import java.sql.Statement; - @Component public class V3_18__Injects_contract_null extends BaseJavaMigration { - @Override - public void migrate(Context context) throws Exception { - Connection connection = context.getConnection(); - Statement select = connection.createStatement(); - select.execute("ALTER TABLE injects ALTER COLUMN inject_injector_contract DROP NOT NULL;"); - } + @Override + public void migrate(Context context) throws Exception { + Connection connection = context.getConnection(); + Statement select = connection.createStatement(); + select.execute("ALTER TABLE injects ALTER COLUMN inject_injector_contract DROP NOT NULL;"); + } } diff --git a/openbas-api/src/main/java/io/openbas/migration/V3_19__Add_index_for_atomic_testings.java b/openbas-api/src/main/java/io/openbas/migration/V3_19__Add_index_for_atomic_testings.java index 2a338b1a38..685a1ce035 100644 --- a/openbas-api/src/main/java/io/openbas/migration/V3_19__Add_index_for_atomic_testings.java +++ b/openbas-api/src/main/java/io/openbas/migration/V3_19__Add_index_for_atomic_testings.java @@ -13,6 +13,7 @@ public class V3_19__Add_index_for_atomic_testings extends BaseJavaMigration { public void migrate(Context context) throws Exception { Connection connection = context.getConnection(); Statement createIndex = connection.createStatement(); - createIndex.execute("CREATE INDEX idx_null_exercise_and_scenario ON injects (inject_id) WHERE inject_scenario IS NULL AND inject_exercise IS NULL;"); + createIndex.execute( + "CREATE INDEX idx_null_exercise_and_scenario ON injects (inject_id) WHERE inject_scenario IS NULL AND inject_exercise IS NULL;"); } -} \ No newline at end of file +} diff --git a/openbas-api/src/main/java/io/openbas/migration/V3_20__AgentJobs.java b/openbas-api/src/main/java/io/openbas/migration/V3_20__AgentJobs.java index 5185925f4c..9cb7ea6da9 100644 --- a/openbas-api/src/main/java/io/openbas/migration/V3_20__AgentJobs.java +++ b/openbas-api/src/main/java/io/openbas/migration/V3_20__AgentJobs.java @@ -1,12 +1,11 @@ package io.openbas.migration; +import java.sql.Connection; +import java.sql.Statement; import org.flywaydb.core.api.migration.BaseJavaMigration; import org.flywaydb.core.api.migration.Context; import org.springframework.stereotype.Component; -import java.sql.Connection; -import java.sql.Statement; - @Component public class V3_20__AgentJobs extends BaseJavaMigration { @@ -16,7 +15,8 @@ public void migrate(Context context) throws Exception { Statement select = connection.createStatement(); select.execute("ALTER TABLE assets ADD column endpoint_agent_version varchar(255);"); // Create table - select.execute(""" + select.execute( + """ CREATE TABLE asset_agent_jobs ( asset_agent_id varchar(255) not null constraint asset_agent_pkey primary key, asset_agent_created_at timestamp not null default now(), @@ -34,4 +34,4 @@ asset_agent_asset varchar(255) CREATE INDEX idx_asset_agent_jobs on asset_agent_jobs (asset_agent_id); """); } -} \ No newline at end of file +} diff --git a/openbas-api/src/main/java/io/openbas/migration/V3_21__Agent_executors.java b/openbas-api/src/main/java/io/openbas/migration/V3_21__Agent_executors.java index 72627e01c8..baf21d9695 100644 --- a/openbas-api/src/main/java/io/openbas/migration/V3_21__Agent_executors.java +++ b/openbas-api/src/main/java/io/openbas/migration/V3_21__Agent_executors.java @@ -1,12 +1,11 @@ package io.openbas.migration; +import java.sql.Connection; +import java.sql.Statement; import org.flywaydb.core.api.migration.BaseJavaMigration; import org.flywaydb.core.api.migration.Context; import org.springframework.stereotype.Component; -import java.sql.Connection; -import java.sql.Statement; - @Component public class V3_21__Agent_executors extends BaseJavaMigration { @@ -15,6 +14,7 @@ public void migrate(Context context) throws Exception { Connection connection = context.getConnection(); Statement select = connection.createStatement(); select.execute("ALTER TABLE assets DROP CONSTRAINT executor_fk;"); - select.execute("ALTER TABLE assets ADD CONSTRAINT executor_fk FOREIGN KEY (asset_executor) REFERENCES executors(executor_id) ON DELETE CASCADE;"); + select.execute( + "ALTER TABLE assets ADD CONSTRAINT executor_fk FOREIGN KEY (asset_executor) REFERENCES executors(executor_id) ON DELETE CASCADE;"); } -} \ No newline at end of file +} diff --git a/openbas-api/src/main/java/io/openbas/migration/V3_22__Endpoints.java b/openbas-api/src/main/java/io/openbas/migration/V3_22__Endpoints.java index b829b0a053..d0b4628628 100644 --- a/openbas-api/src/main/java/io/openbas/migration/V3_22__Endpoints.java +++ b/openbas-api/src/main/java/io/openbas/migration/V3_22__Endpoints.java @@ -1,12 +1,11 @@ package io.openbas.migration; +import java.sql.Connection; +import java.sql.Statement; import org.flywaydb.core.api.migration.BaseJavaMigration; import org.flywaydb.core.api.migration.Context; import org.springframework.stereotype.Component; -import java.sql.Connection; -import java.sql.Statement; - @Component public class V3_22__Endpoints extends BaseJavaMigration { @@ -14,6 +13,7 @@ public class V3_22__Endpoints extends BaseJavaMigration { public void migrate(Context context) throws Exception { Connection connection = context.getConnection(); Statement select = connection.createStatement(); - select.execute("ALTER TABLE assets ADD COLUMN endpoint_arch varchar(255) not null default 'x86_64';"); + select.execute( + "ALTER TABLE assets ADD COLUMN endpoint_arch varchar(255) not null default 'x86_64';"); } } diff --git a/openbas-api/src/main/java/io/openbas/migration/V3_23__Payloads.java b/openbas-api/src/main/java/io/openbas/migration/V3_23__Payloads.java index c9cc60d118..76c30dcc61 100644 --- a/openbas-api/src/main/java/io/openbas/migration/V3_23__Payloads.java +++ b/openbas-api/src/main/java/io/openbas/migration/V3_23__Payloads.java @@ -1,12 +1,11 @@ package io.openbas.migration; +import java.sql.Connection; +import java.sql.Statement; import org.flywaydb.core.api.migration.BaseJavaMigration; import org.flywaydb.core.api.migration.Context; import org.springframework.stereotype.Component; -import java.sql.Connection; -import java.sql.Statement; - @Component public class V3_23__Payloads extends BaseJavaMigration { diff --git a/openbas-api/src/main/java/io/openbas/migration/V3_24__Payload_collector.java b/openbas-api/src/main/java/io/openbas/migration/V3_24__Payload_collector.java index 2bee75fc2b..a8081b88c7 100644 --- a/openbas-api/src/main/java/io/openbas/migration/V3_24__Payload_collector.java +++ b/openbas-api/src/main/java/io/openbas/migration/V3_24__Payload_collector.java @@ -1,12 +1,11 @@ package io.openbas.migration; +import java.sql.Connection; +import java.sql.Statement; import org.flywaydb.core.api.migration.BaseJavaMigration; import org.flywaydb.core.api.migration.Context; import org.springframework.stereotype.Component; -import java.sql.Connection; -import java.sql.Statement; - @Component public class V3_24__Payload_collector extends BaseJavaMigration { @@ -15,6 +14,7 @@ public void migrate(Context context) throws Exception { Connection connection = context.getConnection(); Statement select = connection.createStatement(); select.execute("ALTER TABLE payloads ADD COLUMN payload_collector varchar(255);"); - select.execute("ALTER TABLE payloads ADD CONSTRAINT collector_fk FOREIGN KEY (payload_collector) REFERENCES collectors(collector_id) ON DELETE CASCADE;"); + select.execute( + "ALTER TABLE payloads ADD CONSTRAINT collector_fk FOREIGN KEY (payload_collector) REFERENCES collectors(collector_id) ON DELETE CASCADE;"); } -} \ No newline at end of file +} diff --git a/openbas-api/src/main/java/io/openbas/migration/V3_25__Assets.java b/openbas-api/src/main/java/io/openbas/migration/V3_25__Assets.java index 9e233409a6..5d10f7949b 100644 --- a/openbas-api/src/main/java/io/openbas/migration/V3_25__Assets.java +++ b/openbas-api/src/main/java/io/openbas/migration/V3_25__Assets.java @@ -1,23 +1,24 @@ package io.openbas.migration; +import java.sql.Connection; +import java.sql.Statement; import org.flywaydb.core.api.migration.BaseJavaMigration; import org.flywaydb.core.api.migration.Context; import org.springframework.stereotype.Component; -import java.sql.Connection; -import java.sql.Statement; - @Component public class V3_25__Assets extends BaseJavaMigration { - @Override - public void migrate(Context context) throws Exception { - Connection connection = context.getConnection(); - Statement select = connection.createStatement(); - select.execute("ALTER TABLE assets ADD column security_platform_type varchar(255);"); - select.execute("ALTER TABLE assets ADD column security_platform_logo_light varchar(255);"); - select.execute("ALTER TABLE assets ADD column security_platform_logo_dark varchar(255);"); - select.execute("ALTER TABLE assets ADD constraint fk_security_platform_logo_light foreign key (security_platform_logo_light) references documents on delete set null;"); - select.execute("ALTER TABLE assets ADD constraint fk_security_platform_logo_dark foreign key (security_platform_logo_dark) references documents on delete set null;"); - } -} \ No newline at end of file + @Override + public void migrate(Context context) throws Exception { + Connection connection = context.getConnection(); + Statement select = connection.createStatement(); + select.execute("ALTER TABLE assets ADD column security_platform_type varchar(255);"); + select.execute("ALTER TABLE assets ADD column security_platform_logo_light varchar(255);"); + select.execute("ALTER TABLE assets ADD column security_platform_logo_dark varchar(255);"); + select.execute( + "ALTER TABLE assets ADD constraint fk_security_platform_logo_light foreign key (security_platform_logo_light) references documents on delete set null;"); + select.execute( + "ALTER TABLE assets ADD constraint fk_security_platform_logo_dark foreign key (security_platform_logo_dark) references documents on delete set null;"); + } +} diff --git a/openbas-api/src/main/java/io/openbas/migration/V3_26__Assets_platform.java b/openbas-api/src/main/java/io/openbas/migration/V3_26__Assets_platform.java index ec24c476fa..1807fa1301 100644 --- a/openbas-api/src/main/java/io/openbas/migration/V3_26__Assets_platform.java +++ b/openbas-api/src/main/java/io/openbas/migration/V3_26__Assets_platform.java @@ -1,19 +1,18 @@ package io.openbas.migration; +import java.sql.Connection; +import java.sql.Statement; import org.flywaydb.core.api.migration.BaseJavaMigration; import org.flywaydb.core.api.migration.Context; import org.springframework.stereotype.Component; -import java.sql.Connection; -import java.sql.Statement; - @Component public class V3_26__Assets_platform extends BaseJavaMigration { - @Override - public void migrate(Context context) throws Exception { - Connection connection = context.getConnection(); - Statement select = connection.createStatement(); - select.execute("ALTER TABLE assets ALTER COLUMN endpoint_platform DROP NOT NULL;"); - } -} \ No newline at end of file + @Override + public void migrate(Context context) throws Exception { + Connection connection = context.getConnection(); + Statement select = connection.createStatement(); + select.execute("ALTER TABLE assets ALTER COLUMN endpoint_platform DROP NOT NULL;"); + } +} diff --git a/openbas-api/src/main/java/io/openbas/migration/V3_27__Collectors.java b/openbas-api/src/main/java/io/openbas/migration/V3_27__Collectors.java index bf0ddce0b3..026980f669 100644 --- a/openbas-api/src/main/java/io/openbas/migration/V3_27__Collectors.java +++ b/openbas-api/src/main/java/io/openbas/migration/V3_27__Collectors.java @@ -1,20 +1,20 @@ package io.openbas.migration; +import java.sql.Connection; +import java.sql.Statement; import org.flywaydb.core.api.migration.BaseJavaMigration; import org.flywaydb.core.api.migration.Context; import org.springframework.stereotype.Component; -import java.sql.Connection; -import java.sql.Statement; - @Component public class V3_27__Collectors extends BaseJavaMigration { - @Override - public void migrate(Context context) throws Exception { - Connection connection = context.getConnection(); - Statement select = connection.createStatement(); - select.execute("ALTER TABLE collectors ADD column collector_security_platform varchar(255);"); - select.execute("ALTER TABLE collectors ADD constraint fk_collector_security_platform foreign key (collector_security_platform) references assets on delete set null;"); - } -} \ No newline at end of file + @Override + public void migrate(Context context) throws Exception { + Connection connection = context.getConnection(); + Statement select = connection.createStatement(); + select.execute("ALTER TABLE collectors ADD column collector_security_platform varchar(255);"); + select.execute( + "ALTER TABLE collectors ADD constraint fk_collector_security_platform foreign key (collector_security_platform) references assets on delete set null;"); + } +} diff --git a/openbas-api/src/main/java/io/openbas/migration/V3_28__Payloads.java b/openbas-api/src/main/java/io/openbas/migration/V3_28__Payloads.java index 0d0c18bf0e..24eff050d2 100644 --- a/openbas-api/src/main/java/io/openbas/migration/V3_28__Payloads.java +++ b/openbas-api/src/main/java/io/openbas/migration/V3_28__Payloads.java @@ -1,20 +1,19 @@ package io.openbas.migration; +import java.sql.Connection; +import java.sql.Statement; import org.flywaydb.core.api.migration.BaseJavaMigration; import org.flywaydb.core.api.migration.Context; import org.springframework.stereotype.Component; -import java.sql.Connection; -import java.sql.Statement; - @Component public class V3_28__Payloads extends BaseJavaMigration { - @Override - public void migrate(Context context) throws Exception { - Connection connection = context.getConnection(); - Statement select = connection.createStatement(); - select.execute("ALTER TABLE payloads ADD column payload_source varchar(255);"); - select.execute("ALTER TABLE payloads ADD column payload_status varchar(255);"); - } + @Override + public void migrate(Context context) throws Exception { + Connection connection = context.getConnection(); + Statement select = connection.createStatement(); + select.execute("ALTER TABLE payloads ADD column payload_source varchar(255);"); + select.execute("ALTER TABLE payloads ADD column payload_status varchar(255);"); + } } diff --git a/openbas-api/src/main/java/io/openbas/migration/V3_29__Add_tables_xls_mappers.java b/openbas-api/src/main/java/io/openbas/migration/V3_29__Add_tables_xls_mappers.java index 3f1878505a..2bc7514eb7 100644 --- a/openbas-api/src/main/java/io/openbas/migration/V3_29__Add_tables_xls_mappers.java +++ b/openbas-api/src/main/java/io/openbas/migration/V3_29__Add_tables_xls_mappers.java @@ -1,12 +1,11 @@ package io.openbas.migration; +import java.sql.Connection; +import java.sql.Statement; import org.flywaydb.core.api.migration.BaseJavaMigration; import org.flywaydb.core.api.migration.Context; import org.springframework.stereotype.Component; -import java.sql.Connection; -import java.sql.Statement; - @Component public class V3_29__Add_tables_xls_mappers extends BaseJavaMigration { @@ -15,19 +14,21 @@ public void migrate(Context context) throws Exception { Connection connection = context.getConnection(); Statement select = connection.createStatement(); // Create table - select.execute(""" + select.execute( + """ CREATE TABLE import_mappers ( mapper_id UUID NOT NULL CONSTRAINT import_mappers_pkey PRIMARY KEY, mapper_name VARCHAR(255) NOT NULL, mapper_inject_type_column VARCHAR(255) NOT NULL, mapper_created_at TIMESTAMP DEFAULT now(), mapper_updated_at TIMESTAMP DEFAULT now() - + ); CREATE INDEX idx_import_mappers ON import_mappers(mapper_id); """); - select.execute(""" + select.execute( + """ CREATE TABLE inject_importers ( importer_id UUID NOT NULL CONSTRAINT inject_importers_pkey PRIMARY KEY, importer_mapper_id UUID NOT NULL @@ -41,8 +42,8 @@ importer_updated_at TIMESTAMP DEFAULT now() CREATE INDEX idx_inject_importers ON inject_importers(importer_id); """); - - select.execute(""" + select.execute( + """ CREATE TABLE rule_attributes ( attribute_id UUID NOT NULL CONSTRAINT rule_attributes_pkey PRIMARY KEY, attribute_inject_importer_id UUID NOT NULL @@ -57,14 +58,14 @@ attribute_updated_at TIMESTAMP DEFAULT now() CREATE INDEX idx_rule_attributes on rule_attributes(attribute_id); """); - - select.execute(""" + select.execute( + """ ALTER TABLE injectors_contracts ADD COLUMN injector_contract_import_available BOOLEAN NOT NULL DEFAULT FALSE; """); - select.execute(""" + select.execute( + """ UPDATE injectors_contracts SET injector_contract_import_available = true WHERE injector_contract_labels -> 'en' LIKE ANY(ARRAY['%SMS%', '%Send%mail%']); """); - } -} \ No newline at end of file +} diff --git a/openbas-api/src/main/java/io/openbas/migration/V3_30__Score_type.java b/openbas-api/src/main/java/io/openbas/migration/V3_30__Score_type.java index 2a2fa73d4e..14d6683e66 100644 --- a/openbas-api/src/main/java/io/openbas/migration/V3_30__Score_type.java +++ b/openbas-api/src/main/java/io/openbas/migration/V3_30__Score_type.java @@ -1,19 +1,20 @@ package io.openbas.migration; +import java.sql.Statement; import org.flywaydb.core.api.migration.BaseJavaMigration; import org.flywaydb.core.api.migration.Context; import org.springframework.stereotype.Component; -import java.sql.Statement; - @Component public class V3_30__Score_type extends BaseJavaMigration { - @Override - public void migrate(Context context) throws Exception { - Statement select = context.getConnection().createStatement(); - select.execute("ALTER TABLE challenges alter column challenge_score type DOUBLE PRECISION;"); - select.execute("ALTER TABLE injects_expectations alter column inject_expectation_score type DOUBLE PRECISION;"); - select.execute("ALTER TABLE injects_expectations alter column inject_expectation_expected_score type DOUBLE PRECISION;"); - } + @Override + public void migrate(Context context) throws Exception { + Statement select = context.getConnection().createStatement(); + select.execute("ALTER TABLE challenges alter column challenge_score type DOUBLE PRECISION;"); + select.execute( + "ALTER TABLE injects_expectations alter column inject_expectation_score type DOUBLE PRECISION;"); + select.execute( + "ALTER TABLE injects_expectations alter column inject_expectation_expected_score type DOUBLE PRECISION;"); + } } diff --git a/openbas-api/src/main/java/io/openbas/migration/V3_31__Add_Injects_tests_statuses.java b/openbas-api/src/main/java/io/openbas/migration/V3_31__Add_Injects_tests_statuses.java index b81c35a23f..4cf7b11395 100644 --- a/openbas-api/src/main/java/io/openbas/migration/V3_31__Add_Injects_tests_statuses.java +++ b/openbas-api/src/main/java/io/openbas/migration/V3_31__Add_Injects_tests_statuses.java @@ -1,12 +1,11 @@ package io.openbas.migration; +import java.sql.Connection; +import java.sql.Statement; import org.flywaydb.core.api.migration.BaseJavaMigration; import org.flywaydb.core.api.migration.Context; import org.springframework.stereotype.Component; -import java.sql.Connection; -import java.sql.Statement; - @Component public class V3_31__Add_Injects_tests_statuses extends BaseJavaMigration { @@ -15,7 +14,8 @@ public void migrate(Context context) throws Exception { Connection connection = context.getConnection(); Statement select = connection.createStatement(); // Create table - select.execute(""" + select.execute( + """ CREATE TABLE injects_tests_statuses ( status_id varchar(255) NOT NULL CONSTRAINT inject_test_status_pkey PRIMARY KEY, status_name VARCHAR(255) NOT NULL, @@ -34,5 +34,4 @@ status_updated_at timestamp not null default now() CREATE INDEX idx_inject_test_inject ON injects_tests_statuses(status_inject); """); } - } diff --git a/openbas-api/src/main/java/io/openbas/migration/V3_32__Add_column_lessons_anonymized.java b/openbas-api/src/main/java/io/openbas/migration/V3_32__Add_column_lessons_anonymized.java index 2b2a6ab5d8..757854bc85 100644 --- a/openbas-api/src/main/java/io/openbas/migration/V3_32__Add_column_lessons_anonymized.java +++ b/openbas-api/src/main/java/io/openbas/migration/V3_32__Add_column_lessons_anonymized.java @@ -1,17 +1,16 @@ package io.openbas.migration; +import java.sql.Statement; import org.flywaydb.core.api.migration.BaseJavaMigration; import org.flywaydb.core.api.migration.Context; import org.springframework.stereotype.Component; -import java.sql.Statement; - @Component public class V3_32__Add_column_lessons_anonymized extends BaseJavaMigration { - @Override - public void migrate(Context context) throws Exception { - Statement select = context.getConnection().createStatement(); - select.execute("ALTER TABLE scenarios ADD scenario_lessons_anonymized bool default false;"); - } + @Override + public void migrate(Context context) throws Exception { + Statement select = context.getConnection().createStatement(); + select.execute("ALTER TABLE scenarios ADD scenario_lessons_anonymized bool default false;"); + } } diff --git a/openbas-api/src/main/java/io/openbas/migration/V3_33__Add_Index_inject.java b/openbas-api/src/main/java/io/openbas/migration/V3_33__Add_Index_inject.java index dfd924e166..5b74beea31 100644 --- a/openbas-api/src/main/java/io/openbas/migration/V3_33__Add_Index_inject.java +++ b/openbas-api/src/main/java/io/openbas/migration/V3_33__Add_Index_inject.java @@ -1,21 +1,20 @@ package io.openbas.migration; +import java.sql.Statement; import org.flywaydb.core.api.migration.BaseJavaMigration; import org.flywaydb.core.api.migration.Context; import org.springframework.stereotype.Component; -import java.sql.Statement; - @Component public class V3_33__Add_Index_inject extends BaseJavaMigration { - @Override - public void migrate(Context context) throws Exception { - Statement select = context.getConnection().createStatement(); - select.execute("" + @Override + public void migrate(Context context) throws Exception { + Statement select = context.getConnection().createStatement(); + select.execute( + "" + "CREATE INDEX idx_inject_inject_injector_contract on injects (inject_injector_contract);" + "CREATE INDEX idx_injector_contract_injector on injectors_contracts (injector_id);" - + "" - ); - } + + ""); + } } diff --git a/openbas-api/src/main/java/io/openbas/migration/V3_34__Remove_cascade_delete_dependency.java b/openbas-api/src/main/java/io/openbas/migration/V3_34__Remove_cascade_delete_dependency.java index 0326b164c6..85f446c780 100644 --- a/openbas-api/src/main/java/io/openbas/migration/V3_34__Remove_cascade_delete_dependency.java +++ b/openbas-api/src/main/java/io/openbas/migration/V3_34__Remove_cascade_delete_dependency.java @@ -1,19 +1,19 @@ package io.openbas.migration; +import java.sql.Statement; import org.flywaydb.core.api.migration.BaseJavaMigration; import org.flywaydb.core.api.migration.Context; import org.springframework.stereotype.Component; -import java.sql.Statement; - @Component public class V3_34__Remove_cascade_delete_dependency extends BaseJavaMigration { - @Override - public void migrate(Context context) throws Exception { - Statement select = context.getConnection().createStatement(); - select.execute("ALTER TABLE injects DROP CONSTRAINT fk_depends_from_another;"); - select.execute("ALTER TABLE injects ADD CONSTRAINT fk_depends_from_another " + - "FOREIGN KEY (inject_depends_from_another) REFERENCES injects ON DELETE SET NULL;"); - } + @Override + public void migrate(Context context) throws Exception { + Statement select = context.getConnection().createStatement(); + select.execute("ALTER TABLE injects DROP CONSTRAINT fk_depends_from_another;"); + select.execute( + "ALTER TABLE injects ADD CONSTRAINT fk_depends_from_another " + + "FOREIGN KEY (inject_depends_from_another) REFERENCES injects ON DELETE SET NULL;"); + } } diff --git a/openbas-api/src/main/java/io/openbas/migration/V3_35__Modify_Injects_tests_statuses_status_inject_on_delete.java b/openbas-api/src/main/java/io/openbas/migration/V3_35__Modify_Injects_tests_statuses_status_inject_on_delete.java index fa415f4657..f998cf5f67 100644 --- a/openbas-api/src/main/java/io/openbas/migration/V3_35__Modify_Injects_tests_statuses_status_inject_on_delete.java +++ b/openbas-api/src/main/java/io/openbas/migration/V3_35__Modify_Injects_tests_statuses_status_inject_on_delete.java @@ -1,36 +1,38 @@ package io.openbas.migration; +import java.sql.Connection; +import java.sql.Statement; import org.flywaydb.core.api.migration.BaseJavaMigration; import org.flywaydb.core.api.migration.Context; import org.springframework.stereotype.Component; -import java.sql.Connection; -import java.sql.Statement; - @Component -public class V3_35__Modify_Injects_tests_statuses_status_inject_on_delete extends BaseJavaMigration { +public class V3_35__Modify_Injects_tests_statuses_status_inject_on_delete + extends BaseJavaMigration { @Override public void migrate(Context context) throws Exception { Connection connection = context.getConnection(); Statement select = connection.createStatement(); // Drop the old foreign key constraint - select.execute(""" + select.execute( + """ ALTER TABLE injects_tests_statuses DROP CONSTRAINT inject_test_status_inject_id_fkey; """); // Add the new foreign key constraint with ON DELETE CASCADE - select.execute(""" + select.execute( + """ ALTER TABLE injects_tests_statuses - ADD CONSTRAINT inject_test_status_inject_id_fkey + ADD CONSTRAINT inject_test_status_inject_id_fkey FOREIGN KEY (status_inject) REFERENCES injects(inject_id) ON DELETE CASCADE; """); // Optionally, you can reindex if necessary (usually not required just for FK changes) - select.execute(""" + select.execute( + """ CREATE INDEX IF NOT EXISTS idx_inject_test_inject ON injects_tests_statuses(status_inject); """); } - } diff --git a/openbas-api/src/main/java/io/openbas/migration/V3_36__Alter_inject_expectation_score.java b/openbas-api/src/main/java/io/openbas/migration/V3_36__Alter_inject_expectation_score.java index 3bfb9effc2..6c3a994129 100644 --- a/openbas-api/src/main/java/io/openbas/migration/V3_36__Alter_inject_expectation_score.java +++ b/openbas-api/src/main/java/io/openbas/migration/V3_36__Alter_inject_expectation_score.java @@ -1,12 +1,11 @@ package io.openbas.migration; +import java.sql.Connection; +import java.sql.Statement; import org.flywaydb.core.api.migration.BaseJavaMigration; import org.flywaydb.core.api.migration.Context; import org.springframework.stereotype.Component; -import java.sql.Connection; -import java.sql.Statement; - @Component public class V3_36__Alter_inject_expectation_score extends BaseJavaMigration { diff --git a/openbas-api/src/main/java/io/openbas/migration/V3_37__Add_column_elevation_required_payload.java b/openbas-api/src/main/java/io/openbas/migration/V3_37__Add_column_elevation_required_payload.java index 7f1f3c4f8e..733e9e4369 100644 --- a/openbas-api/src/main/java/io/openbas/migration/V3_37__Add_column_elevation_required_payload.java +++ b/openbas-api/src/main/java/io/openbas/migration/V3_37__Add_column_elevation_required_payload.java @@ -1,17 +1,16 @@ package io.openbas.migration; +import java.sql.Statement; import org.flywaydb.core.api.migration.BaseJavaMigration; import org.flywaydb.core.api.migration.Context; import org.springframework.stereotype.Component; -import java.sql.Statement; - @Component public class V3_37__Add_column_elevation_required_payload extends BaseJavaMigration { - @Override - public void migrate(final Context context) throws Exception { - final Statement select = context.getConnection().createStatement(); - select.execute("ALTER TABLE payloads ADD payload_elevation_required bool default false;"); - } + @Override + public void migrate(final Context context) throws Exception { + final Statement select = context.getConnection().createStatement(); + select.execute("ALTER TABLE payloads ADD payload_elevation_required bool default false;"); + } } diff --git a/openbas-api/src/main/java/io/openbas/migration/V3_38__Add_column_trigger_now.java b/openbas-api/src/main/java/io/openbas/migration/V3_38__Add_column_trigger_now.java index df17f9e4b0..e3ab072076 100644 --- a/openbas-api/src/main/java/io/openbas/migration/V3_38__Add_column_trigger_now.java +++ b/openbas-api/src/main/java/io/openbas/migration/V3_38__Add_column_trigger_now.java @@ -1,17 +1,16 @@ package io.openbas.migration; +import java.sql.Statement; import org.flywaydb.core.api.migration.BaseJavaMigration; import org.flywaydb.core.api.migration.Context; import org.springframework.stereotype.Component; -import java.sql.Statement; - @Component public class V3_38__Add_column_trigger_now extends BaseJavaMigration { - @Override - public void migrate(Context context) throws Exception { - Statement select = context.getConnection().createStatement(); - select.execute("ALTER TABLE injects ADD inject_trigger_now_date timestamp;"); - } + @Override + public void migrate(Context context) throws Exception { + Statement select = context.getConnection().createStatement(); + select.execute("ALTER TABLE injects ADD inject_trigger_now_date timestamp;"); + } } diff --git a/openbas-api/src/main/java/io/openbas/migration/V3_39__Add_column_status_commands_lines.java b/openbas-api/src/main/java/io/openbas/migration/V3_39__Add_column_status_commands_lines.java index daf6a023d4..7f7af49aef 100644 --- a/openbas-api/src/main/java/io/openbas/migration/V3_39__Add_column_status_commands_lines.java +++ b/openbas-api/src/main/java/io/openbas/migration/V3_39__Add_column_status_commands_lines.java @@ -1,17 +1,16 @@ package io.openbas.migration; +import java.sql.Statement; import org.flywaydb.core.api.migration.BaseJavaMigration; import org.flywaydb.core.api.migration.Context; import org.springframework.stereotype.Component; -import java.sql.Statement; - @Component public class V3_39__Add_column_status_commands_lines extends BaseJavaMigration { - @Override - public void migrate(Context context) throws Exception { - Statement select = context.getConnection().createStatement(); - select.execute("ALTER TABLE injects_statuses ADD status_commands_lines text;"); - } + @Override + public void migrate(Context context) throws Exception { + Statement select = context.getConnection().createStatement(); + select.execute("ALTER TABLE injects_statuses ADD status_commands_lines text;"); + } } diff --git a/openbas-api/src/main/java/io/openbas/migration/V3_40__Add_reports_tables.java b/openbas-api/src/main/java/io/openbas/migration/V3_40__Add_reports_tables.java index c795a47a3a..12b0785f19 100644 --- a/openbas-api/src/main/java/io/openbas/migration/V3_40__Add_reports_tables.java +++ b/openbas-api/src/main/java/io/openbas/migration/V3_40__Add_reports_tables.java @@ -1,22 +1,22 @@ package io.openbas.migration; +import java.sql.Connection; +import java.sql.Statement; import org.flywaydb.core.api.migration.BaseJavaMigration; import org.flywaydb.core.api.migration.Context; import org.springframework.stereotype.Component; -import java.sql.Connection; -import java.sql.Statement; - @Component public class V3_40__Add_reports_tables extends BaseJavaMigration { - @Override - public void migrate(Context context) throws Exception { - Connection connection = context.getConnection(); - Statement select = connection.createStatement(); - select.execute("DROP TABLE IF EXISTS reports;"); + @Override + public void migrate(Context context) throws Exception { + Connection connection = context.getConnection(); + Statement select = connection.createStatement(); + select.execute("DROP TABLE IF EXISTS reports;"); - // Create table - select.execute(""" + // Create table + select.execute( + """ CREATE TABLE reports ( report_id UUID NOT NULL CONSTRAINT reports_pkey PRIMARY KEY, report_name VARCHAR(255) NOT NULL, @@ -57,5 +57,5 @@ FOREIGN KEY (inject_id) REFERENCES injects (inject_id) ON DELETE CASCADE CREATE INDEX idx_report_inject_comment_inject ON report_inject_comment (report_id); CREATE INDEX idx_report_inject_comment_report ON report_inject_comment (inject_id); """); - } + } } diff --git a/openbas-api/src/main/java/io/openbas/migration/V3_41__Update_constraint_on_delete_cascade.java b/openbas-api/src/main/java/io/openbas/migration/V3_41__Update_constraint_on_delete_cascade.java index fefeacd197..6bb27f22ff 100644 --- a/openbas-api/src/main/java/io/openbas/migration/V3_41__Update_constraint_on_delete_cascade.java +++ b/openbas-api/src/main/java/io/openbas/migration/V3_41__Update_constraint_on_delete_cascade.java @@ -1,27 +1,31 @@ package io.openbas.migration; +import java.sql.Connection; +import java.sql.Statement; import org.flywaydb.core.api.migration.BaseJavaMigration; import org.flywaydb.core.api.migration.Context; import org.springframework.stereotype.Component; -import java.sql.Connection; -import java.sql.Statement; - @Component public class V3_41__Update_constraint_on_delete_cascade extends BaseJavaMigration { - @Override - public void migrate(Context context) throws Exception { - Connection connection = context.getConnection(); - Statement select = connection.createStatement(); - select.execute("ALTER TABLE inject_importers DROP CONSTRAINT inject_importers_injector_contract_id_fkey;"); - select.execute("ALTER TABLE rule_attributes DROP CONSTRAINT rule_attributes_importer_id_fkey;"); + @Override + public void migrate(Context context) throws Exception { + Connection connection = context.getConnection(); + Statement select = connection.createStatement(); + select.execute( + "ALTER TABLE inject_importers DROP CONSTRAINT inject_importers_injector_contract_id_fkey;"); + select.execute("ALTER TABLE rule_attributes DROP CONSTRAINT rule_attributes_importer_id_fkey;"); - // Add the new foreign key constraint with ON DELETE CASCADE - select.execute("ALTER TABLE inject_importers ADD CONSTRAINT inject_importers_injector_contract_id_fkey FOREIGN KEY (importer_injector_contract_id) REFERENCES injectors_contracts(injector_contract_id) ON DELETE CASCADE;"); - select.execute("ALTER TABLE rule_attributes ADD CONSTRAINT rule_attributes_importer_id_fkey FOREIGN KEY (attribute_inject_importer_id) REFERENCES inject_importers(importer_id) ON DELETE CASCADE;"); + // Add the new foreign key constraint with ON DELETE CASCADE + select.execute( + "ALTER TABLE inject_importers ADD CONSTRAINT inject_importers_injector_contract_id_fkey FOREIGN KEY (importer_injector_contract_id) REFERENCES injectors_contracts(injector_contract_id) ON DELETE CASCADE;"); + select.execute( + "ALTER TABLE rule_attributes ADD CONSTRAINT rule_attributes_importer_id_fkey FOREIGN KEY (attribute_inject_importer_id) REFERENCES inject_importers(importer_id) ON DELETE CASCADE;"); - // Optionally, you can reindex if necessary (usually not required just for FK changes) - select.execute("CREATE INDEX IF NOT EXISTS idx_inject_importers_injector_contracts ON inject_importers(importer_injector_contract_id);"); - select.execute("CREATE INDEX IF NOT EXISTS idx_rule_attributes_inject_importers ON rule_attributes(attribute_inject_importer_id);"); - } + // Optionally, you can reindex if necessary (usually not required just for FK changes) + select.execute( + "CREATE INDEX IF NOT EXISTS idx_inject_importers_injector_contracts ON inject_importers(importer_injector_contract_id);"); + select.execute( + "CREATE INDEX IF NOT EXISTS idx_rule_attributes_inject_importers ON rule_attributes(attribute_inject_importer_id);"); + } } diff --git a/openbas-api/src/main/java/io/openbas/migration/V3_42__Add_column_expiration_time_expectations.java b/openbas-api/src/main/java/io/openbas/migration/V3_42__Add_column_expiration_time_expectations.java index 71eb02eac0..78343e6598 100644 --- a/openbas-api/src/main/java/io/openbas/migration/V3_42__Add_column_expiration_time_expectations.java +++ b/openbas-api/src/main/java/io/openbas/migration/V3_42__Add_column_expiration_time_expectations.java @@ -1,14 +1,13 @@ package io.openbas.migration; -import org.flywaydb.core.api.migration.BaseJavaMigration; -import org.flywaydb.core.api.migration.Context; -import org.springframework.stereotype.Component; +import static io.openbas.expectation.ExpectationPropertiesConfig.DEFAULT_HUMAN_EXPECTATION_EXPIRATION_TIME; +import static io.openbas.expectation.ExpectationPropertiesConfig.DEFAULT_TECHNICAL_EXPECTATION_EXPIRATION_TIME; import java.sql.Connection; import java.sql.Statement; - -import static io.openbas.expectation.ExpectationPropertiesConfig.DEFAULT_HUMAN_EXPECTATION_EXPIRATION_TIME; -import static io.openbas.expectation.ExpectationPropertiesConfig.DEFAULT_TECHNICAL_EXPECTATION_EXPIRATION_TIME; +import org.flywaydb.core.api.migration.BaseJavaMigration; +import org.flywaydb.core.api.migration.Context; +import org.springframework.stereotype.Component; @Component public class V3_42__Add_column_expiration_time_expectations extends BaseJavaMigration { @@ -20,11 +19,15 @@ public void migrate(Context context) throws Exception { statement.execute("ALTER TABLE injects_expectations ADD inject_expiration_time bigint;"); statement.execute( - "UPDATE injects_expectations SET inject_expiration_time = " + DEFAULT_TECHNICAL_EXPECTATION_EXPIRATION_TIME + " " + "UPDATE injects_expectations SET inject_expiration_time = " + + DEFAULT_TECHNICAL_EXPECTATION_EXPIRATION_TIME + + " " + "WHERE inject_expectation_type = 'DETECTION' OR inject_expectation_type = 'PREVENTION';"); statement.execute( - "UPDATE injects_expectations SET inject_expiration_time = " + DEFAULT_HUMAN_EXPECTATION_EXPIRATION_TIME + " " + "UPDATE injects_expectations SET inject_expiration_time = " + + DEFAULT_HUMAN_EXPECTATION_EXPIRATION_TIME + + " " + "WHERE inject_expectation_type = 'MANUAL' OR inject_expectation_type = 'CHALLENGE' " + "OR inject_expectation_type = 'ARTICLE' OR inject_expectation_type = 'DOCUMENT' OR inject_expectation_type = 'TEXT';"); diff --git a/openbas-api/src/main/java/io/openbas/migration/V3_43__Payloads_default_values.java b/openbas-api/src/main/java/io/openbas/migration/V3_43__Payloads_default_values.java index 844087db24..5d4aa90528 100644 --- a/openbas-api/src/main/java/io/openbas/migration/V3_43__Payloads_default_values.java +++ b/openbas-api/src/main/java/io/openbas/migration/V3_43__Payloads_default_values.java @@ -1,24 +1,25 @@ package io.openbas.migration; +import java.sql.Connection; +import java.sql.Statement; import org.flywaydb.core.api.migration.BaseJavaMigration; import org.flywaydb.core.api.migration.Context; import org.springframework.stereotype.Component; -import java.sql.Connection; -import java.sql.Statement; - @Component public class V3_43__Payloads_default_values extends BaseJavaMigration { - @Override - public void migrate(Context context) throws Exception { - Connection connection = context.getConnection(); - Statement select = connection.createStatement(); + @Override + public void migrate(Context context) throws Exception { + Connection connection = context.getConnection(); + Statement select = connection.createStatement(); - select.executeUpdate("UPDATE payloads SET payload_source = 'MANUAL' WHERE payload_source IS NULL;"); - select.executeUpdate("UPDATE payloads SET payload_status = 'UNVERIFIED' WHERE payload_status IS NULL;"); + select.executeUpdate( + "UPDATE payloads SET payload_source = 'MANUAL' WHERE payload_source IS NULL;"); + select.executeUpdate( + "UPDATE payloads SET payload_status = 'UNVERIFIED' WHERE payload_status IS NULL;"); - select.execute("ALTER TABLE payloads ALTER COLUMN payload_source SET DEFAULT 'MANUAL';"); - select.execute("ALTER TABLE payloads ALTER COLUMN payload_status SET DEFAULT 'UNVERIFIED';"); - } + select.execute("ALTER TABLE payloads ALTER COLUMN payload_source SET DEFAULT 'MANUAL';"); + select.execute("ALTER TABLE payloads ALTER COLUMN payload_status SET DEFAULT 'UNVERIFIED';"); + } } diff --git a/openbas-api/src/main/java/io/openbas/migration/V3_44__Add_column_executable_arch.java b/openbas-api/src/main/java/io/openbas/migration/V3_44__Add_column_executable_arch.java index 62e3e83e4d..2cd528ab70 100644 --- a/openbas-api/src/main/java/io/openbas/migration/V3_44__Add_column_executable_arch.java +++ b/openbas-api/src/main/java/io/openbas/migration/V3_44__Add_column_executable_arch.java @@ -1,12 +1,11 @@ package io.openbas.migration; +import java.sql.Connection; +import java.sql.Statement; import org.flywaydb.core.api.migration.BaseJavaMigration; import org.flywaydb.core.api.migration.Context; import org.springframework.stereotype.Component; -import java.sql.Connection; -import java.sql.Statement; - @Component public class V3_44__Add_column_executable_arch extends BaseJavaMigration { @@ -15,6 +14,7 @@ public void migrate(Context context) throws Exception { Connection connection = context.getConnection(); Statement statement = connection.createStatement(); statement.execute("ALTER TABLE payloads ADD executable_arch varchar(255);"); - statement.execute("UPDATE payloads SET executable_arch = 'x86_64' WHERE payload_type ='Executable';"); + statement.execute( + "UPDATE payloads SET executable_arch = 'x86_64' WHERE payload_type ='Executable';"); } } diff --git a/openbas-api/src/main/java/io/openbas/opencti/OpenCTIApi.java b/openbas-api/src/main/java/io/openbas/opencti/OpenCTIApi.java index 5da7f331e8..a6aaac0c3b 100644 --- a/openbas-api/src/main/java/io/openbas/opencti/OpenCTIApi.java +++ b/openbas-api/src/main/java/io/openbas/opencti/OpenCTIApi.java @@ -1,5 +1,7 @@ package io.openbas.opencti; +import static io.openbas.database.model.User.ROLE_USER; + import io.openbas.aop.LogExecutionTime; import io.openbas.rest.exercise.form.ExerciseSimple; import io.openbas.service.ScenarioService; @@ -15,8 +17,6 @@ import org.springframework.web.bind.annotation.PathVariable; import org.springframework.web.bind.annotation.RestController; -import static io.openbas.database.model.User.ROLE_USER; - @RequiredArgsConstructor @RestController @Secured(ROLE_USER) @@ -26,18 +26,24 @@ public class OpenCTIApi { private final ScenarioService scenarioService; - @Operation(summary = "Retrieve the latest exercise by external reference ID (example: a report ID") - @ApiResponses(value = { - @ApiResponse(responseCode = "200", description = "Found the exercise", - content = { - @Content(mediaType = "application/json", schema = @Schema(implementation = ExerciseSimple.class)) - }), - @ApiResponse(responseCode = "404", description = "Exercise not found", content = @Content) - }) + @Operation( + summary = "Retrieve the latest exercise by external reference ID (example: a report ID") + @ApiResponses( + value = { + @ApiResponse( + responseCode = "200", + description = "Found the exercise", + content = { + @Content( + mediaType = "application/json", + schema = @Schema(implementation = ExerciseSimple.class)) + }), + @ApiResponse(responseCode = "404", description = "Exercise not found", content = @Content) + }) @LogExecutionTime @GetMapping(OPENCTI_URI + "/exercises/latest/{externalReferenceId}") - public ExerciseSimple latestExerciseByExternalReference(@PathVariable @NotBlank final String externalReferenceId) { + public ExerciseSimple latestExerciseByExternalReference( + @PathVariable @NotBlank final String externalReferenceId) { return scenarioService.latestExerciseByExternalReference(externalReferenceId); } - } diff --git a/openbas-api/src/main/java/io/openbas/rest/HomeApi.java b/openbas-api/src/main/java/io/openbas/rest/HomeApi.java index bcd9cb8673..6b60f47832 100644 --- a/openbas-api/src/main/java/io/openbas/rest/HomeApi.java +++ b/openbas-api/src/main/java/io/openbas/rest/HomeApi.java @@ -1,5 +1,11 @@ package io.openbas.rest; +import static java.nio.charset.StandardCharsets.UTF_8; + +import java.io.IOException; +import java.io.InputStreamReader; +import java.io.Reader; +import java.io.UncheckedIOException; import org.springframework.beans.factory.annotation.Value; import org.springframework.core.io.ClassPathResource; import org.springframework.core.io.Resource; @@ -10,40 +16,39 @@ import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.RestController; -import java.io.IOException; -import java.io.InputStreamReader; -import java.io.Reader; -import java.io.UncheckedIOException; - -import static java.nio.charset.StandardCharsets.UTF_8; - @RestController public class HomeApi { - private static String readResourceAsString(Resource resource) { - try (Reader reader = new InputStreamReader(resource.getInputStream(), UTF_8)) { - return FileCopyUtils.copyToString(reader); - } catch (IOException e) { - throw new UncheckedIOException(e); - } + private static String readResourceAsString(Resource resource) { + try (Reader reader = new InputStreamReader(resource.getInputStream(), UTF_8)) { + return FileCopyUtils.copyToString(reader); + } catch (IOException e) { + throw new UncheckedIOException(e); } + } - @Value("${server.servlet.context-path}") - private String contextPath; + @Value("${server.servlet.context-path}") + private String contextPath; - @GetMapping(path = {"/", "/{path:^(?!api$|login$|logout$|oauth2$|saml2$|static$|swagger-ui$).*$}/**"}, produces = MediaType.TEXT_HTML_VALUE) - public ResponseEntity home() { - ClassPathResource classPathResource = new ClassPathResource("/build/index.html"); - String index = readResourceAsString(classPathResource); - String basePath = this.contextPath.endsWith("/") ? this.contextPath.substring(0, this.contextPath.length() - 1) : this.contextPath; - String newIndex = index. - replaceAll("%APP_TITLE%", "OpenBAS - Open Breach & Attack Simulation Platform"). - replaceAll("%APP_DESCRIPTION%", "OpenBAS is an open source platform allowing organizations to plan, schedule and conduct adversary simulation campaigns and cyber crisis exercises."). - replaceAll("%APP_FAVICON%", basePath + "/static/ext/favicon.png"). - replaceAll("%APP_MANIFEST%", basePath + "/static/ext/manifest.json"). - replaceAll("%BASE_PATH%", basePath); - return ResponseEntity.ok() - .header(HttpHeaders.CACHE_CONTROL, "no-cache") - .body(newIndex); - } + @GetMapping( + path = {"/", "/{path:^(?!api$|login$|logout$|oauth2$|saml2$|static$|swagger-ui$).*$}/**"}, + produces = MediaType.TEXT_HTML_VALUE) + public ResponseEntity home() { + ClassPathResource classPathResource = new ClassPathResource("/build/index.html"); + String index = readResourceAsString(classPathResource); + String basePath = + this.contextPath.endsWith("/") + ? this.contextPath.substring(0, this.contextPath.length() - 1) + : this.contextPath; + String newIndex = + index + .replaceAll("%APP_TITLE%", "OpenBAS - Open Breach & Attack Simulation Platform") + .replaceAll( + "%APP_DESCRIPTION%", + "OpenBAS is an open source platform allowing organizations to plan, schedule and conduct adversary simulation campaigns and cyber crisis exercises.") + .replaceAll("%APP_FAVICON%", basePath + "/static/ext/favicon.png") + .replaceAll("%APP_MANIFEST%", basePath + "/static/ext/manifest.json") + .replaceAll("%BASE_PATH%", basePath); + return ResponseEntity.ok().header(HttpHeaders.CACHE_CONTROL, "no-cache").body(newIndex); + } } diff --git a/openbas-api/src/main/java/io/openbas/rest/asset/endpoint/EndpointApi.java b/openbas-api/src/main/java/io/openbas/rest/asset/endpoint/EndpointApi.java index 06bb4d5778..c82ecdbfc0 100644 --- a/openbas-api/src/main/java/io/openbas/rest/asset/endpoint/EndpointApi.java +++ b/openbas-api/src/main/java/io/openbas/rest/asset/endpoint/EndpointApi.java @@ -1,5 +1,11 @@ package io.openbas.rest.asset.endpoint; +import static io.openbas.database.model.User.ROLE_ADMIN; +import static io.openbas.database.model.User.ROLE_USER; +import static io.openbas.executors.openbas.OpenBASExecutor.OPENBAS_EXECUTOR_ID; +import static io.openbas.helper.StreamHelper.iterableToSet; +import static io.openbas.utils.pagination.PaginationUtils.buildPaginationJPA; + import io.openbas.asset.EndpointService; import io.openbas.database.model.AssetAgentJob; import io.openbas.database.model.Endpoint; @@ -15,6 +21,10 @@ import jakarta.transaction.Transactional; import jakarta.validation.Valid; import jakarta.validation.constraints.NotBlank; +import java.io.IOException; +import java.time.Instant; +import java.util.List; +import java.util.Optional; import lombok.RequiredArgsConstructor; import org.springframework.beans.factory.annotation.Value; import org.springframework.data.domain.Page; @@ -24,25 +34,16 @@ import org.springframework.security.access.prepost.PreAuthorize; import org.springframework.web.bind.annotation.*; -import java.io.IOException; -import java.time.Instant; -import java.util.List; -import java.util.Optional; - -import static io.openbas.database.model.User.ROLE_ADMIN; -import static io.openbas.database.model.User.ROLE_USER; -import static io.openbas.executors.openbas.OpenBASExecutor.OPENBAS_EXECUTOR_ID; -import static io.openbas.helper.StreamHelper.iterableToSet; -import static io.openbas.utils.pagination.PaginationUtils.buildPaginationJPA; - @RequiredArgsConstructor @RestController @Secured(ROLE_USER) public class EndpointApi { - public static final String ENDPOINT_URI = "/api/endpoints"; + public static final String ENDPOINT_URI = "/api/endpoints"; + + @Value("${info.app.version:unknown}") + String version; - @Value("${info.app.version:unknown}") String version; private final EndpointService endpointService; private final EndpointRepository endpointRepository; private final ExecutorRepository executorRepository; @@ -64,8 +65,10 @@ public Endpoint createEndpoint(@Valid @RequestBody final EndpointInput input) { @Secured(ROLE_ADMIN) @PostMapping(ENDPOINT_URI + "/register") @Transactional(rollbackOn = Exception.class) - public Endpoint upsertEndpoint(@Valid @RequestBody final EndpointRegisterInput input) throws IOException { - Optional optionalEndpoint = this.endpointService.findByExternalReference(input.getExternalReference()); + public Endpoint upsertEndpoint(@Valid @RequestBody final EndpointRegisterInput input) + throws IOException { + Optional optionalEndpoint = + this.endpointService.findByExternalReference(input.getExternalReference()); Endpoint endpoint; if (optionalEndpoint.isPresent()) { endpoint = optionalEndpoint.get(); @@ -87,10 +90,12 @@ public Endpoint upsertEndpoint(@Valid @RequestBody final EndpointRegisterInput i endpoint.setExecutor(executorRepository.findById(OPENBAS_EXECUTOR_ID).orElse(null)); } Endpoint updatedEndpoint = this.endpointService.updateEndpoint(endpoint); - // If agent is not temporary and not the same version as the platform => Create an upgrade task for the agent + // If agent is not temporary and not the same version as the platform => Create an upgrade task + // for the agent if (updatedEndpoint.getParent() == null && !updatedEndpoint.getAgentVersion().equals(version)) { AssetAgentJob assetAgentJob = new AssetAgentJob(); - assetAgentJob.setCommand(this.endpointService.generateUpgradeCommand(updatedEndpoint.getPlatform().name())); + assetAgentJob.setCommand( + this.endpointService.generateUpgradeCommand(updatedEndpoint.getPlatform().name())); assetAgentJob.setAsset(updatedEndpoint); assetAgentJobRepository.save(assetAgentJob); } @@ -100,8 +105,10 @@ public Endpoint upsertEndpoint(@Valid @RequestBody final EndpointRegisterInput i @GetMapping(ENDPOINT_URI + "/jobs/{endpointExternalReference}") @PreAuthorize("isPlanner()") @Transactional(rollbackOn = Exception.class) - public List getEndpointJobs(@PathVariable @NotBlank final String endpointExternalReference) { - return this.assetAgentJobRepository.findAll(AssetAgentJobSpecification.forEndpoint(endpointExternalReference)); + public List getEndpointJobs( + @PathVariable @NotBlank final String endpointExternalReference) { + return this.assetAgentJobRepository.findAll( + AssetAgentJobSpecification.forEndpoint(endpointExternalReference)); } @PostMapping(ENDPOINT_URI + "/jobs/{assetAgentJobId}") @@ -126,13 +133,11 @@ public Endpoint endpoint(@PathVariable @NotBlank final String endpointId) { @PostMapping(ENDPOINT_URI + "/search") public Page endpoints(@RequestBody @Valid SearchPaginationInput searchPaginationInput) { return buildPaginationJPA( - (Specification specification, Pageable pageable) -> this.endpointRepository.findAll( - EndpointSpecification.findEndpointsForInjection().and(specification), - pageable - ), - searchPaginationInput, - Endpoint.class - ); + (Specification specification, Pageable pageable) -> + this.endpointRepository.findAll( + EndpointSpecification.findEndpointsForInjection().and(specification), pageable), + searchPaginationInput, + Endpoint.class); } @PutMapping(ENDPOINT_URI + "/{endpointId}") diff --git a/openbas-api/src/main/java/io/openbas/rest/asset/endpoint/form/EndpointInput.java b/openbas-api/src/main/java/io/openbas/rest/asset/endpoint/form/EndpointInput.java index 60c3a7f4a6..3bf6918a6f 100644 --- a/openbas-api/src/main/java/io/openbas/rest/asset/endpoint/form/EndpointInput.java +++ b/openbas-api/src/main/java/io/openbas/rest/asset/endpoint/form/EndpointInput.java @@ -1,5 +1,7 @@ package io.openbas.rest.asset.endpoint.form; +import static io.openbas.config.AppConfig.MANDATORY_MESSAGE; + import com.fasterxml.jackson.annotation.JsonProperty; import io.openbas.database.model.Endpoint; import io.openbas.rest.asset.form.AssetInput; @@ -9,8 +11,6 @@ import lombok.Data; import lombok.EqualsAndHashCode; -import static io.openbas.config.AppConfig.MANDATORY_MESSAGE; - @EqualsAndHashCode(callSuper = true) @Data public class EndpointInput extends AssetInput { @@ -36,5 +36,4 @@ public class EndpointInput extends AssetInput { @JsonProperty("endpoint_mac_addresses") private String[] macAddresses; - } diff --git a/openbas-api/src/main/java/io/openbas/rest/asset/endpoint/form/EndpointRegisterInput.java b/openbas-api/src/main/java/io/openbas/rest/asset/endpoint/form/EndpointRegisterInput.java index cc1308e635..2a492a5cab 100644 --- a/openbas-api/src/main/java/io/openbas/rest/asset/endpoint/form/EndpointRegisterInput.java +++ b/openbas-api/src/main/java/io/openbas/rest/asset/endpoint/form/EndpointRegisterInput.java @@ -1,17 +1,17 @@ package io.openbas.rest.asset.endpoint.form; +import static io.openbas.config.AppConfig.MANDATORY_MESSAGE; + import com.fasterxml.jackson.annotation.JsonProperty; import jakarta.validation.constraints.NotNull; import lombok.Data; import lombok.EqualsAndHashCode; -import static io.openbas.config.AppConfig.MANDATORY_MESSAGE; - @Data @EqualsAndHashCode(callSuper = true) public class EndpointRegisterInput extends EndpointInput { - @NotNull(message = MANDATORY_MESSAGE) - @JsonProperty("asset_external_reference") - private String externalReference; + @NotNull(message = MANDATORY_MESSAGE) + @JsonProperty("asset_external_reference") + private String externalReference; } diff --git a/openbas-api/src/main/java/io/openbas/rest/asset/form/AssetInput.java b/openbas-api/src/main/java/io/openbas/rest/asset/form/AssetInput.java index 9ab127ea0e..bc99ef6296 100644 --- a/openbas-api/src/main/java/io/openbas/rest/asset/form/AssetInput.java +++ b/openbas-api/src/main/java/io/openbas/rest/asset/form/AssetInput.java @@ -1,15 +1,14 @@ package io.openbas.rest.asset.form; +import static io.openbas.config.AppConfig.MANDATORY_MESSAGE; + import com.fasterxml.jackson.annotation.JsonProperty; import io.swagger.v3.oas.annotations.media.Schema; import jakarta.validation.constraints.NotBlank; -import lombok.Data; - import java.time.Instant; import java.util.ArrayList; import java.util.List; - -import static io.openbas.config.AppConfig.MANDATORY_MESSAGE; +import lombok.Data; @Data public abstract class AssetInput { diff --git a/openbas-api/src/main/java/io/openbas/rest/asset/security_platforms/SecurityPlatformApi.java b/openbas-api/src/main/java/io/openbas/rest/asset/security_platforms/SecurityPlatformApi.java index 4d5ddb21a3..b4998695a5 100644 --- a/openbas-api/src/main/java/io/openbas/rest/asset/security_platforms/SecurityPlatformApi.java +++ b/openbas-api/src/main/java/io/openbas/rest/asset/security_platforms/SecurityPlatformApi.java @@ -1,5 +1,9 @@ package io.openbas.rest.asset.security_platforms; +import static io.openbas.database.model.User.ROLE_USER; +import static io.openbas.helper.StreamHelper.iterableToSet; +import static io.openbas.utils.pagination.PaginationUtils.buildPaginationJPA; + import io.openbas.database.model.*; import io.openbas.database.repository.*; import io.openbas.rest.asset.security_platforms.form.SecurityPlatformInput; @@ -9,6 +13,7 @@ import jakarta.transaction.Transactional; import jakarta.validation.Valid; import jakarta.validation.constraints.NotBlank; +import java.util.Optional; import lombok.RequiredArgsConstructor; import org.springframework.beans.factory.annotation.Value; import org.springframework.data.domain.Page; @@ -16,132 +21,137 @@ import org.springframework.security.access.prepost.PreAuthorize; import org.springframework.web.bind.annotation.*; -import java.util.Optional; - -import static io.openbas.database.model.User.ROLE_USER; -import static io.openbas.helper.StreamHelper.iterableToSet; -import static io.openbas.utils.pagination.PaginationUtils.buildPaginationJPA; - @RequiredArgsConstructor @RestController @Secured(ROLE_USER) public class SecurityPlatformApi { - public static final String SECURITY_PLATFORM_URI = "/api/security_platforms"; + public static final String SECURITY_PLATFORM_URI = "/api/security_platforms"; - @Value("${info.app.version:unknown}") - String version; - private final SecurityPlatformRepository securityPlatformRepository; - private final DocumentRepository documentRepository; - private final TagRepository tagRepository; + @Value("${info.app.version:unknown}") + String version; - @GetMapping(SECURITY_PLATFORM_URI) - public Iterable securityPlatforms() { - return securityPlatformRepository.findAll(); - } + private final SecurityPlatformRepository securityPlatformRepository; + private final DocumentRepository documentRepository; + private final TagRepository tagRepository; - @PostMapping(SECURITY_PLATFORM_URI) - @PreAuthorize("isPlanner()") - @Transactional(rollbackOn = Exception.class) - public SecurityPlatform createSecurityPlatform(@Valid @RequestBody final SecurityPlatformInput input) { - SecurityPlatform securityPlatform = new SecurityPlatform(); - securityPlatform.setUpdateAttributes(input); - securityPlatform.setSecurityPlatformType(input.getSecurityPlatformType()); - if (input.getLogoDark() != null) { - securityPlatform.setLogoDark(documentRepository.findById(input.getLogoDark()).orElse(null)); - } else { - securityPlatform.setLogoDark(null); - } - if (input.getLogoLight() != null) { - securityPlatform.setLogoLight(documentRepository.findById(input.getLogoLight()).orElse(null)); - } else { - securityPlatform.setLogoLight(null); - } - securityPlatform.setTags(iterableToSet(this.tagRepository.findAllById(input.getTagIds()))); - return this.securityPlatformRepository.save(securityPlatform); - } + @GetMapping(SECURITY_PLATFORM_URI) + public Iterable securityPlatforms() { + return securityPlatformRepository.findAll(); + } - @PostMapping(SECURITY_PLATFORM_URI + "/upsert") - @PreAuthorize("isPlanner()") - @org.springframework.transaction.annotation.Transactional(rollbackFor = Exception.class) - public SecurityPlatform upsertSecurityPlatform(@Valid @RequestBody SecurityPlatformUpsertInput input) { - Optional securityPlatform = securityPlatformRepository.findByExternalReference(input.getExternalReference()); - if (securityPlatform.isPresent()) { - SecurityPlatform existingSecurityPlatform = securityPlatform.get(); - existingSecurityPlatform.setUpdateAttributes(input); - existingSecurityPlatform.setSecurityPlatformType(input.getSecurityPlatformType()); - if (input.getLogoDark() != null) { - existingSecurityPlatform.setLogoDark(documentRepository.findById(input.getLogoDark()).orElse(null)); - } else { - existingSecurityPlatform.setLogoDark(null); - } - if (input.getLogoLight() != null) { - existingSecurityPlatform.setLogoLight(documentRepository.findById(input.getLogoLight()).orElse(null)); - } else { - existingSecurityPlatform.setLogoLight(null); - } - existingSecurityPlatform.setTags(iterableToSet(this.tagRepository.findAllById(input.getTagIds()))); - return this.securityPlatformRepository.save(existingSecurityPlatform); - } else { - SecurityPlatform newSecurityPlatform = new SecurityPlatform(); - newSecurityPlatform.setUpdateAttributes(input); - newSecurityPlatform.setSecurityPlatformType(input.getSecurityPlatformType()); - if (input.getLogoDark() != null) { - newSecurityPlatform.setLogoDark(documentRepository.findById(input.getLogoDark()).orElse(null)); - } else { - newSecurityPlatform.setLogoDark(null); - } - if (input.getLogoLight() != null) { - newSecurityPlatform.setLogoLight(documentRepository.findById(input.getLogoLight()).orElse(null)); - } else { - newSecurityPlatform.setLogoLight(null); - } - newSecurityPlatform.setTags(iterableToSet(this.tagRepository.findAllById(input.getTagIds()))); - return this.securityPlatformRepository.save(newSecurityPlatform); - } + @PostMapping(SECURITY_PLATFORM_URI) + @PreAuthorize("isPlanner()") + @Transactional(rollbackOn = Exception.class) + public SecurityPlatform createSecurityPlatform( + @Valid @RequestBody final SecurityPlatformInput input) { + SecurityPlatform securityPlatform = new SecurityPlatform(); + securityPlatform.setUpdateAttributes(input); + securityPlatform.setSecurityPlatformType(input.getSecurityPlatformType()); + if (input.getLogoDark() != null) { + securityPlatform.setLogoDark(documentRepository.findById(input.getLogoDark()).orElse(null)); + } else { + securityPlatform.setLogoDark(null); } - - @GetMapping(SECURITY_PLATFORM_URI + "/{securityPlatformId}") - @PreAuthorize("isPlanner()") - public SecurityPlatform securityPlatform(@PathVariable @NotBlank final String securityPlatformId) { - return this.securityPlatformRepository.findById(securityPlatformId).orElseThrow(ElementNotFoundException::new); + if (input.getLogoLight() != null) { + securityPlatform.setLogoLight(documentRepository.findById(input.getLogoLight()).orElse(null)); + } else { + securityPlatform.setLogoLight(null); } + securityPlatform.setTags(iterableToSet(this.tagRepository.findAllById(input.getTagIds()))); + return this.securityPlatformRepository.save(securityPlatform); + } - @PostMapping(SECURITY_PLATFORM_URI + "/search") - public Page securityPlatforms(@RequestBody @Valid SearchPaginationInput searchPaginationInput) { - return buildPaginationJPA( - this.securityPlatformRepository::findAll, - searchPaginationInput, - SecurityPlatform.class - ); + @PostMapping(SECURITY_PLATFORM_URI + "/upsert") + @PreAuthorize("isPlanner()") + @org.springframework.transaction.annotation.Transactional(rollbackFor = Exception.class) + public SecurityPlatform upsertSecurityPlatform( + @Valid @RequestBody SecurityPlatformUpsertInput input) { + Optional securityPlatform = + securityPlatformRepository.findByExternalReference(input.getExternalReference()); + if (securityPlatform.isPresent()) { + SecurityPlatform existingSecurityPlatform = securityPlatform.get(); + existingSecurityPlatform.setUpdateAttributes(input); + existingSecurityPlatform.setSecurityPlatformType(input.getSecurityPlatformType()); + if (input.getLogoDark() != null) { + existingSecurityPlatform.setLogoDark( + documentRepository.findById(input.getLogoDark()).orElse(null)); + } else { + existingSecurityPlatform.setLogoDark(null); + } + if (input.getLogoLight() != null) { + existingSecurityPlatform.setLogoLight( + documentRepository.findById(input.getLogoLight()).orElse(null)); + } else { + existingSecurityPlatform.setLogoLight(null); + } + existingSecurityPlatform.setTags( + iterableToSet(this.tagRepository.findAllById(input.getTagIds()))); + return this.securityPlatformRepository.save(existingSecurityPlatform); + } else { + SecurityPlatform newSecurityPlatform = new SecurityPlatform(); + newSecurityPlatform.setUpdateAttributes(input); + newSecurityPlatform.setSecurityPlatformType(input.getSecurityPlatformType()); + if (input.getLogoDark() != null) { + newSecurityPlatform.setLogoDark( + documentRepository.findById(input.getLogoDark()).orElse(null)); + } else { + newSecurityPlatform.setLogoDark(null); + } + if (input.getLogoLight() != null) { + newSecurityPlatform.setLogoLight( + documentRepository.findById(input.getLogoLight()).orElse(null)); + } else { + newSecurityPlatform.setLogoLight(null); + } + newSecurityPlatform.setTags(iterableToSet(this.tagRepository.findAllById(input.getTagIds()))); + return this.securityPlatformRepository.save(newSecurityPlatform); } + } - @PutMapping(SECURITY_PLATFORM_URI + "/{securityPlatformId}") - @PreAuthorize("isPlanner()") - @Transactional(rollbackOn = Exception.class) - public SecurityPlatform updateSecurityPlatform( - @PathVariable @NotBlank final String securityPlatformId, - @Valid @RequestBody final SecurityPlatformInput input) { - SecurityPlatform securityPlatform = this.securityPlatformRepository.findById(securityPlatformId).orElseThrow(); - securityPlatform.setUpdateAttributes(input); - if (input.getLogoDark() != null) { - securityPlatform.setLogoDark(documentRepository.findById(input.getLogoDark()).orElse(null)); - } else { - securityPlatform.setLogoDark(null); - } - if (input.getLogoLight() != null) { - securityPlatform.setLogoLight(documentRepository.findById(input.getLogoLight()).orElse(null)); - } else { - securityPlatform.setLogoLight(null); - } - securityPlatform.setTags(iterableToSet(this.tagRepository.findAllById(input.getTagIds()))); - return this.securityPlatformRepository.save(securityPlatform); - } + @GetMapping(SECURITY_PLATFORM_URI + "/{securityPlatformId}") + @PreAuthorize("isPlanner()") + public SecurityPlatform securityPlatform( + @PathVariable @NotBlank final String securityPlatformId) { + return this.securityPlatformRepository + .findById(securityPlatformId) + .orElseThrow(ElementNotFoundException::new); + } + + @PostMapping(SECURITY_PLATFORM_URI + "/search") + public Page securityPlatforms( + @RequestBody @Valid SearchPaginationInput searchPaginationInput) { + return buildPaginationJPA( + this.securityPlatformRepository::findAll, searchPaginationInput, SecurityPlatform.class); + } - @DeleteMapping(SECURITY_PLATFORM_URI + "/{securityPlatformId}") - @PreAuthorize("isPlanner()") - @Transactional(rollbackOn = Exception.class) - public void deleteSecurityPlatform(@PathVariable @NotBlank final String securityPlatformId) { - this.securityPlatformRepository.deleteById(securityPlatformId); + @PutMapping(SECURITY_PLATFORM_URI + "/{securityPlatformId}") + @PreAuthorize("isPlanner()") + @Transactional(rollbackOn = Exception.class) + public SecurityPlatform updateSecurityPlatform( + @PathVariable @NotBlank final String securityPlatformId, + @Valid @RequestBody final SecurityPlatformInput input) { + SecurityPlatform securityPlatform = + this.securityPlatformRepository.findById(securityPlatformId).orElseThrow(); + securityPlatform.setUpdateAttributes(input); + if (input.getLogoDark() != null) { + securityPlatform.setLogoDark(documentRepository.findById(input.getLogoDark()).orElse(null)); + } else { + securityPlatform.setLogoDark(null); } + if (input.getLogoLight() != null) { + securityPlatform.setLogoLight(documentRepository.findById(input.getLogoLight()).orElse(null)); + } else { + securityPlatform.setLogoLight(null); + } + securityPlatform.setTags(iterableToSet(this.tagRepository.findAllById(input.getTagIds()))); + return this.securityPlatformRepository.save(securityPlatform); + } + + @DeleteMapping(SECURITY_PLATFORM_URI + "/{securityPlatformId}") + @PreAuthorize("isPlanner()") + @Transactional(rollbackOn = Exception.class) + public void deleteSecurityPlatform(@PathVariable @NotBlank final String securityPlatformId) { + this.securityPlatformRepository.deleteById(securityPlatformId); + } } diff --git a/openbas-api/src/main/java/io/openbas/rest/asset/security_platforms/form/SecurityPlatformInput.java b/openbas-api/src/main/java/io/openbas/rest/asset/security_platforms/form/SecurityPlatformInput.java index 5f395e429f..83fca13376 100644 --- a/openbas-api/src/main/java/io/openbas/rest/asset/security_platforms/form/SecurityPlatformInput.java +++ b/openbas-api/src/main/java/io/openbas/rest/asset/security_platforms/form/SecurityPlatformInput.java @@ -1,5 +1,7 @@ package io.openbas.rest.asset.security_platforms.form; +import static io.openbas.config.AppConfig.MANDATORY_MESSAGE; + import com.fasterxml.jackson.annotation.JsonProperty; import io.openbas.database.model.SecurityPlatform; import io.openbas.rest.asset.form.AssetInput; @@ -7,8 +9,6 @@ import lombok.Data; import lombok.EqualsAndHashCode; -import static io.openbas.config.AppConfig.MANDATORY_MESSAGE; - @EqualsAndHashCode(callSuper = true) @Data public class SecurityPlatformInput extends AssetInput { diff --git a/openbas-api/src/main/java/io/openbas/rest/asset/security_platforms/form/SecurityPlatformUpsertInput.java b/openbas-api/src/main/java/io/openbas/rest/asset/security_platforms/form/SecurityPlatformUpsertInput.java index 5d6e7ebf4e..18b56d9a91 100644 --- a/openbas-api/src/main/java/io/openbas/rest/asset/security_platforms/form/SecurityPlatformUpsertInput.java +++ b/openbas-api/src/main/java/io/openbas/rest/asset/security_platforms/form/SecurityPlatformUpsertInput.java @@ -1,5 +1,7 @@ package io.openbas.rest.asset.security_platforms.form; +import static io.openbas.config.AppConfig.MANDATORY_MESSAGE; + import com.fasterxml.jackson.annotation.JsonProperty; import io.openbas.database.model.SecurityPlatform; import io.openbas.rest.asset.form.AssetInput; @@ -7,8 +9,6 @@ import lombok.Data; import lombok.EqualsAndHashCode; -import static io.openbas.config.AppConfig.MANDATORY_MESSAGE; - @EqualsAndHashCode(callSuper = true) @Data public class SecurityPlatformUpsertInput extends AssetInput { diff --git a/openbas-api/src/main/java/io/openbas/rest/asset_group/AssetGroupApi.java b/openbas-api/src/main/java/io/openbas/rest/asset_group/AssetGroupApi.java index 700adf1bad..a0c47c3960 100644 --- a/openbas-api/src/main/java/io/openbas/rest/asset_group/AssetGroupApi.java +++ b/openbas-api/src/main/java/io/openbas/rest/asset_group/AssetGroupApi.java @@ -1,5 +1,9 @@ package io.openbas.rest.asset_group; +import static io.openbas.database.model.User.ROLE_USER; +import static io.openbas.database.specification.AssetGroupSpecification.fromIds; +import static io.openbas.helper.StreamHelper.iterableToSet; + import io.openbas.aop.LogExecutionTime; import io.openbas.asset.AssetGroupService; import io.openbas.database.model.AssetGroup; @@ -12,6 +16,7 @@ import jakarta.validation.Valid; import jakarta.validation.constraints.NotBlank; import jakarta.validation.constraints.NotNull; +import java.util.List; import lombok.RequiredArgsConstructor; import org.springframework.data.domain.Page; import org.springframework.security.access.annotation.Secured; @@ -19,12 +24,6 @@ import org.springframework.transaction.annotation.Transactional; import org.springframework.web.bind.annotation.*; -import java.util.List; - -import static io.openbas.database.model.User.ROLE_USER; -import static io.openbas.database.specification.AssetGroupSpecification.fromIds; -import static io.openbas.helper.StreamHelper.iterableToSet; - @RestController @RequiredArgsConstructor @Secured(ROLE_USER) @@ -55,7 +54,8 @@ public List assetGroups() { @LogExecutionTime @PostMapping(ASSET_GROUP_URI + "/search") @PreAuthorize("isObserver()") - public Page assetGroups(@RequestBody @Valid SearchPaginationInput searchPaginationInput) { + public Page assetGroups( + @RequestBody @Valid SearchPaginationInput searchPaginationInput) { return this.assetGroupCriteriaBuilderService.assetGroupPagination(searchPaginationInput); } @@ -63,7 +63,8 @@ public Page assetGroups(@RequestBody @Valid SearchPaginationIn @PreAuthorize("isObserver()") @Transactional(readOnly = true) @Tracing(name = "Find teams", layer = "api", operation = "POST") - public List findTeams(@RequestBody @Valid @NotNull final List assetGroupIds) { + public List findTeams( + @RequestBody @Valid @NotNull final List assetGroupIds) { return this.assetGroupCriteriaBuilderService.find(fromIds(assetGroupIds)); } @@ -101,5 +102,4 @@ public AssetGroup updateAssetsOnAssetGroup( public void deleteAssetGroup(@PathVariable @NotBlank final String assetGroupId) { this.assetGroupService.deleteAssetGroup(assetGroupId); } - } diff --git a/openbas-api/src/main/java/io/openbas/rest/asset_group/AssetGroupCriteriaBuilderService.java b/openbas-api/src/main/java/io/openbas/rest/asset_group/AssetGroupCriteriaBuilderService.java index 62937377ac..598d2f67ca 100644 --- a/openbas-api/src/main/java/io/openbas/rest/asset_group/AssetGroupCriteriaBuilderService.java +++ b/openbas-api/src/main/java/io/openbas/rest/asset_group/AssetGroupCriteriaBuilderService.java @@ -1,5 +1,11 @@ package io.openbas.rest.asset_group; +import static io.openbas.database.criteria.GenericCriteria.countQuery; +import static io.openbas.rest.asset_group.AssetGroupQueryHelper.execution; +import static io.openbas.rest.asset_group.AssetGroupQueryHelper.select; +import static io.openbas.utils.pagination.PaginationUtils.buildPaginationCriteriaBuilder; +import static io.openbas.utils.pagination.SortUtilsCriteriaBuilder.toSortCriteriaBuilder; + import com.fasterxml.jackson.databind.ObjectMapper; import io.openbas.database.model.AssetGroup; import io.openbas.rest.asset_group.form.AssetGroupOutput; @@ -10,6 +16,7 @@ import jakarta.persistence.Tuple; import jakarta.persistence.TypedQuery; import jakarta.persistence.criteria.*; +import java.util.List; import lombok.RequiredArgsConstructor; import org.jetbrains.annotations.NotNull; import org.springframework.data.domain.Page; @@ -18,31 +25,17 @@ import org.springframework.data.jpa.domain.Specification; import org.springframework.stereotype.Service; -import java.util.List; - -import static io.openbas.database.criteria.GenericCriteria.countQuery; -import static io.openbas.rest.asset_group.AssetGroupQueryHelper.execution; -import static io.openbas.rest.asset_group.AssetGroupQueryHelper.select; -import static io.openbas.utils.pagination.PaginationUtils.buildPaginationCriteriaBuilder; -import static io.openbas.utils.pagination.SortUtilsCriteriaBuilder.toSortCriteriaBuilder; - @RequiredArgsConstructor @Service public class AssetGroupCriteriaBuilderService { - @Resource - protected ObjectMapper mapper; + @Resource protected ObjectMapper mapper; - @PersistenceContext - private EntityManager entityManager; + @PersistenceContext private EntityManager entityManager; public Page assetGroupPagination( @NotNull SearchPaginationInput searchPaginationInput) { - return buildPaginationCriteriaBuilder( - this::paginate, - searchPaginationInput, - AssetGroup.class - ); + return buildPaginationCriteriaBuilder(this::paginate, searchPaginationInput, AssetGroup.class); } public List find(Specification specification) { @@ -102,5 +95,4 @@ private Page paginate( return new PageImpl<>(assetGroups, pageable, total); } - } diff --git a/openbas-api/src/main/java/io/openbas/rest/asset_group/AssetGroupQueryHelper.java b/openbas-api/src/main/java/io/openbas/rest/asset_group/AssetGroupQueryHelper.java index 217454dc50..6025afe25f 100644 --- a/openbas-api/src/main/java/io/openbas/rest/asset_group/AssetGroupQueryHelper.java +++ b/openbas-api/src/main/java/io/openbas/rest/asset_group/AssetGroupQueryHelper.java @@ -1,5 +1,7 @@ package io.openbas.rest.asset_group; +import static io.openbas.utils.JpaUtils.createJoinArrayAggOnId; + import com.fasterxml.jackson.databind.ObjectMapper; import io.openbas.database.model.AssetGroup; import io.openbas.database.model.Filters.FilterGroup; @@ -10,68 +12,67 @@ import jakarta.persistence.criteria.CriteriaQuery; import jakarta.persistence.criteria.Expression; import jakarta.persistence.criteria.Root; - import java.util.Arrays; import java.util.Collections; import java.util.List; import java.util.stream.Collectors; -import static io.openbas.utils.JpaUtils.createJoinArrayAggOnId; - public class AssetGroupQueryHelper { - private AssetGroupQueryHelper() { - - } + private AssetGroupQueryHelper() {} // -- SELECT -- - public static void select(CriteriaBuilder cb, CriteriaQuery cq, Root assetGroupRoot) { + public static void select( + CriteriaBuilder cb, CriteriaQuery cq, Root assetGroupRoot) { // Array aggregations Expression assetIdsExpression = createJoinArrayAggOnId(cb, assetGroupRoot, "assets"); Expression tagIdsExpression = createJoinArrayAggOnId(cb, assetGroupRoot, "tags"); // Multiselect cq.multiselect( - assetGroupRoot.get("id").alias("asset_group_id"), - assetGroupRoot.get("name").alias("asset_group_name"), - assetGroupRoot.get("description").alias("asset_group_description"), - assetGroupRoot.get("dynamicFilter").as(String.class).alias("asset_group_dynamic_filter"), - assetIdsExpression.alias("asset_group_assets"), - tagIdsExpression.alias("asset_group_tags") - ).distinct(true); + assetGroupRoot.get("id").alias("asset_group_id"), + assetGroupRoot.get("name").alias("asset_group_name"), + assetGroupRoot.get("description").alias("asset_group_description"), + assetGroupRoot + .get("dynamicFilter") + .as(String.class) + .alias("asset_group_dynamic_filter"), + assetIdsExpression.alias("asset_group_assets"), + tagIdsExpression.alias("asset_group_tags")) + .distinct(true); // Group by - cq.groupBy(Collections.singletonList( - assetGroupRoot.get("id") - )); + cq.groupBy(Collections.singletonList(assetGroupRoot.get("id"))); } // -- EXECUTION -- public static List execution(TypedQuery query, ObjectMapper mapper) { - return query.getResultList() - .stream() - .map(tuple -> { - FilterGroup filterGroup; - try { - filterGroup = mapper.readValue( - tuple.get("asset_group_dynamic_filter", String.class), - FilterGroup.class - ); - } catch (Exception e) { - filterGroup = null; - } - return AssetGroupOutput.builder() - .id(tuple.get("asset_group_id", String.class)) - .name(tuple.get("asset_group_name", String.class)) - .description(tuple.get("asset_group_description", String.class)) - .dynamicFilter(filterGroup) - .assets(Arrays.stream(tuple.get("asset_group_assets", String[].class)).collect(Collectors.toSet())) - .tags(Arrays.stream(tuple.get("asset_group_tags", String[].class)).collect(Collectors.toSet())) - .build(); - }) + return query.getResultList().stream() + .map( + tuple -> { + FilterGroup filterGroup; + try { + filterGroup = + mapper.readValue( + tuple.get("asset_group_dynamic_filter", String.class), FilterGroup.class); + } catch (Exception e) { + filterGroup = null; + } + return AssetGroupOutput.builder() + .id(tuple.get("asset_group_id", String.class)) + .name(tuple.get("asset_group_name", String.class)) + .description(tuple.get("asset_group_description", String.class)) + .dynamicFilter(filterGroup) + .assets( + Arrays.stream(tuple.get("asset_group_assets", String[].class)) + .collect(Collectors.toSet())) + .tags( + Arrays.stream(tuple.get("asset_group_tags", String[].class)) + .collect(Collectors.toSet())) + .build(); + }) .toList(); } - } diff --git a/openbas-api/src/main/java/io/openbas/rest/asset_group/form/AssetGroupInput.java b/openbas-api/src/main/java/io/openbas/rest/asset_group/form/AssetGroupInput.java index 809527a175..e752f7ed76 100644 --- a/openbas-api/src/main/java/io/openbas/rest/asset_group/form/AssetGroupInput.java +++ b/openbas-api/src/main/java/io/openbas/rest/asset_group/form/AssetGroupInput.java @@ -1,15 +1,14 @@ package io.openbas.rest.asset_group.form; +import static io.openbas.config.AppConfig.MANDATORY_MESSAGE; + import com.fasterxml.jackson.annotation.JsonProperty; import io.openbas.database.model.Filters.FilterGroup; import jakarta.validation.constraints.NotBlank; -import lombok.Getter; -import lombok.Setter; - import java.util.ArrayList; import java.util.List; - -import static io.openbas.config.AppConfig.MANDATORY_MESSAGE; +import lombok.Getter; +import lombok.Setter; @Getter @Setter @@ -27,5 +26,4 @@ public class AssetGroupInput { @JsonProperty("asset_group_dynamic_filter") private FilterGroup dynamicFilter; - } diff --git a/openbas-api/src/main/java/io/openbas/rest/asset_group/form/AssetGroupOutput.java b/openbas-api/src/main/java/io/openbas/rest/asset_group/form/AssetGroupOutput.java index ca1ad7b069..468f435cd8 100644 --- a/openbas-api/src/main/java/io/openbas/rest/asset_group/form/AssetGroupOutput.java +++ b/openbas-api/src/main/java/io/openbas/rest/asset_group/form/AssetGroupOutput.java @@ -3,11 +3,10 @@ import com.fasterxml.jackson.annotation.JsonProperty; import io.openbas.database.model.Filters; import jakarta.validation.constraints.NotBlank; +import java.util.Set; import lombok.Builder; import lombok.Data; -import java.util.Set; - @Builder @Data public class AssetGroupOutput { @@ -31,5 +30,4 @@ public class AssetGroupOutput { @JsonProperty("asset_group_tags") private Set tags; - } diff --git a/openbas-api/src/main/java/io/openbas/rest/asset_group/form/UpdateAssetsOnAssetGroupInput.java b/openbas-api/src/main/java/io/openbas/rest/asset_group/form/UpdateAssetsOnAssetGroupInput.java index 973a541a6a..277846788f 100644 --- a/openbas-api/src/main/java/io/openbas/rest/asset_group/form/UpdateAssetsOnAssetGroupInput.java +++ b/openbas-api/src/main/java/io/openbas/rest/asset_group/form/UpdateAssetsOnAssetGroupInput.java @@ -1,16 +1,14 @@ package io.openbas.rest.asset_group.form; import com.fasterxml.jackson.annotation.JsonProperty; +import java.util.List; import lombok.Getter; import lombok.Setter; -import java.util.List; - @Getter @Setter public class UpdateAssetsOnAssetGroupInput { @JsonProperty("asset_group_assets") private List assetIds; - } diff --git a/openbas-api/src/main/java/io/openbas/rest/atomic_testing/AtomicTestingApi.java b/openbas-api/src/main/java/io/openbas/rest/atomic_testing/AtomicTestingApi.java index f650601e82..abde0406a3 100644 --- a/openbas-api/src/main/java/io/openbas/rest/atomic_testing/AtomicTestingApi.java +++ b/openbas-api/src/main/java/io/openbas/rest/atomic_testing/AtomicTestingApi.java @@ -12,14 +12,13 @@ import io.openbas.utils.pagination.SearchPaginationInput; import jakarta.validation.Valid; import jakarta.validation.constraints.NotBlank; +import java.util.List; import lombok.RequiredArgsConstructor; import org.springframework.data.domain.Page; import org.springframework.security.access.prepost.PreAuthorize; import org.springframework.transaction.annotation.Transactional; import org.springframework.web.bind.annotation.*; -import java.util.List; - @RestController @RequestMapping("/api/atomic-testings") @PreAuthorize("isAdmin()") @@ -61,8 +60,7 @@ public InjectResultDTO updateAtomicTesting( } @DeleteMapping("/{injectId}") - public void deleteAtomicTesting( - @PathVariable @NotBlank final String injectId) { + public void deleteAtomicTesting(@PathVariable @NotBlank final String injectId) { atomicTestingService.deleteAtomicTesting(injectId); } @@ -76,8 +74,9 @@ public List findTargetResult( @PathVariable String injectId, @PathVariable String targetId, @PathVariable String targetType, - @RequestParam(required = false) String parentTargetId ) { - return injectExpectationService.findExpectationsByInjectAndTargetAndTargetType(injectId, targetId, parentTargetId, targetType); + @RequestParam(required = false) String parentTargetId) { + return injectExpectationService.findExpectationsByInjectAndTargetAndTargetType( + injectId, targetId, parentTargetId, targetType); } @PutMapping("/{injectId}/tags") @@ -87,6 +86,4 @@ public InjectResultDTO updateAtomicTestingTags( @Valid @RequestBody final AtomicTestingUpdateTagsInput input) { return atomicTestingService.updateAtomicTestingTags(injectId, input); } - - } diff --git a/openbas-api/src/main/java/io/openbas/rest/atomic_testing/form/AtomicTestingInput.java b/openbas-api/src/main/java/io/openbas/rest/atomic_testing/form/AtomicTestingInput.java index 62bf5a3f71..4f74c39acd 100644 --- a/openbas-api/src/main/java/io/openbas/rest/atomic_testing/form/AtomicTestingInput.java +++ b/openbas-api/src/main/java/io/openbas/rest/atomic_testing/form/AtomicTestingInput.java @@ -3,13 +3,12 @@ import com.fasterxml.jackson.annotation.JsonProperty; import com.fasterxml.jackson.databind.node.ObjectNode; import io.openbas.rest.inject.form.InjectDocumentInput; +import java.util.ArrayList; +import java.util.List; import lombok.Getter; import lombok.NoArgsConstructor; import lombok.Setter; -import java.util.ArrayList; -import java.util.List; - @Setter @Getter @NoArgsConstructor @@ -44,5 +43,4 @@ public class AtomicTestingInput { @JsonProperty("inject_tags") private List tagIds = new ArrayList<>(); - } diff --git a/openbas-api/src/main/java/io/openbas/rest/atomic_testing/form/AtomicTestingUpdateTagsInput.java b/openbas-api/src/main/java/io/openbas/rest/atomic_testing/form/AtomicTestingUpdateTagsInput.java index 896f49eb6f..9c13cbc515 100644 --- a/openbas-api/src/main/java/io/openbas/rest/atomic_testing/form/AtomicTestingUpdateTagsInput.java +++ b/openbas-api/src/main/java/io/openbas/rest/atomic_testing/form/AtomicTestingUpdateTagsInput.java @@ -1,17 +1,15 @@ package io.openbas.rest.atomic_testing.form; import com.fasterxml.jackson.annotation.JsonProperty; -import lombok.Getter; -import lombok.Setter; - import java.util.ArrayList; import java.util.List; +import lombok.Getter; +import lombok.Setter; @Setter @Getter public class AtomicTestingUpdateTagsInput { - @JsonProperty("atomic_tags") private List tagIds = new ArrayList<>(); } diff --git a/openbas-api/src/main/java/io/openbas/rest/atomic_testing/form/InjectResultDTO.java b/openbas-api/src/main/java/io/openbas/rest/atomic_testing/form/InjectResultDTO.java index 05b91f2ceb..f955178685 100644 --- a/openbas-api/src/main/java/io/openbas/rest/atomic_testing/form/InjectResultDTO.java +++ b/openbas-api/src/main/java/io/openbas/rest/atomic_testing/form/InjectResultDTO.java @@ -1,22 +1,21 @@ package io.openbas.rest.atomic_testing.form; +import static java.time.Instant.now; + import com.fasterxml.jackson.annotation.JsonProperty; import com.fasterxml.jackson.databind.node.ObjectNode; import io.openbas.database.model.*; import io.openbas.utils.AtomicTestingMapper.ExpectationResultsByType; import io.swagger.v3.oas.annotations.media.Schema; import jakarta.validation.constraints.NotNull; +import java.time.Instant; +import java.util.ArrayList; +import java.util.List; import lombok.Builder; import lombok.Builder.Default; import lombok.Getter; import lombok.Setter; -import java.time.Instant; -import java.util.ArrayList; -import java.util.List; - -import static java.time.Instant.now; - @Setter @Getter @Builder @@ -69,8 +68,7 @@ public class InjectResultDTO { @Schema( description = "Specifies the categories of targetResults for atomic testing.", - example = "assets, asset groups, teams, players" - ) + example = "assets, asset groups, teams, players") @JsonProperty("inject_targets") @NotNull private List targets; diff --git a/openbas-api/src/main/java/io/openbas/rest/atomic_testing/form/InjectTargetWithResult.java b/openbas-api/src/main/java/io/openbas/rest/atomic_testing/form/InjectTargetWithResult.java index f187dc91f8..5a6b8dc894 100644 --- a/openbas-api/src/main/java/io/openbas/rest/atomic_testing/form/InjectTargetWithResult.java +++ b/openbas-api/src/main/java/io/openbas/rest/atomic_testing/form/InjectTargetWithResult.java @@ -5,25 +5,28 @@ import io.openbas.utils.AtomicTestingMapper.ExpectationResultsByType; import jakarta.validation.constraints.NotBlank; import jakarta.validation.constraints.NotNull; -import lombok.Getter; - import java.util.ArrayList; import java.util.List; import java.util.Objects; +import lombok.Getter; @Getter public class InjectTargetWithResult { private final TargetType targetType; private final PLATFORM_TYPE platformType; - @NotBlank - private final String id; + @NotBlank private final String id; private final String name; private final List expectationResultsByTypes; private final List children = new ArrayList<>(); - public InjectTargetWithResult(@NotNull TargetType targetType, @NotNull String id, @NotNull String name, @NotNull List expectationResultsByTypes, - @NotNull List children, PLATFORM_TYPE platformType) { + public InjectTargetWithResult( + @NotNull TargetType targetType, + @NotNull String id, + @NotNull String name, + @NotNull List expectationResultsByTypes, + @NotNull List children, + PLATFORM_TYPE platformType) { this.targetType = targetType; this.platformType = platformType; this.id = id; @@ -32,7 +35,12 @@ public InjectTargetWithResult(@NotNull TargetType targetType, @NotNull String id this.children.addAll(children); } - public InjectTargetWithResult(@NotNull TargetType targetType, @NotNull String id, @NotNull String name, @NotNull List expectationResultsByTypes, PLATFORM_TYPE platformType) { + public InjectTargetWithResult( + @NotNull TargetType targetType, + @NotNull String id, + @NotNull String name, + @NotNull List expectationResultsByTypes, + PLATFORM_TYPE platformType) { this.targetType = targetType; this.platformType = platformType; this.id = id; diff --git a/openbas-api/src/main/java/io/openbas/rest/attack_pattern/AttackPatternApi.java b/openbas-api/src/main/java/io/openbas/rest/attack_pattern/AttackPatternApi.java index f492c9402c..8803a3d38a 100644 --- a/openbas-api/src/main/java/io/openbas/rest/attack_pattern/AttackPatternApi.java +++ b/openbas-api/src/main/java/io/openbas/rest/attack_pattern/AttackPatternApi.java @@ -1,5 +1,12 @@ package io.openbas.rest.attack_pattern; +import static io.openbas.database.model.User.ROLE_ADMIN; +import static io.openbas.database.model.User.ROLE_USER; +import static io.openbas.database.specification.AttackPatternSpecification.byName; +import static io.openbas.helper.DatabaseHelper.updateRelation; +import static io.openbas.helper.StreamHelper.fromIterable; +import static io.openbas.utils.pagination.PaginationUtils.buildPaginationJPA; + import io.openbas.database.model.AttackPattern; import io.openbas.database.model.InjectorContract; import io.openbas.database.model.KillChainPhase; @@ -18,6 +25,10 @@ import jakarta.transaction.Transactional; import jakarta.validation.Valid; import jakarta.validation.constraints.NotBlank; +import java.time.Instant; +import java.util.ArrayList; +import java.util.List; +import java.util.Optional; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.data.domain.Page; import org.springframework.data.domain.Pageable; @@ -26,168 +37,176 @@ import org.springframework.security.access.annotation.Secured; import org.springframework.web.bind.annotation.*; -import java.time.Instant; -import java.util.ArrayList; -import java.util.List; -import java.util.Optional; - -import static io.openbas.database.model.User.ROLE_ADMIN; -import static io.openbas.database.model.User.ROLE_USER; -import static io.openbas.database.specification.AttackPatternSpecification.byName; -import static io.openbas.helper.DatabaseHelper.updateRelation; -import static io.openbas.helper.StreamHelper.fromIterable; -import static io.openbas.utils.pagination.PaginationUtils.buildPaginationJPA; - @RestController @Secured(ROLE_USER) public class AttackPatternApi extends RestBehavior { - public static final String ATTACK_PATTERN_URI = "/api/attack_patterns"; - - private AttackPatternRepository attackPatternRepository; - - private InjectorContractRepository injectorContractRepository; - private KillChainPhaseRepository killChainPhaseRepository; - - @Autowired - public void setAttackPatternRepository(AttackPatternRepository attackPatternRepository) { - this.attackPatternRepository = attackPatternRepository; - } - - @Autowired - public void setKillChainPhaseRepository(KillChainPhaseRepository killChainPhaseRepository) { - this.killChainPhaseRepository = killChainPhaseRepository; - } - - @Autowired - public void setInjectorContractRepository(InjectorContractRepository injectorContractRepository) { - this.injectorContractRepository = injectorContractRepository; - } - - @GetMapping("/api/attack_patterns") - public List attackPatterns() { - return attackPatternRepository.rawAll(); - } - - @PostMapping("/api/attack_patterns/search") - public Page attackPatterns(@RequestBody @Valid final SearchPaginationInput searchPaginationInput) { - return buildPaginationJPA( - (Specification specification, Pageable pageable) -> this.attackPatternRepository.findAll( - specification, pageable), - searchPaginationInput, - AttackPattern.class - ); - } - - @GetMapping("/api/attack_patterns/{attackPatternId}") - public AttackPattern attackPattern(@PathVariable String attackPatternId) { - return attackPatternRepository.findById(attackPatternId).orElseThrow(ElementNotFoundException::new); - } - - @Secured(ROLE_ADMIN) - @PostMapping("/api/attack_patterns") - @Transactional(rollbackOn = Exception.class) - public AttackPattern createAttackPattern(@Valid @RequestBody AttackPatternCreateInput input) { - AttackPattern attackPattern = new AttackPattern(); - attackPattern.setUpdateAttributes(input); - attackPattern.setKillChainPhases(fromIterable(killChainPhaseRepository.findAllById(input.getKillChainPhasesIds()))); - attackPattern.setParent(updateRelation(input.getParentId(), attackPattern.getParent(), attackPatternRepository)); - return attackPatternRepository.save(attackPattern); - } - - @GetMapping("/api/attack_patterns/{attackPatternId}/injector_contracts") - public Iterable injectorContracts(@PathVariable String attackPatternId) { - attackPatternRepository.findById(attackPatternId).orElseThrow(ElementNotFoundException::new); - return injectorContractRepository.findAll(InjectorContractSpecification.fromAttackPattern(attackPatternId)); - } - - @Secured(ROLE_ADMIN) - @PutMapping("/api/attack_patterns/{attackPatternId}") - @Transactional(rollbackOn = Exception.class) - public AttackPattern updateAttackPattern( - @NotBlank @PathVariable final String attackPatternId, - @Valid @RequestBody AttackPatternUpdateInput input) { - AttackPattern attackPattern = this.attackPatternRepository.findById(attackPatternId).orElseThrow(ElementNotFoundException::new); - attackPattern.setUpdateAttributes(input); - attackPattern.setKillChainPhases(fromIterable(this.killChainPhaseRepository.findAllById(input.getKillChainPhasesIds()))); - attackPattern.setUpdatedAt(Instant.now()); - return attackPatternRepository.save(attackPattern); - } - - private List upsertAttackPatterns(List attackPatterns) { - List upserted = new ArrayList<>(); - attackPatterns.forEach(attackPatternInput -> { - String attackPatternExternalId = attackPatternInput.getExternalId(); - Optional optionalAttackPattern = attackPatternRepository.findByExternalId( - attackPatternExternalId); - List killChainPhases = !attackPatternInput.getKillChainPhasesIds().isEmpty() ? - fromIterable(killChainPhaseRepository.findAllById(attackPatternInput.getKillChainPhasesIds())) - : List.of(); - AttackPattern attackPatternParent = attackPatternInput.getParentId() != null ? - attackPatternRepository.findByStixId(attackPatternInput.getParentId()).orElseThrow(ElementNotFoundException::new) : null; - if (optionalAttackPattern.isEmpty()) { - AttackPattern newAttackPattern = new AttackPattern(); - newAttackPattern.setStixId(attackPatternInput.getStixId()); - newAttackPattern.setExternalId(attackPatternExternalId); - newAttackPattern.setKillChainPhases(killChainPhases); - newAttackPattern.setName(attackPatternInput.getName()); - newAttackPattern.setDescription(attackPatternInput.getDescription()); - newAttackPattern.setPlatforms(attackPatternInput.getPlatforms()); - newAttackPattern.setPermissionsRequired(attackPatternInput.getPermissionsRequired()); - newAttackPattern.setParent(attackPatternParent); - upserted.add(newAttackPattern); - } else { - AttackPattern attackPattern = optionalAttackPattern.get(); - attackPattern.setStixId(attackPatternInput.getStixId()); - attackPattern.setKillChainPhases(killChainPhases); - attackPattern.setName(attackPatternInput.getName()); - attackPattern.setDescription(attackPatternInput.getDescription()); - attackPattern.setPlatforms(attackPatternInput.getPlatforms()); - attackPattern.setPermissionsRequired(attackPatternInput.getPermissionsRequired()); - attackPattern.setParent(attackPatternParent); - upserted.add(attackPattern); - } + public static final String ATTACK_PATTERN_URI = "/api/attack_patterns"; + + private AttackPatternRepository attackPatternRepository; + + private InjectorContractRepository injectorContractRepository; + private KillChainPhaseRepository killChainPhaseRepository; + + @Autowired + public void setAttackPatternRepository(AttackPatternRepository attackPatternRepository) { + this.attackPatternRepository = attackPatternRepository; + } + + @Autowired + public void setKillChainPhaseRepository(KillChainPhaseRepository killChainPhaseRepository) { + this.killChainPhaseRepository = killChainPhaseRepository; + } + + @Autowired + public void setInjectorContractRepository(InjectorContractRepository injectorContractRepository) { + this.injectorContractRepository = injectorContractRepository; + } + + @GetMapping("/api/attack_patterns") + public List attackPatterns() { + return attackPatternRepository.rawAll(); + } + + @PostMapping("/api/attack_patterns/search") + public Page attackPatterns( + @RequestBody @Valid final SearchPaginationInput searchPaginationInput) { + return buildPaginationJPA( + (Specification specification, Pageable pageable) -> + this.attackPatternRepository.findAll(specification, pageable), + searchPaginationInput, + AttackPattern.class); + } + + @GetMapping("/api/attack_patterns/{attackPatternId}") + public AttackPattern attackPattern(@PathVariable String attackPatternId) { + return attackPatternRepository + .findById(attackPatternId) + .orElseThrow(ElementNotFoundException::new); + } + + @Secured(ROLE_ADMIN) + @PostMapping("/api/attack_patterns") + @Transactional(rollbackOn = Exception.class) + public AttackPattern createAttackPattern(@Valid @RequestBody AttackPatternCreateInput input) { + AttackPattern attackPattern = new AttackPattern(); + attackPattern.setUpdateAttributes(input); + attackPattern.setKillChainPhases( + fromIterable(killChainPhaseRepository.findAllById(input.getKillChainPhasesIds()))); + attackPattern.setParent( + updateRelation(input.getParentId(), attackPattern.getParent(), attackPatternRepository)); + return attackPatternRepository.save(attackPattern); + } + + @GetMapping("/api/attack_patterns/{attackPatternId}/injector_contracts") + public Iterable injectorContracts(@PathVariable String attackPatternId) { + attackPatternRepository.findById(attackPatternId).orElseThrow(ElementNotFoundException::new); + return injectorContractRepository.findAll( + InjectorContractSpecification.fromAttackPattern(attackPatternId)); + } + + @Secured(ROLE_ADMIN) + @PutMapping("/api/attack_patterns/{attackPatternId}") + @Transactional(rollbackOn = Exception.class) + public AttackPattern updateAttackPattern( + @NotBlank @PathVariable final String attackPatternId, + @Valid @RequestBody AttackPatternUpdateInput input) { + AttackPattern attackPattern = + this.attackPatternRepository + .findById(attackPatternId) + .orElseThrow(ElementNotFoundException::new); + attackPattern.setUpdateAttributes(input); + attackPattern.setKillChainPhases( + fromIterable(this.killChainPhaseRepository.findAllById(input.getKillChainPhasesIds()))); + attackPattern.setUpdatedAt(Instant.now()); + return attackPatternRepository.save(attackPattern); + } + + private List upsertAttackPatterns(List attackPatterns) { + List upserted = new ArrayList<>(); + attackPatterns.forEach( + attackPatternInput -> { + String attackPatternExternalId = attackPatternInput.getExternalId(); + Optional optionalAttackPattern = + attackPatternRepository.findByExternalId(attackPatternExternalId); + List killChainPhases = + !attackPatternInput.getKillChainPhasesIds().isEmpty() + ? fromIterable( + killChainPhaseRepository.findAllById( + attackPatternInput.getKillChainPhasesIds())) + : List.of(); + AttackPattern attackPatternParent = + attackPatternInput.getParentId() != null + ? attackPatternRepository + .findByStixId(attackPatternInput.getParentId()) + .orElseThrow(ElementNotFoundException::new) + : null; + if (optionalAttackPattern.isEmpty()) { + AttackPattern newAttackPattern = new AttackPattern(); + newAttackPattern.setStixId(attackPatternInput.getStixId()); + newAttackPattern.setExternalId(attackPatternExternalId); + newAttackPattern.setKillChainPhases(killChainPhases); + newAttackPattern.setName(attackPatternInput.getName()); + newAttackPattern.setDescription(attackPatternInput.getDescription()); + newAttackPattern.setPlatforms(attackPatternInput.getPlatforms()); + newAttackPattern.setPermissionsRequired(attackPatternInput.getPermissionsRequired()); + newAttackPattern.setParent(attackPatternParent); + upserted.add(newAttackPattern); + } else { + AttackPattern attackPattern = optionalAttackPattern.get(); + attackPattern.setStixId(attackPatternInput.getStixId()); + attackPattern.setKillChainPhases(killChainPhases); + attackPattern.setName(attackPatternInput.getName()); + attackPattern.setDescription(attackPatternInput.getDescription()); + attackPattern.setPlatforms(attackPatternInput.getPlatforms()); + attackPattern.setPermissionsRequired(attackPatternInput.getPermissionsRequired()); + attackPattern.setParent(attackPatternParent); + upserted.add(attackPattern); + } }); - return fromIterable(this.attackPatternRepository.saveAll(upserted)); - } - - @Secured(ROLE_ADMIN) - @PostMapping("/api/attack_patterns/upsert") - @Transactional(rollbackOn = Exception.class) - public Iterable upsertKillChainPhases(@Valid @RequestBody AttackPatternUpsertInput input) { - List upserted = new ArrayList<>(); - List attackPatterns = input.getAttackPatterns(); - List patternsWithoutParent = attackPatterns.stream().filter(a -> a.getParentId() == null) - .toList(); - List patternsWithParent = attackPatterns.stream().filter(a -> a.getParentId() != null) - .toList(); - upserted.addAll(upsertAttackPatterns(patternsWithoutParent)); - upserted.addAll(upsertAttackPatterns(patternsWithParent)); - return upserted; - } - - @Secured(ROLE_ADMIN) - @DeleteMapping("/api/attack_patterns/{attackPatternId}") - @Transactional(rollbackOn = Exception.class) - public void deleteAttackPattern(@PathVariable String attackPatternId) { - attackPatternRepository.deleteById(attackPatternId); - } - - // -- OPTION -- - - @GetMapping(ATTACK_PATTERN_URI + "/options") - public List optionsByName(@RequestParam(required = false) final String searchText) { - return fromIterable(this.attackPatternRepository.findAll(byName(searchText), Sort.by(Sort.Direction.ASC, "name"))) - .stream() - .map(i -> new FilterUtilsJpa.Option(i.getId(), i.getName())) - .toList(); - } - - @PostMapping(ATTACK_PATTERN_URI + "/options") - public List optionsById(@RequestBody final List ids) { - return fromIterable(this.attackPatternRepository.findAllById(ids)) - .stream() - .map(i -> new FilterUtilsJpa.Option(i.getId(), i.getName())) - .toList(); - } + return fromIterable(this.attackPatternRepository.saveAll(upserted)); + } + + @Secured(ROLE_ADMIN) + @PostMapping("/api/attack_patterns/upsert") + @Transactional(rollbackOn = Exception.class) + public Iterable upsertKillChainPhases( + @Valid @RequestBody AttackPatternUpsertInput input) { + List upserted = new ArrayList<>(); + List attackPatterns = input.getAttackPatterns(); + List patternsWithoutParent = + attackPatterns.stream().filter(a -> a.getParentId() == null).toList(); + List patternsWithParent = + attackPatterns.stream().filter(a -> a.getParentId() != null).toList(); + upserted.addAll(upsertAttackPatterns(patternsWithoutParent)); + upserted.addAll(upsertAttackPatterns(patternsWithParent)); + return upserted; + } + + @Secured(ROLE_ADMIN) + @DeleteMapping("/api/attack_patterns/{attackPatternId}") + @Transactional(rollbackOn = Exception.class) + public void deleteAttackPattern(@PathVariable String attackPatternId) { + attackPatternRepository.deleteById(attackPatternId); + } + + // -- OPTION -- + + @GetMapping(ATTACK_PATTERN_URI + "/options") + public List optionsByName( + @RequestParam(required = false) final String searchText) { + return fromIterable( + this.attackPatternRepository.findAll( + byName(searchText), Sort.by(Sort.Direction.ASC, "name"))) + .stream() + .map(i -> new FilterUtilsJpa.Option(i.getId(), i.getName())) + .toList(); + } + + @PostMapping(ATTACK_PATTERN_URI + "/options") + public List optionsById(@RequestBody final List ids) { + return fromIterable(this.attackPatternRepository.findAllById(ids)).stream() + .map(i -> new FilterUtilsJpa.Option(i.getId(), i.getName())) + .toList(); + } } diff --git a/openbas-api/src/main/java/io/openbas/rest/attack_pattern/form/AttackPatternCreateInput.java b/openbas-api/src/main/java/io/openbas/rest/attack_pattern/form/AttackPatternCreateInput.java index 9db267f8f5..885a2357f0 100644 --- a/openbas-api/src/main/java/io/openbas/rest/attack_pattern/form/AttackPatternCreateInput.java +++ b/openbas-api/src/main/java/io/openbas/rest/attack_pattern/form/AttackPatternCreateInput.java @@ -1,45 +1,44 @@ package io.openbas.rest.attack_pattern.form; +import static io.openbas.config.AppConfig.MANDATORY_MESSAGE; + import com.fasterxml.jackson.annotation.JsonProperty; import jakarta.validation.constraints.NotBlank; -import lombok.Getter; -import lombok.Setter; - import java.util.ArrayList; import java.util.List; import java.util.UUID; - -import static io.openbas.config.AppConfig.MANDATORY_MESSAGE; +import lombok.Getter; +import lombok.Setter; @Getter @Setter public class AttackPatternCreateInput { - @JsonProperty("attack_pattern_stix_id") - private String stixId = "attack-pattern--" + UUID.randomUUID();; + @JsonProperty("attack_pattern_stix_id") + private String stixId = "attack-pattern--" + UUID.randomUUID(); - @NotBlank(message = MANDATORY_MESSAGE) - @JsonProperty("attack_pattern_name") - private String name; + ; - @JsonProperty("attack_pattern_description") - private String description; + @NotBlank(message = MANDATORY_MESSAGE) + @JsonProperty("attack_pattern_name") + private String name; - @NotBlank(message = MANDATORY_MESSAGE) - @JsonProperty("attack_pattern_external_id") - private String externalId; + @JsonProperty("attack_pattern_description") + private String description; - @JsonProperty("attack_pattern_platforms") - private String[] platforms = new String[0]; + @NotBlank(message = MANDATORY_MESSAGE) + @JsonProperty("attack_pattern_external_id") + private String externalId; - @JsonProperty("attack_pattern_permissions_required") - private String[] permissionsRequired = new String[0]; + @JsonProperty("attack_pattern_platforms") + private String[] platforms = new String[0]; - @JsonProperty("attack_pattern_kill_chain_phases") - private List killChainPhasesIds = new ArrayList<>(); - - @JsonProperty("attack_pattern_parent") - private String parentId; -} + @JsonProperty("attack_pattern_permissions_required") + private String[] permissionsRequired = new String[0]; + @JsonProperty("attack_pattern_kill_chain_phases") + private List killChainPhasesIds = new ArrayList<>(); + @JsonProperty("attack_pattern_parent") + private String parentId; +} diff --git a/openbas-api/src/main/java/io/openbas/rest/attack_pattern/form/AttackPatternUpdateInput.java b/openbas-api/src/main/java/io/openbas/rest/attack_pattern/form/AttackPatternUpdateInput.java index 0a45a5fc78..3deaf18cb0 100644 --- a/openbas-api/src/main/java/io/openbas/rest/attack_pattern/form/AttackPatternUpdateInput.java +++ b/openbas-api/src/main/java/io/openbas/rest/attack_pattern/form/AttackPatternUpdateInput.java @@ -1,33 +1,29 @@ package io.openbas.rest.attack_pattern.form; +import static io.openbas.config.AppConfig.MANDATORY_MESSAGE; + import com.fasterxml.jackson.annotation.JsonProperty; import jakarta.validation.constraints.NotBlank; -import lombok.Getter; -import lombok.Setter; - import java.util.ArrayList; import java.util.List; - -import static io.openbas.config.AppConfig.MANDATORY_MESSAGE; +import lombok.Getter; +import lombok.Setter; @Getter @Setter public class AttackPatternUpdateInput { - @NotBlank(message = MANDATORY_MESSAGE) - @JsonProperty("attack_pattern_name") - private String name; + @NotBlank(message = MANDATORY_MESSAGE) + @JsonProperty("attack_pattern_name") + private String name; - @JsonProperty("attack_pattern_description") - private String description; + @JsonProperty("attack_pattern_description") + private String description; - @NotBlank(message = MANDATORY_MESSAGE) - @JsonProperty("attack_pattern_external_id") - private String externalId; - - @JsonProperty("attack_pattern_kill_chain_phases") - private List killChainPhasesIds = new ArrayList<>(); + @NotBlank(message = MANDATORY_MESSAGE) + @JsonProperty("attack_pattern_external_id") + private String externalId; + @JsonProperty("attack_pattern_kill_chain_phases") + private List killChainPhasesIds = new ArrayList<>(); } - - diff --git a/openbas-api/src/main/java/io/openbas/rest/attack_pattern/form/AttackPatternUpsertInput.java b/openbas-api/src/main/java/io/openbas/rest/attack_pattern/form/AttackPatternUpsertInput.java index 68b03bef11..f8cd514fe3 100644 --- a/openbas-api/src/main/java/io/openbas/rest/attack_pattern/form/AttackPatternUpsertInput.java +++ b/openbas-api/src/main/java/io/openbas/rest/attack_pattern/form/AttackPatternUpsertInput.java @@ -1,15 +1,13 @@ package io.openbas.rest.attack_pattern.form; import com.fasterxml.jackson.annotation.JsonProperty; -import lombok.Data; - import java.util.ArrayList; import java.util.List; +import lombok.Data; @Data public class AttackPatternUpsertInput { @JsonProperty("attack_patterns") private List attackPatterns = new ArrayList<>(); - } diff --git a/openbas-api/src/main/java/io/openbas/rest/challenge/ChallengeApi.java b/openbas-api/src/main/java/io/openbas/rest/challenge/ChallengeApi.java index 2770d8e1e6..9eb02fd6df 100644 --- a/openbas-api/src/main/java/io/openbas/rest/challenge/ChallengeApi.java +++ b/openbas-api/src/main/java/io/openbas/rest/challenge/ChallengeApi.java @@ -1,5 +1,10 @@ package io.openbas.rest.challenge; +import static io.openbas.config.OpenBASAnonymous.ANONYMOUS; +import static io.openbas.database.model.User.ROLE_ADMIN; +import static io.openbas.helper.StreamHelper.fromIterable; +import static io.openbas.helper.StreamHelper.iterableToSet; + import io.openbas.database.model.Challenge; import io.openbas.database.model.ChallengeFlag; import io.openbas.database.model.ChallengeFlag.FLAG_TYPE; @@ -17,125 +22,133 @@ import io.openbas.service.ChallengeService; import jakarta.transaction.Transactional; import jakarta.validation.Valid; +import java.time.Instant; +import java.util.List; +import java.util.Optional; import lombok.RequiredArgsConstructor; import org.springframework.security.access.annotation.Secured; import org.springframework.security.access.prepost.PreAuthorize; import org.springframework.web.bind.annotation.*; -import java.time.Instant; -import java.util.List; -import java.util.Optional; - -import static io.openbas.config.OpenBASAnonymous.ANONYMOUS; -import static io.openbas.database.model.User.ROLE_ADMIN; -import static io.openbas.helper.StreamHelper.fromIterable; -import static io.openbas.helper.StreamHelper.iterableToSet; - @RestController @RequiredArgsConstructor public class ChallengeApi extends RestBehavior { - private final ChallengeRepository challengeRepository; - private final ChallengeFlagRepository challengeFlagRepository; - private final TagRepository tagRepository; - private final DocumentRepository documentRepository; - private final ExerciseRepository exerciseRepository; - private final ChallengeService challengeService; - private final UserRepository userRepository; + private final ChallengeRepository challengeRepository; + private final ChallengeFlagRepository challengeFlagRepository; + private final TagRepository tagRepository; + private final DocumentRepository documentRepository; + private final ExerciseRepository exerciseRepository; + private final ChallengeService challengeService; + private final UserRepository userRepository; - @GetMapping("/api/challenges") - public Iterable challenges() { - return fromIterable(challengeRepository.findAll()).stream() - .map(challengeService::enrichChallengeWithExercisesOrScenarios).toList(); - } + @GetMapping("/api/challenges") + public Iterable challenges() { + return fromIterable(challengeRepository.findAll()).stream() + .map(challengeService::enrichChallengeWithExercisesOrScenarios) + .toList(); + } - @PreAuthorize("isPlanner()") - @PutMapping("/api/challenges/{challengeId}") - @Transactional(rollbackOn = Exception.class) - public Challenge updateChallenge( - @PathVariable String challengeId, - @Valid @RequestBody ChallengeUpdateInput input) { - Challenge challenge = challengeRepository.findById(challengeId).orElseThrow(ElementNotFoundException::new); - challenge.setTags(iterableToSet(tagRepository.findAllById(input.getTagIds()))); - challenge.setDocuments(fromIterable(documentRepository.findAllById(input.getDocumentIds()))); - challenge.setUpdateAttributes(input); - challenge.setUpdatedAt(Instant.now()); - // Clear all flags - List challengeFlags = challenge.getFlags(); - challengeFlagRepository.deleteAll(challengeFlags); - challengeFlags.clear(); - // Add new ones - input.getFlags().forEach(flagInput -> { - ChallengeFlag challengeFlag = new ChallengeFlag(); - challengeFlag.setType(FLAG_TYPE.valueOf(flagInput.getType())); - challengeFlag.setValue(flagInput.getValue()); - challengeFlag.setChallenge(challenge); - challengeFlags.add(challengeFlag); - }); - Challenge saveChallenge = challengeRepository.save(challenge); - return challengeService.enrichChallengeWithExercisesOrScenarios(saveChallenge); - } + @PreAuthorize("isPlanner()") + @PutMapping("/api/challenges/{challengeId}") + @Transactional(rollbackOn = Exception.class) + public Challenge updateChallenge( + @PathVariable String challengeId, @Valid @RequestBody ChallengeUpdateInput input) { + Challenge challenge = + challengeRepository.findById(challengeId).orElseThrow(ElementNotFoundException::new); + challenge.setTags(iterableToSet(tagRepository.findAllById(input.getTagIds()))); + challenge.setDocuments(fromIterable(documentRepository.findAllById(input.getDocumentIds()))); + challenge.setUpdateAttributes(input); + challenge.setUpdatedAt(Instant.now()); + // Clear all flags + List challengeFlags = challenge.getFlags(); + challengeFlagRepository.deleteAll(challengeFlags); + challengeFlags.clear(); + // Add new ones + input + .getFlags() + .forEach( + flagInput -> { + ChallengeFlag challengeFlag = new ChallengeFlag(); + challengeFlag.setType(FLAG_TYPE.valueOf(flagInput.getType())); + challengeFlag.setValue(flagInput.getValue()); + challengeFlag.setChallenge(challenge); + challengeFlags.add(challengeFlag); + }); + Challenge saveChallenge = challengeRepository.save(challenge); + return challengeService.enrichChallengeWithExercisesOrScenarios(saveChallenge); + } - @PreAuthorize("isPlanner()") - @PostMapping("/api/challenges") - @Transactional(rollbackOn = Exception.class) - public Challenge createChallenge(@Valid @RequestBody ChallengeCreateInput input) { - Challenge challenge = new Challenge(); - challenge.setUpdateAttributes(input); - challenge.setTags(iterableToSet(tagRepository.findAllById(input.getTagIds()))); - challenge.setDocuments(fromIterable(documentRepository.findAllById(input.getDocumentIds()))); - List challengeFlags = input.getFlags().stream().map(flagInput -> { - ChallengeFlag challengeFlag = new ChallengeFlag(); - challengeFlag.setType(FLAG_TYPE.valueOf(flagInput.getType())); - challengeFlag.setValue(flagInput.getValue()); - challengeFlag.setChallenge(challenge); - return challengeFlag; - }).toList(); - challenge.setFlags(challengeFlags); - return challengeRepository.save(challenge); - } + @PreAuthorize("isPlanner()") + @PostMapping("/api/challenges") + @Transactional(rollbackOn = Exception.class) + public Challenge createChallenge(@Valid @RequestBody ChallengeCreateInput input) { + Challenge challenge = new Challenge(); + challenge.setUpdateAttributes(input); + challenge.setTags(iterableToSet(tagRepository.findAllById(input.getTagIds()))); + challenge.setDocuments(fromIterable(documentRepository.findAllById(input.getDocumentIds()))); + List challengeFlags = + input.getFlags().stream() + .map( + flagInput -> { + ChallengeFlag challengeFlag = new ChallengeFlag(); + challengeFlag.setType(FLAG_TYPE.valueOf(flagInput.getType())); + challengeFlag.setValue(flagInput.getValue()); + challengeFlag.setChallenge(challenge); + return challengeFlag; + }) + .toList(); + challenge.setFlags(challengeFlags); + return challengeRepository.save(challenge); + } - @GetMapping("/api/player/challenges/{exerciseId}") - public ChallengesReader playerChallenges(@PathVariable String exerciseId, @RequestParam Optional userId) { - final User user = impersonateUser(userRepository, userId); - if (user.getId().equals(ANONYMOUS)) { - throw new UnsupportedOperationException("User must be logged or dynamic player is required"); - } - return challengeService.playerChallenges(exerciseId, user); + @GetMapping("/api/player/challenges/{exerciseId}") + public ChallengesReader playerChallenges( + @PathVariable String exerciseId, @RequestParam Optional userId) { + final User user = impersonateUser(userRepository, userId); + if (user.getId().equals(ANONYMOUS)) { + throw new UnsupportedOperationException("User must be logged or dynamic player is required"); } + return challengeService.playerChallenges(exerciseId, user); + } - @GetMapping("/api/observer/challenges/{exerciseId}") - public ChallengesReader observerChallenges(@PathVariable String exerciseId) { - Exercise exercise = exerciseRepository.findById(exerciseId).orElseThrow(ElementNotFoundException::new); - ChallengesReader challengesReader = new ChallengesReader(exercise); - Iterable challenges = challengeService.getExerciseChallenges(exerciseId); - challengesReader.setExerciseChallenges(fromIterable(challenges).stream() - .map(challenge -> new ChallengeInformation(challenge, null)).toList()); - return challengesReader; - } + @GetMapping("/api/observer/challenges/{exerciseId}") + public ChallengesReader observerChallenges(@PathVariable String exerciseId) { + Exercise exercise = + exerciseRepository.findById(exerciseId).orElseThrow(ElementNotFoundException::new); + ChallengesReader challengesReader = new ChallengesReader(exercise); + Iterable challenges = challengeService.getExerciseChallenges(exerciseId); + challengesReader.setExerciseChallenges( + fromIterable(challenges).stream() + .map(challenge -> new ChallengeInformation(challenge, null)) + .toList()); + return challengesReader; + } - @Secured(ROLE_ADMIN) - @DeleteMapping("/api/challenges/{challengeId}") - @Transactional(rollbackOn = Exception.class) - public void deleteChallenge(@PathVariable String challengeId) { - challengeRepository.deleteById(challengeId); - } + @Secured(ROLE_ADMIN) + @DeleteMapping("/api/challenges/{challengeId}") + @Transactional(rollbackOn = Exception.class) + public void deleteChallenge(@PathVariable String challengeId) { + challengeRepository.deleteById(challengeId); + } - @PostMapping("/api/challenges/{challengeId}/try") - public ChallengeResult tryChallenge(@PathVariable String challengeId, @Valid @RequestBody ChallengeTryInput input) { - return challengeService.tryChallenge(challengeId, input); - } + @PostMapping("/api/challenges/{challengeId}/try") + public ChallengeResult tryChallenge( + @PathVariable String challengeId, @Valid @RequestBody ChallengeTryInput input) { + return challengeService.tryChallenge(challengeId, input); + } - @PostMapping("/api/player/challenges/{exerciseId}/{challengeId}/validate") - @Transactional(rollbackOn = Exception.class) - public ChallengesReader validateChallenge(@PathVariable String exerciseId, - @PathVariable String challengeId, - @Valid @RequestBody ChallengeTryInput input, - @RequestParam Optional userId) { - final User user = impersonateUser(userRepository, userId); - if (user.getId().equals(ANONYMOUS)) { - throw new UnsupportedOperationException("User must be logged or dynamic player is required"); - } - return challengeService.validateChallenge(exerciseId, challengeId, input, user); + @PostMapping("/api/player/challenges/{exerciseId}/{challengeId}/validate") + @Transactional(rollbackOn = Exception.class) + public ChallengesReader validateChallenge( + @PathVariable String exerciseId, + @PathVariable String challengeId, + @Valid @RequestBody ChallengeTryInput input, + @RequestParam Optional userId) { + final User user = impersonateUser(userRepository, userId); + if (user.getId().equals(ANONYMOUS)) { + throw new UnsupportedOperationException("User must be logged or dynamic player is required"); } + return challengeService.validateChallenge(exerciseId, challengeId, input, user); + } } diff --git a/openbas-api/src/main/java/io/openbas/rest/challenge/ChallengeHelper.java b/openbas-api/src/main/java/io/openbas/rest/challenge/ChallengeHelper.java index 3218b6cdbc..ee7211403e 100644 --- a/openbas-api/src/main/java/io/openbas/rest/challenge/ChallengeHelper.java +++ b/openbas-api/src/main/java/io/openbas/rest/challenge/ChallengeHelper.java @@ -1,39 +1,40 @@ package io.openbas.rest.challenge; +import static io.openbas.injectors.challenge.ChallengeContract.CHALLENGE_PUBLISH; + import com.fasterxml.jackson.core.JsonProcessingException; import com.fasterxml.jackson.databind.ObjectMapper; import io.openbas.database.model.Inject; import io.openbas.injectors.challenge.model.ChallengeContent; import jakarta.validation.constraints.NotNull; - import java.util.List; import java.util.stream.Stream; -import static io.openbas.injectors.challenge.ChallengeContract.CHALLENGE_PUBLISH; - public class ChallengeHelper { - private ChallengeHelper() { - - } - - public static List resolveChallengeIds( - @NotNull final List injects, - ObjectMapper mapper) { - return injects.stream() - .filter(inject -> inject.getInjectorContract() - .map(contract -> contract.getId().equals(CHALLENGE_PUBLISH)) - .orElse(false)) - .filter(inject -> inject.getContent() != null) - .flatMap(inject -> { - try { - ChallengeContent content = mapper.treeToValue(inject.getContent(), ChallengeContent.class); - return content.getChallenges().stream(); - } catch (JsonProcessingException e) { - return Stream.empty(); - } - }) - .distinct().toList(); - } - + private ChallengeHelper() {} + + public static List resolveChallengeIds( + @NotNull final List injects, ObjectMapper mapper) { + return injects.stream() + .filter( + inject -> + inject + .getInjectorContract() + .map(contract -> contract.getId().equals(CHALLENGE_PUBLISH)) + .orElse(false)) + .filter(inject -> inject.getContent() != null) + .flatMap( + inject -> { + try { + ChallengeContent content = + mapper.treeToValue(inject.getContent(), ChallengeContent.class); + return content.getChallenges().stream(); + } catch (JsonProcessingException e) { + return Stream.empty(); + } + }) + .distinct() + .toList(); + } } diff --git a/openbas-api/src/main/java/io/openbas/rest/challenge/ExerciseChallengeApi.java b/openbas-api/src/main/java/io/openbas/rest/challenge/ExerciseChallengeApi.java index 4d9463b5dd..aad18aadde 100644 --- a/openbas-api/src/main/java/io/openbas/rest/challenge/ExerciseChallengeApi.java +++ b/openbas-api/src/main/java/io/openbas/rest/challenge/ExerciseChallengeApi.java @@ -1,5 +1,10 @@ package io.openbas.rest.challenge; +import static io.openbas.helper.StreamHelper.fromIterable; +import static io.openbas.injectors.challenge.ChallengeContract.CHALLENGE_PUBLISH; +import static io.openbas.rest.challenge.ChallengeHelper.resolveChallengeIds; +import static io.openbas.rest.exercise.ExerciseApi.EXERCISE_URI; + import io.openbas.database.model.Inject; import io.openbas.database.repository.ChallengeRepository; import io.openbas.database.repository.InjectRepository; @@ -7,6 +12,7 @@ import io.openbas.rest.challenge.output.ChallengeOutput; import io.openbas.rest.helper.RestBehavior; import jakarta.validation.constraints.NotBlank; +import java.util.List; import lombok.RequiredArgsConstructor; import org.springframework.security.access.prepost.PreAuthorize; import org.springframework.transaction.annotation.Transactional; @@ -14,13 +20,6 @@ import org.springframework.web.bind.annotation.PathVariable; import org.springframework.web.bind.annotation.RestController; -import java.util.List; - -import static io.openbas.helper.StreamHelper.fromIterable; -import static io.openbas.injectors.challenge.ChallengeContract.CHALLENGE_PUBLISH; -import static io.openbas.rest.challenge.ChallengeHelper.resolveChallengeIds; -import static io.openbas.rest.exercise.ExerciseApi.EXERCISE_URI; - @RestController @RequiredArgsConstructor public class ExerciseChallengeApi extends RestBehavior { @@ -31,17 +30,16 @@ public class ExerciseChallengeApi extends RestBehavior { @PreAuthorize("isExerciseObserver(#exerciseId)") @GetMapping(EXERCISE_URI + "/{exerciseId}/challenges") @Transactional(readOnly = true) - public Iterable exerciseChallenges(@PathVariable @NotBlank final String exerciseId) { - List injects = this.injectRepository.findAll( - InjectSpecification.fromExercise(exerciseId) - .and(InjectSpecification.fromContract(CHALLENGE_PUBLISH)) - ); + public Iterable exerciseChallenges( + @PathVariable @NotBlank final String exerciseId) { + List injects = + this.injectRepository.findAll( + InjectSpecification.fromExercise(exerciseId) + .and(InjectSpecification.fromContract(CHALLENGE_PUBLISH))); List challengeIds = resolveChallengeIds(injects, this.mapper); - return fromIterable(this.challengeRepository.findAllById(challengeIds)) - .stream() + return fromIterable(this.challengeRepository.findAllById(challengeIds)).stream() .map(ChallengeOutput::from) .peek(c -> c.setExerciseIds(List.of(exerciseId))) .toList(); } - } diff --git a/openbas-api/src/main/java/io/openbas/rest/challenge/ScenarioChallengeApi.java b/openbas-api/src/main/java/io/openbas/rest/challenge/ScenarioChallengeApi.java index 582af6c872..8c70f80096 100644 --- a/openbas-api/src/main/java/io/openbas/rest/challenge/ScenarioChallengeApi.java +++ b/openbas-api/src/main/java/io/openbas/rest/challenge/ScenarioChallengeApi.java @@ -1,5 +1,10 @@ package io.openbas.rest.challenge; +import static io.openbas.helper.StreamHelper.fromIterable; +import static io.openbas.injectors.challenge.ChallengeContract.CHALLENGE_PUBLISH; +import static io.openbas.rest.challenge.ChallengeHelper.resolveChallengeIds; +import static io.openbas.rest.scenario.ScenarioApi.SCENARIO_URI; + import io.openbas.database.model.Inject; import io.openbas.database.repository.ChallengeRepository; import io.openbas.database.repository.InjectRepository; @@ -7,6 +12,7 @@ import io.openbas.rest.challenge.output.ChallengeOutput; import io.openbas.rest.helper.RestBehavior; import jakarta.validation.constraints.NotBlank; +import java.util.List; import lombok.RequiredArgsConstructor; import org.springframework.security.access.prepost.PreAuthorize; import org.springframework.transaction.annotation.Transactional; @@ -14,13 +20,6 @@ import org.springframework.web.bind.annotation.PathVariable; import org.springframework.web.bind.annotation.RestController; -import java.util.List; - -import static io.openbas.helper.StreamHelper.fromIterable; -import static io.openbas.injectors.challenge.ChallengeContract.CHALLENGE_PUBLISH; -import static io.openbas.rest.challenge.ChallengeHelper.resolveChallengeIds; -import static io.openbas.rest.scenario.ScenarioApi.SCENARIO_URI; - @RestController @RequiredArgsConstructor public class ScenarioChallengeApi extends RestBehavior { @@ -31,17 +30,16 @@ public class ScenarioChallengeApi extends RestBehavior { @PreAuthorize("isScenarioObserver(#scenarioId)") @GetMapping(SCENARIO_URI + "/{scenarioId}/challenges") @Transactional(readOnly = true) - public Iterable scenarioChallenges(@PathVariable @NotBlank final String scenarioId) { - List injects = this.injectRepository.findAll( - InjectSpecification.fromScenario(scenarioId) - .and(InjectSpecification.fromContract(CHALLENGE_PUBLISH)) - ); + public Iterable scenarioChallenges( + @PathVariable @NotBlank final String scenarioId) { + List injects = + this.injectRepository.findAll( + InjectSpecification.fromScenario(scenarioId) + .and(InjectSpecification.fromContract(CHALLENGE_PUBLISH))); List challengeIds = resolveChallengeIds(injects, this.mapper); - return fromIterable(this.challengeRepository.findAllById(challengeIds)) - .stream() + return fromIterable(this.challengeRepository.findAllById(challengeIds)).stream() .map(ChallengeOutput::from) .peek(c -> c.setScenarioIds(List.of(scenarioId))) .toList(); } - } diff --git a/openbas-api/src/main/java/io/openbas/rest/challenge/form/ChallengeCreateInput.java b/openbas-api/src/main/java/io/openbas/rest/challenge/form/ChallengeCreateInput.java index c5078b5c88..bbc93676f1 100644 --- a/openbas-api/src/main/java/io/openbas/rest/challenge/form/ChallengeCreateInput.java +++ b/openbas-api/src/main/java/io/openbas/rest/challenge/form/ChallengeCreateInput.java @@ -1,105 +1,103 @@ package io.openbas.rest.challenge.form; -import com.fasterxml.jackson.annotation.JsonProperty; +import static io.openbas.config.AppConfig.EMPTY_MESSAGE; +import static io.openbas.config.AppConfig.MANDATORY_MESSAGE; +import com.fasterxml.jackson.annotation.JsonProperty; import jakarta.validation.constraints.NotBlank; import jakarta.validation.constraints.NotEmpty; - import java.util.ArrayList; import java.util.List; -import static io.openbas.config.AppConfig.EMPTY_MESSAGE; -import static io.openbas.config.AppConfig.MANDATORY_MESSAGE; - public class ChallengeCreateInput { - @NotBlank(message = MANDATORY_MESSAGE) - @JsonProperty("challenge_name") - private String name; + @NotBlank(message = MANDATORY_MESSAGE) + @JsonProperty("challenge_name") + private String name; - @JsonProperty("challenge_category") - private String category; + @JsonProperty("challenge_category") + private String category; - @JsonProperty("challenge_content") - private String content; + @JsonProperty("challenge_content") + private String content; - @JsonProperty("challenge_score") - private Integer score; + @JsonProperty("challenge_score") + private Integer score; - @JsonProperty("challenge_max_attempts") - private Integer maxAttempts; + @JsonProperty("challenge_max_attempts") + private Integer maxAttempts; - @JsonProperty("challenge_tags") - private List tagIds = new ArrayList<>(); + @JsonProperty("challenge_tags") + private List tagIds = new ArrayList<>(); - @JsonProperty("challenge_documents") - private List documentIds = new ArrayList<>(); + @JsonProperty("challenge_documents") + private List documentIds = new ArrayList<>(); - @NotEmpty(message = EMPTY_MESSAGE) - @JsonProperty("challenge_flags") - private List flags = new ArrayList<>(); + @NotEmpty(message = EMPTY_MESSAGE) + @JsonProperty("challenge_flags") + private List flags = new ArrayList<>(); - public String getName() { - return name; - } + public String getName() { + return name; + } - public void setName(String name) { - this.name = name; - } + public void setName(String name) { + this.name = name; + } - public String getCategory() { - return category; - } + public String getCategory() { + return category; + } - public void setCategory(String category) { - this.category = category; - } + public void setCategory(String category) { + this.category = category; + } - public String getContent() { - return content; - } + public String getContent() { + return content; + } - public void setContent(String content) { - this.content = content; - } + public void setContent(String content) { + this.content = content; + } - public Integer getScore() { - return score; - } + public Integer getScore() { + return score; + } - public void setScore(Integer score) { - this.score = score; - } + public void setScore(Integer score) { + this.score = score; + } - public Integer getMaxAttempts() { - return maxAttempts; - } + public Integer getMaxAttempts() { + return maxAttempts; + } - public void setMaxAttempts(Integer maxAttempts) { - this.maxAttempts = maxAttempts; - } + public void setMaxAttempts(Integer maxAttempts) { + this.maxAttempts = maxAttempts; + } - public List getTagIds() { - return tagIds; - } + public List getTagIds() { + return tagIds; + } - public void setTagIds(List tagIds) { - this.tagIds = tagIds; - } + public void setTagIds(List tagIds) { + this.tagIds = tagIds; + } - public List getDocumentIds() { - return documentIds; - } + public List getDocumentIds() { + return documentIds; + } - public void setDocumentIds(List documentIds) { - this.documentIds = documentIds; - } + public void setDocumentIds(List documentIds) { + this.documentIds = documentIds; + } - public List getFlags() { - return flags; - } + public List getFlags() { + return flags; + } - public void setFlags(List flags) { - this.flags = flags; - } + public void setFlags(List flags) { + this.flags = flags; + } } diff --git a/openbas-api/src/main/java/io/openbas/rest/challenge/form/ChallengeTryInput.java b/openbas-api/src/main/java/io/openbas/rest/challenge/form/ChallengeTryInput.java index e69aa9c841..117c8ee552 100644 --- a/openbas-api/src/main/java/io/openbas/rest/challenge/form/ChallengeTryInput.java +++ b/openbas-api/src/main/java/io/openbas/rest/challenge/form/ChallengeTryInput.java @@ -4,14 +4,14 @@ public class ChallengeTryInput { - @JsonProperty("challenge_value") - private String value; + @JsonProperty("challenge_value") + private String value; - public String getValue() { - return value; - } + public String getValue() { + return value; + } - public void setValue(String value) { - this.value = value; - } + public void setValue(String value) { + this.value = value; + } } diff --git a/openbas-api/src/main/java/io/openbas/rest/challenge/form/ChallengeUpdateInput.java b/openbas-api/src/main/java/io/openbas/rest/challenge/form/ChallengeUpdateInput.java index 92e5a57441..239398a73e 100644 --- a/openbas-api/src/main/java/io/openbas/rest/challenge/form/ChallengeUpdateInput.java +++ b/openbas-api/src/main/java/io/openbas/rest/challenge/form/ChallengeUpdateInput.java @@ -1,104 +1,103 @@ package io.openbas.rest.challenge.form; -import com.fasterxml.jackson.annotation.JsonProperty; +import static io.openbas.config.AppConfig.EMPTY_MESSAGE; +import static io.openbas.config.AppConfig.MANDATORY_MESSAGE; +import com.fasterxml.jackson.annotation.JsonProperty; import jakarta.validation.constraints.NotBlank; import jakarta.validation.constraints.NotEmpty; import java.util.ArrayList; import java.util.List; -import static io.openbas.config.AppConfig.EMPTY_MESSAGE; -import static io.openbas.config.AppConfig.MANDATORY_MESSAGE; - public class ChallengeUpdateInput { - @NotBlank(message = MANDATORY_MESSAGE) - @JsonProperty("challenge_name") - private String name; + @NotBlank(message = MANDATORY_MESSAGE) + @JsonProperty("challenge_name") + private String name; - @JsonProperty("challenge_category") - private String category; + @JsonProperty("challenge_category") + private String category; - @JsonProperty("challenge_content") - private String content; + @JsonProperty("challenge_content") + private String content; - @JsonProperty("challenge_score") - private Integer score; + @JsonProperty("challenge_score") + private Integer score; - @JsonProperty("challenge_max_attempts") - private Integer maxAttempts; + @JsonProperty("challenge_max_attempts") + private Integer maxAttempts; - @JsonProperty("challenge_tags") - private List tagIds = new ArrayList<>(); + @JsonProperty("challenge_tags") + private List tagIds = new ArrayList<>(); - @JsonProperty("challenge_documents") - private List documentIds = new ArrayList<>(); + @JsonProperty("challenge_documents") + private List documentIds = new ArrayList<>(); - @NotEmpty(message = EMPTY_MESSAGE) - @JsonProperty("challenge_flags") - private List flags = new ArrayList<>(); + @NotEmpty(message = EMPTY_MESSAGE) + @JsonProperty("challenge_flags") + private List flags = new ArrayList<>(); - public String getName() { - return name; - } + public String getName() { + return name; + } - public void setName(String name) { - this.name = name; - } + public void setName(String name) { + this.name = name; + } - public String getCategory() { - return category; - } + public String getCategory() { + return category; + } - public void setCategory(String category) { - this.category = category; - } + public void setCategory(String category) { + this.category = category; + } - public String getContent() { - return content; - } + public String getContent() { + return content; + } - public void setContent(String content) { - this.content = content; - } + public void setContent(String content) { + this.content = content; + } - public Integer getScore() { - return score; - } + public Integer getScore() { + return score; + } - public void setScore(Integer score) { - this.score = score; - } + public void setScore(Integer score) { + this.score = score; + } - public Integer getMaxAttempts() { - return maxAttempts; - } + public Integer getMaxAttempts() { + return maxAttempts; + } - public void setMaxAttempts(Integer maxAttempts) { - this.maxAttempts = maxAttempts; - } + public void setMaxAttempts(Integer maxAttempts) { + this.maxAttempts = maxAttempts; + } - public List getTagIds() { - return tagIds; - } + public List getTagIds() { + return tagIds; + } - public void setTagIds(List tagIds) { - this.tagIds = tagIds; - } + public void setTagIds(List tagIds) { + this.tagIds = tagIds; + } - public List getDocumentIds() { - return documentIds; - } + public List getDocumentIds() { + return documentIds; + } - public void setDocumentIds(List documentIds) { - this.documentIds = documentIds; - } + public void setDocumentIds(List documentIds) { + this.documentIds = documentIds; + } - public List getFlags() { - return flags; - } + public List getFlags() { + return flags; + } - public void setFlags(List flags) { - this.flags = flags; - } + public void setFlags(List flags) { + this.flags = flags; + } } diff --git a/openbas-api/src/main/java/io/openbas/rest/challenge/form/FlagInput.java b/openbas-api/src/main/java/io/openbas/rest/challenge/form/FlagInput.java index 6e678d867c..379bdb141b 100644 --- a/openbas-api/src/main/java/io/openbas/rest/challenge/form/FlagInput.java +++ b/openbas-api/src/main/java/io/openbas/rest/challenge/form/FlagInput.java @@ -1,34 +1,33 @@ package io.openbas.rest.challenge.form; -import com.fasterxml.jackson.annotation.JsonProperty; +import static io.openbas.config.AppConfig.MANDATORY_MESSAGE; +import com.fasterxml.jackson.annotation.JsonProperty; import jakarta.validation.constraints.NotBlank; -import static io.openbas.config.AppConfig.MANDATORY_MESSAGE; - public class FlagInput { - @NotBlank(message = MANDATORY_MESSAGE) - @JsonProperty("flag_type") - private String type; + @NotBlank(message = MANDATORY_MESSAGE) + @JsonProperty("flag_type") + private String type; - @NotBlank(message = MANDATORY_MESSAGE) - @JsonProperty("flag_value") - private String value; + @NotBlank(message = MANDATORY_MESSAGE) + @JsonProperty("flag_value") + private String value; - public String getType() { - return type; - } + public String getType() { + return type; + } - public void setType(String type) { - this.type = type; - } + public void setType(String type) { + this.type = type; + } - public String getValue() { - return value; - } + public String getValue() { + return value; + } - public void setValue(String value) { - this.value = value; - } + public void setValue(String value) { + this.value = value; + } } diff --git a/openbas-api/src/main/java/io/openbas/rest/challenge/output/ChallengeOutput.java b/openbas-api/src/main/java/io/openbas/rest/challenge/output/ChallengeOutput.java index 4a522d5128..c1e454fd20 100644 --- a/openbas-api/src/main/java/io/openbas/rest/challenge/output/ChallengeOutput.java +++ b/openbas-api/src/main/java/io/openbas/rest/challenge/output/ChallengeOutput.java @@ -6,14 +6,13 @@ import io.openbas.database.model.Document; import io.openbas.database.model.Tag; import jakarta.validation.constraints.NotBlank; -import lombok.Data; -import org.springframework.util.CollectionUtils; - import java.util.ArrayList; import java.util.HashSet; import java.util.List; import java.util.Set; import java.util.stream.Collectors; +import lombok.Data; +import org.springframework.util.CollectionUtils; @Data public class ChallengeOutput { @@ -63,9 +62,9 @@ public static ChallengeOutput from(@org.jetbrains.annotations.NotNull final Chal if (!CollectionUtils.isEmpty(challenge.getFlags())) { challengeOutput.setFlags(challenge.getFlags()); } - challengeOutput.setTags(challenge.getTags().stream().map(Tag::getId).collect(Collectors.toSet())); + challengeOutput.setTags( + challenge.getTags().stream().map(Tag::getId).collect(Collectors.toSet())); challengeOutput.setDocuments(challenge.getDocuments().stream().map(Document::getId).toList()); return challengeOutput; } - } diff --git a/openbas-api/src/main/java/io/openbas/rest/challenge/response/ChallengeInformation.java b/openbas-api/src/main/java/io/openbas/rest/challenge/response/ChallengeInformation.java index fe816139ab..93239e4850 100644 --- a/openbas-api/src/main/java/io/openbas/rest/challenge/response/ChallengeInformation.java +++ b/openbas-api/src/main/java/io/openbas/rest/challenge/response/ChallengeInformation.java @@ -6,22 +6,22 @@ public class ChallengeInformation { - @JsonProperty("challenge_detail") - private final PublicChallenge challenge; + @JsonProperty("challenge_detail") + private final PublicChallenge challenge; - @JsonProperty("challenge_expectation") - private final InjectExpectation expectation; + @JsonProperty("challenge_expectation") + private final InjectExpectation expectation; - public ChallengeInformation(Challenge challenge, InjectExpectation expectation) { - this.challenge = new PublicChallenge(challenge); - this.expectation = expectation; - } + public ChallengeInformation(Challenge challenge, InjectExpectation expectation) { + this.challenge = new PublicChallenge(challenge); + this.expectation = expectation; + } - public PublicChallenge getChallenge() { - return challenge; - } + public PublicChallenge getChallenge() { + return challenge; + } - public InjectExpectation getExpectation() { - return expectation; - } + public InjectExpectation getExpectation() { + return expectation; + } } diff --git a/openbas-api/src/main/java/io/openbas/rest/challenge/response/ChallengeResult.java b/openbas-api/src/main/java/io/openbas/rest/challenge/response/ChallengeResult.java index 225bb944f1..c959875671 100644 --- a/openbas-api/src/main/java/io/openbas/rest/challenge/response/ChallengeResult.java +++ b/openbas-api/src/main/java/io/openbas/rest/challenge/response/ChallengeResult.java @@ -7,11 +7,10 @@ @Setter @Getter public class ChallengeResult { - @JsonProperty("result") - private Boolean result; - - public ChallengeResult(Boolean result) { - this.result = result; - } + @JsonProperty("result") + private Boolean result; + public ChallengeResult(Boolean result) { + this.result = result; + } } diff --git a/openbas-api/src/main/java/io/openbas/rest/challenge/response/ChallengesReader.java b/openbas-api/src/main/java/io/openbas/rest/challenge/response/ChallengesReader.java index ea8ecdbba8..70cfa1c2db 100644 --- a/openbas-api/src/main/java/io/openbas/rest/challenge/response/ChallengesReader.java +++ b/openbas-api/src/main/java/io/openbas/rest/challenge/response/ChallengesReader.java @@ -3,47 +3,46 @@ import com.fasterxml.jackson.annotation.JsonProperty; import io.openbas.database.model.Exercise; import io.openbas.rest.exercise.response.PublicExercise; - import java.util.ArrayList; import java.util.List; public class ChallengesReader { - @JsonProperty("exercise_id") - private String id; + @JsonProperty("exercise_id") + private String id; - @JsonProperty("exercise_information") - private PublicExercise exercise; + @JsonProperty("exercise_information") + private PublicExercise exercise; - @JsonProperty("exercise_challenges") - private List exerciseChallenges = new ArrayList<>(); + @JsonProperty("exercise_challenges") + private List exerciseChallenges = new ArrayList<>(); - public ChallengesReader(Exercise exercise) { - this.id = exercise.getId(); - this.exercise = new PublicExercise(exercise); - } + public ChallengesReader(Exercise exercise) { + this.id = exercise.getId(); + this.exercise = new PublicExercise(exercise); + } - public String getId() { - return id; - } + public String getId() { + return id; + } - public void setId(String id) { - this.id = id; - } + public void setId(String id) { + this.id = id; + } - public PublicExercise getExercise() { - return exercise; - } + public PublicExercise getExercise() { + return exercise; + } - public void setExercise(PublicExercise exercise) { - this.exercise = exercise; - } + public void setExercise(PublicExercise exercise) { + this.exercise = exercise; + } - public List getExerciseChallenges() { - return exerciseChallenges; - } + public List getExerciseChallenges() { + return exerciseChallenges; + } - public void setExerciseChallenges(List exerciseChallenges) { - this.exerciseChallenges = exerciseChallenges; - } + public void setExerciseChallenges(List exerciseChallenges) { + this.exerciseChallenges = exerciseChallenges; + } } diff --git a/openbas-api/src/main/java/io/openbas/rest/challenge/response/PublicChallenge.java b/openbas-api/src/main/java/io/openbas/rest/challenge/response/PublicChallenge.java index c5b65c192a..1ccea573c9 100644 --- a/openbas-api/src/main/java/io/openbas/rest/challenge/response/PublicChallenge.java +++ b/openbas-api/src/main/java/io/openbas/rest/challenge/response/PublicChallenge.java @@ -4,132 +4,131 @@ import io.openbas.database.model.Challenge; import io.openbas.database.model.Document; import io.openbas.database.model.Tag; - import java.time.Instant; import java.util.List; public class PublicChallenge { - @JsonProperty("challenge_id") - private String id; + @JsonProperty("challenge_id") + private String id; - @JsonProperty("challenge_name") - private String name; + @JsonProperty("challenge_name") + private String name; - @JsonProperty("challenge_category") - private String category; + @JsonProperty("challenge_category") + private String category; - @JsonProperty("challenge_content") - private String content; + @JsonProperty("challenge_content") + private String content; - @JsonProperty("challenge_score") - private Double score; + @JsonProperty("challenge_score") + private Double score; - @JsonProperty("challenge_flags") - private List flags; + @JsonProperty("challenge_flags") + private List flags; - @JsonProperty("challenge_max_attempts") - private Integer maxAttempts; + @JsonProperty("challenge_max_attempts") + private Integer maxAttempts; - @JsonProperty("challenge_tags") - private List tags; + @JsonProperty("challenge_tags") + private List tags; - @JsonProperty("challenge_documents") - private List documents; + @JsonProperty("challenge_documents") + private List documents; - @JsonProperty("challenge_virtual_publication") - private Instant virtualPublication; + @JsonProperty("challenge_virtual_publication") + private Instant virtualPublication; - public PublicChallenge(Challenge challenge) { - this.id = challenge.getId(); - this.name = challenge.getName(); - this.category = challenge.getCategory(); - this.content = challenge.getContent(); - this.score = challenge.getScore(); - this.maxAttempts = challenge.getMaxAttempts(); - this.tags = challenge.getTags().stream().map(Tag::getId).toList(); - this.virtualPublication = challenge.getVirtualPublication(); - this.documents = challenge.getDocuments().stream().map(Document::getId).toList(); - this.flags = challenge.getFlags().stream().map(PublicChallengeFlag::new).toList(); - } + public PublicChallenge(Challenge challenge) { + this.id = challenge.getId(); + this.name = challenge.getName(); + this.category = challenge.getCategory(); + this.content = challenge.getContent(); + this.score = challenge.getScore(); + this.maxAttempts = challenge.getMaxAttempts(); + this.tags = challenge.getTags().stream().map(Tag::getId).toList(); + this.virtualPublication = challenge.getVirtualPublication(); + this.documents = challenge.getDocuments().stream().map(Document::getId).toList(); + this.flags = challenge.getFlags().stream().map(PublicChallengeFlag::new).toList(); + } - public String getId() { - return id; - } + public String getId() { + return id; + } - public void setId(String id) { - this.id = id; - } + public void setId(String id) { + this.id = id; + } - public String getName() { - return name; - } + public String getName() { + return name; + } - public void setName(String name) { - this.name = name; - } + public void setName(String name) { + this.name = name; + } - public String getCategory() { - return category; - } + public String getCategory() { + return category; + } - public void setCategory(String category) { - this.category = category; - } + public void setCategory(String category) { + this.category = category; + } - public String getContent() { - return content; - } + public String getContent() { + return content; + } - public void setContent(String content) { - this.content = content; - } + public void setContent(String content) { + this.content = content; + } - public Double getScore() { - return score; - } + public Double getScore() { + return score; + } - public void setScore(Double score) { - this.score = score; - } + public void setScore(Double score) { + this.score = score; + } - public Integer getMaxAttempts() { - return maxAttempts; - } + public Integer getMaxAttempts() { + return maxAttempts; + } - public void setMaxAttempts(Integer maxAttempts) { - this.maxAttempts = maxAttempts; - } + public void setMaxAttempts(Integer maxAttempts) { + this.maxAttempts = maxAttempts; + } - public List getTags() { - return tags; - } + public List getTags() { + return tags; + } - public void setTags(List tags) { - this.tags = tags; - } + public void setTags(List tags) { + this.tags = tags; + } - public List getDocuments() { - return documents; - } + public List getDocuments() { + return documents; + } - public void setDocuments(List documents) { - this.documents = documents; - } - - public Instant getVirtualPublication() { - return virtualPublication; - } - - public void setVirtualPublication(Instant virtualPublication) { - this.virtualPublication = virtualPublication; - } - - public List getFlags() { - return flags; - } - - public void setFlags(List flags) { - this.flags = flags; - } + public void setDocuments(List documents) { + this.documents = documents; + } + + public Instant getVirtualPublication() { + return virtualPublication; + } + + public void setVirtualPublication(Instant virtualPublication) { + this.virtualPublication = virtualPublication; + } + + public List getFlags() { + return flags; + } + + public void setFlags(List flags) { + this.flags = flags; + } } diff --git a/openbas-api/src/main/java/io/openbas/rest/challenge/response/PublicChallengeFlag.java b/openbas-api/src/main/java/io/openbas/rest/challenge/response/PublicChallengeFlag.java index d1804d90a4..c3eaf62f2b 100644 --- a/openbas-api/src/main/java/io/openbas/rest/challenge/response/PublicChallengeFlag.java +++ b/openbas-api/src/main/java/io/openbas/rest/challenge/response/PublicChallengeFlag.java @@ -9,19 +9,18 @@ @Getter public class PublicChallengeFlag { - @JsonProperty("flag_id") - private String id; + @JsonProperty("flag_id") + private String id; - @JsonProperty("flag_type") - private ChallengeFlag.FLAG_TYPE type; + @JsonProperty("flag_type") + private ChallengeFlag.FLAG_TYPE type; - @JsonProperty("flag_challenge") - private String challenge; - - public PublicChallengeFlag(ChallengeFlag challengeFlag) { - this.id = challengeFlag.getId(); - this.type = challengeFlag.getType(); - this.challenge = challengeFlag.getChallenge().getId(); - } + @JsonProperty("flag_challenge") + private String challenge; + public PublicChallengeFlag(ChallengeFlag challengeFlag) { + this.id = challengeFlag.getId(); + this.type = challengeFlag.getType(); + this.challenge = challengeFlag.getChallenge().getId(); + } } diff --git a/openbas-api/src/main/java/io/openbas/rest/channel/ChannelApi.java b/openbas-api/src/main/java/io/openbas/rest/channel/ChannelApi.java index 65082e3974..0888667910 100644 --- a/openbas-api/src/main/java/io/openbas/rest/channel/ChannelApi.java +++ b/openbas-api/src/main/java/io/openbas/rest/channel/ChannelApi.java @@ -1,5 +1,10 @@ package io.openbas.rest.channel; +import static io.openbas.config.OpenBASAnonymous.ANONYMOUS; +import static io.openbas.database.model.User.ROLE_ADMIN; +import static io.openbas.rest.channel.ChannelHelper.enrichArticleWithVirtualPublication; +import static io.openbas.rest.scenario.ScenarioApi.SCENARIO_URI; + import io.openbas.database.model.*; import io.openbas.database.repository.*; import io.openbas.rest.channel.form.*; @@ -11,273 +16,302 @@ import jakarta.transaction.Transactional; import jakarta.validation.Valid; import jakarta.validation.constraints.NotBlank; -import lombok.RequiredArgsConstructor; -import org.springframework.security.access.annotation.Secured; -import org.springframework.security.access.prepost.PreAuthorize; -import org.springframework.web.bind.annotation.*; - import java.time.Instant; import java.util.ArrayList; import java.util.List; import java.util.Optional; - -import static io.openbas.config.OpenBASAnonymous.ANONYMOUS; -import static io.openbas.database.model.User.ROLE_ADMIN; -import static io.openbas.rest.channel.ChannelHelper.enrichArticleWithVirtualPublication; -import static io.openbas.rest.scenario.ScenarioApi.SCENARIO_URI; +import lombok.RequiredArgsConstructor; +import org.springframework.security.access.annotation.Secured; +import org.springframework.security.access.prepost.PreAuthorize; +import org.springframework.web.bind.annotation.*; @RestController @RequiredArgsConstructor public class ChannelApi extends RestBehavior { - private final ExerciseRepository exerciseRepository; - private final ScenarioService scenarioService; - private final ArticleRepository articleRepository; - private final ChannelRepository channelRepository; - private final DocumentRepository documentRepository; - private final UserRepository userRepository; - private final ChannelService channelService; + private final ExerciseRepository exerciseRepository; + private final ScenarioService scenarioService; + private final ArticleRepository articleRepository; + private final ChannelRepository channelRepository; + private final DocumentRepository documentRepository; + private final UserRepository userRepository; + private final ChannelService channelService; - // -- CHANNELS -- + // -- CHANNELS -- - @GetMapping("/api/channels") - public Iterable channels() { - return channelRepository.findAll(); - } + @GetMapping("/api/channels") + public Iterable channels() { + return channelRepository.findAll(); + } - @GetMapping("/api/channels/{channelId}") - public Channel channel(@PathVariable String channelId) { - return channelRepository.findById(channelId).orElseThrow(ElementNotFoundException::new); - } + @GetMapping("/api/channels/{channelId}") + public Channel channel(@PathVariable String channelId) { + return channelRepository.findById(channelId).orElseThrow(ElementNotFoundException::new); + } - @Secured(ROLE_ADMIN) - @PutMapping("/api/channels/{channelId}") - public Channel updateChannel(@PathVariable String channelId, @Valid @RequestBody ChannelUpdateInput input) { - Channel channel = channelRepository.findById(channelId).orElseThrow(ElementNotFoundException::new); - channel.setUpdateAttributes(input); - channel.setUpdatedAt(Instant.now()); - return channelRepository.save(channel); - } + @Secured(ROLE_ADMIN) + @PutMapping("/api/channels/{channelId}") + public Channel updateChannel( + @PathVariable String channelId, @Valid @RequestBody ChannelUpdateInput input) { + Channel channel = + channelRepository.findById(channelId).orElseThrow(ElementNotFoundException::new); + channel.setUpdateAttributes(input); + channel.setUpdatedAt(Instant.now()); + return channelRepository.save(channel); + } - @Secured(ROLE_ADMIN) - @PutMapping("/api/channels/{channelId}/logos") - public Channel updateChannelLogos(@PathVariable String channelId, @Valid @RequestBody ChannelUpdateLogoInput input) { - Channel channel = channelRepository.findById(channelId).orElseThrow(ElementNotFoundException::new); - if (input.getLogoDark() != null) { - channel.setLogoDark(documentRepository.findById(input.getLogoDark()).orElse(null)); - } else { - channel.setLogoDark(null); - } - if (input.getLogoLight() != null) { - channel.setLogoLight(documentRepository.findById(input.getLogoLight()).orElse(null)); - } else { - channel.setLogoLight(null); - } - return channelRepository.save(channel); + @Secured(ROLE_ADMIN) + @PutMapping("/api/channels/{channelId}/logos") + public Channel updateChannelLogos( + @PathVariable String channelId, @Valid @RequestBody ChannelUpdateLogoInput input) { + Channel channel = + channelRepository.findById(channelId).orElseThrow(ElementNotFoundException::new); + if (input.getLogoDark() != null) { + channel.setLogoDark(documentRepository.findById(input.getLogoDark()).orElse(null)); + } else { + channel.setLogoDark(null); } - - @Secured(ROLE_ADMIN) - @PostMapping("/api/channels") - @Transactional(rollbackOn = Exception.class) - public Channel createChannel(@Valid @RequestBody ChannelCreateInput input) { - Channel channel = new Channel(); - channel.setUpdateAttributes(input); - return channelRepository.save(channel); + if (input.getLogoLight() != null) { + channel.setLogoLight(documentRepository.findById(input.getLogoLight()).orElse(null)); + } else { + channel.setLogoLight(null); } + return channelRepository.save(channel); + } - @Secured(ROLE_ADMIN) - @DeleteMapping("/api/channels/{channelId}") - public void deleteChannel(@PathVariable String channelId) { - channelRepository.deleteById(channelId); - } + @Secured(ROLE_ADMIN) + @PostMapping("/api/channels") + @Transactional(rollbackOn = Exception.class) + public Channel createChannel(@Valid @RequestBody ChannelCreateInput input) { + Channel channel = new Channel(); + channel.setUpdateAttributes(input); + return channelRepository.save(channel); + } + + @Secured(ROLE_ADMIN) + @DeleteMapping("/api/channels/{channelId}") + public void deleteChannel(@PathVariable String channelId) { + channelRepository.deleteById(channelId); + } - @GetMapping("/api/observer/channels/{exerciseId}/{channelId}") - @PreAuthorize("isExerciseObserver(#exerciseId)") - public ChannelReader observerArticles(@PathVariable String exerciseId, @PathVariable String channelId) { - ChannelReader channelReader; - Channel channel = channelRepository.findById(channelId).orElseThrow(ElementNotFoundException::new); + @GetMapping("/api/observer/channels/{exerciseId}/{channelId}") + @PreAuthorize("isExerciseObserver(#exerciseId)") + public ChannelReader observerArticles( + @PathVariable String exerciseId, @PathVariable String channelId) { + ChannelReader channelReader; + Channel channel = + channelRepository.findById(channelId).orElseThrow(ElementNotFoundException::new); - Optional exerciseOpt = this.exerciseRepository.findById(exerciseId); - if (exerciseOpt.isPresent()) { - Exercise exercise = exerciseOpt.get(); - channelReader = new ChannelReader(channel, exercise); - List
publishedArticles = exercise.getArticlesForChannel(channel); - List
articles = enrichArticleWithVirtualPublication(exercise.getInjects(), publishedArticles, this.mapper); - channelReader.setChannelArticles(articles); - } else { - Scenario scenario = this.scenarioService.scenario(exerciseId); - channelReader = new ChannelReader(channel, scenario); - List
publishedArticles = scenario.getArticlesForChannel(channel); - List
articles = enrichArticleWithVirtualPublication(scenario.getInjects(), publishedArticles, this.mapper); - channelReader.setChannelArticles(articles); - } - return channelReader; + Optional exerciseOpt = this.exerciseRepository.findById(exerciseId); + if (exerciseOpt.isPresent()) { + Exercise exercise = exerciseOpt.get(); + channelReader = new ChannelReader(channel, exercise); + List
publishedArticles = exercise.getArticlesForChannel(channel); + List
articles = + enrichArticleWithVirtualPublication( + exercise.getInjects(), publishedArticles, this.mapper); + channelReader.setChannelArticles(articles); + } else { + Scenario scenario = this.scenarioService.scenario(exerciseId); + channelReader = new ChannelReader(channel, scenario); + List
publishedArticles = scenario.getArticlesForChannel(channel); + List
articles = + enrichArticleWithVirtualPublication( + scenario.getInjects(), publishedArticles, this.mapper); + channelReader.setChannelArticles(articles); } + return channelReader; + } - @GetMapping("/api/player/channels/{exerciseId}/{channelId}") - public ChannelReader playerArticles( - @PathVariable String exerciseId, - @PathVariable String channelId, - @RequestParam Optional userId) { - final User user = impersonateUser(userRepository, userId); - if (user.getId().equals(ANONYMOUS)) { - throw new UnsupportedOperationException("User must be logged or dynamic player is required"); - } - return channelService.validateArticles(exerciseId, channelId, user); + @GetMapping("/api/player/channels/{exerciseId}/{channelId}") + public ChannelReader playerArticles( + @PathVariable String exerciseId, + @PathVariable String channelId, + @RequestParam Optional userId) { + final User user = impersonateUser(userRepository, userId); + if (user.getId().equals(ANONYMOUS)) { + throw new UnsupportedOperationException("User must be logged or dynamic player is required"); } + return channelService.validateArticles(exerciseId, channelId, user); + } - // -- EXERCISES -- + // -- EXERCISES -- - @PreAuthorize("isExercisePlanner(#exerciseId)") - @PostMapping("/api/exercises/{exerciseId}/articles") - @Transactional(rollbackOn = Exception.class) - public Article createArticleForExercise( - @PathVariable String exerciseId, - @Valid @RequestBody ArticleCreateInput input) { - Exercise exercise = exerciseRepository.findById(exerciseId).orElseThrow(ElementNotFoundException::new); - Article article = new Article(); - article.setUpdateAttributes(input); - article.setChannel(channelRepository.findById(input.getChannelId()).orElseThrow(ElementNotFoundException::new)); - article.setExercise(exerciseRepository.findById(exerciseId).orElseThrow(ElementNotFoundException::new)); - Article savedArticle = articleRepository.save(article); - List articleDocuments = input.getDocuments(); - List finalArticleDocuments = new ArrayList<>(); - articleDocuments.forEach(articleDocument -> { - Optional doc = documentRepository.findById(articleDocument); - if (doc.isPresent()) { - Document document = doc.get(); - finalArticleDocuments.add(document); - // If Document not yet linked directly to the exercise, attached it - if (!document.getExercises().contains(exercise)) { - exercise.getDocuments().add(document); - exerciseRepository.save(exercise); - } + @PreAuthorize("isExercisePlanner(#exerciseId)") + @PostMapping("/api/exercises/{exerciseId}/articles") + @Transactional(rollbackOn = Exception.class) + public Article createArticleForExercise( + @PathVariable String exerciseId, @Valid @RequestBody ArticleCreateInput input) { + Exercise exercise = + exerciseRepository.findById(exerciseId).orElseThrow(ElementNotFoundException::new); + Article article = new Article(); + article.setUpdateAttributes(input); + article.setChannel( + channelRepository + .findById(input.getChannelId()) + .orElseThrow(ElementNotFoundException::new)); + article.setExercise( + exerciseRepository.findById(exerciseId).orElseThrow(ElementNotFoundException::new)); + Article savedArticle = articleRepository.save(article); + List articleDocuments = input.getDocuments(); + List finalArticleDocuments = new ArrayList<>(); + articleDocuments.forEach( + articleDocument -> { + Optional doc = documentRepository.findById(articleDocument); + if (doc.isPresent()) { + Document document = doc.get(); + finalArticleDocuments.add(document); + // If Document not yet linked directly to the exercise, attached it + if (!document.getExercises().contains(exercise)) { + exercise.getDocuments().add(document); + exerciseRepository.save(exercise); } + } }); - savedArticle.setDocuments(finalArticleDocuments); - return enrichArticleWithVirtualPublication(exercise.getInjects(), savedArticle, this.mapper); - } + savedArticle.setDocuments(finalArticleDocuments); + return enrichArticleWithVirtualPublication(exercise.getInjects(), savedArticle, this.mapper); + } - @PreAuthorize("isExercisePlanner(#exerciseId)") - @PutMapping("/api/exercises/{exerciseId}/articles/{articleId}") - public Article updateArticleForExercise( - @PathVariable String exerciseId, - @PathVariable String articleId, - @Valid @RequestBody ArticleUpdateInput input) { - Exercise exercise = exerciseRepository.findById(exerciseId).orElseThrow(ElementNotFoundException::new); - Article article = articleRepository.findById(articleId).orElseThrow(ElementNotFoundException::new); - List newDocumentsIds = input.getDocuments(); - List currentDocumentIds = article.getDocuments().stream().map(Document::getId).toList(); - article.setChannel(channelRepository.findById(input.getChannelId()).orElseThrow(ElementNotFoundException::new)); - article.setUpdateAttributes(input); - // Original List - List articleDocuments = new ArrayList<>(article.getDocuments()); - // region Set documents - // To delete - article.getDocuments().stream() - .filter(articleDoc -> !newDocumentsIds.contains(articleDoc.getId())) - .forEach(articleDocuments::remove); - // To add - newDocumentsIds.stream().filter(doc -> !currentDocumentIds.contains(doc)).forEach(in -> { - Optional doc = documentRepository.findById(in); - if (doc.isPresent()) { + @PreAuthorize("isExercisePlanner(#exerciseId)") + @PutMapping("/api/exercises/{exerciseId}/articles/{articleId}") + public Article updateArticleForExercise( + @PathVariable String exerciseId, + @PathVariable String articleId, + @Valid @RequestBody ArticleUpdateInput input) { + Exercise exercise = + exerciseRepository.findById(exerciseId).orElseThrow(ElementNotFoundException::new); + Article article = + articleRepository.findById(articleId).orElseThrow(ElementNotFoundException::new); + List newDocumentsIds = input.getDocuments(); + List currentDocumentIds = article.getDocuments().stream().map(Document::getId).toList(); + article.setChannel( + channelRepository + .findById(input.getChannelId()) + .orElseThrow(ElementNotFoundException::new)); + article.setUpdateAttributes(input); + // Original List + List articleDocuments = new ArrayList<>(article.getDocuments()); + // region Set documents + // To delete + article.getDocuments().stream() + .filter(articleDoc -> !newDocumentsIds.contains(articleDoc.getId())) + .forEach(articleDocuments::remove); + // To add + newDocumentsIds.stream() + .filter(doc -> !currentDocumentIds.contains(doc)) + .forEach( + in -> { + Optional doc = documentRepository.findById(in); + if (doc.isPresent()) { Document document = doc.get(); articleDocuments.add(document); // If Document not yet linked directly to the exercise, attached it if (!document.getExercises().contains(exercise)) { - exercise.getDocuments().add(document); - exerciseRepository.save(exercise); + exercise.getDocuments().add(document); + exerciseRepository.save(exercise); } - } - }); - article.setDocuments(articleDocuments); - Article savedArticle = articleRepository.save(article); - return enrichArticleWithVirtualPublication(exercise.getInjects(), savedArticle, this.mapper); - } + } + }); + article.setDocuments(articleDocuments); + Article savedArticle = articleRepository.save(article); + return enrichArticleWithVirtualPublication(exercise.getInjects(), savedArticle, this.mapper); + } - @PreAuthorize("isExercisePlanner(#exerciseId)") - @DeleteMapping("/api/exercises/{exerciseId}/articles/{articleId}") - @Transactional(rollbackOn = Exception.class) - public void deleteArticleForExercise(@PathVariable String exerciseId, @PathVariable String articleId) { - articleRepository.deleteById(articleId); - } + @PreAuthorize("isExercisePlanner(#exerciseId)") + @DeleteMapping("/api/exercises/{exerciseId}/articles/{articleId}") + @Transactional(rollbackOn = Exception.class) + public void deleteArticleForExercise( + @PathVariable String exerciseId, @PathVariable String articleId) { + articleRepository.deleteById(articleId); + } - // -- SCENARIOS -- + // -- SCENARIOS -- - @PreAuthorize("isScenarioPlanner(#scenarioId)") - @PostMapping(SCENARIO_URI + "/{scenarioId}/articles") - @Transactional(rollbackOn = Exception.class) - public Article createArticleForScenario( - @PathVariable @NotBlank final String scenarioId, - @Valid @RequestBody ArticleCreateInput input) { - Scenario scenario = this.scenarioService.scenario(scenarioId); - Article article = new Article(); - article.setUpdateAttributes(input); - article.setChannel(this.channelRepository.findById(input.getChannelId()).orElseThrow(ElementNotFoundException::new)); - article.setScenario(scenario); - Article savedArticle = this.articleRepository.save(article); - List articleDocuments = input.getDocuments(); - List finalArticleDocuments = new ArrayList<>(); - articleDocuments.forEach(articleDocument -> { - Optional doc = this.documentRepository.findById(articleDocument); - if (doc.isPresent()) { - Document document = doc.get(); - finalArticleDocuments.add(document); - // If Document not yet linked directly to the exercise, attached it - if (!document.getScenarios().contains(scenario)) { - scenario.getDocuments().add(document); - this.scenarioService.updateScenario(scenario); - } + @PreAuthorize("isScenarioPlanner(#scenarioId)") + @PostMapping(SCENARIO_URI + "/{scenarioId}/articles") + @Transactional(rollbackOn = Exception.class) + public Article createArticleForScenario( + @PathVariable @NotBlank final String scenarioId, + @Valid @RequestBody ArticleCreateInput input) { + Scenario scenario = this.scenarioService.scenario(scenarioId); + Article article = new Article(); + article.setUpdateAttributes(input); + article.setChannel( + this.channelRepository + .findById(input.getChannelId()) + .orElseThrow(ElementNotFoundException::new)); + article.setScenario(scenario); + Article savedArticle = this.articleRepository.save(article); + List articleDocuments = input.getDocuments(); + List finalArticleDocuments = new ArrayList<>(); + articleDocuments.forEach( + articleDocument -> { + Optional doc = this.documentRepository.findById(articleDocument); + if (doc.isPresent()) { + Document document = doc.get(); + finalArticleDocuments.add(document); + // If Document not yet linked directly to the exercise, attached it + if (!document.getScenarios().contains(scenario)) { + scenario.getDocuments().add(document); + this.scenarioService.updateScenario(scenario); } + } }); - savedArticle.setDocuments(finalArticleDocuments); - return enrichArticleWithVirtualPublication(scenario.getInjects(), savedArticle, this.mapper); - } + savedArticle.setDocuments(finalArticleDocuments); + return enrichArticleWithVirtualPublication(scenario.getInjects(), savedArticle, this.mapper); + } - @PreAuthorize("isScenarioPlanner(#scenarioId)") - @PutMapping(SCENARIO_URI + "/{scenarioId}/articles/{articleId}") - @Transactional(rollbackOn = Exception.class) - public Article updateArticleForScenario( - @PathVariable @NotBlank final String scenarioId, - @PathVariable @NotBlank final String articleId, - @Valid @RequestBody ArticleUpdateInput input) { - Scenario scenario = this.scenarioService.scenario(scenarioId); - Article article = articleRepository.findById(articleId).orElseThrow(ElementNotFoundException::new); - List newDocumentsIds = input.getDocuments(); - List currentDocumentIds = article.getDocuments().stream().map(Document::getId).toList(); - article.setChannel(channelRepository.findById(input.getChannelId()).orElseThrow(ElementNotFoundException::new)); - article.setUpdateAttributes(input); - // Original List - List articleDocuments = new ArrayList<>(article.getDocuments()); - // region Set documents - // To delete - article.getDocuments().stream() - .filter(articleDoc -> !newDocumentsIds.contains(articleDoc.getId())) - .forEach(articleDocuments::remove); - // To add - newDocumentsIds.stream().filter(doc -> !currentDocumentIds.contains(doc)).forEach(in -> { - Optional doc = documentRepository.findById(in); - if (doc.isPresent()) { + @PreAuthorize("isScenarioPlanner(#scenarioId)") + @PutMapping(SCENARIO_URI + "/{scenarioId}/articles/{articleId}") + @Transactional(rollbackOn = Exception.class) + public Article updateArticleForScenario( + @PathVariable @NotBlank final String scenarioId, + @PathVariable @NotBlank final String articleId, + @Valid @RequestBody ArticleUpdateInput input) { + Scenario scenario = this.scenarioService.scenario(scenarioId); + Article article = + articleRepository.findById(articleId).orElseThrow(ElementNotFoundException::new); + List newDocumentsIds = input.getDocuments(); + List currentDocumentIds = article.getDocuments().stream().map(Document::getId).toList(); + article.setChannel( + channelRepository + .findById(input.getChannelId()) + .orElseThrow(ElementNotFoundException::new)); + article.setUpdateAttributes(input); + // Original List + List articleDocuments = new ArrayList<>(article.getDocuments()); + // region Set documents + // To delete + article.getDocuments().stream() + .filter(articleDoc -> !newDocumentsIds.contains(articleDoc.getId())) + .forEach(articleDocuments::remove); + // To add + newDocumentsIds.stream() + .filter(doc -> !currentDocumentIds.contains(doc)) + .forEach( + in -> { + Optional doc = documentRepository.findById(in); + if (doc.isPresent()) { Document document = doc.get(); articleDocuments.add(document); // If Document not yet linked directly to the exercise, attached it if (!document.getScenarios().contains(scenario)) { - scenario.getDocuments().add(document); - this.scenarioService.updateScenario(scenario); + scenario.getDocuments().add(document); + this.scenarioService.updateScenario(scenario); } - } - }); - article.setDocuments(articleDocuments); - Article savedArticle = articleRepository.save(article); - return enrichArticleWithVirtualPublication(scenario.getInjects(), savedArticle, this.mapper); - } + } + }); + article.setDocuments(articleDocuments); + Article savedArticle = articleRepository.save(article); + return enrichArticleWithVirtualPublication(scenario.getInjects(), savedArticle, this.mapper); + } - @PreAuthorize("isScenarioPlanner(#scenarioId)") - @DeleteMapping(SCENARIO_URI + "/{scenarioId}/articles/{articleId}") - @Transactional(rollbackOn = Exception.class) - public void deleteArticleForScenario( - @PathVariable @NotBlank final String scenarioId, - @PathVariable @NotBlank final String articleId) { - articleRepository.deleteById(articleId); - } + @PreAuthorize("isScenarioPlanner(#scenarioId)") + @DeleteMapping(SCENARIO_URI + "/{scenarioId}/articles/{articleId}") + @Transactional(rollbackOn = Exception.class) + public void deleteArticleForScenario( + @PathVariable @NotBlank final String scenarioId, + @PathVariable @NotBlank final String articleId) { + articleRepository.deleteById(articleId); + } } diff --git a/openbas-api/src/main/java/io/openbas/rest/channel/ChannelHelper.java b/openbas-api/src/main/java/io/openbas/rest/channel/ChannelHelper.java index 3a08eecedf..f81f512376 100644 --- a/openbas-api/src/main/java/io/openbas/rest/channel/ChannelHelper.java +++ b/openbas-api/src/main/java/io/openbas/rest/channel/ChannelHelper.java @@ -1,5 +1,10 @@ package io.openbas.rest.channel; +import static io.openbas.database.model.Inject.SPEED_STANDARD; +import static io.openbas.injectors.channel.ChannelContract.CHANNEL_PUBLISH; +import static java.util.Comparator.naturalOrder; +import static java.util.Comparator.nullsFirst; + import com.fasterxml.jackson.core.JsonProcessingException; import com.fasterxml.jackson.databind.ObjectMapper; import io.openbas.database.model.Article; @@ -7,7 +12,6 @@ import io.openbas.injectors.channel.model.ChannelContent; import io.openbas.rest.channel.model.VirtualArticle; import io.openbas.rest.exception.ElementNotFoundException; - import java.time.Instant; import java.util.Comparator; import java.util.List; @@ -16,63 +20,53 @@ import java.util.stream.Collectors; import java.util.stream.Stream; -import static io.openbas.database.model.Inject.SPEED_STANDARD; -import static io.openbas.injectors.channel.ChannelContract.CHANNEL_PUBLISH; -import static java.util.Comparator.naturalOrder; -import static java.util.Comparator.nullsFirst; - public class ChannelHelper { - private ChannelHelper() { - - } + private ChannelHelper() {} - public static Article enrichArticleWithVirtualPublication( - List injects, - Article article, - ObjectMapper mapper) { - return enrichArticleWithVirtualPublication( - injects, - List.of(article), - mapper).stream() - .findFirst() - .orElseThrow(ElementNotFoundException::new); - } + public static Article enrichArticleWithVirtualPublication( + List injects, Article article, ObjectMapper mapper) { + return enrichArticleWithVirtualPublication(injects, List.of(article), mapper).stream() + .findFirst() + .orElseThrow(ElementNotFoundException::new); + } - public static List
enrichArticleWithVirtualPublication( - List injects, - List
articles, - ObjectMapper mapper) { - Instant now = Instant.now(); - Map toPublishArticleIdsMap = injects.stream() - .filter(inject -> inject.getInjectorContract() + public static List
enrichArticleWithVirtualPublication( + List injects, List
articles, ObjectMapper mapper) { + Instant now = Instant.now(); + Map toPublishArticleIdsMap = + injects.stream() + .filter( + inject -> + inject + .getInjectorContract() .map(contract -> contract.getId().equals(CHANNEL_PUBLISH)) .orElse(false)) - .filter(inject -> inject.getContent() != null) - .sorted(Comparator.comparing(Inject::getDependsDuration)) - .flatMap(inject -> convertToVirtualArticles(inject, now, mapper)) - .filter(Objects::nonNull) - .distinct() - .collect(Collectors.toMap(VirtualArticle::id, VirtualArticle::date)); - return articles.stream() - .peek(article -> article.setVirtualPublication(toPublishArticleIdsMap.get(article.getId()))) - .sorted(Comparator.comparing(Article::getVirtualPublication, nullsFirst(naturalOrder())) - .thenComparing(Article::getCreatedAt) - .reversed()) - .toList(); - } + .filter(inject -> inject.getContent() != null) + .sorted(Comparator.comparing(Inject::getDependsDuration)) + .flatMap(inject -> convertToVirtualArticles(inject, now, mapper)) + .filter(Objects::nonNull) + .distinct() + .collect(Collectors.toMap(VirtualArticle::id, VirtualArticle::date)); + return articles.stream() + .peek(article -> article.setVirtualPublication(toPublishArticleIdsMap.get(article.getId()))) + .sorted( + Comparator.comparing(Article::getVirtualPublication, nullsFirst(naturalOrder())) + .thenComparing(Article::getCreatedAt) + .reversed()) + .toList(); + } - private static Stream convertToVirtualArticles(Inject inject, Instant now, ObjectMapper mapper) { - Instant virtualInjectDate = inject.computeInjectDate(now, SPEED_STANDARD); - try { - ChannelContent content = mapper.treeToValue(inject.getContent(), ChannelContent.class); - return content.getArticles() - .stream() - .map(article -> new VirtualArticle(virtualInjectDate, article)); - } catch (JsonProcessingException e) { - // Log the error if necessary - return Stream.empty(); - } + private static Stream convertToVirtualArticles( + Inject inject, Instant now, ObjectMapper mapper) { + Instant virtualInjectDate = inject.computeInjectDate(now, SPEED_STANDARD); + try { + ChannelContent content = mapper.treeToValue(inject.getContent(), ChannelContent.class); + return content.getArticles().stream() + .map(article -> new VirtualArticle(virtualInjectDate, article)); + } catch (JsonProcessingException e) { + // Log the error if necessary + return Stream.empty(); } - + } } diff --git a/openbas-api/src/main/java/io/openbas/rest/channel/ExerciseArticleApi.java b/openbas-api/src/main/java/io/openbas/rest/channel/ExerciseArticleApi.java index 613cf23a32..754a4ffbf6 100644 --- a/openbas-api/src/main/java/io/openbas/rest/channel/ExerciseArticleApi.java +++ b/openbas-api/src/main/java/io/openbas/rest/channel/ExerciseArticleApi.java @@ -1,5 +1,9 @@ package io.openbas.rest.channel; +import static io.openbas.injectors.channel.ChannelContract.CHANNEL_PUBLISH; +import static io.openbas.rest.channel.ChannelHelper.enrichArticleWithVirtualPublication; +import static io.openbas.rest.exercise.ExerciseApi.EXERCISE_URI; + import io.openbas.database.model.Article; import io.openbas.database.model.Inject; import io.openbas.database.repository.ArticleRepository; @@ -9,6 +13,7 @@ import io.openbas.rest.channel.output.ArticleOutput; import io.openbas.rest.helper.RestBehavior; import jakarta.validation.constraints.NotBlank; +import java.util.List; import lombok.RequiredArgsConstructor; import org.springframework.security.access.prepost.PreAuthorize; import org.springframework.transaction.annotation.Transactional; @@ -16,12 +21,6 @@ import org.springframework.web.bind.annotation.PathVariable; import org.springframework.web.bind.annotation.RestController; -import java.util.List; - -import static io.openbas.injectors.channel.ChannelContract.CHANNEL_PUBLISH; -import static io.openbas.rest.channel.ChannelHelper.enrichArticleWithVirtualPublication; -import static io.openbas.rest.exercise.ExerciseApi.EXERCISE_URI; - @RestController @RequiredArgsConstructor public class ExerciseArticleApi extends RestBehavior { @@ -33,15 +32,14 @@ public class ExerciseArticleApi extends RestBehavior { @GetMapping(EXERCISE_URI + "/{exerciseId}/articles") @Transactional(readOnly = true) public Iterable exerciseArticles(@PathVariable @NotBlank final String exerciseId) { - List injects = this.injectRepository.findAll( - InjectSpecification.fromExercise(exerciseId) - .and(InjectSpecification.fromContract(CHANNEL_PUBLISH)) - ); - List
articles = this.articleRepository.findAll(ArticleSpecification.fromExercise(exerciseId)); - return enrichArticleWithVirtualPublication(injects, articles, this.mapper) - .stream() + List injects = + this.injectRepository.findAll( + InjectSpecification.fromExercise(exerciseId) + .and(InjectSpecification.fromContract(CHANNEL_PUBLISH))); + List
articles = + this.articleRepository.findAll(ArticleSpecification.fromExercise(exerciseId)); + return enrichArticleWithVirtualPublication(injects, articles, this.mapper).stream() .map(ArticleOutput::from) .toList(); } - } diff --git a/openbas-api/src/main/java/io/openbas/rest/channel/ScenarioArticleApi.java b/openbas-api/src/main/java/io/openbas/rest/channel/ScenarioArticleApi.java index 3c8d461f2a..1419d50b64 100644 --- a/openbas-api/src/main/java/io/openbas/rest/channel/ScenarioArticleApi.java +++ b/openbas-api/src/main/java/io/openbas/rest/channel/ScenarioArticleApi.java @@ -1,5 +1,9 @@ package io.openbas.rest.channel; +import static io.openbas.injectors.channel.ChannelContract.CHANNEL_PUBLISH; +import static io.openbas.rest.channel.ChannelHelper.enrichArticleWithVirtualPublication; +import static io.openbas.rest.scenario.ScenarioApi.SCENARIO_URI; + import io.openbas.database.model.Article; import io.openbas.database.model.Inject; import io.openbas.database.repository.ArticleRepository; @@ -9,6 +13,7 @@ import io.openbas.rest.channel.output.ArticleOutput; import io.openbas.rest.helper.RestBehavior; import jakarta.validation.constraints.NotBlank; +import java.util.List; import lombok.RequiredArgsConstructor; import org.springframework.security.access.prepost.PreAuthorize; import org.springframework.transaction.annotation.Transactional; @@ -16,12 +21,6 @@ import org.springframework.web.bind.annotation.PathVariable; import org.springframework.web.bind.annotation.RestController; -import java.util.List; - -import static io.openbas.injectors.channel.ChannelContract.CHANNEL_PUBLISH; -import static io.openbas.rest.channel.ChannelHelper.enrichArticleWithVirtualPublication; -import static io.openbas.rest.scenario.ScenarioApi.SCENARIO_URI; - @RestController @RequiredArgsConstructor public class ScenarioArticleApi extends RestBehavior { @@ -33,15 +32,14 @@ public class ScenarioArticleApi extends RestBehavior { @GetMapping(SCENARIO_URI + "/{scenarioId}/articles") @Transactional(readOnly = true) public Iterable scenarioArticles(@PathVariable @NotBlank final String scenarioId) { - List injects = this.injectRepository.findAll( - InjectSpecification.fromScenario(scenarioId) - .and(InjectSpecification.fromContract(CHANNEL_PUBLISH)) - ); - List
articles = this.articleRepository.findAll(ArticleSpecification.fromScenario(scenarioId)); - return enrichArticleWithVirtualPublication(injects, articles, this.mapper) - .stream() + List injects = + this.injectRepository.findAll( + InjectSpecification.fromScenario(scenarioId) + .and(InjectSpecification.fromContract(CHANNEL_PUBLISH))); + List
articles = + this.articleRepository.findAll(ArticleSpecification.fromScenario(scenarioId)); + return enrichArticleWithVirtualPublication(injects, articles, this.mapper).stream() .map(ArticleOutput::from) .toList(); } - } diff --git a/openbas-api/src/main/java/io/openbas/rest/channel/form/ArticleCreateInput.java b/openbas-api/src/main/java/io/openbas/rest/channel/form/ArticleCreateInput.java index ea58b871b1..41747a1e62 100644 --- a/openbas-api/src/main/java/io/openbas/rest/channel/form/ArticleCreateInput.java +++ b/openbas-api/src/main/java/io/openbas/rest/channel/form/ArticleCreateInput.java @@ -1,114 +1,112 @@ package io.openbas.rest.channel.form; -import com.fasterxml.jackson.annotation.JsonProperty; +import static io.openbas.config.AppConfig.MANDATORY_MESSAGE; +import com.fasterxml.jackson.annotation.JsonProperty; import jakarta.validation.constraints.NotBlank; - import java.util.ArrayList; import java.util.List; -import static io.openbas.config.AppConfig.MANDATORY_MESSAGE; - public class ArticleCreateInput { - @NotBlank(message = MANDATORY_MESSAGE) - @JsonProperty("article_name") - private String name; + @NotBlank(message = MANDATORY_MESSAGE) + @JsonProperty("article_name") + private String name; - @JsonProperty("article_content") - private String content; + @JsonProperty("article_content") + private String content; - @JsonProperty("article_author") - private String author; + @JsonProperty("article_author") + private String author; - @JsonProperty("article_shares") - private Integer shares; + @JsonProperty("article_shares") + private Integer shares; - @JsonProperty("article_likes") - private Integer likes; + @JsonProperty("article_likes") + private Integer likes; - @JsonProperty("article_comments") - private Integer comments; + @JsonProperty("article_comments") + private Integer comments; - @JsonProperty("article_documents") - private List documents = new ArrayList<>(); + @JsonProperty("article_documents") + private List documents = new ArrayList<>(); - @NotBlank(message = MANDATORY_MESSAGE) - @JsonProperty("article_channel") - private String channelId; + @NotBlank(message = MANDATORY_MESSAGE) + @JsonProperty("article_channel") + private String channelId; - @JsonProperty("article_published") - private boolean published; + @JsonProperty("article_published") + private boolean published; - public String getName() { - return name; - } + public String getName() { + return name; + } - public void setName(String name) { - this.name = name; - } + public void setName(String name) { + this.name = name; + } - public String getContent() { - return content; - } + public String getContent() { + return content; + } - public void setContent(String content) { - this.content = content; - } + public void setContent(String content) { + this.content = content; + } - public String getAuthor() { - return author; - } + public String getAuthor() { + return author; + } - public void setAuthor(String author) { - this.author = author; - } + public void setAuthor(String author) { + this.author = author; + } - public Integer getShares() { - return shares; - } + public Integer getShares() { + return shares; + } - public void setShares(Integer shares) { - this.shares = shares; - } + public void setShares(Integer shares) { + this.shares = shares; + } - public Integer getLikes() { - return likes; - } + public Integer getLikes() { + return likes; + } - public void setLikes(Integer likes) { - this.likes = likes; - } + public void setLikes(Integer likes) { + this.likes = likes; + } - public Integer getComments() { - return comments; - } + public Integer getComments() { + return comments; + } - public void setComments(Integer comments) { - this.comments = comments; - } + public void setComments(Integer comments) { + this.comments = comments; + } - public List getDocuments() { - return documents; - } + public List getDocuments() { + return documents; + } - public void setDocuments(List documents) { - this.documents = documents; - } + public void setDocuments(List documents) { + this.documents = documents; + } - public boolean isPublished() { - return published; - } + public boolean isPublished() { + return published; + } - public void setPublished(boolean published) { - this.published = published; - } + public void setPublished(boolean published) { + this.published = published; + } - public String getChannelId() { - return channelId; - } + public String getChannelId() { + return channelId; + } - public void setChannelId(String channelId) { - this.channelId = channelId; - } + public void setChannelId(String channelId) { + this.channelId = channelId; + } } diff --git a/openbas-api/src/main/java/io/openbas/rest/channel/form/ArticleUpdateInput.java b/openbas-api/src/main/java/io/openbas/rest/channel/form/ArticleUpdateInput.java index 861c78f14f..bbb7f0d28b 100644 --- a/openbas-api/src/main/java/io/openbas/rest/channel/form/ArticleUpdateInput.java +++ b/openbas-api/src/main/java/io/openbas/rest/channel/form/ArticleUpdateInput.java @@ -1,114 +1,112 @@ package io.openbas.rest.channel.form; -import com.fasterxml.jackson.annotation.JsonProperty; +import static io.openbas.config.AppConfig.MANDATORY_MESSAGE; +import com.fasterxml.jackson.annotation.JsonProperty; import jakarta.validation.constraints.NotBlank; - import java.util.ArrayList; import java.util.List; -import static io.openbas.config.AppConfig.MANDATORY_MESSAGE; - public class ArticleUpdateInput { - @NotBlank(message = MANDATORY_MESSAGE) - @JsonProperty("article_name") - private String name; + @NotBlank(message = MANDATORY_MESSAGE) + @JsonProperty("article_name") + private String name; - @JsonProperty("article_content") - private String content; + @JsonProperty("article_content") + private String content; - @JsonProperty("article_author") - private String author; + @JsonProperty("article_author") + private String author; - @JsonProperty("article_shares") - private Integer shares; + @JsonProperty("article_shares") + private Integer shares; - @JsonProperty("article_likes") - private Integer likes; + @JsonProperty("article_likes") + private Integer likes; - @JsonProperty("article_comments") - private Integer comments; + @JsonProperty("article_comments") + private Integer comments; - @JsonProperty("article_documents") - private List documents = new ArrayList<>(); + @JsonProperty("article_documents") + private List documents = new ArrayList<>(); - @NotBlank(message = MANDATORY_MESSAGE) - @JsonProperty("article_channel") - private String channelId; + @NotBlank(message = MANDATORY_MESSAGE) + @JsonProperty("article_channel") + private String channelId; - @JsonProperty("article_published") - private boolean published; + @JsonProperty("article_published") + private boolean published; - public String getName() { - return name; - } + public String getName() { + return name; + } - public void setName(String name) { - this.name = name; - } + public void setName(String name) { + this.name = name; + } - public String getContent() { - return content; - } + public String getContent() { + return content; + } - public void setContent(String content) { - this.content = content; - } + public void setContent(String content) { + this.content = content; + } - public String getAuthor() { - return author; - } + public String getAuthor() { + return author; + } - public void setAuthor(String author) { - this.author = author; - } + public void setAuthor(String author) { + this.author = author; + } - public Integer getShares() { - return shares; - } + public Integer getShares() { + return shares; + } - public void setShares(Integer shares) { - this.shares = shares; - } + public void setShares(Integer shares) { + this.shares = shares; + } - public Integer getLikes() { - return likes; - } + public Integer getLikes() { + return likes; + } - public void setLikes(Integer likes) { - this.likes = likes; - } + public void setLikes(Integer likes) { + this.likes = likes; + } - public Integer getComments() { - return comments; - } + public Integer getComments() { + return comments; + } - public void setComments(Integer comments) { - this.comments = comments; - } + public void setComments(Integer comments) { + this.comments = comments; + } - public List getDocuments() { - return documents; - } + public List getDocuments() { + return documents; + } - public void setDocuments(List documents) { - this.documents = documents; - } + public void setDocuments(List documents) { + this.documents = documents; + } - public boolean isPublished() { - return published; - } + public boolean isPublished() { + return published; + } - public void setPublished(boolean published) { - this.published = published; - } + public void setPublished(boolean published) { + this.published = published; + } - public String getChannelId() { - return channelId; - } + public String getChannelId() { + return channelId; + } - public void setChannelId(String channelId) { - this.channelId = channelId; - } + public void setChannelId(String channelId) { + this.channelId = channelId; + } } diff --git a/openbas-api/src/main/java/io/openbas/rest/channel/form/ChannelCreateInput.java b/openbas-api/src/main/java/io/openbas/rest/channel/form/ChannelCreateInput.java index 1077937f5b..e5ba711870 100644 --- a/openbas-api/src/main/java/io/openbas/rest/channel/form/ChannelCreateInput.java +++ b/openbas-api/src/main/java/io/openbas/rest/channel/form/ChannelCreateInput.java @@ -1,46 +1,45 @@ package io.openbas.rest.channel.form; -import com.fasterxml.jackson.annotation.JsonProperty; +import static io.openbas.config.AppConfig.MANDATORY_MESSAGE; +import com.fasterxml.jackson.annotation.JsonProperty; import jakarta.validation.constraints.NotBlank; -import static io.openbas.config.AppConfig.MANDATORY_MESSAGE; - public class ChannelCreateInput { - @NotBlank(message = MANDATORY_MESSAGE) - @JsonProperty("channel_type") - private String type; + @NotBlank(message = MANDATORY_MESSAGE) + @JsonProperty("channel_type") + private String type; - @NotBlank(message = MANDATORY_MESSAGE) - @JsonProperty("channel_name") - private String name; + @NotBlank(message = MANDATORY_MESSAGE) + @JsonProperty("channel_name") + private String name; - @NotBlank(message = MANDATORY_MESSAGE) - @JsonProperty("channel_description") - private String description; + @NotBlank(message = MANDATORY_MESSAGE) + @JsonProperty("channel_description") + private String description; - public String getType() { - return type; - } + public String getType() { + return type; + } - public void setType(String type) { - this.type = type; - } + public void setType(String type) { + this.type = type; + } - public String getName() { - return name; - } + public String getName() { + return name; + } - public void setName(String name) { - this.name = name; - } + public void setName(String name) { + this.name = name; + } - public String getDescription() { - return description; - } + public String getDescription() { + return description; + } - public void setDescription(String description) { - this.description = description; - } + public void setDescription(String description) { + this.description = description; + } } diff --git a/openbas-api/src/main/java/io/openbas/rest/channel/form/ChannelUpdateInput.java b/openbas-api/src/main/java/io/openbas/rest/channel/form/ChannelUpdateInput.java index 27e99baa3f..0005759f21 100644 --- a/openbas-api/src/main/java/io/openbas/rest/channel/form/ChannelUpdateInput.java +++ b/openbas-api/src/main/java/io/openbas/rest/channel/form/ChannelUpdateInput.java @@ -1,100 +1,99 @@ package io.openbas.rest.channel.form; -import com.fasterxml.jackson.annotation.JsonProperty; +import static io.openbas.config.AppConfig.MANDATORY_MESSAGE; +import com.fasterxml.jackson.annotation.JsonProperty; import jakarta.validation.constraints.NotBlank; -import static io.openbas.config.AppConfig.MANDATORY_MESSAGE; - public class ChannelUpdateInput { - @NotBlank(message = MANDATORY_MESSAGE) - @JsonProperty("channel_type") - private String type; + @NotBlank(message = MANDATORY_MESSAGE) + @JsonProperty("channel_type") + private String type; - @NotBlank(message = MANDATORY_MESSAGE) - @JsonProperty("channel_name") - private String name; + @NotBlank(message = MANDATORY_MESSAGE) + @JsonProperty("channel_name") + private String name; - @NotBlank(message = MANDATORY_MESSAGE) - @JsonProperty("channel_description") - private String description; + @NotBlank(message = MANDATORY_MESSAGE) + @JsonProperty("channel_description") + private String description; - @JsonProperty("channel_mode") - private String mode; + @JsonProperty("channel_mode") + private String mode; - @JsonProperty("channel_primary_color_dark") - private String primaryColorDark; + @JsonProperty("channel_primary_color_dark") + private String primaryColorDark; - @JsonProperty("channel_primary_color_light") - private String primaryColorLight; + @JsonProperty("channel_primary_color_light") + private String primaryColorLight; - @JsonProperty("channel_secondary_color_dark") - private String secondaryColorDark; + @JsonProperty("channel_secondary_color_dark") + private String secondaryColorDark; - @JsonProperty("channel_secondary_color_light") - private String secondaryColorLight; + @JsonProperty("channel_secondary_color_light") + private String secondaryColorLight; - public String getType() { - return type; - } + public String getType() { + return type; + } - public void setType(String type) { - this.type = type; - } + public void setType(String type) { + this.type = type; + } - public String getName() { - return name; - } + public String getName() { + return name; + } - public void setName(String name) { - this.name = name; - } + public void setName(String name) { + this.name = name; + } - public String getDescription() { - return description; - } + public String getDescription() { + return description; + } - public String getMode() { - return mode; - } + public String getMode() { + return mode; + } - public void setMode(String mode) { - this.mode = mode; - } + public void setMode(String mode) { + this.mode = mode; + } - public void setDescription(String description) { - this.description = description; - } + public void setDescription(String description) { + this.description = description; + } - public String getPrimaryColorDark() { - return primaryColorDark; - } + public String getPrimaryColorDark() { + return primaryColorDark; + } - public void setPrimaryColorDark(String primaryColorDark) { - this.primaryColorDark = primaryColorDark; - } + public void setPrimaryColorDark(String primaryColorDark) { + this.primaryColorDark = primaryColorDark; + } - public String getPrimaryColorLight() { - return primaryColorLight; - } + public String getPrimaryColorLight() { + return primaryColorLight; + } - public void setPrimaryColorLight(String primaryColorLight) { - this.primaryColorLight = primaryColorLight; - } + public void setPrimaryColorLight(String primaryColorLight) { + this.primaryColorLight = primaryColorLight; + } - public String getSecondaryColorDark() { - return secondaryColorDark; - } + public String getSecondaryColorDark() { + return secondaryColorDark; + } - public void setSecondaryColorDark(String secondaryColorDark) { - this.secondaryColorDark = secondaryColorDark; - } + public void setSecondaryColorDark(String secondaryColorDark) { + this.secondaryColorDark = secondaryColorDark; + } - public String getSecondaryColorLight() { - return secondaryColorLight; - } + public String getSecondaryColorLight() { + return secondaryColorLight; + } - public void setSecondaryColorLight(String secondaryColorLight) { - this.secondaryColorLight = secondaryColorLight; - } + public void setSecondaryColorLight(String secondaryColorLight) { + this.secondaryColorLight = secondaryColorLight; + } } diff --git a/openbas-api/src/main/java/io/openbas/rest/channel/form/ChannelUpdateLogoInput.java b/openbas-api/src/main/java/io/openbas/rest/channel/form/ChannelUpdateLogoInput.java index ab475ffb8c..6886dc3074 100644 --- a/openbas-api/src/main/java/io/openbas/rest/channel/form/ChannelUpdateLogoInput.java +++ b/openbas-api/src/main/java/io/openbas/rest/channel/form/ChannelUpdateLogoInput.java @@ -4,25 +4,25 @@ public class ChannelUpdateLogoInput { - @JsonProperty("channel_logo_dark") - private String logoDark; + @JsonProperty("channel_logo_dark") + private String logoDark; - @JsonProperty("channel_logo_light") - private String logoLight; + @JsonProperty("channel_logo_light") + private String logoLight; - public String getLogoDark() { - return logoDark; - } + public String getLogoDark() { + return logoDark; + } - public void setLogoDark(String logoDark) { - this.logoDark = logoDark; - } + public void setLogoDark(String logoDark) { + this.logoDark = logoDark; + } - public String getLogoLight() { - return logoLight; - } + public String getLogoLight() { + return logoLight; + } - public void setLogoLight(String logoLight) { - this.logoLight = logoLight; - } + public void setLogoLight(String logoLight) { + this.logoLight = logoLight; + } } diff --git a/openbas-api/src/main/java/io/openbas/rest/channel/model/VirtualArticle.java b/openbas-api/src/main/java/io/openbas/rest/channel/model/VirtualArticle.java index 11eadfbd09..d5716c2871 100644 --- a/openbas-api/src/main/java/io/openbas/rest/channel/model/VirtualArticle.java +++ b/openbas-api/src/main/java/io/openbas/rest/channel/model/VirtualArticle.java @@ -4,17 +4,16 @@ import java.util.Objects; public record VirtualArticle(Instant date, String id) { - @Override - public boolean equals(Object o) { - if (this == o) return true; - if (o == null || getClass() != o.getClass()) return false; - VirtualArticle that = (VirtualArticle) o; - return id.equals(that.id); - } + @Override + public boolean equals(Object o) { + if (this == o) return true; + if (o == null || getClass() != o.getClass()) return false; + VirtualArticle that = (VirtualArticle) o; + return id.equals(that.id); + } - @Override - public int hashCode() { - return Objects.hash(id); - } + @Override + public int hashCode() { + return Objects.hash(id); + } } - diff --git a/openbas-api/src/main/java/io/openbas/rest/channel/output/ArticleOutput.java b/openbas-api/src/main/java/io/openbas/rest/channel/output/ArticleOutput.java index 888c997457..4004c946f7 100644 --- a/openbas-api/src/main/java/io/openbas/rest/channel/output/ArticleOutput.java +++ b/openbas-api/src/main/java/io/openbas/rest/channel/output/ArticleOutput.java @@ -1,5 +1,7 @@ package io.openbas.rest.channel.output; +import static java.util.Optional.ofNullable; + import com.fasterxml.jackson.annotation.JsonProperty; import io.openbas.database.model.Article; import io.openbas.database.model.Document; @@ -7,13 +9,10 @@ import io.openbas.database.model.Scenario; import jakarta.persistence.Transient; import jakarta.validation.constraints.NotBlank; -import lombok.Data; - import java.time.Instant; import java.util.ArrayList; import java.util.List; - -import static java.util.Optional.ofNullable; +import lombok.Data; @Data public class ArticleOutput { @@ -53,8 +52,7 @@ public class ArticleOutput { @JsonProperty("article_documents") private List documents = new ArrayList<>(); - @Transient - private Instant virtualPublication; + @Transient private Instant virtualPublication; @JsonProperty("article_virtual_publication") public Instant getVirtualPublication() { @@ -82,5 +80,4 @@ public static ArticleOutput from(@org.jetbrains.annotations.NotNull final Articl articleOutput.setVirtualPublication(article.getVirtualPublication()); return articleOutput; } - } diff --git a/openbas-api/src/main/java/io/openbas/rest/channel/response/ChannelReader.java b/openbas-api/src/main/java/io/openbas/rest/channel/response/ChannelReader.java index b35d3aa9b8..d14ad3f8dd 100644 --- a/openbas-api/src/main/java/io/openbas/rest/channel/response/ChannelReader.java +++ b/openbas-api/src/main/java/io/openbas/rest/channel/response/ChannelReader.java @@ -1,48 +1,46 @@ package io.openbas.rest.channel.response; +import static lombok.AccessLevel.NONE; + import com.fasterxml.jackson.annotation.JsonProperty; import io.openbas.database.model.Article; import io.openbas.database.model.Channel; import io.openbas.database.model.Exercise; import io.openbas.database.model.Scenario; -import lombok.Getter; -import lombok.Setter; - import java.util.ArrayList; import java.util.List; - -import static lombok.AccessLevel.NONE; +import lombok.Getter; +import lombok.Setter; @Getter @Setter public class ChannelReader { - @Setter(NONE) - @JsonProperty("channel_id") - private String id; - - @JsonProperty("channel_information") - private Channel channel; + @Setter(NONE) + @JsonProperty("channel_id") + private String id; - @JsonProperty("channel_exercise") - private Exercise exercise; + @JsonProperty("channel_information") + private Channel channel; - @JsonProperty("channel_scenario") - private Scenario scenario; + @JsonProperty("channel_exercise") + private Exercise exercise; - @JsonProperty("channel_articles") - private List
channelArticles = new ArrayList<>(); + @JsonProperty("channel_scenario") + private Scenario scenario; - public ChannelReader(Channel channel, Exercise exercise) { - this.id = channel.getId(); - this.channel = channel; - this.exercise = exercise; - } + @JsonProperty("channel_articles") + private List
channelArticles = new ArrayList<>(); - public ChannelReader(Channel channel, Scenario scenario) { - this.id = channel.getId(); - this.channel = channel; - this.scenario = scenario; - } + public ChannelReader(Channel channel, Exercise exercise) { + this.id = channel.getId(); + this.channel = channel; + this.exercise = exercise; + } + public ChannelReader(Channel channel, Scenario scenario) { + this.id = channel.getId(); + this.channel = channel; + this.scenario = scenario; + } } diff --git a/openbas-api/src/main/java/io/openbas/rest/collector/CollectorApi.java b/openbas-api/src/main/java/io/openbas/rest/collector/CollectorApi.java index 9e0b5e049f..e944d90ece 100644 --- a/openbas-api/src/main/java/io/openbas/rest/collector/CollectorApi.java +++ b/openbas-api/src/main/java/io/openbas/rest/collector/CollectorApi.java @@ -1,5 +1,7 @@ package io.openbas.rest.collector; +import static io.openbas.database.model.User.ROLE_ADMIN; + import com.fasterxml.jackson.databind.ObjectMapper; import io.openbas.config.OpenBASConfig; import io.openbas.database.model.Collector; @@ -13,110 +15,133 @@ import jakarta.annotation.Resource; import jakarta.transaction.Transactional; import jakarta.validation.Valid; +import java.time.Instant; +import java.util.Optional; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.http.MediaType; import org.springframework.security.access.annotation.Secured; import org.springframework.web.bind.annotation.*; import org.springframework.web.multipart.MultipartFile; -import java.time.Instant; -import java.util.Optional; - -import static io.openbas.database.model.User.ROLE_ADMIN; - @RestController public class CollectorApi extends RestBehavior { - @Resource - private OpenBASConfig openBASConfig; - - private CollectorRepository collectorRepository; - - private FileService fileService; - - private SecurityPlatformRepository securityPlatformRepository; - - @Resource - protected ObjectMapper mapper; - - @Autowired - public void setFileService(FileService fileService) { - this.fileService = fileService; - } - - @Autowired - public void setCollectorRepository(CollectorRepository collectorRepository) { - this.collectorRepository = collectorRepository; - } - - @Autowired - public void setSecurityPlatformRepository(SecurityPlatformRepository securityPlatformRepository) { - this.securityPlatformRepository = securityPlatformRepository; - } - - @GetMapping("/api/collectors") - public Iterable collectors() { - return collectorRepository.findAll(); + @Resource private OpenBASConfig openBASConfig; + + private CollectorRepository collectorRepository; + + private FileService fileService; + + private SecurityPlatformRepository securityPlatformRepository; + + @Resource protected ObjectMapper mapper; + + @Autowired + public void setFileService(FileService fileService) { + this.fileService = fileService; + } + + @Autowired + public void setCollectorRepository(CollectorRepository collectorRepository) { + this.collectorRepository = collectorRepository; + } + + @Autowired + public void setSecurityPlatformRepository(SecurityPlatformRepository securityPlatformRepository) { + this.securityPlatformRepository = securityPlatformRepository; + } + + @GetMapping("/api/collectors") + public Iterable collectors() { + return collectorRepository.findAll(); + } + + private Collector updateCollector( + Collector collector, + String type, + String name, + int period, + Instant lastExecution, + String securityPlatform) { + collector.setUpdatedAt(Instant.now()); + collector.setExternal(true); + collector.setType(type); + collector.setName(name); + collector.setPeriod(period); + collector.setLastExecution(lastExecution); + if (securityPlatform != null) { + collector.setSecurityPlatform( + securityPlatformRepository.findById(securityPlatform).orElseThrow()); } - - private Collector updateCollector(Collector collector, String type, String name, int period, Instant lastExecution, String securityPlatform) { - collector.setUpdatedAt(Instant.now()); - collector.setExternal(true); - collector.setType(type); - collector.setName(name); - collector.setPeriod(period); - collector.setLastExecution(lastExecution); - if( securityPlatform != null ) { - collector.setSecurityPlatform(securityPlatformRepository.findById(securityPlatform).orElseThrow()); + return collectorRepository.save(collector); + } + + @Secured(ROLE_ADMIN) + @PutMapping("/api/collectors/{collectorId}") + @Transactional(rollbackOn = Exception.class) + public Collector updateCollector( + @PathVariable String collectorId, @Valid @RequestBody CollectorUpdateInput input) { + Collector collector = + collectorRepository.findById(collectorId).orElseThrow(ElementNotFoundException::new); + return updateCollector( + collector, + collector.getType(), + collector.getName(), + collector.getPeriod(), + input.getLastExecution(), + collector.getSecurityPlatform() != null ? collector.getSecurityPlatform().getId() : null); + } + + @Secured(ROLE_ADMIN) + @PostMapping( + value = "/api/collectors", + produces = {MediaType.APPLICATION_JSON_VALUE}, + consumes = {MediaType.APPLICATION_JSON_VALUE, MediaType.MULTIPART_FORM_DATA_VALUE}) + @Transactional(rollbackOn = Exception.class) + public Collector registerCollector( + @Valid @RequestPart("input") CollectorCreateInput input, + @RequestPart("icon") Optional file) { + try { + // Upload icon + if (file.isPresent() && "image/png".equals(file.get().getContentType())) { + fileService.uploadFile( + FileService.COLLECTORS_IMAGES_BASE_PATH + input.getType() + ".png", file.get()); + } + // We need to support upsert for registration + Collector collector = collectorRepository.findById(input.getId()).orElse(null); + if (collector == null) { + Collector collectorChecking = collectorRepository.findByType(input.getType()).orElse(null); + if (collectorChecking != null) { + throw new Exception( + "The collector " + + input.getType() + + " already exists with a different ID, please delete it or contact your administrator."); } - return collectorRepository.save(collector); - } - - @Secured(ROLE_ADMIN) - @PutMapping("/api/collectors/{collectorId}") - @Transactional(rollbackOn = Exception.class) - public Collector updateCollector(@PathVariable String collectorId, @Valid @RequestBody CollectorUpdateInput input) { - Collector collector = collectorRepository.findById(collectorId).orElseThrow(ElementNotFoundException::new); - return updateCollector(collector, collector.getType(), collector.getName(), collector.getPeriod(), input.getLastExecution(), collector.getSecurityPlatform() != null ? collector.getSecurityPlatform().getId() : null); - } - - @Secured(ROLE_ADMIN) - @PostMapping(value = "/api/collectors", - produces = {MediaType.APPLICATION_JSON_VALUE}, - consumes = {MediaType.APPLICATION_JSON_VALUE, MediaType.MULTIPART_FORM_DATA_VALUE}) - @Transactional(rollbackOn = Exception.class) - public Collector registerCollector(@Valid @RequestPart("input") CollectorCreateInput input, - @RequestPart("icon") Optional file) { - try { - // Upload icon - if (file.isPresent() && "image/png".equals(file.get().getContentType())) { - fileService.uploadFile(FileService.COLLECTORS_IMAGES_BASE_PATH + input.getType() + ".png", file.get()); - } - // We need to support upsert for registration - Collector collector = collectorRepository.findById(input.getId()).orElse(null); - if( collector == null ) { - Collector collectorChecking = collectorRepository.findByType(input.getType()).orElse(null); - if (collectorChecking != null ) { - throw new Exception("The collector " + input.getType() + " already exists with a different ID, please delete it or contact your administrator."); - } - } - if (collector != null) { - return updateCollector(collector, input.getType(), input.getName(), input.getPeriod(), collector.getLastExecution(), input.getSecurityPlatform()); - } else { - // save the injector - Collector newCollector = new Collector(); - newCollector.setId(input.getId()); - newCollector.setExternal(true); - newCollector.setName(input.getName()); - newCollector.setType(input.getType()); - newCollector.setPeriod(input.getPeriod()); - if( input.getSecurityPlatform() != null ) { - newCollector.setSecurityPlatform(securityPlatformRepository.findById(input.getSecurityPlatform()).orElseThrow()); - } - return collectorRepository.save(newCollector); - } - } catch (Exception e) { - throw new RuntimeException(e); + } + if (collector != null) { + return updateCollector( + collector, + input.getType(), + input.getName(), + input.getPeriod(), + collector.getLastExecution(), + input.getSecurityPlatform()); + } else { + // save the injector + Collector newCollector = new Collector(); + newCollector.setId(input.getId()); + newCollector.setExternal(true); + newCollector.setName(input.getName()); + newCollector.setType(input.getType()); + newCollector.setPeriod(input.getPeriod()); + if (input.getSecurityPlatform() != null) { + newCollector.setSecurityPlatform( + securityPlatformRepository.findById(input.getSecurityPlatform()).orElseThrow()); } + return collectorRepository.save(newCollector); + } + } catch (Exception e) { + throw new RuntimeException(e); } + } } diff --git a/openbas-api/src/main/java/io/openbas/rest/collector/form/CollectorCreateInput.java b/openbas-api/src/main/java/io/openbas/rest/collector/form/CollectorCreateInput.java index 26fd74cb00..3f5abb2354 100644 --- a/openbas-api/src/main/java/io/openbas/rest/collector/form/CollectorCreateInput.java +++ b/openbas-api/src/main/java/io/openbas/rest/collector/form/CollectorCreateInput.java @@ -1,31 +1,31 @@ package io.openbas.rest.collector.form; +import static io.openbas.config.AppConfig.MANDATORY_MESSAGE; + import com.fasterxml.jackson.annotation.JsonProperty; import jakarta.validation.constraints.NotBlank; import lombok.Getter; import lombok.Setter; -import static io.openbas.config.AppConfig.MANDATORY_MESSAGE; - @Getter @Setter public class CollectorCreateInput { - @NotBlank(message = MANDATORY_MESSAGE) - @JsonProperty("collector_id") - private String id; + @NotBlank(message = MANDATORY_MESSAGE) + @JsonProperty("collector_id") + private String id; - @NotBlank(message = MANDATORY_MESSAGE) - @JsonProperty("collector_name") - private String name; + @NotBlank(message = MANDATORY_MESSAGE) + @JsonProperty("collector_name") + private String name; - @NotBlank(message = MANDATORY_MESSAGE) - @JsonProperty("collector_type") - private String type; + @NotBlank(message = MANDATORY_MESSAGE) + @JsonProperty("collector_type") + private String type; - @JsonProperty("collector_period") - private int period; + @JsonProperty("collector_period") + private int period; - @JsonProperty("collector_security_platform") - private String securityPlatform; + @JsonProperty("collector_security_platform") + private String securityPlatform; } diff --git a/openbas-api/src/main/java/io/openbas/rest/collector/form/CollectorUpdateInput.java b/openbas-api/src/main/java/io/openbas/rest/collector/form/CollectorUpdateInput.java index 2a57cc2b20..1813c47d52 100644 --- a/openbas-api/src/main/java/io/openbas/rest/collector/form/CollectorUpdateInput.java +++ b/openbas-api/src/main/java/io/openbas/rest/collector/form/CollectorUpdateInput.java @@ -1,18 +1,14 @@ package io.openbas.rest.collector.form; import com.fasterxml.jackson.annotation.JsonProperty; -import jakarta.validation.constraints.NotBlank; +import java.time.Instant; import lombok.Getter; import lombok.Setter; -import java.time.Instant; - -import static io.openbas.config.AppConfig.MANDATORY_MESSAGE; - @Getter @Setter public class CollectorUpdateInput { - @JsonProperty("collector_last_execution") - private Instant lastExecution; + @JsonProperty("collector_last_execution") + private Instant lastExecution; } diff --git a/openbas-api/src/main/java/io/openbas/rest/comcheck/ComcheckApi.java b/openbas-api/src/main/java/io/openbas/rest/comcheck/ComcheckApi.java index 8d1d94756f..aa1586ed3e 100644 --- a/openbas-api/src/main/java/io/openbas/rest/comcheck/ComcheckApi.java +++ b/openbas-api/src/main/java/io/openbas/rest/comcheck/ComcheckApi.java @@ -1,5 +1,8 @@ package io.openbas.rest.comcheck; +import static io.openbas.helper.StreamHelper.fromIterable; +import static java.time.Instant.now; + import io.openbas.database.model.*; import io.openbas.database.repository.ComcheckRepository; import io.openbas.database.repository.ComcheckStatusRepository; @@ -10,91 +13,96 @@ import io.openbas.rest.helper.RestBehavior; import jakarta.transaction.Transactional; import jakarta.validation.Valid; +import java.util.List; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.security.access.prepost.PreAuthorize; import org.springframework.web.bind.annotation.*; -import java.util.List; - -import static io.openbas.helper.StreamHelper.fromIterable; -import static java.time.Instant.now; - @RestController public class ComcheckApi extends RestBehavior { - private ComcheckRepository comcheckRepository; - private TeamRepository teamRepository; - private ExerciseRepository exerciseRepository; - private ComcheckStatusRepository comcheckStatusRepository; + private ComcheckRepository comcheckRepository; + private TeamRepository teamRepository; + private ExerciseRepository exerciseRepository; + private ComcheckStatusRepository comcheckStatusRepository; - @Autowired - public void setComcheckStatusRepository(ComcheckStatusRepository comcheckStatusRepository) { - this.comcheckStatusRepository = comcheckStatusRepository; - } + @Autowired + public void setComcheckStatusRepository(ComcheckStatusRepository comcheckStatusRepository) { + this.comcheckStatusRepository = comcheckStatusRepository; + } - @Autowired - public void setComcheckRepository(ComcheckRepository comcheckRepository) { - this.comcheckRepository = comcheckRepository; - } + @Autowired + public void setComcheckRepository(ComcheckRepository comcheckRepository) { + this.comcheckRepository = comcheckRepository; + } - @Autowired - public void setTeamRepository(TeamRepository teamRepository) { - this.teamRepository = teamRepository; - } + @Autowired + public void setTeamRepository(TeamRepository teamRepository) { + this.teamRepository = teamRepository; + } - @Autowired - public void setExerciseRepository(ExerciseRepository exerciseRepository) { - this.exerciseRepository = exerciseRepository; - } + @Autowired + public void setExerciseRepository(ExerciseRepository exerciseRepository) { + this.exerciseRepository = exerciseRepository; + } - @GetMapping("/api/comcheck/{comcheckStatusId}") - @Transactional(rollbackOn = Exception.class) - public ComcheckStatus checkValidation(@PathVariable String comcheckStatusId) { - ComcheckStatus comcheckStatus = comcheckStatusRepository.findById(comcheckStatusId).orElseThrow(ElementNotFoundException::new); - Comcheck comcheck = comcheckStatus.getComcheck(); - if (!comcheck.getState().equals(Comcheck.COMCHECK_STATUS.RUNNING)) { - throw new UnsupportedOperationException("This comcheck is closed."); - } - comcheckStatus.setReceiveDate(now()); - ComcheckStatus status = comcheckStatusRepository.save(comcheckStatus); - boolean finishedComcheck = comcheck.getComcheckStatus().stream() - .noneMatch(st -> st.getState().equals(ComcheckStatus.CHECK_STATUS.RUNNING)); - if (finishedComcheck) { - comcheck.setState(Comcheck.COMCHECK_STATUS.FINISHED); - comcheckRepository.save(comcheck); - } - return status; + @GetMapping("/api/comcheck/{comcheckStatusId}") + @Transactional(rollbackOn = Exception.class) + public ComcheckStatus checkValidation(@PathVariable String comcheckStatusId) { + ComcheckStatus comcheckStatus = + comcheckStatusRepository + .findById(comcheckStatusId) + .orElseThrow(ElementNotFoundException::new); + Comcheck comcheck = comcheckStatus.getComcheck(); + if (!comcheck.getState().equals(Comcheck.COMCHECK_STATUS.RUNNING)) { + throw new UnsupportedOperationException("This comcheck is closed."); } - - @DeleteMapping("/api/exercises/{exerciseId}/comchecks/{comcheckId}") - @PreAuthorize("isExercisePlanner(#exerciseId)") - @Transactional(rollbackOn = Exception.class) - public void deleteComcheck(@PathVariable String exerciseId, @PathVariable String comcheckId) { - comcheckRepository.deleteById(comcheckId); + comcheckStatus.setReceiveDate(now()); + ComcheckStatus status = comcheckStatusRepository.save(comcheckStatus); + boolean finishedComcheck = + comcheck.getComcheckStatus().stream() + .noneMatch(st -> st.getState().equals(ComcheckStatus.CHECK_STATUS.RUNNING)); + if (finishedComcheck) { + comcheck.setState(Comcheck.COMCHECK_STATUS.FINISHED); + comcheckRepository.save(comcheck); } + return status; + } - @PostMapping("/api/exercises/{exerciseId}/comchecks") - @Transactional(rollbackOn = Exception.class) - public Comcheck communicationCheck(@PathVariable String exerciseId, - @Valid @RequestBody ComcheckInput comCheck) { - // 01. Create the comcheck and get the ID - Comcheck check = new Comcheck(); - check.setUpdateAttributes(comCheck); - check.setName(comCheck.getName()); - check.setStart(now()); - Exercise exercise = exerciseRepository.findById(exerciseId).orElseThrow(ElementNotFoundException::new); - check.setExercise(exercise); - // 02. Get users - List teamIds = comCheck.getTeamIds(); - List teams = teamIds.isEmpty() ? exercise.getTeams() : - fromIterable(teamRepository.findAllById(teamIds)); - List users = teams.stream().flatMap(team -> team.getUsers().stream()).distinct().toList(); - List comcheckStatuses = users.stream().map(user -> { - ComcheckStatus comcheckStatus = new ComcheckStatus(user); - comcheckStatus.setComcheck(check); - return comcheckStatus; - }).toList(); - check.setComcheckStatus(comcheckStatuses); - return comcheckRepository.save(check); - } + @DeleteMapping("/api/exercises/{exerciseId}/comchecks/{comcheckId}") + @PreAuthorize("isExercisePlanner(#exerciseId)") + @Transactional(rollbackOn = Exception.class) + public void deleteComcheck(@PathVariable String exerciseId, @PathVariable String comcheckId) { + comcheckRepository.deleteById(comcheckId); + } + + @PostMapping("/api/exercises/{exerciseId}/comchecks") + @Transactional(rollbackOn = Exception.class) + public Comcheck communicationCheck( + @PathVariable String exerciseId, @Valid @RequestBody ComcheckInput comCheck) { + // 01. Create the comcheck and get the ID + Comcheck check = new Comcheck(); + check.setUpdateAttributes(comCheck); + check.setName(comCheck.getName()); + check.setStart(now()); + Exercise exercise = + exerciseRepository.findById(exerciseId).orElseThrow(ElementNotFoundException::new); + check.setExercise(exercise); + // 02. Get users + List teamIds = comCheck.getTeamIds(); + List teams = + teamIds.isEmpty() ? exercise.getTeams() : fromIterable(teamRepository.findAllById(teamIds)); + List users = teams.stream().flatMap(team -> team.getUsers().stream()).distinct().toList(); + List comcheckStatuses = + users.stream() + .map( + user -> { + ComcheckStatus comcheckStatus = new ComcheckStatus(user); + comcheckStatus.setComcheck(check); + return comcheckStatus; + }) + .toList(); + check.setComcheckStatus(comcheckStatuses); + return comcheckRepository.save(check); + } } diff --git a/openbas-api/src/main/java/io/openbas/rest/comcheck/form/ComcheckInput.java b/openbas-api/src/main/java/io/openbas/rest/comcheck/form/ComcheckInput.java index efd92f5f8d..941a8dc8ec 100644 --- a/openbas-api/src/main/java/io/openbas/rest/comcheck/form/ComcheckInput.java +++ b/openbas-api/src/main/java/io/openbas/rest/comcheck/form/ComcheckInput.java @@ -1,68 +1,67 @@ package io.openbas.rest.comcheck.form; -import com.fasterxml.jackson.annotation.JsonProperty; +import static io.openbas.config.AppConfig.MANDATORY_MESSAGE; +import com.fasterxml.jackson.annotation.JsonProperty; import jakarta.validation.constraints.NotBlank; import java.time.Instant; import java.util.ArrayList; import java.util.List; -import static io.openbas.config.AppConfig.MANDATORY_MESSAGE; - public class ComcheckInput { - @NotBlank(message = MANDATORY_MESSAGE) - @JsonProperty("comcheck_name") - private String name; + @NotBlank(message = MANDATORY_MESSAGE) + @JsonProperty("comcheck_name") + private String name; - @JsonProperty("comcheck_end_date") - private Instant end; + @JsonProperty("comcheck_end_date") + private Instant end; - @JsonProperty("comcheck_subject") - private String subject; + @JsonProperty("comcheck_subject") + private String subject; - @JsonProperty("comcheck_message") - private String message; + @JsonProperty("comcheck_message") + private String message; - @JsonProperty("comcheck_teams") - private List teamIds = new ArrayList<>(); + @JsonProperty("comcheck_teams") + private List teamIds = new ArrayList<>(); - public String getName() { - return name; - } + public String getName() { + return name; + } - public void setName(String name) { - this.name = name; - } + public void setName(String name) { + this.name = name; + } - public List getTeamIds() { - return teamIds; - } + public List getTeamIds() { + return teamIds; + } - public void setTeamIds(List teamIds) { - this.teamIds = teamIds; - } + public void setTeamIds(List teamIds) { + this.teamIds = teamIds; + } - public Instant getEnd() { - return end; - } + public Instant getEnd() { + return end; + } - public void setEnd(Instant end) { - this.end = end; - } + public void setEnd(Instant end) { + this.end = end; + } - public String getSubject() { - return subject; - } + public String getSubject() { + return subject; + } - public void setSubject(String subject) { - this.subject = subject; - } + public void setSubject(String subject) { + this.subject = subject; + } - public String getMessage() { - return message; - } + public String getMessage() { + return message; + } - public void setMessage(String message) { - this.message = message; - } + public void setMessage(String message) { + this.message = message; + } } diff --git a/openbas-api/src/main/java/io/openbas/rest/document/DocumentApi.java b/openbas-api/src/main/java/io/openbas/rest/document/DocumentApi.java index c9895b6526..f1743b074a 100644 --- a/openbas-api/src/main/java/io/openbas/rest/document/DocumentApi.java +++ b/openbas-api/src/main/java/io/openbas/rest/document/DocumentApi.java @@ -1,5 +1,13 @@ package io.openbas.rest.document; +import static io.openbas.config.OpenBASAnonymous.ANONYMOUS; +import static io.openbas.config.SessionHelper.currentUser; +import static io.openbas.database.specification.DocumentSpecification.findGrantedFor; +import static io.openbas.helper.StreamHelper.fromIterable; +import static io.openbas.helper.StreamHelper.iterableToSet; +import static io.openbas.injectors.challenge.ChallengeContract.CHALLENGE_PUBLISH; +import static io.openbas.utils.pagination.PaginationUtils.buildPaginationJPA; + import com.fasterxml.jackson.core.JsonProcessingException; import io.openbas.config.OpenBASPrincipal; import io.openbas.database.model.*; @@ -18,6 +26,11 @@ import jakarta.servlet.http.HttpServletResponse; import jakarta.transaction.Transactional; import jakarta.validation.Valid; +import java.io.IOException; +import java.io.InputStream; +import java.util.*; +import java.util.concurrent.TimeUnit; +import java.util.stream.Stream; import org.apache.commons.codec.digest.DigestUtils; import org.apache.commons.io.FilenameUtils; import org.apache.commons.io.IOUtils; @@ -32,527 +45,586 @@ import org.springframework.web.bind.annotation.*; import org.springframework.web.multipart.MultipartFile; -import java.io.IOException; -import java.io.InputStream; -import java.util.*; -import java.util.concurrent.TimeUnit; -import java.util.stream.Stream; - -import static io.openbas.config.OpenBASAnonymous.ANONYMOUS; -import static io.openbas.config.SessionHelper.currentUser; -import static io.openbas.database.specification.DocumentSpecification.findGrantedFor; -import static io.openbas.helper.StreamHelper.fromIterable; -import static io.openbas.helper.StreamHelper.iterableToSet; -import static io.openbas.injectors.challenge.ChallengeContract.CHALLENGE_PUBLISH; -import static io.openbas.utils.pagination.PaginationUtils.buildPaginationJPA; - - @RestController public class DocumentApi extends RestBehavior { - private FileService fileService; - private TagRepository tagRepository; - private DocumentRepository documentRepository; - private ExerciseRepository exerciseRepository; - private ScenarioRepository scenarioRepository; - private InjectService injectService; - private InjectDocumentRepository injectDocumentRepository; - private ChallengeRepository challengeRepository; - private UserRepository userRepository; - private InjectorRepository injectorRepository; - private CollectorRepository collectorRepository; - private SecurityPlatformRepository securityPlatformRepository; - - @Autowired - public void setUserRepository(UserRepository userRepository) { - this.userRepository = userRepository; - } - - @Autowired - public void setInjectDocumentRepository(InjectDocumentRepository injectDocumentRepository) { - this.injectDocumentRepository = injectDocumentRepository; - } - - @Autowired - public void setInjectService(InjectService injectService) { - this.injectService = injectService; - } - - @Autowired - public void setExerciseRepository(ExerciseRepository exerciseRepository) { - this.exerciseRepository = exerciseRepository; - } - - @Autowired - public void setScenarioRepository(ScenarioRepository scenarioRepository) { - this.scenarioRepository = scenarioRepository; - } - - @Autowired - public void setTagRepository(TagRepository tagRepository) { - this.tagRepository = tagRepository; - } - - @Autowired - public void setDocumentRepository(DocumentRepository documentRepository) { - this.documentRepository = documentRepository; - } - - @Autowired - public void setChallengeRepository(ChallengeRepository challengeRepository) { - this.challengeRepository = challengeRepository; - } - - @Autowired - public void setInjectorRepository(InjectorRepository injectorRepository) { - this.injectorRepository = injectorRepository; - } - - @Autowired - public void setCollectorRepository(CollectorRepository collectorRepository) { - this.collectorRepository = collectorRepository; - } - - @Autowired - public void setSecurityPlatformRepository(SecurityPlatformRepository securityPlatformRepository) { - this.securityPlatformRepository = securityPlatformRepository; - } - - @Autowired - public void setFileService(FileService fileService) { - this.fileService = fileService; - } - - private Optional resolveDocument(String documentId) { - OpenBASPrincipal user = currentUser(); - if (user.isAdmin()) { - return documentRepository.findById(documentId); - } else { - return documentRepository.findByIdGranted(documentId, user.getId()); + private FileService fileService; + private TagRepository tagRepository; + private DocumentRepository documentRepository; + private ExerciseRepository exerciseRepository; + private ScenarioRepository scenarioRepository; + private InjectService injectService; + private InjectDocumentRepository injectDocumentRepository; + private ChallengeRepository challengeRepository; + private UserRepository userRepository; + private InjectorRepository injectorRepository; + private CollectorRepository collectorRepository; + private SecurityPlatformRepository securityPlatformRepository; + + @Autowired + public void setUserRepository(UserRepository userRepository) { + this.userRepository = userRepository; + } + + @Autowired + public void setInjectDocumentRepository(InjectDocumentRepository injectDocumentRepository) { + this.injectDocumentRepository = injectDocumentRepository; + } + + @Autowired + public void setInjectService(InjectService injectService) { + this.injectService = injectService; + } + + @Autowired + public void setExerciseRepository(ExerciseRepository exerciseRepository) { + this.exerciseRepository = exerciseRepository; + } + + @Autowired + public void setScenarioRepository(ScenarioRepository scenarioRepository) { + this.scenarioRepository = scenarioRepository; + } + + @Autowired + public void setTagRepository(TagRepository tagRepository) { + this.tagRepository = tagRepository; + } + + @Autowired + public void setDocumentRepository(DocumentRepository documentRepository) { + this.documentRepository = documentRepository; + } + + @Autowired + public void setChallengeRepository(ChallengeRepository challengeRepository) { + this.challengeRepository = challengeRepository; + } + + @Autowired + public void setInjectorRepository(InjectorRepository injectorRepository) { + this.injectorRepository = injectorRepository; + } + + @Autowired + public void setCollectorRepository(CollectorRepository collectorRepository) { + this.collectorRepository = collectorRepository; + } + + @Autowired + public void setSecurityPlatformRepository(SecurityPlatformRepository securityPlatformRepository) { + this.securityPlatformRepository = securityPlatformRepository; + } + + @Autowired + public void setFileService(FileService fileService) { + this.fileService = fileService; + } + + private Optional resolveDocument(String documentId) { + OpenBASPrincipal user = currentUser(); + if (user.isAdmin()) { + return documentRepository.findById(documentId); + } else { + return documentRepository.findByIdGranted(documentId, user.getId()); + } + } + + @PostMapping("/api/documents") + @Transactional(rollbackOn = Exception.class) + public Document uploadDocument( + @Valid @RequestPart("input") DocumentCreateInput input, + @RequestPart("file") MultipartFile file) + throws Exception { + String extension = FilenameUtils.getExtension(file.getOriginalFilename()); + String fileTarget = DigestUtils.md5Hex(file.getInputStream()) + "." + extension; + Optional targetDocument = documentRepository.findByTarget(fileTarget); + if (targetDocument.isPresent()) { + Document document = targetDocument.get(); + // Compute exercises + if (!document.getExercises().isEmpty()) { + Set exercises = new HashSet<>(document.getExercises()); + List inputExercises = + fromIterable(exerciseRepository.findAllById(input.getExerciseIds())); + exercises.addAll(inputExercises); + document.setExercises(exercises); + } + // Compute scenarios + if (!document.getScenarios().isEmpty()) { + Set scenarios = new HashSet<>(document.getScenarios()); + List inputScenarios = + fromIterable(scenarioRepository.findAllById(input.getScenarioIds())); + scenarios.addAll(inputScenarios); + document.setScenarios(scenarios); + } + // Compute tags + Set tags = new HashSet<>(document.getTags()); + List inputTags = fromIterable(tagRepository.findAllById(input.getTagIds())); + tags.addAll(inputTags); + document.setTags(tags); + return documentRepository.save(document); + } else { + fileService.uploadFile(fileTarget, file); + Document document = new Document(); + document.setTarget(fileTarget); + document.setName(file.getOriginalFilename()); + document.setDescription(input.getDescription()); + if (!input.getExerciseIds().isEmpty()) { + document.setExercises( + iterableToSet(exerciseRepository.findAllById(input.getExerciseIds()))); + } + if (!input.getScenarioIds().isEmpty()) { + document.setScenarios( + iterableToSet(scenarioRepository.findAllById(input.getScenarioIds()))); + } + document.setTags(iterableToSet(tagRepository.findAllById(input.getTagIds()))); + document.setType(file.getContentType()); + return documentRepository.save(document); + } + } + + @PostMapping("/api/documents/upsert") + @Transactional(rollbackOn = Exception.class) + public Document upsertDocument( + @Valid @RequestPart("input") DocumentCreateInput input, + @RequestPart("file") MultipartFile file) + throws Exception { + String extension = FilenameUtils.getExtension(file.getOriginalFilename()); + String fileTarget = DigestUtils.md5Hex(file.getInputStream()) + "." + extension; + Optional targetDocument = documentRepository.findByTarget(fileTarget); + // Document already exists by hash + if (targetDocument.isPresent()) { + Document document = targetDocument.get(); + // Compute exercises + if (!document.getExercises().isEmpty()) { + Set exercises = new HashSet<>(document.getExercises()); + List inputExercises = + fromIterable(exerciseRepository.findAllById(input.getExerciseIds())); + exercises.addAll(inputExercises); + document.setExercises(exercises); + } + // Compute scenarios + if (!document.getScenarios().isEmpty()) { + Set scenarios = new HashSet<>(document.getScenarios()); + List inputScenarios = + fromIterable(scenarioRepository.findAllById(input.getScenarioIds())); + scenarios.addAll(inputScenarios); + document.setScenarios(scenarios); + } + // Compute tags + Set tags = new HashSet<>(document.getTags()); + List inputTags = fromIterable(tagRepository.findAllById(input.getTagIds())); + tags.addAll(inputTags); + document.setTags(tags); + return documentRepository.save(document); + } else { + Optional existingDocument = + documentRepository.findByName(file.getOriginalFilename()); + if (existingDocument.isPresent()) { + Document document = existingDocument.get(); + // Update doc + fileService.uploadFile(fileTarget, file); + document.setDescription(input.getDescription()); + + // Compute exercises + if (!document.getExercises().isEmpty()) { + Set exercises = new HashSet<>(document.getExercises()); + List inputExercises = + fromIterable(exerciseRepository.findAllById(input.getExerciseIds())); + exercises.addAll(inputExercises); + document.setExercises(exercises); } - } - - @PostMapping("/api/documents") - @Transactional(rollbackOn = Exception.class) - public Document uploadDocument(@Valid @RequestPart("input") DocumentCreateInput input, - @RequestPart("file") MultipartFile file) throws Exception { - String extension = FilenameUtils.getExtension(file.getOriginalFilename()); - String fileTarget = DigestUtils.md5Hex(file.getInputStream()) + "." + extension; - Optional targetDocument = documentRepository.findByTarget(fileTarget); - if (targetDocument.isPresent()) { - Document document = targetDocument.get(); - // Compute exercises - if (!document.getExercises().isEmpty()) { - Set exercises = new HashSet<>(document.getExercises()); - List inputExercises = fromIterable(exerciseRepository.findAllById(input.getExerciseIds())); - exercises.addAll(inputExercises); - document.setExercises(exercises); - } - // Compute scenarios - if (!document.getScenarios().isEmpty()) { - Set scenarios = new HashSet<>(document.getScenarios()); - List inputScenarios = fromIterable(scenarioRepository.findAllById(input.getScenarioIds())); - scenarios.addAll(inputScenarios); - document.setScenarios(scenarios); - } - // Compute tags - Set tags = new HashSet<>(document.getTags()); - List inputTags = fromIterable(tagRepository.findAllById(input.getTagIds())); - tags.addAll(inputTags); - document.setTags(tags); - return documentRepository.save(document); - } else { - fileService.uploadFile(fileTarget, file); - Document document = new Document(); - document.setTarget(fileTarget); - document.setName(file.getOriginalFilename()); - document.setDescription(input.getDescription()); - if (!input.getExerciseIds().isEmpty()) { - document.setExercises(iterableToSet(exerciseRepository.findAllById(input.getExerciseIds()))); - } - if (!input.getScenarioIds().isEmpty()) { - document.setScenarios(iterableToSet(scenarioRepository.findAllById(input.getScenarioIds()))); - } - document.setTags(iterableToSet(tagRepository.findAllById(input.getTagIds()))); - document.setType(file.getContentType()); - return documentRepository.save(document); + // Compute scenarios + if (!document.getScenarios().isEmpty()) { + Set scenarios = new HashSet<>(document.getScenarios()); + List inputScenarios = + fromIterable(scenarioRepository.findAllById(input.getScenarioIds())); + scenarios.addAll(inputScenarios); + document.setScenarios(scenarios); } - } - - @PostMapping("/api/documents/upsert") - @Transactional(rollbackOn = Exception.class) - public Document upsertDocument(@Valid @RequestPart("input") DocumentCreateInput input, - @RequestPart("file") MultipartFile file) throws Exception { - String extension = FilenameUtils.getExtension(file.getOriginalFilename()); - String fileTarget = DigestUtils.md5Hex(file.getInputStream()) + "." + extension; - Optional targetDocument = documentRepository.findByTarget(fileTarget); - // Document already exists by hash - if (targetDocument.isPresent()) { - Document document = targetDocument.get(); - // Compute exercises - if (!document.getExercises().isEmpty()) { - Set exercises = new HashSet<>(document.getExercises()); - List inputExercises = fromIterable(exerciseRepository.findAllById(input.getExerciseIds())); - exercises.addAll(inputExercises); - document.setExercises(exercises); - } - // Compute scenarios - if (!document.getScenarios().isEmpty()) { - Set scenarios = new HashSet<>(document.getScenarios()); - List inputScenarios = fromIterable(scenarioRepository.findAllById(input.getScenarioIds())); - scenarios.addAll(inputScenarios); - document.setScenarios(scenarios); - } - // Compute tags - Set tags = new HashSet<>(document.getTags()); - List inputTags = fromIterable(tagRepository.findAllById(input.getTagIds())); - tags.addAll(inputTags); - document.setTags(tags); - return documentRepository.save(document); - } else { - Optional existingDocument = documentRepository.findByName(file.getOriginalFilename()); - if (existingDocument.isPresent()) { - Document document = existingDocument.get(); - // Update doc - fileService.uploadFile(fileTarget, file); - document.setDescription(input.getDescription()); - - // Compute exercises - if (!document.getExercises().isEmpty()) { - Set exercises = new HashSet<>(document.getExercises()); - List inputExercises = fromIterable(exerciseRepository.findAllById(input.getExerciseIds())); - exercises.addAll(inputExercises); - document.setExercises(exercises); - } - // Compute scenarios - if (!document.getScenarios().isEmpty()) { - Set scenarios = new HashSet<>(document.getScenarios()); - List inputScenarios = fromIterable(scenarioRepository.findAllById(input.getScenarioIds())); - scenarios.addAll(inputScenarios); - document.setScenarios(scenarios); - } - // Compute tags - Set tags = new HashSet<>(document.getTags()); - List inputTags = fromIterable(tagRepository.findAllById(input.getTagIds())); - tags.addAll(inputTags); - document.setTags(tags); - return documentRepository.save(document); - } else { - fileService.uploadFile(fileTarget, file); - Document document = new Document(); - document.setTarget(fileTarget); - document.setName(file.getOriginalFilename()); - document.setDescription(input.getDescription()); - if (!input.getExerciseIds().isEmpty()) { - document.setExercises(iterableToSet(exerciseRepository.findAllById(input.getExerciseIds()))); - } - if (!input.getScenarioIds().isEmpty()) { - document.setScenarios(iterableToSet(scenarioRepository.findAllById(input.getScenarioIds()))); - } - document.setTags(iterableToSet(tagRepository.findAllById(input.getTagIds()))); - document.setType(file.getContentType()); - return documentRepository.save(document); - } - } - } - - @GetMapping("/api/documents") - public List documents() { - OpenBASPrincipal user = currentUser(); - if (user.isAdmin()) { - return documentRepository.rawAllDocuments(); - } else { - return documentRepository.rawAllDocumentsByAccessLevel(user.getId()); + // Compute tags + Set tags = new HashSet<>(document.getTags()); + List inputTags = fromIterable(tagRepository.findAllById(input.getTagIds())); + tags.addAll(inputTags); + document.setTags(tags); + return documentRepository.save(document); + } else { + fileService.uploadFile(fileTarget, file); + Document document = new Document(); + document.setTarget(fileTarget); + document.setName(file.getOriginalFilename()); + document.setDescription(input.getDescription()); + if (!input.getExerciseIds().isEmpty()) { + document.setExercises( + iterableToSet(exerciseRepository.findAllById(input.getExerciseIds()))); } - } - - @PostMapping("/api/documents/search") - public Page searchDocuments(@RequestBody @Valid final SearchPaginationInput searchPaginationInput) { - OpenBASPrincipal user = currentUser(); - if (user.isAdmin()) { - return buildPaginationJPA( - (Specification specification, Pageable pageable) -> this.documentRepository.findAll( - specification, pageable), - searchPaginationInput, - Document.class - ).map(RawPaginationDocument::new); - } else { - return buildPaginationJPA( - (Specification specification, Pageable pageable) -> this.documentRepository.findAll( - findGrantedFor(user.getId()).and(specification), - pageable - ), - searchPaginationInput, - Document.class - ).map(RawPaginationDocument::new); + if (!input.getScenarioIds().isEmpty()) { + document.setScenarios( + iterableToSet(scenarioRepository.findAllById(input.getScenarioIds()))); } - } - - @GetMapping("/api/documents/{documentId}") - public Document document(@PathVariable String documentId) { - return resolveDocument(documentId).orElseThrow(ElementNotFoundException::new); - } - - @GetMapping("/api/documents/{documentId}/tags") - public Set documentTags(@PathVariable String documentId) { - Document document = resolveDocument(documentId).orElseThrow(ElementNotFoundException::new); - return document.getTags(); - } - - @PutMapping("/api/documents/{documentId}/tags") - public Document documentTags(@PathVariable String documentId, @RequestBody DocumentTagUpdateInput input) { - Document document = resolveDocument(documentId).orElseThrow(ElementNotFoundException::new); - document.setTags(iterableToSet(tagRepository.findAllById(input.getTagIds()))); - return documentRepository.save(document); - } - - @Transactional(rollbackOn = Exception.class) - @PutMapping("/api/documents/{documentId}") - public Document updateDocumentInformation(@PathVariable String documentId, - @Valid @RequestBody DocumentUpdateInput input) { - Document document = resolveDocument(documentId).orElseThrow(ElementNotFoundException::new); - document.setUpdateAttributes(input); document.setTags(iterableToSet(tagRepository.findAllById(input.getTagIds()))); - - // Get removed exercises - Stream askExerciseIdsStream = document.getExercises() - .stream() - .filter(exercise -> !exercise.isUserHasAccess(userRepository.findById(currentUser().getId()).orElseThrow(ElementNotFoundException::new))) - .map(Exercise::getId); - List askExerciseIds = Stream.concat(askExerciseIdsStream, input.getExerciseIds().stream()).distinct().toList(); - List removedExercises = document.getExercises().stream() - .filter(exercise -> !askExerciseIds.contains(exercise.getId())).toList(); - document.setExercises(iterableToSet(exerciseRepository.findAllById(askExerciseIds))); - // In case of exercise removal, all inject doc attachment for exercise - removedExercises.forEach(exercise -> injectService.cleanInjectsDocExercise(exercise.getId(), documentId)); - - // Get removed scenarios - Stream askScenarioIdsStream = document.getScenarios().stream() - .filter(scenario -> !scenario.isUserHasAccess(userRepository.findById(currentUser().getId()).orElseThrow(ElementNotFoundException::new))) - .map(Scenario::getId); - List askScenarioIds = Stream.concat(askScenarioIdsStream, input.getScenarioIds().stream()).distinct().toList(); - List removedScenarios = document.getScenarios().stream() - .filter(scenario -> !askScenarioIds.contains(scenario.getId())).toList(); - document.setScenarios(iterableToSet(scenarioRepository.findAllById(askScenarioIds))); - // In case of scenario removal, all inject doc attachment for scenario - removedScenarios.forEach(scenario -> injectService.cleanInjectsDocScenario(scenario.getId(), documentId)); - - // Save and return + document.setType(file.getContentType()); return documentRepository.save(document); - } - - @GetMapping("/api/documents/{documentId}/file") - public void downloadDocument(@PathVariable String documentId, HttpServletResponse response) throws IOException { - Document document = resolveDocument(documentId).orElseThrow(ElementNotFoundException::new); - response.addHeader(HttpHeaders.CONTENT_DISPOSITION, "attachment; filename=" + document.getName()); - response.addHeader(HttpHeaders.CONTENT_TYPE, document.getType()); - response.setStatus(HttpServletResponse.SC_OK); - try (InputStream fileStream = fileService.getFile(document).orElseThrow(ElementNotFoundException::new)) { - fileStream.transferTo(response.getOutputStream()); - } - } - - @GetMapping(value = "/api/images/injectors/{injectorType}", produces = MediaType.IMAGE_PNG_VALUE) - public @ResponseBody ResponseEntity getInjectorImage(@PathVariable String injectorType) throws IOException { - Optional fileStream = fileService.getInjectorImage(injectorType); - if (fileStream.isPresent()) { - return ResponseEntity.ok() - .cacheControl(CacheControl.maxAge(5, TimeUnit.MINUTES)) - .body(IOUtils.toByteArray(fileStream.get())); - } - return null; - } - - @GetMapping(value = "/api/images/injectors/id/{injectorId}", produces = MediaType.IMAGE_PNG_VALUE) - public @ResponseBody ResponseEntity getInjectorImageFromId(@PathVariable String injectorId) throws IOException { - Injector injector = this.injectorRepository.findById(injectorId).orElseThrow(ElementNotFoundException::new); - Optional fileStream = fileService.getInjectorImage(injector.getType()); - if (fileStream.isPresent()) { - return ResponseEntity.ok() - .cacheControl(CacheControl.maxAge(5, TimeUnit.MINUTES)) - .body(IOUtils.toByteArray(fileStream.get())); - } - return null; - } - - @GetMapping(value = "/api/images/collectors/{collectorType}", produces = MediaType.IMAGE_PNG_VALUE) - public @ResponseBody ResponseEntity getCollectorImage(@PathVariable String collectorType) throws IOException { - Optional fileStream = fileService.getCollectorImage(collectorType); - if (fileStream.isPresent()) { - return ResponseEntity.ok() - .cacheControl(CacheControl.maxAge(5, TimeUnit.MINUTES)) - .body(IOUtils.toByteArray(fileStream.get())); - } - return null; - } - - public void downloadCollectorImage(@PathVariable String collectorType, HttpServletResponse response) throws IOException { - response.addHeader(HttpHeaders.CONTENT_DISPOSITION, "attachment; filename=" + collectorType + ".png"); - response.addHeader(HttpHeaders.CONTENT_TYPE, MediaType.IMAGE_PNG_VALUE); - response.setStatus(HttpServletResponse.SC_OK); - try (InputStream fileStream = fileService.getCollectorImage(collectorType).orElseThrow(ElementNotFoundException::new)) { - fileStream.transferTo(response.getOutputStream()); - } - } - - @GetMapping(value = "/api/images/collectors/id/{collectorId}", produces = MediaType.IMAGE_PNG_VALUE) - public @ResponseBody ResponseEntity getCollectorImageFromId(@PathVariable String collectorId) throws IOException { - Collector collector = this.collectorRepository.findById(collectorId).orElseThrow(ElementNotFoundException::new); - Optional fileStream = fileService.getCollectorImage(collector.getType()); - if (fileStream.isPresent()) { - return ResponseEntity.ok() - .cacheControl(CacheControl.maxAge(5, TimeUnit.MINUTES)) - .body(IOUtils.toByteArray(fileStream.get())); - } - return null; - } - - @GetMapping(value = "/api/images/security_platforms/id/{assetId}/{theme}") - public void getSecurityPlatformImageFromId(@PathVariable String assetId, @PathVariable String theme, HttpServletResponse response) throws IOException { - SecurityPlatform securityPlatform = this.securityPlatformRepository.findById(assetId).orElseThrow(ElementNotFoundException::new); - if( theme.equals("dark") ) { - if( securityPlatform.getLogoDark() != null ) { - downloadDocument(securityPlatform.getLogoDark().getId(), response); - } - } - if( securityPlatform.getLogoLight() != null ) { - downloadDocument(securityPlatform.getLogoLight().getId(), response); - } - downloadCollectorImage("openbas_fake_detector", response); - } - - @GetMapping(value = "/api/images/executors/{executorId}", produces = MediaType.IMAGE_PNG_VALUE) - public @ResponseBody ResponseEntity getExecutorImage(@PathVariable String executorId) throws IOException { - Optional fileStream = fileService.getExecutorImage(executorId); - if (fileStream.isPresent()) { - return ResponseEntity.ok() - .cacheControl(CacheControl.maxAge(5, TimeUnit.MINUTES)) - .body(IOUtils.toByteArray(fileStream.get())); - } - return null; - } - - private List getExercisePlayerDocuments(Exercise exercise) { - List
articles = exercise.getArticles(); - List injects = exercise.getInjects(); - return getPlayerDocuments(articles, injects); - } - - private List getScenarioPlayerDocuments(Scenario scenario) { - List
articles = scenario.getArticles(); - List injects = scenario.getInjects(); - return getPlayerDocuments(articles, injects); - } - - private List getPlayerDocuments(List
articles, List injects) { - Stream channelsDocs = articles.stream() - .map(Article::getChannel) - .flatMap(channel -> channel.getLogos().stream()); - Stream articlesDocs = articles.stream() - .flatMap(article -> article.getDocuments().stream()); - List challenges = injects.stream() - .filter(inject -> inject.getInjectorContract() + } + } + } + + @GetMapping("/api/documents") + public List documents() { + OpenBASPrincipal user = currentUser(); + if (user.isAdmin()) { + return documentRepository.rawAllDocuments(); + } else { + return documentRepository.rawAllDocumentsByAccessLevel(user.getId()); + } + } + + @PostMapping("/api/documents/search") + public Page searchDocuments( + @RequestBody @Valid final SearchPaginationInput searchPaginationInput) { + OpenBASPrincipal user = currentUser(); + if (user.isAdmin()) { + return buildPaginationJPA( + (Specification specification, Pageable pageable) -> + this.documentRepository.findAll(specification, pageable), + searchPaginationInput, + Document.class) + .map(RawPaginationDocument::new); + } else { + return buildPaginationJPA( + (Specification specification, Pageable pageable) -> + this.documentRepository.findAll( + findGrantedFor(user.getId()).and(specification), pageable), + searchPaginationInput, + Document.class) + .map(RawPaginationDocument::new); + } + } + + @GetMapping("/api/documents/{documentId}") + public Document document(@PathVariable String documentId) { + return resolveDocument(documentId).orElseThrow(ElementNotFoundException::new); + } + + @GetMapping("/api/documents/{documentId}/tags") + public Set documentTags(@PathVariable String documentId) { + Document document = resolveDocument(documentId).orElseThrow(ElementNotFoundException::new); + return document.getTags(); + } + + @PutMapping("/api/documents/{documentId}/tags") + public Document documentTags( + @PathVariable String documentId, @RequestBody DocumentTagUpdateInput input) { + Document document = resolveDocument(documentId).orElseThrow(ElementNotFoundException::new); + document.setTags(iterableToSet(tagRepository.findAllById(input.getTagIds()))); + return documentRepository.save(document); + } + + @Transactional(rollbackOn = Exception.class) + @PutMapping("/api/documents/{documentId}") + public Document updateDocumentInformation( + @PathVariable String documentId, @Valid @RequestBody DocumentUpdateInput input) { + Document document = resolveDocument(documentId).orElseThrow(ElementNotFoundException::new); + document.setUpdateAttributes(input); + document.setTags(iterableToSet(tagRepository.findAllById(input.getTagIds()))); + + // Get removed exercises + Stream askExerciseIdsStream = + document.getExercises().stream() + .filter( + exercise -> + !exercise.isUserHasAccess( + userRepository + .findById(currentUser().getId()) + .orElseThrow(ElementNotFoundException::new))) + .map(Exercise::getId); + List askExerciseIds = + Stream.concat(askExerciseIdsStream, input.getExerciseIds().stream()).distinct().toList(); + List removedExercises = + document.getExercises().stream() + .filter(exercise -> !askExerciseIds.contains(exercise.getId())) + .toList(); + document.setExercises(iterableToSet(exerciseRepository.findAllById(askExerciseIds))); + // In case of exercise removal, all inject doc attachment for exercise + removedExercises.forEach( + exercise -> injectService.cleanInjectsDocExercise(exercise.getId(), documentId)); + + // Get removed scenarios + Stream askScenarioIdsStream = + document.getScenarios().stream() + .filter( + scenario -> + !scenario.isUserHasAccess( + userRepository + .findById(currentUser().getId()) + .orElseThrow(ElementNotFoundException::new))) + .map(Scenario::getId); + List askScenarioIds = + Stream.concat(askScenarioIdsStream, input.getScenarioIds().stream()).distinct().toList(); + List removedScenarios = + document.getScenarios().stream() + .filter(scenario -> !askScenarioIds.contains(scenario.getId())) + .toList(); + document.setScenarios(iterableToSet(scenarioRepository.findAllById(askScenarioIds))); + // In case of scenario removal, all inject doc attachment for scenario + removedScenarios.forEach( + scenario -> injectService.cleanInjectsDocScenario(scenario.getId(), documentId)); + + // Save and return + return documentRepository.save(document); + } + + @GetMapping("/api/documents/{documentId}/file") + public void downloadDocument(@PathVariable String documentId, HttpServletResponse response) + throws IOException { + Document document = resolveDocument(documentId).orElseThrow(ElementNotFoundException::new); + response.addHeader( + HttpHeaders.CONTENT_DISPOSITION, "attachment; filename=" + document.getName()); + response.addHeader(HttpHeaders.CONTENT_TYPE, document.getType()); + response.setStatus(HttpServletResponse.SC_OK); + try (InputStream fileStream = + fileService.getFile(document).orElseThrow(ElementNotFoundException::new)) { + fileStream.transferTo(response.getOutputStream()); + } + } + + @GetMapping(value = "/api/images/injectors/{injectorType}", produces = MediaType.IMAGE_PNG_VALUE) + public @ResponseBody ResponseEntity getInjectorImage(@PathVariable String injectorType) + throws IOException { + Optional fileStream = fileService.getInjectorImage(injectorType); + if (fileStream.isPresent()) { + return ResponseEntity.ok() + .cacheControl(CacheControl.maxAge(5, TimeUnit.MINUTES)) + .body(IOUtils.toByteArray(fileStream.get())); + } + return null; + } + + @GetMapping(value = "/api/images/injectors/id/{injectorId}", produces = MediaType.IMAGE_PNG_VALUE) + public @ResponseBody ResponseEntity getInjectorImageFromId( + @PathVariable String injectorId) throws IOException { + Injector injector = + this.injectorRepository.findById(injectorId).orElseThrow(ElementNotFoundException::new); + Optional fileStream = fileService.getInjectorImage(injector.getType()); + if (fileStream.isPresent()) { + return ResponseEntity.ok() + .cacheControl(CacheControl.maxAge(5, TimeUnit.MINUTES)) + .body(IOUtils.toByteArray(fileStream.get())); + } + return null; + } + + @GetMapping( + value = "/api/images/collectors/{collectorType}", + produces = MediaType.IMAGE_PNG_VALUE) + public @ResponseBody ResponseEntity getCollectorImage(@PathVariable String collectorType) + throws IOException { + Optional fileStream = fileService.getCollectorImage(collectorType); + if (fileStream.isPresent()) { + return ResponseEntity.ok() + .cacheControl(CacheControl.maxAge(5, TimeUnit.MINUTES)) + .body(IOUtils.toByteArray(fileStream.get())); + } + return null; + } + + public void downloadCollectorImage( + @PathVariable String collectorType, HttpServletResponse response) throws IOException { + response.addHeader( + HttpHeaders.CONTENT_DISPOSITION, "attachment; filename=" + collectorType + ".png"); + response.addHeader(HttpHeaders.CONTENT_TYPE, MediaType.IMAGE_PNG_VALUE); + response.setStatus(HttpServletResponse.SC_OK); + try (InputStream fileStream = + fileService.getCollectorImage(collectorType).orElseThrow(ElementNotFoundException::new)) { + fileStream.transferTo(response.getOutputStream()); + } + } + + @GetMapping( + value = "/api/images/collectors/id/{collectorId}", + produces = MediaType.IMAGE_PNG_VALUE) + public @ResponseBody ResponseEntity getCollectorImageFromId( + @PathVariable String collectorId) throws IOException { + Collector collector = + this.collectorRepository.findById(collectorId).orElseThrow(ElementNotFoundException::new); + Optional fileStream = fileService.getCollectorImage(collector.getType()); + if (fileStream.isPresent()) { + return ResponseEntity.ok() + .cacheControl(CacheControl.maxAge(5, TimeUnit.MINUTES)) + .body(IOUtils.toByteArray(fileStream.get())); + } + return null; + } + + @GetMapping(value = "/api/images/security_platforms/id/{assetId}/{theme}") + public void getSecurityPlatformImageFromId( + @PathVariable String assetId, @PathVariable String theme, HttpServletResponse response) + throws IOException { + SecurityPlatform securityPlatform = + this.securityPlatformRepository + .findById(assetId) + .orElseThrow(ElementNotFoundException::new); + if (theme.equals("dark")) { + if (securityPlatform.getLogoDark() != null) { + downloadDocument(securityPlatform.getLogoDark().getId(), response); + } + } + if (securityPlatform.getLogoLight() != null) { + downloadDocument(securityPlatform.getLogoLight().getId(), response); + } + downloadCollectorImage("openbas_fake_detector", response); + } + + @GetMapping(value = "/api/images/executors/{executorId}", produces = MediaType.IMAGE_PNG_VALUE) + public @ResponseBody ResponseEntity getExecutorImage(@PathVariable String executorId) + throws IOException { + Optional fileStream = fileService.getExecutorImage(executorId); + if (fileStream.isPresent()) { + return ResponseEntity.ok() + .cacheControl(CacheControl.maxAge(5, TimeUnit.MINUTES)) + .body(IOUtils.toByteArray(fileStream.get())); + } + return null; + } + + private List getExercisePlayerDocuments(Exercise exercise) { + List
articles = exercise.getArticles(); + List injects = exercise.getInjects(); + return getPlayerDocuments(articles, injects); + } + + private List getScenarioPlayerDocuments(Scenario scenario) { + List
articles = scenario.getArticles(); + List injects = scenario.getInjects(); + return getPlayerDocuments(articles, injects); + } + + private List getPlayerDocuments(List
articles, List injects) { + Stream channelsDocs = + articles.stream().map(Article::getChannel).flatMap(channel -> channel.getLogos().stream()); + Stream articlesDocs = + articles.stream().flatMap(article -> article.getDocuments().stream()); + List challenges = + injects.stream() + .filter( + inject -> + inject + .getInjectorContract() .map(contract -> contract.getId().equals(CHALLENGE_PUBLISH)) .orElse(false)) - .filter(inject -> inject.getContent() != null) - .flatMap(inject -> { - try { - ChallengeContent content = mapper.treeToValue(inject.getContent(), ChallengeContent.class); - return content.getChallenges().stream(); - } catch (JsonProcessingException e) { - return Stream.empty(); - } + .filter(inject -> inject.getContent() != null) + .flatMap( + inject -> { + try { + ChallengeContent content = + mapper.treeToValue(inject.getContent(), ChallengeContent.class); + return content.getChallenges().stream(); + } catch (JsonProcessingException e) { + return Stream.empty(); + } }) - .toList(); - Stream challengesDocs = fromIterable(challengeRepository.findAllById(challenges)).stream() - .flatMap(challenge -> challenge.getDocuments().stream()); - return Stream.of(channelsDocs, articlesDocs, challengesDocs).flatMap(documentStream -> documentStream).distinct() - .toList(); - } - - @Transactional(rollbackOn = Exception.class) - @DeleteMapping("/api/documents/{documentId}") - public void deleteDocument(@PathVariable String documentId) { - injectDocumentRepository.deleteDocumentFromAllReferences(documentId); - List documents = documentRepository.removeById(documentId); - documents.forEach(document -> { - try { - fileService.deleteFile(document.getTarget()); - } catch (Exception e) { - // Fail no longer available in the storage. - } + .toList(); + Stream challengesDocs = + fromIterable(challengeRepository.findAllById(challenges)).stream() + .flatMap(challenge -> challenge.getDocuments().stream()); + return Stream.of(channelsDocs, articlesDocs, challengesDocs) + .flatMap(documentStream -> documentStream) + .distinct() + .toList(); + } + + @Transactional(rollbackOn = Exception.class) + @DeleteMapping("/api/documents/{documentId}") + public void deleteDocument(@PathVariable String documentId) { + injectDocumentRepository.deleteDocumentFromAllReferences(documentId); + List documents = documentRepository.removeById(documentId); + documents.forEach( + document -> { + try { + fileService.deleteFile(document.getTarget()); + } catch (Exception e) { + // Fail no longer available in the storage. + } }); - } - - // -- EXERCISE & SENARIO-- - - @GetMapping("/api/player/{exerciseOrScenarioId}/documents") - public List playerDocuments(@PathVariable String exerciseOrScenarioId, @RequestParam Optional userId) { - Optional exerciseOpt = this.exerciseRepository.findById(exerciseOrScenarioId); - Optional scenarioOpt = this.scenarioRepository.findById(exerciseOrScenarioId); - - final User user = impersonateUser(userRepository, userId); - if (user.getId().equals(ANONYMOUS)) { - throw new UnsupportedOperationException("User must be logged or dynamic player is required"); - } - - if (exerciseOpt.isPresent()) { - if (!exerciseOpt.get().isUserHasAccess(user) && !exerciseOpt.get().getUsers().contains(user)) { - throw new UnsupportedOperationException("The given player is not in this exercise"); - } - return getExercisePlayerDocuments(exerciseOpt.get()); - } else if (scenarioOpt.isPresent()) { - if (!scenarioOpt.get().isUserHasAccess(user) && !scenarioOpt.get().getUsers().contains(user)) { - throw new UnsupportedOperationException("The given player is not in this exercise"); - } - return getScenarioPlayerDocuments(scenarioOpt.get()); - } else { - throw new IllegalArgumentException("Exercise or scenario ID not found"); - } - } - - @GetMapping("/api/player/{exerciseOrScenarioId}/documents/{documentId}/file") - public void downloadPlayerDocument( - @PathVariable String exerciseOrScenarioId, - @PathVariable String documentId, - @RequestParam Optional userId, HttpServletResponse response) throws IOException { - Optional exerciseOpt = this.exerciseRepository.findById(exerciseOrScenarioId); - Optional scenarioOpt = this.scenarioRepository.findById(exerciseOrScenarioId); - - final User user = impersonateUser(userRepository, userId); - if (user.getId().equals(ANONYMOUS)) { - throw new UnsupportedOperationException("User must be logged or dynamic player is required"); - } - - Document document = null; - if (exerciseOpt.isPresent()) { - if (!exerciseOpt.get().isUserHasAccess(user) && !exerciseOpt.get().getUsers().contains(user)) { - throw new UnsupportedOperationException("The given player is not in this exercise"); - } - document = getExercisePlayerDocuments(exerciseOpt.get()) - .stream() - .filter(doc -> doc.getId().equals(documentId)) - .findFirst() - .orElseThrow(ElementNotFoundException::new); - } else if (scenarioOpt.isPresent()) { - if (!scenarioOpt.get().isUserHasAccess(user) && !scenarioOpt.get().getUsers().contains(user)) { - throw new UnsupportedOperationException("The given player is not in this exercise"); - } - document = getScenarioPlayerDocuments(scenarioOpt.get()) - .stream() - .filter(doc -> doc.getId().equals(documentId)) - .findFirst() - .orElseThrow(ElementNotFoundException::new); - } - - if (document != null) { - response.addHeader(HttpHeaders.CONTENT_DISPOSITION, "attachment; filename=" + document.getName()); - response.addHeader(HttpHeaders.CONTENT_TYPE, document.getType()); - response.setStatus(HttpServletResponse.SC_OK); - try (InputStream fileStream = fileService.getFile(document).orElseThrow(ElementNotFoundException::new)) { - fileStream.transferTo(response.getOutputStream()); - } - } - } - + } + + // -- EXERCISE & SENARIO-- + + @GetMapping("/api/player/{exerciseOrScenarioId}/documents") + public List playerDocuments( + @PathVariable String exerciseOrScenarioId, @RequestParam Optional userId) { + Optional exerciseOpt = this.exerciseRepository.findById(exerciseOrScenarioId); + Optional scenarioOpt = this.scenarioRepository.findById(exerciseOrScenarioId); + + final User user = impersonateUser(userRepository, userId); + if (user.getId().equals(ANONYMOUS)) { + throw new UnsupportedOperationException("User must be logged or dynamic player is required"); + } + + if (exerciseOpt.isPresent()) { + if (!exerciseOpt.get().isUserHasAccess(user) + && !exerciseOpt.get().getUsers().contains(user)) { + throw new UnsupportedOperationException("The given player is not in this exercise"); + } + return getExercisePlayerDocuments(exerciseOpt.get()); + } else if (scenarioOpt.isPresent()) { + if (!scenarioOpt.get().isUserHasAccess(user) + && !scenarioOpt.get().getUsers().contains(user)) { + throw new UnsupportedOperationException("The given player is not in this exercise"); + } + return getScenarioPlayerDocuments(scenarioOpt.get()); + } else { + throw new IllegalArgumentException("Exercise or scenario ID not found"); + } + } + + @GetMapping("/api/player/{exerciseOrScenarioId}/documents/{documentId}/file") + public void downloadPlayerDocument( + @PathVariable String exerciseOrScenarioId, + @PathVariable String documentId, + @RequestParam Optional userId, + HttpServletResponse response) + throws IOException { + Optional exerciseOpt = this.exerciseRepository.findById(exerciseOrScenarioId); + Optional scenarioOpt = this.scenarioRepository.findById(exerciseOrScenarioId); + + final User user = impersonateUser(userRepository, userId); + if (user.getId().equals(ANONYMOUS)) { + throw new UnsupportedOperationException("User must be logged or dynamic player is required"); + } + + Document document = null; + if (exerciseOpt.isPresent()) { + if (!exerciseOpt.get().isUserHasAccess(user) + && !exerciseOpt.get().getUsers().contains(user)) { + throw new UnsupportedOperationException("The given player is not in this exercise"); + } + document = + getExercisePlayerDocuments(exerciseOpt.get()).stream() + .filter(doc -> doc.getId().equals(documentId)) + .findFirst() + .orElseThrow(ElementNotFoundException::new); + } else if (scenarioOpt.isPresent()) { + if (!scenarioOpt.get().isUserHasAccess(user) + && !scenarioOpt.get().getUsers().contains(user)) { + throw new UnsupportedOperationException("The given player is not in this exercise"); + } + document = + getScenarioPlayerDocuments(scenarioOpt.get()).stream() + .filter(doc -> doc.getId().equals(documentId)) + .findFirst() + .orElseThrow(ElementNotFoundException::new); + } + + if (document != null) { + response.addHeader( + HttpHeaders.CONTENT_DISPOSITION, "attachment; filename=" + document.getName()); + response.addHeader(HttpHeaders.CONTENT_TYPE, document.getType()); + response.setStatus(HttpServletResponse.SC_OK); + try (InputStream fileStream = + fileService.getFile(document).orElseThrow(ElementNotFoundException::new)) { + fileStream.transferTo(response.getOutputStream()); + } + } + } } diff --git a/openbas-api/src/main/java/io/openbas/rest/document/form/DocumentCreateInput.java b/openbas-api/src/main/java/io/openbas/rest/document/form/DocumentCreateInput.java index 80c5f747ac..78a3faa5bd 100644 --- a/openbas-api/src/main/java/io/openbas/rest/document/form/DocumentCreateInput.java +++ b/openbas-api/src/main/java/io/openbas/rest/document/form/DocumentCreateInput.java @@ -1,26 +1,24 @@ package io.openbas.rest.document.form; import com.fasterxml.jackson.annotation.JsonProperty; -import lombok.Getter; -import lombok.Setter; - import java.util.ArrayList; import java.util.List; +import lombok.Getter; +import lombok.Setter; @Setter @Getter public class DocumentCreateInput { - @JsonProperty("document_description") - private String description; - - @JsonProperty("document_tags") - private List tagIds = new ArrayList<>(); + @JsonProperty("document_description") + private String description; - @JsonProperty("document_exercises") - private List exerciseIds = new ArrayList<>(); + @JsonProperty("document_tags") + private List tagIds = new ArrayList<>(); - @JsonProperty("document_scenarios") - private List scenarioIds = new ArrayList<>(); + @JsonProperty("document_exercises") + private List exerciseIds = new ArrayList<>(); + @JsonProperty("document_scenarios") + private List scenarioIds = new ArrayList<>(); } diff --git a/openbas-api/src/main/java/io/openbas/rest/document/form/DocumentTagUpdateInput.java b/openbas-api/src/main/java/io/openbas/rest/document/form/DocumentTagUpdateInput.java index 9201f9ebfe..81a078a6f5 100644 --- a/openbas-api/src/main/java/io/openbas/rest/document/form/DocumentTagUpdateInput.java +++ b/openbas-api/src/main/java/io/openbas/rest/document/form/DocumentTagUpdateInput.java @@ -1,19 +1,18 @@ package io.openbas.rest.document.form; import com.fasterxml.jackson.annotation.JsonProperty; - import java.util.List; public class DocumentTagUpdateInput { - @JsonProperty("tags") - private List tagIds; + @JsonProperty("tags") + private List tagIds; - public List getTagIds() { - return tagIds; - } + public List getTagIds() { + return tagIds; + } - public void setTagIds(List tagIds) { - this.tagIds = tagIds; - } + public void setTagIds(List tagIds) { + this.tagIds = tagIds; + } } diff --git a/openbas-api/src/main/java/io/openbas/rest/document/form/DocumentUpdateInput.java b/openbas-api/src/main/java/io/openbas/rest/document/form/DocumentUpdateInput.java index c677a883c7..9e0b79c17d 100644 --- a/openbas-api/src/main/java/io/openbas/rest/document/form/DocumentUpdateInput.java +++ b/openbas-api/src/main/java/io/openbas/rest/document/form/DocumentUpdateInput.java @@ -1,11 +1,10 @@ package io.openbas.rest.document.form; import com.fasterxml.jackson.annotation.JsonProperty; -import lombok.Getter; -import lombok.Setter; - import java.util.ArrayList; import java.util.List; +import lombok.Getter; +import lombok.Setter; @Setter @Getter @@ -22,5 +21,4 @@ public class DocumentUpdateInput { @JsonProperty("document_scenarios") private List scenarioIds = new ArrayList<>(); - } diff --git a/openbas-api/src/main/java/io/openbas/rest/exception/AlreadyExistingException.java b/openbas-api/src/main/java/io/openbas/rest/exception/AlreadyExistingException.java index c90a786c34..eeed784858 100644 --- a/openbas-api/src/main/java/io/openbas/rest/exception/AlreadyExistingException.java +++ b/openbas-api/src/main/java/io/openbas/rest/exception/AlreadyExistingException.java @@ -1,12 +1,12 @@ package io.openbas.rest.exception; -public class AlreadyExistingException extends RuntimeException{ +public class AlreadyExistingException extends RuntimeException { - public AlreadyExistingException() { - super(); - } + public AlreadyExistingException() { + super(); + } - public AlreadyExistingException(String errorMessage) { - super(errorMessage); - } + public AlreadyExistingException(String errorMessage) { + super(errorMessage); + } } diff --git a/openbas-api/src/main/java/io/openbas/rest/exception/BadRequestException.java b/openbas-api/src/main/java/io/openbas/rest/exception/BadRequestException.java index 3f3a0c9cd9..0a3c5b186c 100644 --- a/openbas-api/src/main/java/io/openbas/rest/exception/BadRequestException.java +++ b/openbas-api/src/main/java/io/openbas/rest/exception/BadRequestException.java @@ -4,13 +4,13 @@ import org.springframework.web.bind.annotation.ResponseStatus; @ResponseStatus(HttpStatus.BAD_REQUEST) -public class BadRequestException extends RuntimeException{ +public class BadRequestException extends RuntimeException { - public BadRequestException() { - super(); - } + public BadRequestException() { + super(); + } - public BadRequestException(String errorMessage) { - super(errorMessage); - } + public BadRequestException(String errorMessage) { + super(errorMessage); + } } diff --git a/openbas-api/src/main/java/io/openbas/rest/exception/ElementNotFoundException.java b/openbas-api/src/main/java/io/openbas/rest/exception/ElementNotFoundException.java index c35b44e4ef..1b9eb9b0c7 100644 --- a/openbas-api/src/main/java/io/openbas/rest/exception/ElementNotFoundException.java +++ b/openbas-api/src/main/java/io/openbas/rest/exception/ElementNotFoundException.java @@ -1,12 +1,12 @@ package io.openbas.rest.exception; -public class ElementNotFoundException extends RuntimeException{ +public class ElementNotFoundException extends RuntimeException { - public ElementNotFoundException() { - super(); - } + public ElementNotFoundException() { + super(); + } - public ElementNotFoundException(String errorMessage) { - super(errorMessage); - } + public ElementNotFoundException(String errorMessage) { + super(errorMessage); + } } diff --git a/openbas-api/src/main/java/io/openbas/rest/exception/FileTooBigException.java b/openbas-api/src/main/java/io/openbas/rest/exception/FileTooBigException.java index dc4867428d..739eae5728 100644 --- a/openbas-api/src/main/java/io/openbas/rest/exception/FileTooBigException.java +++ b/openbas-api/src/main/java/io/openbas/rest/exception/FileTooBigException.java @@ -4,13 +4,13 @@ import org.springframework.web.bind.annotation.ResponseStatus; @ResponseStatus(HttpStatus.BAD_REQUEST) -public class FileTooBigException extends RuntimeException{ +public class FileTooBigException extends RuntimeException { - public FileTooBigException() { - super(); - } + public FileTooBigException() { + super(); + } - public FileTooBigException(String errorMessage) { - super(errorMessage); - } + public FileTooBigException(String errorMessage) { + super(errorMessage); + } } diff --git a/openbas-api/src/main/java/io/openbas/rest/exception/ImportException.java b/openbas-api/src/main/java/io/openbas/rest/exception/ImportException.java index 31a4bd9fca..552cb3d68f 100644 --- a/openbas-api/src/main/java/io/openbas/rest/exception/ImportException.java +++ b/openbas-api/src/main/java/io/openbas/rest/exception/ImportException.java @@ -2,14 +2,14 @@ public class ImportException extends Exception { - private final String field; + private final String field; - public ImportException(String field, String message) { - super(message); - this.field = field; - } + public ImportException(String field, String message) { + super(message); + this.field = field; + } - public String getField() { - return field; - } + public String getField() { + return field; + } } diff --git a/openbas-api/src/main/java/io/openbas/rest/exception/InputValidationException.java b/openbas-api/src/main/java/io/openbas/rest/exception/InputValidationException.java index de519b46ac..50ec28fb22 100644 --- a/openbas-api/src/main/java/io/openbas/rest/exception/InputValidationException.java +++ b/openbas-api/src/main/java/io/openbas/rest/exception/InputValidationException.java @@ -2,14 +2,14 @@ public class InputValidationException extends Exception { - private final String field; + private final String field; - public InputValidationException(String field, String message) { - super(message); - this.field = field; - } + public InputValidationException(String field, String message) { + super(message); + this.field = field; + } - public String getField() { - return field; - } + public String getField() { + return field; + } } diff --git a/openbas-api/src/main/java/io/openbas/rest/executor/ExecutorApi.java b/openbas-api/src/main/java/io/openbas/rest/executor/ExecutorApi.java index 7a8c1d5d40..43888dfb4a 100644 --- a/openbas-api/src/main/java/io/openbas/rest/executor/ExecutorApi.java +++ b/openbas-api/src/main/java/io/openbas/rest/executor/ExecutorApi.java @@ -1,5 +1,8 @@ package io.openbas.rest.executor; +import static io.openbas.asset.EndpointService.JFROG_BASE; +import static io.openbas.database.model.User.ROLE_ADMIN; + import com.fasterxml.jackson.databind.ObjectMapper; import io.openbas.asset.EndpointService; import io.openbas.database.model.Executor; @@ -14,6 +17,12 @@ import jakarta.annotation.Resource; import jakarta.transaction.Transactional; import jakarta.validation.Valid; +import java.io.BufferedInputStream; +import java.io.IOException; +import java.io.InputStream; +import java.net.URL; +import java.time.Instant; +import java.util.Optional; import org.apache.commons.io.IOUtils; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Value; @@ -24,178 +33,182 @@ import org.springframework.web.bind.annotation.*; import org.springframework.web.multipart.MultipartFile; -import java.io.BufferedInputStream; -import java.io.IOException; -import java.io.InputStream; -import java.net.URL; -import java.time.Instant; -import java.util.Optional; - -import static io.openbas.asset.EndpointService.JFROG_BASE; -import static io.openbas.database.model.User.ROLE_ADMIN; - @RestController public class ExecutorApi extends RestBehavior { - @Value("${info.app.version:unknown}") String version; - - private ExecutorRepository executorRepository; - private EndpointService endpointService; - private FileService fileService; - private TokenRepository tokenRepository; - - @Resource - protected ObjectMapper mapper; - - @Autowired - public void setTokenRepository(TokenRepository tokenRepository) { - this.tokenRepository = tokenRepository; - } - - @Autowired - public void setEndpointService(EndpointService endpointService) { - this.endpointService = endpointService; - } - - @Autowired - public void setFileService(FileService fileService) { - this.fileService = fileService; - } - - @Autowired - public void setExecutorRepository(ExecutorRepository executorRepository) { - this.executorRepository = executorRepository; + @Value("${info.app.version:unknown}") + String version; + + private ExecutorRepository executorRepository; + private EndpointService endpointService; + private FileService fileService; + private TokenRepository tokenRepository; + + @Resource protected ObjectMapper mapper; + + @Autowired + public void setTokenRepository(TokenRepository tokenRepository) { + this.tokenRepository = tokenRepository; + } + + @Autowired + public void setEndpointService(EndpointService endpointService) { + this.endpointService = endpointService; + } + + @Autowired + public void setFileService(FileService fileService) { + this.fileService = fileService; + } + + @Autowired + public void setExecutorRepository(ExecutorRepository executorRepository) { + this.executorRepository = executorRepository; + } + + @GetMapping("/api/executors") + public Iterable executors() { + return executorRepository.findAll(); + } + + private Executor updateExecutor(Executor executor, String type, String name, String[] platforms) { + executor.setUpdatedAt(Instant.now()); + executor.setType(type); + executor.setName(name); + executor.setPlatforms(platforms); + return executorRepository.save(executor); + } + + @Secured(ROLE_ADMIN) + @PutMapping("/api/executors/{executorId}") + public Executor updateExecutor( + @PathVariable String executorId, @Valid @RequestBody ExecutorUpdateInput input) { + Executor executor = + executorRepository.findById(executorId).orElseThrow(ElementNotFoundException::new); + return updateExecutor( + executor, executor.getType(), executor.getName(), executor.getPlatforms()); + } + + @Secured(ROLE_ADMIN) + @PostMapping( + value = "/api/executors", + produces = {MediaType.APPLICATION_JSON_VALUE}, + consumes = {MediaType.APPLICATION_JSON_VALUE, MediaType.MULTIPART_FORM_DATA_VALUE}) + @Transactional(rollbackOn = Exception.class) + public Executor registerExecutor( + @Valid @RequestPart("input") ExecutorCreateInput input, + @RequestPart("icon") Optional file) { + try { + // Upload icon + if (file.isPresent() && "image/png".equals(file.get().getContentType())) { + fileService.uploadFile( + FileService.EXECUTORS_IMAGES_BASE_PATH + input.getType() + ".png", file.get()); + } + // We need to support upsert for registration + Executor executor = executorRepository.findById(input.getId()).orElse(null); + if (executor == null) { + Executor executorChecking = executorRepository.findByType(input.getType()).orElse(null); + if (executorChecking != null) { + throw new Exception( + "The executor " + + input.getType() + + " already exists with a different ID, please delete it or contact your administrator."); + } + } + if (executor != null) { + return updateExecutor(executor, input.getType(), input.getName(), input.getPlatforms()); + } else { + // save the injector + Executor newExecutor = new Executor(); + newExecutor.setId(input.getId()); + newExecutor.setName(input.getName()); + newExecutor.setType(input.getType()); + newExecutor.setPlatforms(input.getPlatforms()); + return executorRepository.save(newExecutor); + } + } catch (Exception e) { + throw new RuntimeException(e); } - - @GetMapping("/api/executors") - public Iterable executors() { - return executorRepository.findAll(); + } + + // Public API + @GetMapping( + value = "/api/agent/executable/openbas/{platform}/{architecture}", + produces = MediaType.APPLICATION_OCTET_STREAM_VALUE) + public @ResponseBody ResponseEntity getOpenBasAgentExecutable( + @PathVariable String platform, @PathVariable String architecture) throws IOException { + InputStream in = null; + String filename = null; + if (platform.equals("windows") && architecture.equals("x86_64")) { + filename = "openbas-agent-" + version + ".exe"; + String resourcePath = "/openbas-agent/windows/x86_64/"; + in = getClass().getResourceAsStream("/agents" + resourcePath + filename); + if (in == null) { // Dev mode, get from artifactory + filename = "openbas-agent-latest.exe"; + in = new BufferedInputStream(new URL(JFROG_BASE + resourcePath + filename).openStream()); + } } - - private Executor updateExecutor(Executor executor, String type, String name, String[] platforms) { - executor.setUpdatedAt(Instant.now()); - executor.setType(type); - executor.setName(name); - executor.setPlatforms(platforms); - return executorRepository.save(executor); - } - - @Secured(ROLE_ADMIN) - @PutMapping("/api/executors/{executorId}") - public Executor updateExecutor(@PathVariable String executorId, @Valid @RequestBody ExecutorUpdateInput input) { - Executor executor = executorRepository.findById(executorId).orElseThrow(ElementNotFoundException::new); - return updateExecutor(executor, executor.getType(), executor.getName(), executor.getPlatforms()); + if (platform.equals("linux") || platform.equals("macos")) { + filename = "openbas-agent-" + version; + String resourcePath = "/openbas-agent/" + platform + "/" + architecture + "/"; + in = getClass().getResourceAsStream("/agents" + resourcePath + filename); + if (in == null) { // Dev mode, get from artifactory + filename = "openbas-agent-latest"; + in = new BufferedInputStream(new URL(JFROG_BASE + resourcePath + filename).openStream()); + } } - - @Secured(ROLE_ADMIN) - @PostMapping(value = "/api/executors", - produces = {MediaType.APPLICATION_JSON_VALUE}, - consumes = {MediaType.APPLICATION_JSON_VALUE, MediaType.MULTIPART_FORM_DATA_VALUE}) - @Transactional(rollbackOn = Exception.class) - public Executor registerExecutor(@Valid @RequestPart("input") ExecutorCreateInput input, - @RequestPart("icon") Optional file) { - try { - // Upload icon - if (file.isPresent() && "image/png".equals(file.get().getContentType())) { - fileService.uploadFile(FileService.EXECUTORS_IMAGES_BASE_PATH + input.getType() + ".png", file.get()); - } - // We need to support upsert for registration - Executor executor = executorRepository.findById(input.getId()).orElse(null); - if (executor == null) { - Executor executorChecking = executorRepository.findByType(input.getType()).orElse(null); - if (executorChecking != null) { - throw new Exception("The executor " + input.getType() + " already exists with a different ID, please delete it or contact your administrator."); - } - } - if (executor != null) { - return updateExecutor(executor, input.getType(), input.getName(), input.getPlatforms()); - } else { - // save the injector - Executor newExecutor = new Executor(); - newExecutor.setId(input.getId()); - newExecutor.setName(input.getName()); - newExecutor.setType(input.getType()); - newExecutor.setPlatforms(input.getPlatforms()); - return executorRepository.save(newExecutor); - } - } catch (Exception e) { - throw new RuntimeException(e); - } + if (in != null) { + HttpHeaders headers = new HttpHeaders(); + headers.add(HttpHeaders.CONTENT_DISPOSITION, "attachment; filename=" + filename); + return ResponseEntity.ok() + .headers(headers) + .contentType(MediaType.APPLICATION_OCTET_STREAM) + .body(IOUtils.toByteArray(in)); } - - // Public API - @GetMapping(value = "/api/agent/executable/openbas/{platform}/{architecture}", produces = MediaType.APPLICATION_OCTET_STREAM_VALUE) - public @ResponseBody ResponseEntity getOpenBasAgentExecutable(@PathVariable String platform, @PathVariable String architecture) throws IOException { - InputStream in = null; - String filename = null; - if (platform.equals("windows") && architecture.equals("x86_64")) { - filename = "openbas-agent-" + version + ".exe"; - String resourcePath = "/openbas-agent/windows/x86_64/"; - in = getClass().getResourceAsStream("/agents" + resourcePath + filename); - if (in == null) { // Dev mode, get from artifactory - filename = "openbas-agent-latest.exe"; - in = new BufferedInputStream(new URL(JFROG_BASE + resourcePath + filename).openStream()); - } - } - if (platform.equals("linux") || platform.equals("macos")) { - filename = "openbas-agent-" + version; - String resourcePath = "/openbas-agent/" + platform + "/" + architecture + "/"; - in = getClass().getResourceAsStream("/agents" + resourcePath + filename); - if (in == null) { // Dev mode, get from artifactory - filename = "openbas-agent-latest"; - in = new BufferedInputStream(new URL(JFROG_BASE + resourcePath + filename).openStream()); - } - } - if (in != null) { - HttpHeaders headers = new HttpHeaders(); - headers.add(HttpHeaders.CONTENT_DISPOSITION, "attachment; filename=" + filename); - return ResponseEntity.ok() - .headers(headers) - .contentType(MediaType.APPLICATION_OCTET_STREAM) - .body(IOUtils.toByteArray(in)); - } - throw new UnsupportedOperationException("Agent " + platform + " executable not supported"); + throw new UnsupportedOperationException("Agent " + platform + " executable not supported"); + } + + // Public API + @GetMapping( + value = "/api/agent/package/openbas/{platform}/{architecture}", + produces = MediaType.APPLICATION_OCTET_STREAM_VALUE) + public @ResponseBody ResponseEntity getOpenBasAgentPackage( + @PathVariable String platform, @PathVariable String architecture) throws IOException { + byte[] file = null; + String filename = null; + if (platform.equals("windows") && architecture.equals("x86_64")) { + filename = "openbas-agent-installer-" + version + ".exe"; + String resourcePath = "/openbas-agent/windows/x86_64/"; + InputStream in = getClass().getResourceAsStream("/agents" + resourcePath + filename); + if (in != null) { + file = IOUtils.toByteArray(in); + } else { // Dev mode, get from artifactory + filename = "openbas-agent-installer-latest.exe"; + in = new BufferedInputStream(new URL(JFROG_BASE + resourcePath + filename).openStream()); + file = IOUtils.toByteArray(in); + } } - - // Public API - @GetMapping(value = "/api/agent/package/openbas/{platform}/{architecture}", produces = MediaType.APPLICATION_OCTET_STREAM_VALUE) - public @ResponseBody ResponseEntity getOpenBasAgentPackage(@PathVariable String platform, @PathVariable String architecture) throws IOException { - byte[] file = null; - String filename = null; - if (platform.equals("windows") && architecture.equals("x86_64")) { - filename = "openbas-agent-installer-" + version + ".exe"; - String resourcePath = "/openbas-agent/windows/x86_64/"; - InputStream in = getClass().getResourceAsStream("/agents" + resourcePath + filename); - if (in != null) { - file = IOUtils.toByteArray(in); - } else { // Dev mode, get from artifactory - filename = "openbas-agent-installer-latest.exe"; - in = new BufferedInputStream(new URL(JFROG_BASE + resourcePath + filename).openStream()); - file = IOUtils.toByteArray(in); - } - } - // linux - No package needed - if (file != null) { - HttpHeaders headers = new HttpHeaders(); - headers.add(HttpHeaders.CONTENT_DISPOSITION, "attachment; filename=" + filename); - return ResponseEntity.ok() - .headers(headers) - .contentType(MediaType.APPLICATION_OCTET_STREAM) - .body(file); - } - throw new UnsupportedOperationException("Agent " + platform + " package not supported"); + // linux - No package needed + if (file != null) { + HttpHeaders headers = new HttpHeaders(); + headers.add(HttpHeaders.CONTENT_DISPOSITION, "attachment; filename=" + filename); + return ResponseEntity.ok() + .headers(headers) + .contentType(MediaType.APPLICATION_OCTET_STREAM) + .body(file); } - - // Public API - @GetMapping(value = "/api/agent/installer/openbas/{platform}/{token}") - public @ResponseBody ResponseEntity getOpenBasAgentInstaller(@PathVariable String platform, @PathVariable String token) throws IOException { - Optional resolvedToken = tokenRepository.findByValue(token); - if (resolvedToken.isEmpty() ) { - throw new UnsupportedOperationException("Invalid token"); - } - String installCommand = this.endpointService.generateInstallCommand(platform, token); - return ResponseEntity.ok() - .contentType(MediaType.TEXT_PLAIN) - .body(installCommand); + throw new UnsupportedOperationException("Agent " + platform + " package not supported"); + } + + // Public API + @GetMapping(value = "/api/agent/installer/openbas/{platform}/{token}") + public @ResponseBody ResponseEntity getOpenBasAgentInstaller( + @PathVariable String platform, @PathVariable String token) throws IOException { + Optional resolvedToken = tokenRepository.findByValue(token); + if (resolvedToken.isEmpty()) { + throw new UnsupportedOperationException("Invalid token"); } + String installCommand = this.endpointService.generateInstallCommand(platform, token); + return ResponseEntity.ok().contentType(MediaType.TEXT_PLAIN).body(installCommand); + } } diff --git a/openbas-api/src/main/java/io/openbas/rest/executor/form/ExecutorCreateInput.java b/openbas-api/src/main/java/io/openbas/rest/executor/form/ExecutorCreateInput.java index 9b8df846e0..ae92936d64 100644 --- a/openbas-api/src/main/java/io/openbas/rest/executor/form/ExecutorCreateInput.java +++ b/openbas-api/src/main/java/io/openbas/rest/executor/form/ExecutorCreateInput.java @@ -1,28 +1,28 @@ package io.openbas.rest.executor.form; +import static io.openbas.config.AppConfig.MANDATORY_MESSAGE; + import com.fasterxml.jackson.annotation.JsonProperty; import jakarta.validation.constraints.NotBlank; import lombok.Getter; import lombok.Setter; -import static io.openbas.config.AppConfig.MANDATORY_MESSAGE; - @Getter @Setter public class ExecutorCreateInput { - @NotBlank(message = MANDATORY_MESSAGE) - @JsonProperty("executor_id") - private String id; + @NotBlank(message = MANDATORY_MESSAGE) + @JsonProperty("executor_id") + private String id; - @NotBlank(message = MANDATORY_MESSAGE) - @JsonProperty("executor_name") - private String name; + @NotBlank(message = MANDATORY_MESSAGE) + @JsonProperty("executor_name") + private String name; - @NotBlank(message = MANDATORY_MESSAGE) - @JsonProperty("executor_type") - private String type; + @NotBlank(message = MANDATORY_MESSAGE) + @JsonProperty("executor_type") + private String type; - @JsonProperty("executor_platforms") - private String[] platforms; + @JsonProperty("executor_platforms") + private String[] platforms; } diff --git a/openbas-api/src/main/java/io/openbas/rest/executor/form/ExecutorUpdateInput.java b/openbas-api/src/main/java/io/openbas/rest/executor/form/ExecutorUpdateInput.java index 9b5be9277f..0f0a92289f 100644 --- a/openbas-api/src/main/java/io/openbas/rest/executor/form/ExecutorUpdateInput.java +++ b/openbas-api/src/main/java/io/openbas/rest/executor/form/ExecutorUpdateInput.java @@ -1,15 +1,14 @@ package io.openbas.rest.executor.form; import com.fasterxml.jackson.annotation.JsonProperty; +import java.time.Instant; import lombok.Getter; import lombok.Setter; -import java.time.Instant; - @Getter @Setter public class ExecutorUpdateInput { - @JsonProperty("executor_last_execution") - private Instant lastExecution; + @JsonProperty("executor_last_execution") + private Instant lastExecution; } diff --git a/openbas-api/src/main/java/io/openbas/rest/exercise/ExerciseApi.java b/openbas-api/src/main/java/io/openbas/rest/exercise/ExerciseApi.java index 9348e37fe4..a77ed715f7 100644 --- a/openbas-api/src/main/java/io/openbas/rest/exercise/ExerciseApi.java +++ b/openbas-api/src/main/java/io/openbas/rest/exercise/ExerciseApi.java @@ -1,5 +1,18 @@ package io.openbas.rest.exercise; +import static io.openbas.config.SessionHelper.currentUser; +import static io.openbas.database.model.User.ROLE_ADMIN; +import static io.openbas.database.model.User.ROLE_USER; +import static io.openbas.database.specification.ExerciseSpecification.findGrantedFor; +import static io.openbas.helper.StreamHelper.fromIterable; +import static io.openbas.helper.StreamHelper.iterableToSet; +import static io.openbas.service.ImportService.EXPORT_ENTRY_ATTACHMENT; +import static io.openbas.service.ImportService.EXPORT_ENTRY_EXERCISE; +import static io.openbas.utils.pagination.PaginationUtils.buildPaginationCriteriaBuilder; +import static java.time.Duration.between; +import static java.time.Instant.now; +import static java.time.temporal.ChronoUnit.MINUTES; + import com.fasterxml.jackson.databind.ObjectMapper; import io.openbas.aop.LogExecutionTime; import io.openbas.database.model.*; @@ -24,6 +37,16 @@ import jakarta.transaction.Transactional; import jakarta.validation.Valid; import jakarta.validation.constraints.NotBlank; +import java.io.IOException; +import java.io.InputStream; +import java.time.Instant; +import java.util.*; +import java.util.logging.Level; +import java.util.logging.Logger; +import java.util.stream.Collectors; +import java.util.stream.StreamSupport; +import java.util.zip.ZipEntry; +import java.util.zip.ZipOutputStream; import lombok.RequiredArgsConstructor; import org.springframework.data.domain.Page; import org.springframework.data.domain.Pageable; @@ -36,784 +59,896 @@ import org.springframework.web.multipart.MultipartFile; import org.springframework.web.server.ResponseStatusException; -import java.io.IOException; -import java.io.InputStream; -import java.time.Instant; -import java.util.*; -import java.util.logging.Level; -import java.util.logging.Logger; -import java.util.stream.Collectors; -import java.util.stream.StreamSupport; -import java.util.zip.ZipEntry; -import java.util.zip.ZipOutputStream; - -import static io.openbas.config.SessionHelper.currentUser; -import static io.openbas.database.model.User.ROLE_ADMIN; -import static io.openbas.database.model.User.ROLE_USER; -import static io.openbas.database.specification.ExerciseSpecification.findGrantedFor; -import static io.openbas.helper.StreamHelper.fromIterable; -import static io.openbas.helper.StreamHelper.iterableToSet; -import static io.openbas.service.ImportService.EXPORT_ENTRY_ATTACHMENT; -import static io.openbas.service.ImportService.EXPORT_ENTRY_EXERCISE; -import static io.openbas.utils.pagination.PaginationUtils.buildPaginationCriteriaBuilder; -import static java.time.Duration.between; -import static java.time.Instant.now; -import static java.time.temporal.ChronoUnit.MINUTES; - @RestController @Secured(ROLE_USER) @RequiredArgsConstructor public class ExerciseApi extends RestBehavior { - public static final String EXERCISE_URI = "/api/exercises"; - - private static final Logger LOGGER = Logger.getLogger(ExerciseApi.class.getName()); - - // region repositories - private final LogRepository logRepository; - private final TagRepository tagRepository; - private final UserRepository userRepository; - private final PauseRepository pauseRepository; - private final DocumentRepository documentRepository; - private final ExerciseRepository exerciseRepository; - private final TeamRepository teamRepository; - private final ExerciseTeamUserRepository exerciseTeamUserRepository; - private final LogRepository exerciseLogRepository; - private final DryRunRepository dryRunRepository; - private final DryInjectRepository dryInjectRepository; - private final ComcheckRepository comcheckRepository; - private final ImportService importService; - private final LessonsCategoryRepository lessonsCategoryRepository; - private final LessonsQuestionRepository lessonsQuestionRepository; - private final LessonsAnswerRepository lessonsAnswerRepository; - private final InjectStatusRepository injectStatusRepository; - private final InjectRepository injectRepository; - private final InjectExpectationRepository injectExpectationRepository; - private final ScenarioRepository scenarioRepository; - private final CommunicationRepository communicationRepository; - private final ObjectiveRepository objectiveRepository; - private final EvaluationRepository evaluationRepository; - private final KillChainPhaseRepository killChainPhaseRepository; - private final GrantRepository grantRepository; - // endregion - - // region services - private final DryrunService dryrunService; - private final FileService fileService; - private final InjectService injectService; - private final ChallengeService challengeService; - private final VariableService variableService; - private final ExerciseService exerciseService; - // endregion - - // region logs - @GetMapping(EXERCISE_URI + "/{exercise}/logs") - public Iterable logs(@PathVariable String exercise) { - return exerciseLogRepository.findAll(ExerciseLogSpecification.fromExercise(exercise)); - } - - @PostMapping(EXERCISE_URI + "/{exerciseId}/logs") - @Transactional(rollbackOn = Exception.class) - public Log createLog(@PathVariable String exerciseId, @Valid @RequestBody LogCreateInput input) { - Exercise exercise = exerciseRepository.findById(exerciseId).orElseThrow(ElementNotFoundException::new); - Log log = new Log(); - log.setUpdateAttributes(input); - log.setExercise(exercise); - log.setTags(iterableToSet(tagRepository.findAllById(input.getTagIds()))); - log.setUser(userRepository.findById(currentUser().getId()).orElseThrow(ElementNotFoundException::new)); - return exerciseLogRepository.save(log); - } - - @PutMapping(EXERCISE_URI + "/{exerciseId}/logs/{logId}") - @PreAuthorize("isExercisePlanner(#exerciseId)") - @Transactional(rollbackOn = Exception.class) - public Log updateLog(@PathVariable String exerciseId, @PathVariable String logId, - @Valid @RequestBody LogCreateInput input) { - Log log = logRepository.findById(logId).orElseThrow(ElementNotFoundException::new); - log.setUpdateAttributes(input); - log.setTags(iterableToSet(tagRepository.findAllById(input.getTagIds()))); - return logRepository.save(log); - } - - @DeleteMapping(EXERCISE_URI + "/{exerciseId}/logs/{logId}") - @PreAuthorize("isExercisePlanner(#exerciseId)") - @Transactional(rollbackOn = Exception.class) - public void deleteLog(@PathVariable String exerciseId, @PathVariable String logId) { - logRepository.deleteById(logId); - } - // endregion - - // region dryruns - @GetMapping(EXERCISE_URI + "/{exerciseId}/dryruns") - public Iterable dryruns(@PathVariable String exerciseId) { - return dryRunRepository.findAll(DryRunSpecification.fromExercise(exerciseId)); - } - - @PostMapping(EXERCISE_URI + "/{exerciseId}/dryruns") - @PreAuthorize("isExercisePlanner(#exerciseId)") - @Transactional(rollbackOn = Exception.class) - public Dryrun createDryrun(@PathVariable String exerciseId, @Valid @RequestBody DryrunCreateInput input) { - Exercise exercise = exerciseRepository.findById(exerciseId).orElseThrow(ElementNotFoundException::new); - List userIds = input.getUserIds(); - List users = userIds.isEmpty() ? List.of( - userRepository.findById(currentUser().getId()).orElseThrow(ElementNotFoundException::new)) - : fromIterable(userRepository.findAllById(userIds)); - return dryrunService.provisionDryrun(exercise, users, input.getName()); - } - - @GetMapping(EXERCISE_URI + "/{exerciseId}/dryruns/{dryrunId}") - @PreAuthorize("isExerciseObserver(#exerciseId)") - public Dryrun dryrun(@PathVariable String exerciseId, @PathVariable String dryrunId) { - Specification filters = DryRunSpecification.fromExercise(exerciseId).and(DryRunSpecification.id(dryrunId)); - return dryRunRepository.findOne(filters).orElseThrow(ElementNotFoundException::new); - } - - @DeleteMapping(EXERCISE_URI + "/{exerciseId}/dryruns/{dryrunId}") - @PreAuthorize("isExercisePlanner(#exerciseId)") - @Transactional(rollbackOn = Exception.class) - public void deleteDryrun(@PathVariable String exerciseId, @PathVariable String dryrunId) { - dryRunRepository.deleteById(dryrunId); - } - - @GetMapping(EXERCISE_URI + "/{exerciseId}/dryruns/{dryrunId}/dryinjects") - @PreAuthorize("isExerciseObserver(#exerciseId)") - public List dryrunInjects(@PathVariable String exerciseId, @PathVariable String dryrunId) { - return dryInjectRepository.findAll(DryInjectSpecification.fromDryRun(dryrunId)); - } - // endregion - - // region comchecks - @GetMapping(EXERCISE_URI + "/{exercise}/comchecks") - public Iterable comchecks(@PathVariable String exercise) { - return comcheckRepository.findAll(ComcheckSpecification.fromExercise(exercise)); - } - - @GetMapping(EXERCISE_URI + "/{exercise}/comchecks/{comcheck}") - public Comcheck comcheck(@PathVariable String exercise, @PathVariable String comcheck) { - Specification filters = ComcheckSpecification.fromExercise(exercise) - .and(ComcheckSpecification.id(comcheck)); - return comcheckRepository.findOne(filters).orElseThrow(ElementNotFoundException::new); - } - - @GetMapping(EXERCISE_URI + "/{exercise}/comchecks/{comcheck}/statuses") - public List comcheckStatuses(@PathVariable String exercise, @PathVariable String comcheck) { - return comcheck(exercise, comcheck).getComcheckStatus(); - } - // endregion - - // region teams - @GetMapping(EXERCISE_URI + "/{exerciseId}/teams") - @PreAuthorize("isExerciseObserver(#exerciseId)") - public Iterable getExerciseTeams(@PathVariable String exerciseId) { - return TeamHelper.rawTeamToSimplerTeam(teamRepository.rawTeamByExerciseId(exerciseId), - injectExpectationRepository, injectRepository, communicationRepository, exerciseTeamUserRepository, scenarioRepository); - } - - @Transactional(rollbackOn = Exception.class) - @PutMapping(EXERCISE_URI + "/{exerciseId}/teams/add") - @PreAuthorize("isExercisePlanner(#exerciseId)") - public Iterable addExerciseTeams( - @PathVariable String exerciseId, - @Valid @RequestBody ExerciseUpdateTeamsInput input) { - Exercise exercise = this.exerciseService.exercise(exerciseId); - // Add teams to exercise - List teams = exercise.getTeams(); - List teamsToAdd = fromIterable(this.teamRepository.findAllById(input.getTeamIds())); - List existingTeamIds = teams.stream().map(Team::getId).toList(); - teams.addAll(teamsToAdd.stream().filter(t -> !existingTeamIds.contains(t.getId())).toList()); - exercise.setTeams(teams); - this.exerciseService.updateExercise(exercise); - return teamsToAdd; - } - - @Transactional(rollbackOn = Exception.class) - @PutMapping(EXERCISE_URI + "/{exerciseId}/teams/remove") - @PreAuthorize("isExercisePlanner(#exerciseId)") - public Iterable removeExerciseTeams(@PathVariable String exerciseId, - @Valid @RequestBody ExerciseUpdateTeamsInput input) { - Exercise exercise = this.exerciseService.exercise(exerciseId); - // Remove teams from exercise - List teams = exercise.getTeams().stream().filter(team -> !input.getTeamIds().contains(team.getId())).toList(); - exercise.setTeams(new ArrayList<>(teams)); - this.exerciseService.updateExercise(exercise); - // Remove all association between users / exercises / teams - input.getTeamIds().forEach(exerciseTeamUserRepository::deleteTeamFromAllReferences); - return teamRepository.findAllById(input.getTeamIds()); - } - - @Transactional(rollbackOn = Exception.class) - @PutMapping(EXERCISE_URI + "/{exerciseId}/teams/replace") - @PreAuthorize("isExercisePlanner(#exerciseId)") - public Iterable replaceExerciseTeams( - @PathVariable String exerciseId, - @Valid @RequestBody ExerciseUpdateTeamsInput input) { - Exercise exercise = this.exerciseService.exercise(exerciseId); - // Replace teams from exercise - List teams = fromIterable(this.teamRepository.findAllById(input.getTeamIds())); - exercise.setTeams(teams); - this.exerciseService.updateExercise(exercise); - return teams; - } - - @Transactional(rollbackOn = Exception.class) - @PutMapping(EXERCISE_URI + "/{exerciseId}/teams/{teamId}/players/enable") - @PreAuthorize("isExercisePlanner(#exerciseId)") - public Exercise enableExerciseTeamPlayers(@PathVariable String exerciseId, @PathVariable String teamId, - @Valid @RequestBody ExerciseTeamPlayersEnableInput input) { - Exercise exercise = exerciseRepository.findById(exerciseId).orElseThrow(ElementNotFoundException::new); - Team team = teamRepository.findById(teamId).orElseThrow(ElementNotFoundException::new); - input.getPlayersIds().forEach(playerId -> { - ExerciseTeamUser exerciseTeamUser = new ExerciseTeamUser(); - exerciseTeamUser.setExercise(exercise); - exerciseTeamUser.setTeam(team); - exerciseTeamUser.setUser(userRepository.findById(playerId).orElseThrow(ElementNotFoundException::new)); - exerciseTeamUserRepository.save(exerciseTeamUser); - }); - return exerciseRepository.findById(exerciseId).orElseThrow(ElementNotFoundException::new); - } - - @Transactional(rollbackOn = Exception.class) - @PutMapping(EXERCISE_URI + "/{exerciseId}/teams/{teamId}/players/disable") - @PreAuthorize("isExercisePlanner(#exerciseId)") - public Exercise disableExerciseTeamPlayers(@PathVariable String exerciseId, @PathVariable String teamId, - @Valid @RequestBody ExerciseTeamPlayersEnableInput input) { - input.getPlayersIds().forEach(playerId -> { - ExerciseTeamUserId exerciseTeamUserId = new ExerciseTeamUserId(); - exerciseTeamUserId.setExerciseId(exerciseId); - exerciseTeamUserId.setTeamId(teamId); - exerciseTeamUserId.setUserId(playerId); - exerciseTeamUserRepository.deleteById(exerciseTeamUserId); - }); - return exerciseRepository.findById(exerciseId).orElseThrow(ElementNotFoundException::new); - } - - @Transactional(rollbackOn = Exception.class) - @PutMapping(EXERCISE_URI + "/{exerciseId}/teams/{teamId}/players/add") - @PreAuthorize("isExercisePlanner(#exerciseId)") - public Exercise addExerciseTeamPlayers(@PathVariable String exerciseId, @PathVariable String teamId, - @Valid @RequestBody ExerciseTeamPlayersEnableInput input) { - Exercise exercise = exerciseRepository.findById(exerciseId).orElseThrow(ElementNotFoundException::new); - Team team = teamRepository.findById(teamId).orElseThrow(ElementNotFoundException::new); - Iterable teamUsers = userRepository.findAllById(input.getPlayersIds()); - team.getUsers().addAll(fromIterable(teamUsers)); - teamRepository.save(team); - input.getPlayersIds().forEach(playerId -> { - ExerciseTeamUser exerciseTeamUser = new ExerciseTeamUser(); - exerciseTeamUser.setExercise(exercise); - exerciseTeamUser.setTeam(team); - exerciseTeamUser.setUser(userRepository.findById(playerId).orElseThrow(ElementNotFoundException::new)); - exerciseTeamUserRepository.save(exerciseTeamUser); - }); - return exercise; - } - - @PutMapping(EXERCISE_URI + "/{exerciseId}/teams/{teamId}/players/remove") - @PreAuthorize("isExercisePlanner(#exerciseId)") - @Transactional(rollbackOn = Exception.class) - public Exercise removeExerciseTeamPlayers(@PathVariable String exerciseId, @PathVariable String teamId, - @Valid @RequestBody ExerciseTeamPlayersEnableInput input) { - Team team = teamRepository.findById(teamId).orElseThrow(ElementNotFoundException::new); - Iterable teamUsers = userRepository.findAllById(input.getPlayersIds()); - team.getUsers().removeAll(fromIterable(teamUsers)); - teamRepository.save(team); - input.getPlayersIds().forEach(playerId -> { - ExerciseTeamUserId exerciseTeamUserId = new ExerciseTeamUserId(); - exerciseTeamUserId.setExerciseId(exerciseId); - exerciseTeamUserId.setTeamId(teamId); - exerciseTeamUserId.setUserId(playerId); - exerciseTeamUserRepository.deleteById(exerciseTeamUserId); - }); - return exerciseRepository.findById(exerciseId).orElseThrow(ElementNotFoundException::new); - } - // endregion - - // region exercises - @PostMapping(EXERCISE_URI) - public Exercise createExercise(@Valid @RequestBody ExerciseCreateInput input) { - if (input == null) { - throw new ResponseStatusException(HttpStatus.BAD_REQUEST, "Exercise input cannot be null"); - } - Exercise exercise = new Exercise(); - exercise.setUpdateAttributes(input); - exercise.setTags(iterableToSet(this.tagRepository.findAllById(input.getTagIds()))); - return this.exerciseService.createExercise(exercise); - } - - @PostMapping(EXERCISE_URI + "/{exerciseId}") - @Transactional(rollbackOn = Exception.class) - public Exercise duplicateExercise(@PathVariable @NotBlank final String exerciseId) { - return exerciseService.getDuplicateExercise(exerciseId); - } - - @PutMapping(EXERCISE_URI + "/{exerciseId}") - @PreAuthorize("isExercisePlanner(#exerciseId)") - @Transactional(rollbackOn = Exception.class) - public Exercise updateExerciseInformation(@PathVariable String exerciseId, - @Valid @RequestBody ExerciseUpdateInput input) { - Exercise exercise = exerciseRepository.findById(exerciseId).orElseThrow(ElementNotFoundException::new); - exercise.setTags(iterableToSet(this.tagRepository.findAllById(input.getTagIds()))); - exercise.setUpdateAttributes(input); - return exerciseRepository.save(exercise); - } - - @PutMapping(EXERCISE_URI + "/{exerciseId}/start_date") - @PreAuthorize("isExercisePlanner(#exerciseId)") - @Transactional(rollbackOn = Exception.class) - public Exercise updateExerciseStart(@PathVariable String exerciseId, - @Valid @RequestBody ExerciseUpdateStartDateInput input) throws InputValidationException { - Exercise exercise = exerciseRepository.findById(exerciseId).orElseThrow(ElementNotFoundException::new); - if (!exercise.getStatus().equals(ExerciseStatus.SCHEDULED)) { - String message = "Change date is only possible in scheduling state"; - throw new InputValidationException("exercise_start_date", message); - } - exercise.setUpdateAttributes(input); - return exerciseRepository.save(exercise); - } - - @PutMapping(EXERCISE_URI + "/{exerciseId}/tags") - @PreAuthorize("isExercisePlanner(#exerciseId)") - @Transactional(rollbackOn = Exception.class) - public Exercise updateExerciseTags(@PathVariable String exerciseId, - @Valid @RequestBody ExerciseUpdateTagsInput input) { - Exercise exercise = exerciseRepository.findById(exerciseId).orElseThrow(ElementNotFoundException::new); - exercise.setTags(iterableToSet(tagRepository.findAllById(input.getTagIds()))); - return exerciseRepository.save(exercise); - } - - @PutMapping(EXERCISE_URI + "/{exerciseId}/logos") - @PreAuthorize("isExercisePlanner(#exerciseId)") - @Transactional(rollbackOn = Exception.class) - public Exercise updateExerciseLogos(@PathVariable String exerciseId, - @Valid @RequestBody ExerciseUpdateLogoInput input) { - Exercise exercise = exerciseRepository.findById(exerciseId).orElseThrow(ElementNotFoundException::new); - exercise.setLogoDark(documentRepository.findById(input.getLogoDark()).orElse(null)); - exercise.setLogoLight(documentRepository.findById(input.getLogoLight()).orElse(null)); - return exerciseRepository.save(exercise); - } - - @PutMapping(EXERCISE_URI + "/{exerciseId}/lessons") - @PreAuthorize("isExercisePlanner(#exerciseId)") - @Transactional(rollbackOn = Exception.class) - public Exercise updateExerciseLessons(@PathVariable String exerciseId, - @Valid @RequestBody LessonsInput input) { - Exercise exercise = exerciseRepository.findById(exerciseId).orElseThrow(ElementNotFoundException::new); - exercise.setLessonsAnonymized(input.isLessonsAnonymized()); - return exerciseRepository.save(exercise); - } - - @DeleteMapping(EXERCISE_URI + "/{exerciseId}") - @PreAuthorize("isExercisePlanner(#exerciseId)") - @Transactional(rollbackOn = Exception.class) - public void deleteExercise(@PathVariable String exerciseId) { - exerciseRepository.deleteById(exerciseId); - } - - @GetMapping(EXERCISE_URI + "/{exerciseId}") - @PreAuthorize("isExerciseObserver(#exerciseId)") - @org.springframework.transaction.annotation.Transactional(readOnly = true) - public ExerciseDetails exercise(@PathVariable String exerciseId) { - // We get the raw exercise - RawExercise rawExercise = exerciseRepository.rawDetailsById(exerciseId); - // We get the injects linked to this exercise - List rawInjects = injectRepository.findRawByIds( - rawExercise.getInject_ids().stream().distinct().toList()); - // We get the tuple exercise/team/user - List listRawExerciseTeamUsers = exerciseTeamUserRepository.rawByExerciseIds( - List.of(exerciseId)); - // We get the objectives of this exercise - List rawObjectives = objectiveRepository.rawByExerciseIds(List.of(exerciseId)); - // We make a map of the Evaluations by objective - Map> mapEvaluationsByObjective = evaluationRepository.rawByObjectiveIds( - rawObjectives.stream() - .map(RawObjective::getObjective_id).toList()).stream() - .collect(Collectors.groupingBy(RawEvaluation::getEvaluation_objective)); - // We make a map of grants of users id by type of grant (Planner, Observer) - Map> rawGrants = grantRepository.rawByExerciseIds(List.of(exerciseId)).stream() - .collect(Collectors.groupingBy(RawGrant::getGrant_name)); - // We get all the kill chain phases - List killChainPhase = StreamSupport.stream( - killChainPhaseRepository.findAllById( - rawInjects.stream().flatMap(rawInject -> rawInject.getInject_kill_chain_phases().stream()).toList() - ).spliterator(), false).collect(Collectors.toList()); - - // We create objectives and fill them with evaluations - List objectives = rawObjectives.stream().map(rawObjective -> { - Objective objective = new Objective(); - if (mapEvaluationsByObjective.get(rawObjective.getObjective_id()) != null) { - objective.setEvaluations(mapEvaluationsByObjective.get(rawObjective.getObjective_id()).stream().map( - rawEvaluation -> { - Evaluation evaluation = new Evaluation(); - evaluation.setId(rawEvaluation.getEvaluation_id()); - evaluation.setScore(rawEvaluation.getEvaluation_score()); - return evaluation; - } - ).toList()); - } - return objective; - }).toList(); - - List listExerciseTeamUsers = listRawExerciseTeamUsers.stream().map( - ExerciseTeamUser::fromRawExerciseTeamUser - ).toList(); - - // From the raw injects, we recreate Injects with minimal objects for calculations - List injects = rawInjects.stream().map(rawInject -> { - Inject inject = new Inject(); - if (rawInject.getInject_scenario() != null) { - inject.setScenario(new Scenario()); - inject.getScenario().setId(rawInject.getInject_scenario()); - } - // We set the communications - inject.setCommunications(rawInject.getInject_communications().stream().map(com -> { - Communication communication = new Communication(); - communication.setId(com); - return communication; - }).toList()); - // We set the status too - if (rawInject.getStatus_name() != null) { - InjectStatus injectStatus = new InjectStatus(); - injectStatus.setName(ExecutionStatus.valueOf(rawInject.getStatus_name())); - inject.setStatus(injectStatus); - } - // We recreate an exercise out of the raw exercise - Exercise exercise = new Exercise(); - exercise.setStatus(ExerciseStatus.valueOf(rawExercise.getExercise_status())); - exercise.setStart(rawExercise.getExercise_start_date()); - exercise.setPauses( - // We set the pauses as they are used for calculations - pauseRepository.rawAllForExercise(exerciseId).stream().map(rawPause -> { - Pause pause = new Pause(); - pause.setExercise(new Exercise()); - pause.getExercise().setId(exerciseId); - pause.setDate(rawPause.getPause_date()); - pause.setId(rawPause.getPause_id()); - pause.setDuration(rawPause.getPause_duration()); - return pause; - }).toList() - ); - exercise.setCurrentPause(rawExercise.getExercise_pause_date()); - inject.setExercise(exercise); - return inject; - }).toList(); - - // We create an ExerciseDetails object and populate it - ExerciseDetails detail = ExerciseDetails.fromRawExercise(rawExercise, injects, listExerciseTeamUsers, objectives); - detail.setPlatforms( - rawInjects.stream().flatMap(inject -> inject.getInject_platforms().stream()).distinct().toList()); - detail.setCommunicationsNumber( - rawInjects.stream().mapToLong(rawInject -> rawInject.getInject_communications().size()).sum()); - detail.setKillChainPhases(killChainPhase); - if (rawGrants.get(Grant.GRANT_TYPE.OBSERVER.name()) != null) { - detail.setObservers(rawGrants.get(Grant.GRANT_TYPE.OBSERVER.name()).stream().map(RawGrant::getUser_id) - .collect(Collectors.toSet())); - } - if (rawGrants.get(Grant.GRANT_TYPE.PLANNER.name()) != null) { - detail.setPlanners(rawGrants.get(Grant.GRANT_TYPE.PLANNER.name()).stream().map(RawGrant::getUser_id) - .collect(Collectors.toSet())); - } - - return detail; - } - - @LogExecutionTime - @GetMapping(EXERCISE_URI + "/{exerciseId}/results") - @PreAuthorize("isExerciseObserver(#exerciseId)") - public List globalResults(@NotBlank @PathVariable String exerciseId) { - return exerciseService.getGlobalResults(exerciseId); - } - - @GetMapping(EXERCISE_URI + "/{exerciseId}/injects/results") - @PreAuthorize("isExerciseObserver(#exerciseId)") - public List injectResults(@NotBlank final @PathVariable String exerciseId) { - return exerciseRepository.findById(exerciseId) - .map(Exercise::getInjects) - .map(ResultUtils::computeInjectExpectationResults) - .orElseThrow(() -> new RuntimeException("Exercise not found with ID: " + exerciseId)); - } - - @DeleteMapping(EXERCISE_URI + "/{exerciseId}/{documentId}") - @PreAuthorize("isExercisePlanner(#exerciseId)") - @Transactional(rollbackOn = Exception.class) - public Exercise deleteDocument(@PathVariable String exerciseId, @PathVariable String documentId) { - Exercise exercise = exerciseRepository.findById(exerciseId).orElseThrow(ElementNotFoundException::new); - exercise.setUpdatedAt(now()); - Document doc = documentRepository.findById(documentId).orElseThrow(ElementNotFoundException::new); - Set docExercises = doc.getExercises().stream().filter(ex -> !ex.getId().equals(exerciseId)) - .collect(Collectors.toSet()); - if (docExercises.isEmpty()) { - // Document is no longer associate to any exercise, delete it - documentRepository.delete(doc); - // All associations with this document will be automatically cleanup. - } else { - // Document associated to other exercise, cleanup - doc.setExercises(docExercises); - documentRepository.save(doc); - // Delete document from all exercise injects - injectService.cleanInjectsDocExercise(exerciseId, documentId); - } - return exerciseRepository.save(exercise); - } - - @PutMapping(EXERCISE_URI + "/{exerciseId}/status") - @PreAuthorize("isExercisePlanner(#exerciseId)") - @Transactional(rollbackOn = Exception.class) - public Exercise changeExerciseStatus( - @PathVariable String exerciseId, - @Valid @RequestBody ExerciseUpdateStatusInput input) { - ExerciseStatus status = input.getStatus(); - Exercise exercise = this.exerciseRepository.findById(exerciseId).orElseThrow(ElementNotFoundException::new); - // Check if next status is possible - List nextPossibleStatus = exercise.nextPossibleStatus(); - if (!nextPossibleStatus.contains(status)) { - throw new UnsupportedOperationException("Exercise cant support moving to status " + status.name()); - } - // In case of rescheduled of an exercise. - boolean isCloseState = - ExerciseStatus.CANCELED.equals(exercise.getStatus()) || ExerciseStatus.FINISHED.equals(exercise.getStatus()); - if (isCloseState && ExerciseStatus.SCHEDULED.equals(status)) { - exercise.setStart(null); - exercise.setEnd(null); - // Reset pauses - exercise.setCurrentPause(null); - pauseRepository.deleteAll(pauseRepository.findAllForExercise(exerciseId)); - // Reset injects outcome, communications and expectations - this.injectStatusRepository.deleteAllById( - exercise.getInjects() - .stream() - .map(Inject::getStatus) - .map(i -> i.map(InjectStatus::getId).orElse("")) + public static final String EXERCISE_URI = "/api/exercises"; + + private static final Logger LOGGER = Logger.getLogger(ExerciseApi.class.getName()); + + // region repositories + private final LogRepository logRepository; + private final TagRepository tagRepository; + private final UserRepository userRepository; + private final PauseRepository pauseRepository; + private final DocumentRepository documentRepository; + private final ExerciseRepository exerciseRepository; + private final TeamRepository teamRepository; + private final ExerciseTeamUserRepository exerciseTeamUserRepository; + private final LogRepository exerciseLogRepository; + private final DryRunRepository dryRunRepository; + private final DryInjectRepository dryInjectRepository; + private final ComcheckRepository comcheckRepository; + private final ImportService importService; + private final LessonsCategoryRepository lessonsCategoryRepository; + private final LessonsQuestionRepository lessonsQuestionRepository; + private final LessonsAnswerRepository lessonsAnswerRepository; + private final InjectStatusRepository injectStatusRepository; + private final InjectRepository injectRepository; + private final InjectExpectationRepository injectExpectationRepository; + private final ScenarioRepository scenarioRepository; + private final CommunicationRepository communicationRepository; + private final ObjectiveRepository objectiveRepository; + private final EvaluationRepository evaluationRepository; + private final KillChainPhaseRepository killChainPhaseRepository; + private final GrantRepository grantRepository; + // endregion + + // region services + private final DryrunService dryrunService; + private final FileService fileService; + private final InjectService injectService; + private final ChallengeService challengeService; + private final VariableService variableService; + private final ExerciseService exerciseService; + + // endregion + + // region logs + @GetMapping(EXERCISE_URI + "/{exercise}/logs") + public Iterable logs(@PathVariable String exercise) { + return exerciseLogRepository.findAll(ExerciseLogSpecification.fromExercise(exercise)); + } + + @PostMapping(EXERCISE_URI + "/{exerciseId}/logs") + @Transactional(rollbackOn = Exception.class) + public Log createLog(@PathVariable String exerciseId, @Valid @RequestBody LogCreateInput input) { + Exercise exercise = + exerciseRepository.findById(exerciseId).orElseThrow(ElementNotFoundException::new); + Log log = new Log(); + log.setUpdateAttributes(input); + log.setExercise(exercise); + log.setTags(iterableToSet(tagRepository.findAllById(input.getTagIds()))); + log.setUser( + userRepository.findById(currentUser().getId()).orElseThrow(ElementNotFoundException::new)); + return exerciseLogRepository.save(log); + } + + @PutMapping(EXERCISE_URI + "/{exerciseId}/logs/{logId}") + @PreAuthorize("isExercisePlanner(#exerciseId)") + @Transactional(rollbackOn = Exception.class) + public Log updateLog( + @PathVariable String exerciseId, + @PathVariable String logId, + @Valid @RequestBody LogCreateInput input) { + Log log = logRepository.findById(logId).orElseThrow(ElementNotFoundException::new); + log.setUpdateAttributes(input); + log.setTags(iterableToSet(tagRepository.findAllById(input.getTagIds()))); + return logRepository.save(log); + } + + @DeleteMapping(EXERCISE_URI + "/{exerciseId}/logs/{logId}") + @PreAuthorize("isExercisePlanner(#exerciseId)") + @Transactional(rollbackOn = Exception.class) + public void deleteLog(@PathVariable String exerciseId, @PathVariable String logId) { + logRepository.deleteById(logId); + } + + // endregion + + // region dryruns + @GetMapping(EXERCISE_URI + "/{exerciseId}/dryruns") + public Iterable dryruns(@PathVariable String exerciseId) { + return dryRunRepository.findAll(DryRunSpecification.fromExercise(exerciseId)); + } + + @PostMapping(EXERCISE_URI + "/{exerciseId}/dryruns") + @PreAuthorize("isExercisePlanner(#exerciseId)") + @Transactional(rollbackOn = Exception.class) + public Dryrun createDryrun( + @PathVariable String exerciseId, @Valid @RequestBody DryrunCreateInput input) { + Exercise exercise = + exerciseRepository.findById(exerciseId).orElseThrow(ElementNotFoundException::new); + List userIds = input.getUserIds(); + List users = + userIds.isEmpty() + ? List.of( + userRepository + .findById(currentUser().getId()) + .orElseThrow(ElementNotFoundException::new)) + : fromIterable(userRepository.findAllById(userIds)); + return dryrunService.provisionDryrun(exercise, users, input.getName()); + } + + @GetMapping(EXERCISE_URI + "/{exerciseId}/dryruns/{dryrunId}") + @PreAuthorize("isExerciseObserver(#exerciseId)") + public Dryrun dryrun(@PathVariable String exerciseId, @PathVariable String dryrunId) { + Specification filters = + DryRunSpecification.fromExercise(exerciseId).and(DryRunSpecification.id(dryrunId)); + return dryRunRepository.findOne(filters).orElseThrow(ElementNotFoundException::new); + } + + @DeleteMapping(EXERCISE_URI + "/{exerciseId}/dryruns/{dryrunId}") + @PreAuthorize("isExercisePlanner(#exerciseId)") + @Transactional(rollbackOn = Exception.class) + public void deleteDryrun(@PathVariable String exerciseId, @PathVariable String dryrunId) { + dryRunRepository.deleteById(dryrunId); + } + + @GetMapping(EXERCISE_URI + "/{exerciseId}/dryruns/{dryrunId}/dryinjects") + @PreAuthorize("isExerciseObserver(#exerciseId)") + public List dryrunInjects( + @PathVariable String exerciseId, @PathVariable String dryrunId) { + return dryInjectRepository.findAll(DryInjectSpecification.fromDryRun(dryrunId)); + } + + // endregion + + // region comchecks + @GetMapping(EXERCISE_URI + "/{exercise}/comchecks") + public Iterable comchecks(@PathVariable String exercise) { + return comcheckRepository.findAll(ComcheckSpecification.fromExercise(exercise)); + } + + @GetMapping(EXERCISE_URI + "/{exercise}/comchecks/{comcheck}") + public Comcheck comcheck(@PathVariable String exercise, @PathVariable String comcheck) { + Specification filters = + ComcheckSpecification.fromExercise(exercise).and(ComcheckSpecification.id(comcheck)); + return comcheckRepository.findOne(filters).orElseThrow(ElementNotFoundException::new); + } + + @GetMapping(EXERCISE_URI + "/{exercise}/comchecks/{comcheck}/statuses") + public List comcheckStatuses( + @PathVariable String exercise, @PathVariable String comcheck) { + return comcheck(exercise, comcheck).getComcheckStatus(); + } + + // endregion + + // region teams + @GetMapping(EXERCISE_URI + "/{exerciseId}/teams") + @PreAuthorize("isExerciseObserver(#exerciseId)") + public Iterable getExerciseTeams(@PathVariable String exerciseId) { + return TeamHelper.rawTeamToSimplerTeam( + teamRepository.rawTeamByExerciseId(exerciseId), + injectExpectationRepository, + injectRepository, + communicationRepository, + exerciseTeamUserRepository, + scenarioRepository); + } + + @Transactional(rollbackOn = Exception.class) + @PutMapping(EXERCISE_URI + "/{exerciseId}/teams/add") + @PreAuthorize("isExercisePlanner(#exerciseId)") + public Iterable addExerciseTeams( + @PathVariable String exerciseId, @Valid @RequestBody ExerciseUpdateTeamsInput input) { + Exercise exercise = this.exerciseService.exercise(exerciseId); + // Add teams to exercise + List teams = exercise.getTeams(); + List teamsToAdd = fromIterable(this.teamRepository.findAllById(input.getTeamIds())); + List existingTeamIds = teams.stream().map(Team::getId).toList(); + teams.addAll(teamsToAdd.stream().filter(t -> !existingTeamIds.contains(t.getId())).toList()); + exercise.setTeams(teams); + this.exerciseService.updateExercise(exercise); + return teamsToAdd; + } + + @Transactional(rollbackOn = Exception.class) + @PutMapping(EXERCISE_URI + "/{exerciseId}/teams/remove") + @PreAuthorize("isExercisePlanner(#exerciseId)") + public Iterable removeExerciseTeams( + @PathVariable String exerciseId, @Valid @RequestBody ExerciseUpdateTeamsInput input) { + Exercise exercise = this.exerciseService.exercise(exerciseId); + // Remove teams from exercise + List teams = + exercise.getTeams().stream() + .filter(team -> !input.getTeamIds().contains(team.getId())) + .toList(); + exercise.setTeams(new ArrayList<>(teams)); + this.exerciseService.updateExercise(exercise); + // Remove all association between users / exercises / teams + input.getTeamIds().forEach(exerciseTeamUserRepository::deleteTeamFromAllReferences); + return teamRepository.findAllById(input.getTeamIds()); + } + + @Transactional(rollbackOn = Exception.class) + @PutMapping(EXERCISE_URI + "/{exerciseId}/teams/replace") + @PreAuthorize("isExercisePlanner(#exerciseId)") + public Iterable replaceExerciseTeams( + @PathVariable String exerciseId, @Valid @RequestBody ExerciseUpdateTeamsInput input) { + Exercise exercise = this.exerciseService.exercise(exerciseId); + // Replace teams from exercise + List teams = fromIterable(this.teamRepository.findAllById(input.getTeamIds())); + exercise.setTeams(teams); + this.exerciseService.updateExercise(exercise); + return teams; + } + + @Transactional(rollbackOn = Exception.class) + @PutMapping(EXERCISE_URI + "/{exerciseId}/teams/{teamId}/players/enable") + @PreAuthorize("isExercisePlanner(#exerciseId)") + public Exercise enableExerciseTeamPlayers( + @PathVariable String exerciseId, + @PathVariable String teamId, + @Valid @RequestBody ExerciseTeamPlayersEnableInput input) { + Exercise exercise = + exerciseRepository.findById(exerciseId).orElseThrow(ElementNotFoundException::new); + Team team = teamRepository.findById(teamId).orElseThrow(ElementNotFoundException::new); + input + .getPlayersIds() + .forEach( + playerId -> { + ExerciseTeamUser exerciseTeamUser = new ExerciseTeamUser(); + exerciseTeamUser.setExercise(exercise); + exerciseTeamUser.setTeam(team); + exerciseTeamUser.setUser( + userRepository.findById(playerId).orElseThrow(ElementNotFoundException::new)); + exerciseTeamUserRepository.save(exerciseTeamUser); + }); + return exerciseRepository.findById(exerciseId).orElseThrow(ElementNotFoundException::new); + } + + @Transactional(rollbackOn = Exception.class) + @PutMapping(EXERCISE_URI + "/{exerciseId}/teams/{teamId}/players/disable") + @PreAuthorize("isExercisePlanner(#exerciseId)") + public Exercise disableExerciseTeamPlayers( + @PathVariable String exerciseId, + @PathVariable String teamId, + @Valid @RequestBody ExerciseTeamPlayersEnableInput input) { + input + .getPlayersIds() + .forEach( + playerId -> { + ExerciseTeamUserId exerciseTeamUserId = new ExerciseTeamUserId(); + exerciseTeamUserId.setExerciseId(exerciseId); + exerciseTeamUserId.setTeamId(teamId); + exerciseTeamUserId.setUserId(playerId); + exerciseTeamUserRepository.deleteById(exerciseTeamUserId); + }); + return exerciseRepository.findById(exerciseId).orElseThrow(ElementNotFoundException::new); + } + + @Transactional(rollbackOn = Exception.class) + @PutMapping(EXERCISE_URI + "/{exerciseId}/teams/{teamId}/players/add") + @PreAuthorize("isExercisePlanner(#exerciseId)") + public Exercise addExerciseTeamPlayers( + @PathVariable String exerciseId, + @PathVariable String teamId, + @Valid @RequestBody ExerciseTeamPlayersEnableInput input) { + Exercise exercise = + exerciseRepository.findById(exerciseId).orElseThrow(ElementNotFoundException::new); + Team team = teamRepository.findById(teamId).orElseThrow(ElementNotFoundException::new); + Iterable teamUsers = userRepository.findAllById(input.getPlayersIds()); + team.getUsers().addAll(fromIterable(teamUsers)); + teamRepository.save(team); + input + .getPlayersIds() + .forEach( + playerId -> { + ExerciseTeamUser exerciseTeamUser = new ExerciseTeamUser(); + exerciseTeamUser.setExercise(exercise); + exerciseTeamUser.setTeam(team); + exerciseTeamUser.setUser( + userRepository.findById(playerId).orElseThrow(ElementNotFoundException::new)); + exerciseTeamUserRepository.save(exerciseTeamUser); + }); + return exercise; + } + + @PutMapping(EXERCISE_URI + "/{exerciseId}/teams/{teamId}/players/remove") + @PreAuthorize("isExercisePlanner(#exerciseId)") + @Transactional(rollbackOn = Exception.class) + public Exercise removeExerciseTeamPlayers( + @PathVariable String exerciseId, + @PathVariable String teamId, + @Valid @RequestBody ExerciseTeamPlayersEnableInput input) { + Team team = teamRepository.findById(teamId).orElseThrow(ElementNotFoundException::new); + Iterable teamUsers = userRepository.findAllById(input.getPlayersIds()); + team.getUsers().removeAll(fromIterable(teamUsers)); + teamRepository.save(team); + input + .getPlayersIds() + .forEach( + playerId -> { + ExerciseTeamUserId exerciseTeamUserId = new ExerciseTeamUserId(); + exerciseTeamUserId.setExerciseId(exerciseId); + exerciseTeamUserId.setTeamId(teamId); + exerciseTeamUserId.setUserId(playerId); + exerciseTeamUserRepository.deleteById(exerciseTeamUserId); + }); + return exerciseRepository.findById(exerciseId).orElseThrow(ElementNotFoundException::new); + } + + // endregion + + // region exercises + @PostMapping(EXERCISE_URI) + public Exercise createExercise(@Valid @RequestBody ExerciseCreateInput input) { + if (input == null) { + throw new ResponseStatusException(HttpStatus.BAD_REQUEST, "Exercise input cannot be null"); + } + Exercise exercise = new Exercise(); + exercise.setUpdateAttributes(input); + exercise.setTags(iterableToSet(this.tagRepository.findAllById(input.getTagIds()))); + return this.exerciseService.createExercise(exercise); + } + + @PostMapping(EXERCISE_URI + "/{exerciseId}") + @Transactional(rollbackOn = Exception.class) + public Exercise duplicateExercise(@PathVariable @NotBlank final String exerciseId) { + return exerciseService.getDuplicateExercise(exerciseId); + } + + @PutMapping(EXERCISE_URI + "/{exerciseId}") + @PreAuthorize("isExercisePlanner(#exerciseId)") + @Transactional(rollbackOn = Exception.class) + public Exercise updateExerciseInformation( + @PathVariable String exerciseId, @Valid @RequestBody ExerciseUpdateInput input) { + Exercise exercise = + exerciseRepository.findById(exerciseId).orElseThrow(ElementNotFoundException::new); + exercise.setTags(iterableToSet(this.tagRepository.findAllById(input.getTagIds()))); + exercise.setUpdateAttributes(input); + return exerciseRepository.save(exercise); + } + + @PutMapping(EXERCISE_URI + "/{exerciseId}/start_date") + @PreAuthorize("isExercisePlanner(#exerciseId)") + @Transactional(rollbackOn = Exception.class) + public Exercise updateExerciseStart( + @PathVariable String exerciseId, @Valid @RequestBody ExerciseUpdateStartDateInput input) + throws InputValidationException { + Exercise exercise = + exerciseRepository.findById(exerciseId).orElseThrow(ElementNotFoundException::new); + if (!exercise.getStatus().equals(ExerciseStatus.SCHEDULED)) { + String message = "Change date is only possible in scheduling state"; + throw new InputValidationException("exercise_start_date", message); + } + exercise.setUpdateAttributes(input); + return exerciseRepository.save(exercise); + } + + @PutMapping(EXERCISE_URI + "/{exerciseId}/tags") + @PreAuthorize("isExercisePlanner(#exerciseId)") + @Transactional(rollbackOn = Exception.class) + public Exercise updateExerciseTags( + @PathVariable String exerciseId, @Valid @RequestBody ExerciseUpdateTagsInput input) { + Exercise exercise = + exerciseRepository.findById(exerciseId).orElseThrow(ElementNotFoundException::new); + exercise.setTags(iterableToSet(tagRepository.findAllById(input.getTagIds()))); + return exerciseRepository.save(exercise); + } + + @PutMapping(EXERCISE_URI + "/{exerciseId}/logos") + @PreAuthorize("isExercisePlanner(#exerciseId)") + @Transactional(rollbackOn = Exception.class) + public Exercise updateExerciseLogos( + @PathVariable String exerciseId, @Valid @RequestBody ExerciseUpdateLogoInput input) { + Exercise exercise = + exerciseRepository.findById(exerciseId).orElseThrow(ElementNotFoundException::new); + exercise.setLogoDark(documentRepository.findById(input.getLogoDark()).orElse(null)); + exercise.setLogoLight(documentRepository.findById(input.getLogoLight()).orElse(null)); + return exerciseRepository.save(exercise); + } + + @PutMapping(EXERCISE_URI + "/{exerciseId}/lessons") + @PreAuthorize("isExercisePlanner(#exerciseId)") + @Transactional(rollbackOn = Exception.class) + public Exercise updateExerciseLessons( + @PathVariable String exerciseId, @Valid @RequestBody LessonsInput input) { + Exercise exercise = + exerciseRepository.findById(exerciseId).orElseThrow(ElementNotFoundException::new); + exercise.setLessonsAnonymized(input.isLessonsAnonymized()); + return exerciseRepository.save(exercise); + } + + @DeleteMapping(EXERCISE_URI + "/{exerciseId}") + @PreAuthorize("isExercisePlanner(#exerciseId)") + @Transactional(rollbackOn = Exception.class) + public void deleteExercise(@PathVariable String exerciseId) { + exerciseRepository.deleteById(exerciseId); + } + + @GetMapping(EXERCISE_URI + "/{exerciseId}") + @PreAuthorize("isExerciseObserver(#exerciseId)") + @org.springframework.transaction.annotation.Transactional(readOnly = true) + public ExerciseDetails exercise(@PathVariable String exerciseId) { + // We get the raw exercise + RawExercise rawExercise = exerciseRepository.rawDetailsById(exerciseId); + // We get the injects linked to this exercise + List rawInjects = + injectRepository.findRawByIds(rawExercise.getInject_ids().stream().distinct().toList()); + // We get the tuple exercise/team/user + List listRawExerciseTeamUsers = + exerciseTeamUserRepository.rawByExerciseIds(List.of(exerciseId)); + // We get the objectives of this exercise + List rawObjectives = objectiveRepository.rawByExerciseIds(List.of(exerciseId)); + // We make a map of the Evaluations by objective + Map> mapEvaluationsByObjective = + evaluationRepository + .rawByObjectiveIds(rawObjectives.stream().map(RawObjective::getObjective_id).toList()) + .stream() + .collect(Collectors.groupingBy(RawEvaluation::getEvaluation_objective)); + // We make a map of grants of users id by type of grant (Planner, Observer) + Map> rawGrants = + grantRepository.rawByExerciseIds(List.of(exerciseId)).stream() + .collect(Collectors.groupingBy(RawGrant::getGrant_name)); + // We get all the kill chain phases + List killChainPhase = + StreamSupport.stream( + killChainPhaseRepository + .findAllById( + rawInjects.stream() + .flatMap(rawInject -> rawInject.getInject_kill_chain_phases().stream()) + .toList()) + .spliterator(), + false) + .collect(Collectors.toList()); + + // We create objectives and fill them with evaluations + List objectives = + rawObjectives.stream() + .map( + rawObjective -> { + Objective objective = new Objective(); + if (mapEvaluationsByObjective.get(rawObjective.getObjective_id()) != null) { + objective.setEvaluations( + mapEvaluationsByObjective.get(rawObjective.getObjective_id()).stream() + .map( + rawEvaluation -> { + Evaluation evaluation = new Evaluation(); + evaluation.setId(rawEvaluation.getEvaluation_id()); + evaluation.setScore(rawEvaluation.getEvaluation_score()); + return evaluation; + }) .toList()); - exercise.getInjects().forEach(Inject::clean); - // Reset lessons learned answers - List lessonsAnswers = lessonsCategoryRepository.findAll( - LessonsCategorySpecification.fromExercise(exerciseId)).stream().flatMap( - lessonsCategory -> lessonsQuestionRepository.findAll( - LessonsQuestionSpecification.fromCategory(lessonsCategory.getId())).stream().flatMap( - lessonsQuestion -> lessonsAnswerRepository.findAll( - LessonsAnswerSpecification.fromQuestion(lessonsQuestion.getId())).stream())).toList(); - lessonsAnswerRepository.deleteAll(lessonsAnswers); - // Delete exercise transient files (communications, ...) - fileService.deleteDirectory(exerciseId); - } - // In case of manual start - if (ExerciseStatus.SCHEDULED.equals(exercise.getStatus()) && ExerciseStatus.RUNNING.equals(status)) { - Instant nextMinute = now().truncatedTo(MINUTES).plus(1, MINUTES); - exercise.setStart(nextMinute); - } - // If exercise move from pause to running state, - // we log the pause date to be able to recompute inject dates. - if (ExerciseStatus.PAUSED.equals(exercise.getStatus()) && ExerciseStatus.RUNNING.equals(status)) { - Instant lastPause = exercise.getCurrentPause().orElseThrow(ElementNotFoundException::new); - exercise.setCurrentPause(null); - Pause pause = new Pause(); - pause.setDate(lastPause); - pause.setExercise(exercise); - pause.setDuration(between(lastPause, now()).getSeconds()); - pauseRepository.save(pause); - } - // If pause is asked, just set the pause date. - if (ExerciseStatus.RUNNING.equals(exercise.getStatus()) && ExerciseStatus.PAUSED.equals(status)) { - exercise.setCurrentPause(Instant.now()); - } - // Cancelation - if (ExerciseStatus.RUNNING.equals(exercise.getStatus()) && ExerciseStatus.CANCELED.equals(status)) { - exercise.setEnd(now()); - } - exercise.setUpdatedAt(now()); - exercise.setStatus(status); - return exerciseRepository.save(exercise); - } - - @LogExecutionTime - @GetMapping(EXERCISE_URI) - public List exercises() { - return exerciseService.exercises(); - } - - @LogExecutionTime - @PostMapping(EXERCISE_URI + "/search") - public Page exercises(@RequestBody @Valid final SearchPaginationInput searchPaginationInput) { - if (currentUser().isAdmin()) { - return buildPaginationCriteriaBuilder( - this.exerciseService::exercises, - searchPaginationInput, - Exercise.class - ); - } else { - return buildPaginationCriteriaBuilder( - (Specification specification, Specification specificationCount, Pageable pageable) -> this.exerciseService.exercises( - findGrantedFor(currentUser().getId()).and(specification), - findGrantedFor(currentUser().getId()).and(specificationCount), - pageable - ), - searchPaginationInput, - Exercise.class - ); - } - } - - // endregion - - // region communication - @GetMapping(EXERCISE_URI + "/{exerciseId}/communications") - @PreAuthorize("isExerciseObserver(#exerciseId)") - public Iterable exerciseCommunications(@PathVariable String exerciseId) { - Exercise exercise = exerciseRepository.findById(exerciseId).orElseThrow(ElementNotFoundException::new); - List communications = new ArrayList<>(); - exercise.getInjects().forEach(injectDoc -> communications.addAll(injectDoc.getCommunications())); - return communications; - } - - @GetMapping("/api/communications/attachment") - // @PreAuthorize("isExerciseObserver(#exerciseId)") - public void downloadAttachment(@RequestParam String file, HttpServletResponse response) throws IOException { - FileContainer fileContainer = fileService.getFileContainer(file).orElseThrow(ElementNotFoundException::new); - response.addHeader(HttpHeaders.CONTENT_DISPOSITION, "attachment; filename=" + fileContainer.getName()); - response.addHeader(HttpHeaders.CONTENT_TYPE, fileContainer.getContentType()); - response.setStatus(HttpServletResponse.SC_OK); - fileContainer.getInputStream().transferTo(response.getOutputStream()); - } - // endregion - - // region import/export - @GetMapping(EXERCISE_URI + "/{exerciseId}/export") - @PreAuthorize("isExerciseObserver(#exerciseId)") - public void exerciseExport(@NotBlank @PathVariable final String exerciseId, - @RequestParam(required = false) final boolean isWithTeams, - @RequestParam(required = false) final boolean isWithPlayers, - @RequestParam(required = false) final boolean isWithVariableValues, HttpServletResponse response) - throws IOException { - // Setup the mapper for export - List documentIds = new ArrayList<>(); - ObjectMapper objectMapper = mapper.copy(); - if (!isWithPlayers) { - objectMapper.addMixIn(ExerciseFileExport.class, ExerciseExportMixins.ExerciseFileExport.class); - } - // Start exporting exercise - ExerciseFileExport importExport = new ExerciseFileExport(); - importExport.setVersion(1); - Exercise exercise = exerciseRepository.findById(exerciseId).orElseThrow(ElementNotFoundException::new); - objectMapper.addMixIn(Exercise.class, ExerciseExportMixins.Exercise.class); - // Build the export - importExport.setExercise(exercise); - importExport.setDocuments(exercise.getDocuments()); - documentIds.addAll(exercise.getDocuments().stream().map(Document::getId).toList()); - objectMapper.addMixIn(Document.class, ExerciseExportMixins.Document.class); - List exerciseTags = new ArrayList<>(exercise.getTags()); - // Objectives - List objectives = exercise.getObjectives(); - importExport.setObjectives(objectives); - objectMapper.addMixIn(Objective.class, ExerciseExportMixins.Objective.class); - // Lessons categories - List lessonsCategories = exercise.getLessonsCategories(); - importExport.setLessonsCategories(lessonsCategories); - objectMapper.addMixIn(LessonsCategory.class, ExerciseExportMixins.LessonsCategory.class); - // Lessons questions - List lessonsQuestions = lessonsCategories.stream() - .flatMap(category -> category.getQuestions().stream()).toList(); - importExport.setLessonsQuestions(lessonsQuestions); - objectMapper.addMixIn(LessonsQuestion.class, ExerciseExportMixins.LessonsQuestion.class); - if (isWithTeams) { - // Teams - List teams = exercise.getTeams(); - importExport.setTeams(teams); - objectMapper.addMixIn(Team.class, - isWithPlayers ? ExerciseExportMixins.Team.class : ExerciseExportMixins.EmptyTeam.class); - exerciseTags.addAll(teams.stream().flatMap(team -> team.getTags().stream()).toList()); - } - if (isWithPlayers) { - // players - List players = exercise.getTeams().stream().flatMap(team -> team.getUsers().stream()).distinct().toList(); - exerciseTags.addAll(players.stream().flatMap(user -> user.getTags().stream()).toList()); - importExport.setUsers(players); - objectMapper.addMixIn(User.class, ExerciseExportMixins.User.class); - // organizations - List organizations = players.stream() - .map(User::getOrganization) - .filter(Objects::nonNull) - .distinct() - .toList(); - exerciseTags.addAll(organizations.stream().flatMap(org -> org.getTags().stream()).toList()); - importExport.setOrganizations(organizations); - objectMapper.addMixIn(Organization.class, ExerciseExportMixins.Organization.class); - } - // Injects - List injects = exercise.getInjects(); - exerciseTags.addAll(injects.stream().flatMap(inject -> inject.getTags().stream()).toList()); - importExport.setInjects(injects); - objectMapper.addMixIn(Inject.class, ExerciseExportMixins.Inject.class); - // Documents - exerciseTags.addAll(exercise.getDocuments().stream().flatMap(doc -> doc.getTags().stream()).toList()); - // Articles / Channels - List
articles = exercise.getArticles(); - importExport.setArticles(articles); - objectMapper.addMixIn(Article.class, ExerciseExportMixins.Article.class); - List channels = articles.stream().map(Article::getChannel).distinct().toList(); - documentIds.addAll(channels.stream().flatMap(channel -> channel.getLogos().stream()).map(Document::getId).toList()); - importExport.setChannels(channels); - objectMapper.addMixIn(Channel.class, ExerciseExportMixins.Channel.class); - // Challenges - List challenges = fromIterable(challengeService.getExerciseChallenges(exerciseId)); - importExport.setChallenges(challenges); - documentIds.addAll( - challenges.stream().flatMap(challenge -> challenge.getDocuments().stream()).map(Document::getId).toList()); - objectMapper.addMixIn(Challenge.class, ExerciseExportMixins.Challenge.class); - exerciseTags.addAll(challenges.stream().flatMap(challenge -> challenge.getTags().stream()).toList()); - // Tags - importExport.setTags(exerciseTags.stream().distinct().toList()); - objectMapper.addMixIn(Tag.class, ExerciseExportMixins.Tag.class); - // -- Variables -- - List variables = this.variableService.variablesFromExercise(exerciseId); - importExport.setVariables(variables); - if (isWithVariableValues) { - objectMapper.addMixIn(Variable.class, VariableWithValueMixin.class); - } else { - objectMapper.addMixIn(Variable.class, VariableMixin.class); - } - // Build the response - String infos = "(" + - (isWithTeams ? "with_teams" : "no_teams") + - " & " + - (isWithPlayers ? "with_players" : "no_players") + - " & " + - (isWithVariableValues ? "with_variable_values" : "no_variable_values") + - ")"; - String zipName = (exercise.getName() + "_" + now().toString()) + "_" + infos + ".zip"; - response.addHeader(HttpHeaders.CONTENT_DISPOSITION, "attachment; filename=" + zipName); - response.addHeader(HttpHeaders.CONTENT_TYPE, "application/zip"); - response.setStatus(HttpServletResponse.SC_OK); - ZipOutputStream zipExport = new ZipOutputStream(response.getOutputStream()); - ZipEntry zipEntry = new ZipEntry(exercise.getName() + ".json"); - zipEntry.setComment(EXPORT_ENTRY_EXERCISE); - zipExport.putNextEntry(zipEntry); - zipExport.write(objectMapper.writerWithDefaultPrettyPrinter().writeValueAsBytes(importExport)); - zipExport.closeEntry(); - // Add the documents - documentIds.stream().distinct().forEach(docId -> { - Document doc = documentRepository.findById(docId).orElseThrow(ElementNotFoundException::new); - Optional docStream = fileService.getFile(doc); - if (docStream.isPresent()) { + } + return objective; + }) + .toList(); + + List listExerciseTeamUsers = + listRawExerciseTeamUsers.stream().map(ExerciseTeamUser::fromRawExerciseTeamUser).toList(); + + // From the raw injects, we recreate Injects with minimal objects for calculations + List injects = + rawInjects.stream() + .map( + rawInject -> { + Inject inject = new Inject(); + if (rawInject.getInject_scenario() != null) { + inject.setScenario(new Scenario()); + inject.getScenario().setId(rawInject.getInject_scenario()); + } + // We set the communications + inject.setCommunications( + rawInject.getInject_communications().stream() + .map( + com -> { + Communication communication = new Communication(); + communication.setId(com); + return communication; + }) + .toList()); + // We set the status too + if (rawInject.getStatus_name() != null) { + InjectStatus injectStatus = new InjectStatus(); + injectStatus.setName(ExecutionStatus.valueOf(rawInject.getStatus_name())); + inject.setStatus(injectStatus); + } + // We recreate an exercise out of the raw exercise + Exercise exercise = new Exercise(); + exercise.setStatus(ExerciseStatus.valueOf(rawExercise.getExercise_status())); + exercise.setStart(rawExercise.getExercise_start_date()); + exercise.setPauses( + // We set the pauses as they are used for calculations + pauseRepository.rawAllForExercise(exerciseId).stream() + .map( + rawPause -> { + Pause pause = new Pause(); + pause.setExercise(new Exercise()); + pause.getExercise().setId(exerciseId); + pause.setDate(rawPause.getPause_date()); + pause.setId(rawPause.getPause_id()); + pause.setDuration(rawPause.getPause_duration()); + return pause; + }) + .toList()); + exercise.setCurrentPause(rawExercise.getExercise_pause_date()); + inject.setExercise(exercise); + return inject; + }) + .toList(); + + // We create an ExerciseDetails object and populate it + ExerciseDetails detail = + ExerciseDetails.fromRawExercise(rawExercise, injects, listExerciseTeamUsers, objectives); + detail.setPlatforms( + rawInjects.stream() + .flatMap(inject -> inject.getInject_platforms().stream()) + .distinct() + .toList()); + detail.setCommunicationsNumber( + rawInjects.stream() + .mapToLong(rawInject -> rawInject.getInject_communications().size()) + .sum()); + detail.setKillChainPhases(killChainPhase); + if (rawGrants.get(Grant.GRANT_TYPE.OBSERVER.name()) != null) { + detail.setObservers( + rawGrants.get(Grant.GRANT_TYPE.OBSERVER.name()).stream() + .map(RawGrant::getUser_id) + .collect(Collectors.toSet())); + } + if (rawGrants.get(Grant.GRANT_TYPE.PLANNER.name()) != null) { + detail.setPlanners( + rawGrants.get(Grant.GRANT_TYPE.PLANNER.name()).stream() + .map(RawGrant::getUser_id) + .collect(Collectors.toSet())); + } + + return detail; + } + + @LogExecutionTime + @GetMapping(EXERCISE_URI + "/{exerciseId}/results") + @PreAuthorize("isExerciseObserver(#exerciseId)") + public List globalResults(@NotBlank @PathVariable String exerciseId) { + return exerciseService.getGlobalResults(exerciseId); + } + + @GetMapping(EXERCISE_URI + "/{exerciseId}/injects/results") + @PreAuthorize("isExerciseObserver(#exerciseId)") + public List injectResults( + @NotBlank final @PathVariable String exerciseId) { + return exerciseRepository + .findById(exerciseId) + .map(Exercise::getInjects) + .map(ResultUtils::computeInjectExpectationResults) + .orElseThrow(() -> new RuntimeException("Exercise not found with ID: " + exerciseId)); + } + + @DeleteMapping(EXERCISE_URI + "/{exerciseId}/{documentId}") + @PreAuthorize("isExercisePlanner(#exerciseId)") + @Transactional(rollbackOn = Exception.class) + public Exercise deleteDocument(@PathVariable String exerciseId, @PathVariable String documentId) { + Exercise exercise = + exerciseRepository.findById(exerciseId).orElseThrow(ElementNotFoundException::new); + exercise.setUpdatedAt(now()); + Document doc = + documentRepository.findById(documentId).orElseThrow(ElementNotFoundException::new); + Set docExercises = + doc.getExercises().stream() + .filter(ex -> !ex.getId().equals(exerciseId)) + .collect(Collectors.toSet()); + if (docExercises.isEmpty()) { + // Document is no longer associate to any exercise, delete it + documentRepository.delete(doc); + // All associations with this document will be automatically cleanup. + } else { + // Document associated to other exercise, cleanup + doc.setExercises(docExercises); + documentRepository.save(doc); + // Delete document from all exercise injects + injectService.cleanInjectsDocExercise(exerciseId, documentId); + } + return exerciseRepository.save(exercise); + } + + @PutMapping(EXERCISE_URI + "/{exerciseId}/status") + @PreAuthorize("isExercisePlanner(#exerciseId)") + @Transactional(rollbackOn = Exception.class) + public Exercise changeExerciseStatus( + @PathVariable String exerciseId, @Valid @RequestBody ExerciseUpdateStatusInput input) { + ExerciseStatus status = input.getStatus(); + Exercise exercise = + this.exerciseRepository.findById(exerciseId).orElseThrow(ElementNotFoundException::new); + // Check if next status is possible + List nextPossibleStatus = exercise.nextPossibleStatus(); + if (!nextPossibleStatus.contains(status)) { + throw new UnsupportedOperationException( + "Exercise cant support moving to status " + status.name()); + } + // In case of rescheduled of an exercise. + boolean isCloseState = + ExerciseStatus.CANCELED.equals(exercise.getStatus()) + || ExerciseStatus.FINISHED.equals(exercise.getStatus()); + if (isCloseState && ExerciseStatus.SCHEDULED.equals(status)) { + exercise.setStart(null); + exercise.setEnd(null); + // Reset pauses + exercise.setCurrentPause(null); + pauseRepository.deleteAll(pauseRepository.findAllForExercise(exerciseId)); + // Reset injects outcome, communications and expectations + this.injectStatusRepository.deleteAllById( + exercise.getInjects().stream() + .map(Inject::getStatus) + .map(i -> i.map(InjectStatus::getId).orElse("")) + .toList()); + exercise.getInjects().forEach(Inject::clean); + // Reset lessons learned answers + List lessonsAnswers = + lessonsCategoryRepository + .findAll(LessonsCategorySpecification.fromExercise(exerciseId)) + .stream() + .flatMap( + lessonsCategory -> + lessonsQuestionRepository + .findAll( + LessonsQuestionSpecification.fromCategory(lessonsCategory.getId())) + .stream() + .flatMap( + lessonsQuestion -> + lessonsAnswerRepository + .findAll( + LessonsAnswerSpecification.fromQuestion( + lessonsQuestion.getId())) + .stream())) + .toList(); + lessonsAnswerRepository.deleteAll(lessonsAnswers); + // Delete exercise transient files (communications, ...) + fileService.deleteDirectory(exerciseId); + } + // In case of manual start + if (ExerciseStatus.SCHEDULED.equals(exercise.getStatus()) + && ExerciseStatus.RUNNING.equals(status)) { + Instant nextMinute = now().truncatedTo(MINUTES).plus(1, MINUTES); + exercise.setStart(nextMinute); + } + // If exercise move from pause to running state, + // we log the pause date to be able to recompute inject dates. + if (ExerciseStatus.PAUSED.equals(exercise.getStatus()) + && ExerciseStatus.RUNNING.equals(status)) { + Instant lastPause = exercise.getCurrentPause().orElseThrow(ElementNotFoundException::new); + exercise.setCurrentPause(null); + Pause pause = new Pause(); + pause.setDate(lastPause); + pause.setExercise(exercise); + pause.setDuration(between(lastPause, now()).getSeconds()); + pauseRepository.save(pause); + } + // If pause is asked, just set the pause date. + if (ExerciseStatus.RUNNING.equals(exercise.getStatus()) + && ExerciseStatus.PAUSED.equals(status)) { + exercise.setCurrentPause(Instant.now()); + } + // Cancelation + if (ExerciseStatus.RUNNING.equals(exercise.getStatus()) + && ExerciseStatus.CANCELED.equals(status)) { + exercise.setEnd(now()); + } + exercise.setUpdatedAt(now()); + exercise.setStatus(status); + return exerciseRepository.save(exercise); + } + + @LogExecutionTime + @GetMapping(EXERCISE_URI) + public List exercises() { + return exerciseService.exercises(); + } + + @LogExecutionTime + @PostMapping(EXERCISE_URI + "/search") + public Page exercises( + @RequestBody @Valid final SearchPaginationInput searchPaginationInput) { + if (currentUser().isAdmin()) { + return buildPaginationCriteriaBuilder( + this.exerciseService::exercises, searchPaginationInput, Exercise.class); + } else { + return buildPaginationCriteriaBuilder( + (Specification specification, + Specification specificationCount, + Pageable pageable) -> + this.exerciseService.exercises( + findGrantedFor(currentUser().getId()).and(specification), + findGrantedFor(currentUser().getId()).and(specificationCount), + pageable), + searchPaginationInput, + Exercise.class); + } + } + + // endregion + + // region communication + @GetMapping(EXERCISE_URI + "/{exerciseId}/communications") + @PreAuthorize("isExerciseObserver(#exerciseId)") + public Iterable exerciseCommunications(@PathVariable String exerciseId) { + Exercise exercise = + exerciseRepository.findById(exerciseId).orElseThrow(ElementNotFoundException::new); + List communications = new ArrayList<>(); + exercise + .getInjects() + .forEach(injectDoc -> communications.addAll(injectDoc.getCommunications())); + return communications; + } + + @GetMapping("/api/communications/attachment") + // @PreAuthorize("isExerciseObserver(#exerciseId)") + public void downloadAttachment(@RequestParam String file, HttpServletResponse response) + throws IOException { + FileContainer fileContainer = + fileService.getFileContainer(file).orElseThrow(ElementNotFoundException::new); + response.addHeader( + HttpHeaders.CONTENT_DISPOSITION, "attachment; filename=" + fileContainer.getName()); + response.addHeader(HttpHeaders.CONTENT_TYPE, fileContainer.getContentType()); + response.setStatus(HttpServletResponse.SC_OK); + fileContainer.getInputStream().transferTo(response.getOutputStream()); + } + + // endregion + + // region import/export + @GetMapping(EXERCISE_URI + "/{exerciseId}/export") + @PreAuthorize("isExerciseObserver(#exerciseId)") + public void exerciseExport( + @NotBlank @PathVariable final String exerciseId, + @RequestParam(required = false) final boolean isWithTeams, + @RequestParam(required = false) final boolean isWithPlayers, + @RequestParam(required = false) final boolean isWithVariableValues, + HttpServletResponse response) + throws IOException { + // Setup the mapper for export + List documentIds = new ArrayList<>(); + ObjectMapper objectMapper = mapper.copy(); + if (!isWithPlayers) { + objectMapper.addMixIn( + ExerciseFileExport.class, ExerciseExportMixins.ExerciseFileExport.class); + } + // Start exporting exercise + ExerciseFileExport importExport = new ExerciseFileExport(); + importExport.setVersion(1); + Exercise exercise = + exerciseRepository.findById(exerciseId).orElseThrow(ElementNotFoundException::new); + objectMapper.addMixIn(Exercise.class, ExerciseExportMixins.Exercise.class); + // Build the export + importExport.setExercise(exercise); + importExport.setDocuments(exercise.getDocuments()); + documentIds.addAll(exercise.getDocuments().stream().map(Document::getId).toList()); + objectMapper.addMixIn(Document.class, ExerciseExportMixins.Document.class); + List exerciseTags = new ArrayList<>(exercise.getTags()); + // Objectives + List objectives = exercise.getObjectives(); + importExport.setObjectives(objectives); + objectMapper.addMixIn(Objective.class, ExerciseExportMixins.Objective.class); + // Lessons categories + List lessonsCategories = exercise.getLessonsCategories(); + importExport.setLessonsCategories(lessonsCategories); + objectMapper.addMixIn(LessonsCategory.class, ExerciseExportMixins.LessonsCategory.class); + // Lessons questions + List lessonsQuestions = + lessonsCategories.stream().flatMap(category -> category.getQuestions().stream()).toList(); + importExport.setLessonsQuestions(lessonsQuestions); + objectMapper.addMixIn(LessonsQuestion.class, ExerciseExportMixins.LessonsQuestion.class); + if (isWithTeams) { + // Teams + List teams = exercise.getTeams(); + importExport.setTeams(teams); + objectMapper.addMixIn( + Team.class, + isWithPlayers ? ExerciseExportMixins.Team.class : ExerciseExportMixins.EmptyTeam.class); + exerciseTags.addAll(teams.stream().flatMap(team -> team.getTags().stream()).toList()); + } + if (isWithPlayers) { + // players + List players = + exercise.getTeams().stream() + .flatMap(team -> team.getUsers().stream()) + .distinct() + .toList(); + exerciseTags.addAll(players.stream().flatMap(user -> user.getTags().stream()).toList()); + importExport.setUsers(players); + objectMapper.addMixIn(User.class, ExerciseExportMixins.User.class); + // organizations + List organizations = + players.stream().map(User::getOrganization).filter(Objects::nonNull).distinct().toList(); + exerciseTags.addAll(organizations.stream().flatMap(org -> org.getTags().stream()).toList()); + importExport.setOrganizations(organizations); + objectMapper.addMixIn(Organization.class, ExerciseExportMixins.Organization.class); + } + // Injects + List injects = exercise.getInjects(); + exerciseTags.addAll(injects.stream().flatMap(inject -> inject.getTags().stream()).toList()); + importExport.setInjects(injects); + objectMapper.addMixIn(Inject.class, ExerciseExportMixins.Inject.class); + // Documents + exerciseTags.addAll( + exercise.getDocuments().stream().flatMap(doc -> doc.getTags().stream()).toList()); + // Articles / Channels + List
articles = exercise.getArticles(); + importExport.setArticles(articles); + objectMapper.addMixIn(Article.class, ExerciseExportMixins.Article.class); + List channels = articles.stream().map(Article::getChannel).distinct().toList(); + documentIds.addAll( + channels.stream() + .flatMap(channel -> channel.getLogos().stream()) + .map(Document::getId) + .toList()); + importExport.setChannels(channels); + objectMapper.addMixIn(Channel.class, ExerciseExportMixins.Channel.class); + // Challenges + List challenges = fromIterable(challengeService.getExerciseChallenges(exerciseId)); + importExport.setChallenges(challenges); + documentIds.addAll( + challenges.stream() + .flatMap(challenge -> challenge.getDocuments().stream()) + .map(Document::getId) + .toList()); + objectMapper.addMixIn(Challenge.class, ExerciseExportMixins.Challenge.class); + exerciseTags.addAll( + challenges.stream().flatMap(challenge -> challenge.getTags().stream()).toList()); + // Tags + importExport.setTags(exerciseTags.stream().distinct().toList()); + objectMapper.addMixIn(Tag.class, ExerciseExportMixins.Tag.class); + // -- Variables -- + List variables = this.variableService.variablesFromExercise(exerciseId); + importExport.setVariables(variables); + if (isWithVariableValues) { + objectMapper.addMixIn(Variable.class, VariableWithValueMixin.class); + } else { + objectMapper.addMixIn(Variable.class, VariableMixin.class); + } + // Build the response + String infos = + "(" + + (isWithTeams ? "with_teams" : "no_teams") + + " & " + + (isWithPlayers ? "with_players" : "no_players") + + " & " + + (isWithVariableValues ? "with_variable_values" : "no_variable_values") + + ")"; + String zipName = (exercise.getName() + "_" + now().toString()) + "_" + infos + ".zip"; + response.addHeader(HttpHeaders.CONTENT_DISPOSITION, "attachment; filename=" + zipName); + response.addHeader(HttpHeaders.CONTENT_TYPE, "application/zip"); + response.setStatus(HttpServletResponse.SC_OK); + ZipOutputStream zipExport = new ZipOutputStream(response.getOutputStream()); + ZipEntry zipEntry = new ZipEntry(exercise.getName() + ".json"); + zipEntry.setComment(EXPORT_ENTRY_EXERCISE); + zipExport.putNextEntry(zipEntry); + zipExport.write(objectMapper.writerWithDefaultPrettyPrinter().writeValueAsBytes(importExport)); + zipExport.closeEntry(); + // Add the documents + documentIds.stream() + .distinct() + .forEach( + docId -> { + Document doc = + documentRepository.findById(docId).orElseThrow(ElementNotFoundException::new); + Optional docStream = fileService.getFile(doc); + if (docStream.isPresent()) { try { - ZipEntry zipDoc = new ZipEntry(doc.getTarget()); - zipDoc.setComment(EXPORT_ENTRY_ATTACHMENT); - byte[] data = docStream.get().readAllBytes(); - zipExport.putNextEntry(zipDoc); - zipExport.write(data); - zipExport.closeEntry(); + ZipEntry zipDoc = new ZipEntry(doc.getTarget()); + zipDoc.setComment(EXPORT_ENTRY_ATTACHMENT); + byte[] data = docStream.get().readAllBytes(); + zipExport.putNextEntry(zipDoc); + zipExport.write(data); + zipExport.closeEntry(); } catch (IOException e) { - LOGGER.log(Level.SEVERE, e.getMessage(), e); + LOGGER.log(Level.SEVERE, e.getMessage(), e); } - } - }); - zipExport.finish(); - zipExport.close(); - } - - @PostMapping(EXERCISE_URI + "/import") - @Secured(ROLE_ADMIN) - public void exerciseImport(@RequestPart("file") MultipartFile file) throws Exception { - importService.handleFileImport(file); - } - - // endregion + } + }); + zipExport.finish(); + zipExport.close(); + } + + @PostMapping(EXERCISE_URI + "/import") + @Secured(ROLE_ADMIN) + public void exerciseImport(@RequestPart("file") MultipartFile file) throws Exception { + importService.handleFileImport(file); + } + + // endregion } diff --git a/openbas-api/src/main/java/io/openbas/rest/exercise/ExerciseExpectationApi.java b/openbas-api/src/main/java/io/openbas/rest/exercise/ExerciseExpectationApi.java index baa7d6bc1e..06def1bfbf 100644 --- a/openbas-api/src/main/java/io/openbas/rest/exercise/ExerciseExpectationApi.java +++ b/openbas-api/src/main/java/io/openbas/rest/exercise/ExerciseExpectationApi.java @@ -4,15 +4,13 @@ import io.openbas.rest.helper.RestBehavior; import io.openbas.service.ExerciseExpectationService; import jakarta.validation.constraints.NotBlank; +import java.util.List; import lombok.RequiredArgsConstructor; import org.springframework.security.access.prepost.PreAuthorize; -import org.springframework.transaction.annotation.Transactional; import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.PathVariable; import org.springframework.web.bind.annotation.RestController; -import java.util.List; - @RequiredArgsConstructor @RestController public class ExerciseExpectationApi extends RestBehavior { @@ -21,8 +19,8 @@ public class ExerciseExpectationApi extends RestBehavior { @GetMapping(value = "/api/exercises/{exerciseId}/expectations") @PreAuthorize("isExerciseObserver(#exerciseId)") - public List exerciseInjectExpectations(@PathVariable @NotBlank final String exerciseId) { + public List exerciseInjectExpectations( + @PathVariable @NotBlank final String exerciseId) { return this.exerciseExpectationService.injectExpectations(exerciseId); } - } diff --git a/openbas-api/src/main/java/io/openbas/rest/exercise/ExerciseImportApi.java b/openbas-api/src/main/java/io/openbas/rest/exercise/ExerciseImportApi.java index 8f2656618a..3429f78376 100644 --- a/openbas-api/src/main/java/io/openbas/rest/exercise/ExerciseImportApi.java +++ b/openbas-api/src/main/java/io/openbas/rest/exercise/ExerciseImportApi.java @@ -1,5 +1,8 @@ package io.openbas.rest.exercise; +import static io.openbas.database.model.User.ROLE_USER; +import static io.openbas.rest.exercise.ExerciseApi.EXERCISE_URI; + import io.openbas.database.model.Exercise; import io.openbas.database.model.ImportMapper; import io.openbas.database.repository.ImportMapperRepository; @@ -12,6 +15,7 @@ import jakarta.transaction.Transactional; import jakarta.validation.Valid; import jakarta.validation.constraints.NotBlank; +import java.util.UUID; import lombok.RequiredArgsConstructor; import lombok.extern.java.Log; import org.springframework.security.access.annotation.Secured; @@ -20,11 +24,6 @@ import org.springframework.web.bind.annotation.RequestBody; import org.springframework.web.bind.annotation.RestController; -import java.util.UUID; - -import static io.openbas.database.model.User.ROLE_USER; -import static io.openbas.rest.exercise.ExerciseApi.EXERCISE_URI; - @RestController @RequiredArgsConstructor @Log @@ -45,15 +44,17 @@ public ImportTestSummary dryRunImportXLSFile( Exercise exercise = this.exerciseService.exercise(exerciseId); // Getting the mapper to use - ImportMapper importMapper = this.importMapperRepository - .findById(UUID.fromString(input.getImportMapperId())) - .orElseThrow(() -> new ElementNotFoundException( - String.format("The import mapper %s was not found", input.getImportMapperId()) - )); + ImportMapper importMapper = + this.importMapperRepository + .findById(UUID.fromString(input.getImportMapperId())) + .orElseThrow( + () -> + new ElementNotFoundException( + String.format( + "The import mapper %s was not found", input.getImportMapperId()))); return this.injectService.importInjectIntoExerciseFromXLS( - exercise, importMapper, importId, input.getName(), input.getTimezoneOffset(), false - ); + exercise, importMapper, importId, input.getName(), input.getTimezoneOffset(), false); } @PostMapping(EXERCISE_URI + "/{exerciseId}/xls/{importId}/import") @@ -71,15 +72,18 @@ public ImportTestSummary validateImportXLSFile( } // Getting the mapper to use - ImportMapper importMapper = importMapperRepository - .findById(UUID.fromString(input.getImportMapperId())) - .orElseThrow(() -> new ElementNotFoundException( - String.format("The import mapper %s was not found", input.getImportMapperId()) - )); + ImportMapper importMapper = + importMapperRepository + .findById(UUID.fromString(input.getImportMapperId())) + .orElseThrow( + () -> + new ElementNotFoundException( + String.format( + "The import mapper %s was not found", input.getImportMapperId()))); - ImportTestSummary importTestSummary = injectService.importInjectIntoExerciseFromXLS( - exercise, importMapper, importId, input.getName(), input.getTimezoneOffset(), true - ); + ImportTestSummary importTestSummary = + injectService.importInjectIntoExerciseFromXLS( + exercise, importMapper, importId, input.getName(), input.getTimezoneOffset(), true); this.exerciseService.updateExercise(exercise); return importTestSummary; } diff --git a/openbas-api/src/main/java/io/openbas/rest/exercise/ExercisePlayerApi.java b/openbas-api/src/main/java/io/openbas/rest/exercise/ExercisePlayerApi.java index 7faafd0bd5..6a505aeca8 100644 --- a/openbas-api/src/main/java/io/openbas/rest/exercise/ExercisePlayerApi.java +++ b/openbas-api/src/main/java/io/openbas/rest/exercise/ExercisePlayerApi.java @@ -6,14 +6,13 @@ import io.openbas.rest.exception.ElementNotFoundException; import io.openbas.rest.exercise.response.PublicExercise; import io.openbas.rest.helper.RestBehavior; +import java.util.Optional; import lombok.RequiredArgsConstructor; import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.PathVariable; import org.springframework.web.bind.annotation.RequestParam; import org.springframework.web.bind.annotation.RestController; -import java.util.Optional; - @RestController @RequiredArgsConstructor public class ExercisePlayerApi extends RestBehavior { @@ -24,10 +23,11 @@ public class ExercisePlayerApi extends RestBehavior { private final ExerciseRepository exerciseRepository; @GetMapping(EXERCISE_URI + "/{exerciseId}") - public PublicExercise playerExercise(@PathVariable String exerciseId, @RequestParam Optional userId) { + public PublicExercise playerExercise( + @PathVariable String exerciseId, @RequestParam Optional userId) { impersonateUser(this.userRepository, userId); - Exercise exercise = this.exerciseRepository.findById(exerciseId).orElseThrow(ElementNotFoundException::new); + Exercise exercise = + this.exerciseRepository.findById(exerciseId).orElseThrow(ElementNotFoundException::new); return new PublicExercise(exercise); } - } diff --git a/openbas-api/src/main/java/io/openbas/rest/exercise/ExerciseService.java b/openbas-api/src/main/java/io/openbas/rest/exercise/ExerciseService.java index 95d8d6dcbb..3c0555e9ad 100644 --- a/openbas-api/src/main/java/io/openbas/rest/exercise/ExerciseService.java +++ b/openbas-api/src/main/java/io/openbas/rest/exercise/ExerciseService.java @@ -1,5 +1,14 @@ package io.openbas.rest.exercise; +import static io.openbas.config.SessionHelper.currentUser; +import static io.openbas.database.criteria.GenericCriteria.countQuery; +import static io.openbas.utils.Constants.ARTICLES; +import static io.openbas.utils.JpaUtils.createJoinArrayAggOnId; +import static io.openbas.utils.StringUtils.duplicateString; +import static io.openbas.utils.pagination.SortUtilsCriteriaBuilder.toSortCriteriaBuilder; +import static java.time.Instant.now; +import static java.util.Optional.ofNullable; + import com.fasterxml.jackson.databind.JsonNode; import com.fasterxml.jackson.databind.node.ArrayNode; import io.openbas.config.OpenBASConfig; @@ -25,6 +34,9 @@ import jakarta.persistence.criteria.*; import jakarta.transaction.Transactional; import jakarta.validation.constraints.NotBlank; +import java.time.Instant; +import java.util.*; +import java.util.stream.Collectors; import lombok.RequiredArgsConstructor; import org.jetbrains.annotations.NotNull; import org.springframework.beans.factory.annotation.Value; @@ -35,26 +47,12 @@ import org.springframework.stereotype.Service; import org.springframework.validation.annotation.Validated; -import java.time.Instant; -import java.util.*; -import java.util.stream.Collectors; - -import static io.openbas.config.SessionHelper.currentUser; -import static io.openbas.database.criteria.GenericCriteria.countQuery; -import static io.openbas.utils.Constants.ARTICLES; -import static io.openbas.utils.JpaUtils.createJoinArrayAggOnId; -import static io.openbas.utils.StringUtils.duplicateString; -import static io.openbas.utils.pagination.SortUtilsCriteriaBuilder.toSortCriteriaBuilder; -import static java.time.Instant.now; -import static java.util.Optional.ofNullable; - @RequiredArgsConstructor @Validated @Service public class ExerciseService { - @PersistenceContext - private EntityManager entityManager; + @PersistenceContext private EntityManager entityManager; private final GrantService grantService; private final InjectDuplicateService injectDuplicateService; @@ -75,22 +73,26 @@ public class ExerciseService { @Value("${openbas.mail.imap.username}") private String imapUsername; - @Resource - private OpenBASConfig openBASConfig; + @Resource private OpenBASConfig openBASConfig; + // endregion - public List exercises(){ + public List exercises() { // We get the exercises depending on whether or not we are granted - List exercises = currentUser().isAdmin() ? exerciseRepository.rawAll() - : exerciseRepository.rawAllGranted(currentUser().getId()); - - return exercises.stream().map(exercise->exerciseMapper.fromRawExerciseSimple(exercise)).collect(Collectors.toList()); + List exercises = + currentUser().isAdmin() + ? exerciseRepository.rawAll() + : exerciseRepository.rawAllGranted(currentUser().getId()); + + return exercises.stream() + .map(exercise -> exerciseMapper.fromRawExerciseSimple(exercise)) + .collect(Collectors.toList()); } public Page exercises( - Specification specification, - Specification specificationCount, - Pageable pageable) { + Specification specification, + Specification specificationCount, + Pageable pageable) { CriteriaBuilder cb = this.entityManager.getCriteriaBuilder(); CriteriaQuery cq = cb.createTupleQuery(); @@ -120,9 +122,11 @@ public Page exercises( List exercises = execution(query); for (ExerciseSimple exercise : exercises) { - if (exercise.getInjectIds() != null) { - exercise.setExpectationResultByTypes(resultUtils.getResultsByTypes(List.of(exercise.getInjectIds()))); - exercise.setTargets(resultUtils.getInjectTargetWithResults(List.of(exercise.getInjectIds()))); + if (exercise.getInjectIds() != null) { + exercise.setExpectationResultByTypes( + resultUtils.getResultsByTypes(List.of(exercise.getInjectIds()))); + exercise.setTargets( + resultUtils.getInjectTargetWithResults(List.of(exercise.getInjectIds()))); } } @@ -141,49 +145,47 @@ private void select(CriteriaBuilder cb, CriteriaQuery cq, Root // SELECT cq.multiselect( - exerciseRoot.get("id").alias("exercise_id"), - exerciseRoot.get("name").alias("exercise_name"), - exerciseRoot.get("status").alias("exercise_status"), - exerciseRoot.get("subtitle").alias("exercise_subtitle"), - exerciseRoot.get("category").alias("exercise_category"), - exerciseRoot.get("start").alias("exercise_start_date"), - exerciseRoot.get("updatedAt").alias("exercise_updated_at"), - tagIdsExpression.alias("exercise_tags"), - injectIdsExpression.alias("exercise_injects") - ).distinct(true); + exerciseRoot.get("id").alias("exercise_id"), + exerciseRoot.get("name").alias("exercise_name"), + exerciseRoot.get("status").alias("exercise_status"), + exerciseRoot.get("subtitle").alias("exercise_subtitle"), + exerciseRoot.get("category").alias("exercise_category"), + exerciseRoot.get("start").alias("exercise_start_date"), + exerciseRoot.get("updatedAt").alias("exercise_updated_at"), + tagIdsExpression.alias("exercise_tags"), + injectIdsExpression.alias("exercise_injects")) + .distinct(true); // GROUP BY - cq.groupBy(Collections.singletonList( - exerciseRoot.get("id") - )); + cq.groupBy(Collections.singletonList(exerciseRoot.get("id"))); } // -- EXECUTION -- private List execution(TypedQuery query) { - return query.getResultList() - .stream() - .map(tuple -> { - ExerciseSimple exerciseSimple = new ExerciseSimple(); - exerciseSimple.setId(tuple.get("exercise_id", String.class)); - exerciseSimple.setName(tuple.get("exercise_name", String.class)); - exerciseSimple.setStatus(tuple.get("exercise_status", ExerciseStatus.class)); - exerciseSimple.setSubtitle(tuple.get("exercise_subtitle", String.class)); - exerciseSimple.setCategory(tuple.get("exercise_category", String.class)); - exerciseSimple.setStart(tuple.get("exercise_start_date", Instant.class)); - exerciseSimple.setUpdatedAt(tuple.get("exercise_updated_at", Instant.class)); - exerciseSimple.setTags( - Arrays.stream(tuple.get("exercise_tags", String[].class)) - .map(t -> { - Tag tag = new Tag(); - tag.setId(t); - return tag; - }) - .collect(Collectors.toSet()) - ); - exerciseSimple.setInjectIds(tuple.get("exercise_injects", String[].class)); - return exerciseSimple; - }) + return query.getResultList().stream() + .map( + tuple -> { + ExerciseSimple exerciseSimple = new ExerciseSimple(); + exerciseSimple.setId(tuple.get("exercise_id", String.class)); + exerciseSimple.setName(tuple.get("exercise_name", String.class)); + exerciseSimple.setStatus(tuple.get("exercise_status", ExerciseStatus.class)); + exerciseSimple.setSubtitle(tuple.get("exercise_subtitle", String.class)); + exerciseSimple.setCategory(tuple.get("exercise_category", String.class)); + exerciseSimple.setStart(tuple.get("exercise_start_date", Instant.class)); + exerciseSimple.setUpdatedAt(tuple.get("exercise_updated_at", Instant.class)); + exerciseSimple.setTags( + Arrays.stream(tuple.get("exercise_tags", String[].class)) + .map( + t -> { + Tag tag = new Tag(); + tag.setId(t); + return tag; + }) + .collect(Collectors.toSet())); + exerciseSimple.setInjectIds(tuple.get("exercise_injects", String[].class)); + return exerciseSimple; + }) .toList(); } @@ -205,7 +207,8 @@ public Exercise createExercise(@NotNull final Exercise exercise) { // -- READ -- public Exercise exercise(@NotBlank final String exerciseId) { - return this.exerciseRepository.findById(exerciseId) + return this.exerciseRepository + .findById(exerciseId) .orElseThrow(() -> new ElementNotFoundException("Exercise not found")); } @@ -255,59 +258,76 @@ private Exercise copyExercice(Exercise exerciseOrigin) { return exerciseDuplicate; } - private void getListOfExerciseTeams(@NotNull Exercise exercise, @NotNull Exercise exerciseOrigin) { + private void getListOfExerciseTeams( + @NotNull Exercise exercise, @NotNull Exercise exerciseOrigin) { Map contextualTeams = new HashMap<>(); List exerciseTeams = new ArrayList<>(); - exerciseOrigin.getTeams().forEach(scenarioTeam -> { - if (scenarioTeam.getContextual()) { - Team team = teamService.copyContextualTeam(scenarioTeam); - Team teamSaved = this.teamRepository.save(team); - exerciseTeams.add(teamSaved); - contextualTeams.put(scenarioTeam.getId(), teamSaved); - } else { - exerciseTeams.add(scenarioTeam); - } - }); + exerciseOrigin + .getTeams() + .forEach( + scenarioTeam -> { + if (scenarioTeam.getContextual()) { + Team team = teamService.copyContextualTeam(scenarioTeam); + Team teamSaved = this.teamRepository.save(team); + exerciseTeams.add(teamSaved); + contextualTeams.put(scenarioTeam.getId(), teamSaved); + } else { + exerciseTeams.add(scenarioTeam); + } + }); exercise.setTeams(new ArrayList<>(exerciseTeams)); - exercise.getInjects().forEach(inject -> { - List teams = new ArrayList<>(); - inject.getTeams().forEach(team -> { - if (team.getContextual()) { - teams.add(contextualTeams.get(team.getId())); - } else { - teams.add(team); - } - }); - inject.setTeams(teams); - }); + exercise + .getInjects() + .forEach( + inject -> { + List teams = new ArrayList<>(); + inject + .getTeams() + .forEach( + team -> { + if (team.getContextual()) { + teams.add(contextualTeams.get(team.getId())); + } else { + teams.add(team); + } + }); + inject.setTeams(teams); + }); } private void getListOfDuplicatedInjects(Exercise exercise, Exercise exerciseOrigin) { - List injectListForExercise = exerciseOrigin.getInjects() - .stream().map(inject -> injectDuplicateService.createInjectForExercise(exercise.getId(), inject.getId(), false)) - .toList(); + List injectListForExercise = + exerciseOrigin.getInjects().stream() + .map( + inject -> + injectDuplicateService.createInjectForExercise( + exercise.getId(), inject.getId(), false)) + .toList(); exercise.setInjects(new ArrayList<>(injectListForExercise)); } private void getListOfArticles(Exercise exercise, Exercise exerciseOrigin) { List
articleList = new ArrayList<>(); Map mapIdArticleOriginNew = new HashMap<>(); - exerciseOrigin.getArticles().forEach(article -> { - Article exerciceArticle = new Article(); - exerciceArticle.setName(article.getName()); - exerciceArticle.setContent(article.getContent()); - exerciceArticle.setAuthor(article.getAuthor()); - exerciceArticle.setShares(article.getShares()); - exerciceArticle.setLikes(article.getLikes()); - exerciceArticle.setComments(article.getComments()); - exerciceArticle.setChannel(article.getChannel()); - exerciceArticle.setDocuments(new ArrayList<>(article.getDocuments())); - exerciceArticle.setExercise(exercise); - Article save = articleRepository.save(exerciceArticle); - articleList.add(save); - mapIdArticleOriginNew.put(article.getId(), save.getId()); - }); + exerciseOrigin + .getArticles() + .forEach( + article -> { + Article exerciceArticle = new Article(); + exerciceArticle.setName(article.getName()); + exerciceArticle.setContent(article.getContent()); + exerciceArticle.setAuthor(article.getAuthor()); + exerciceArticle.setShares(article.getShares()); + exerciceArticle.setLikes(article.getLikes()); + exerciceArticle.setComments(article.getComments()); + exerciceArticle.setChannel(article.getChannel()); + exerciceArticle.setDocuments(new ArrayList<>(article.getDocuments())); + exerciceArticle.setExercise(exercise); + Article save = articleRepository.save(exerciceArticle); + articleList.add(save); + mapIdArticleOriginNew.put(article.getId(), save.getId()); + }); exercise.setArticles(articleList); for (Inject inject : exercise.getInjects()) { if (ofNullable(inject.getContent()).map(c -> c.has(ARTICLES)).orElse(Boolean.FALSE)) { @@ -329,15 +349,19 @@ private void getListOfArticles(Exercise exercise, Exercise exerciseOrigin) { private void getListOfVariables(Exercise exercise, Exercise exerciseOrigin) { List variables = variableService.variablesFromExercise(exerciseOrigin.getId()); - List variableList = variables.stream().map(variable -> { - Variable variable1 = new Variable(); - variable1.setKey(variable.getKey()); - variable1.setDescription(variable.getDescription()); - variable1.setValue(variable.getValue()); - variable1.setType(variable.getType()); - variable1.setExercise(exercise); - return variable1; - }).toList(); + List variableList = + variables.stream() + .map( + variable -> { + Variable variable1 = new Variable(); + variable1.setKey(variable.getKey()); + variable1.setDescription(variable.getDescription()); + variable1.setValue(variable.getValue()); + variable1.setType(variable.getType()); + variable1.setExercise(exercise); + return variable1; + }) + .toList(); variableService.createVariables(variableList); } @@ -403,11 +427,13 @@ private void getObjectives(Exercise duplicatedExercise, Exercise originalExercis // -- ScenarioExercise-- public Iterable scenarioExercises(@NotBlank String scenarioId) { - return exerciseRepository.rawAllByScenarioId(List.of(scenarioId)) - .stream().map(rawExerciseSimple -> exerciseMapper.fromRawExerciseSimple(rawExerciseSimple)).toList(); + return exerciseRepository.rawAllByScenarioId(List.of(scenarioId)).stream() + .map(rawExerciseSimple -> exerciseMapper.fromRawExerciseSimple(rawExerciseSimple)) + .toList(); } - public List getGlobalResults(@NotBlank String exerciseId) { + public List getGlobalResults( + @NotBlank String exerciseId) { return resultUtils.getResultsByTypes(exerciseRepository.findInjectsByExercise(exerciseId)); } } diff --git a/openbas-api/src/main/java/io/openbas/rest/exercise/exports/ExerciseExportMixins.java b/openbas-api/src/main/java/io/openbas/rest/exercise/exports/ExerciseExportMixins.java index 89cfcbe90d..6e422e85e3 100644 --- a/openbas-api/src/main/java/io/openbas/rest/exercise/exports/ExerciseExportMixins.java +++ b/openbas-api/src/main/java/io/openbas/rest/exercise/exports/ExerciseExportMixins.java @@ -6,202 +6,183 @@ public class ExerciseExportMixins { @JsonIgnoreProperties(value = {"exercise_users", "exercise_organizations"}) - public static class ExerciseFileExport { - - } - - @JsonIncludeProperties(value = { - "exercise_id", - "exercise_name", - "exercise_description", - "exercise_subtitle", - "exercise_image", - "exercise_message_header", - "exercise_message_footer", - "exercise_mail_from", - "exercise_tags", - "exercise_documents", - }) - public static class Exercise { - - } - - @JsonIncludeProperties(value = { - "document_id", - "document_name", - "document_target", - "document_description", - "document_tags", - }) - public static class Document { - - } - - @JsonIncludeProperties(value = { - "organization_id", - "organization_name", - "organization_description", - "organization_tags", - }) - public static class Organization { - - } - - @JsonIncludeProperties(value = { - "team_id", - "team_name", - "team_description", - "team_tags", - "team_organization", - "team_users", - }) - public static class Team { - - } - - @JsonIncludeProperties(value = { - "team_id", - "team_name", - "team_description", - "team_tags", - }) - public static class EmptyTeam { - - } - - @JsonIncludeProperties(value = { - "inject_id", - "inject_title", - "inject_description", - "inject_country", - "inject_city", - "inject_injector_contract", - "inject_all_teams", - "inject_depends_on", - "inject_depends_duration", - "inject_tags", - "inject_documents", - "inject_teams", - "inject_content", - }) - public static class Inject { - - } - - @JsonIncludeProperties(value = { - "user_id", - "user_firstname", - "user_lastname", - "user_lang", - "user_email", - "user_phone", - "user_pgp_key", - "user_organization", - "user_country", - "user_city", - "user_tags", - }) - public static class User { - - } - - @JsonIncludeProperties(value = { - "objective_id", - "objective_title", - "objective_description", - "objective_priority", - }) - public static class Objective { - - } - - @JsonIncludeProperties(value = { - "poll_id", - "poll_question", - }) - public static class Poll { - - } - - @JsonIncludeProperties(value = { - "tag_id", - "tag_name", - "tag_color", - }) - public static class Tag { - - } - - @JsonIncludeProperties(value = { - "channel_id", - "channel_type", - "channel_name", - "channel_description", - "channel_mode", - "channel_primary_color_dark", - "channel_primary_color_light", - "channel_secondary_color_dark", - "channel_secondary_color_light", - "channel_logo_dark", - "channel_logo_light", - }) - public static class Channel { - - } - - @JsonIncludeProperties(value = { - "article_id", - "article_name", - "article_content", - "article_author", - "article_shares", - "article_likes", - "article_comments", - "article_channel", - "article_documents", - "article_exercise", - }) - public static class Article { - - } - - @JsonIncludeProperties(value = { - "challenge_id", - "challenge_name", - "challenge_category", - "challenge_content", - "challenge_score", - "challenge_max_attempts", - "challenge_flags", - "challenge_tags", - "challenge_documents", - }) - public static class Challenge { - - } - - @JsonIncludeProperties(value = { - "lessonscategory_id", - "lessons_category_name", - "lessons_category_description", - "lessons_category_order", - "lessons_category_questions", - "lessons_category_teams", - }) - public static class LessonsCategory { - - } - - @JsonIncludeProperties(value = { - "lessonsquestion_id", - "lessons_question_category", - "lessons_question_content", - "lessons_question_explanation", - "lessons_question_order", - }) - public static class LessonsQuestion { - - } + public static class ExerciseFileExport {} + + @JsonIncludeProperties( + value = { + "exercise_id", + "exercise_name", + "exercise_description", + "exercise_subtitle", + "exercise_image", + "exercise_message_header", + "exercise_message_footer", + "exercise_mail_from", + "exercise_tags", + "exercise_documents", + }) + public static class Exercise {} + + @JsonIncludeProperties( + value = { + "document_id", + "document_name", + "document_target", + "document_description", + "document_tags", + }) + public static class Document {} + + @JsonIncludeProperties( + value = { + "organization_id", + "organization_name", + "organization_description", + "organization_tags", + }) + public static class Organization {} + + @JsonIncludeProperties( + value = { + "team_id", + "team_name", + "team_description", + "team_tags", + "team_organization", + "team_users", + }) + public static class Team {} + + @JsonIncludeProperties( + value = { + "team_id", + "team_name", + "team_description", + "team_tags", + }) + public static class EmptyTeam {} + + @JsonIncludeProperties( + value = { + "inject_id", + "inject_title", + "inject_description", + "inject_country", + "inject_city", + "inject_injector_contract", + "inject_all_teams", + "inject_depends_on", + "inject_depends_duration", + "inject_tags", + "inject_documents", + "inject_teams", + "inject_content", + }) + public static class Inject {} + + @JsonIncludeProperties( + value = { + "user_id", + "user_firstname", + "user_lastname", + "user_lang", + "user_email", + "user_phone", + "user_pgp_key", + "user_organization", + "user_country", + "user_city", + "user_tags", + }) + public static class User {} + + @JsonIncludeProperties( + value = { + "objective_id", + "objective_title", + "objective_description", + "objective_priority", + }) + public static class Objective {} + + @JsonIncludeProperties( + value = { + "poll_id", + "poll_question", + }) + public static class Poll {} + + @JsonIncludeProperties( + value = { + "tag_id", + "tag_name", + "tag_color", + }) + public static class Tag {} + + @JsonIncludeProperties( + value = { + "channel_id", + "channel_type", + "channel_name", + "channel_description", + "channel_mode", + "channel_primary_color_dark", + "channel_primary_color_light", + "channel_secondary_color_dark", + "channel_secondary_color_light", + "channel_logo_dark", + "channel_logo_light", + }) + public static class Channel {} + + @JsonIncludeProperties( + value = { + "article_id", + "article_name", + "article_content", + "article_author", + "article_shares", + "article_likes", + "article_comments", + "article_channel", + "article_documents", + "article_exercise", + }) + public static class Article {} + + @JsonIncludeProperties( + value = { + "challenge_id", + "challenge_name", + "challenge_category", + "challenge_content", + "challenge_score", + "challenge_max_attempts", + "challenge_flags", + "challenge_tags", + "challenge_documents", + }) + public static class Challenge {} + + @JsonIncludeProperties( + value = { + "lessonscategory_id", + "lessons_category_name", + "lessons_category_description", + "lessons_category_order", + "lessons_category_questions", + "lessons_category_teams", + }) + public static class LessonsCategory {} + + @JsonIncludeProperties( + value = { + "lessonsquestion_id", + "lessons_question_category", + "lessons_question_content", + "lessons_question_explanation", + "lessons_question_order", + }) + public static class LessonsQuestion {} } - - diff --git a/openbas-api/src/main/java/io/openbas/rest/exercise/exports/ExerciseFileExport.java b/openbas-api/src/main/java/io/openbas/rest/exercise/exports/ExerciseFileExport.java index 45a2057b37..fd768f459c 100644 --- a/openbas-api/src/main/java/io/openbas/rest/exercise/exports/ExerciseFileExport.java +++ b/openbas-api/src/main/java/io/openbas/rest/exercise/exports/ExerciseFileExport.java @@ -1,16 +1,15 @@ package io.openbas.rest.exercise.exports; +import static com.fasterxml.jackson.annotation.JsonInclude.Include.NON_NULL; + import com.fasterxml.jackson.annotation.JsonIgnore; import com.fasterxml.jackson.annotation.JsonInclude; import com.fasterxml.jackson.annotation.JsonProperty; import io.openbas.database.model.*; -import lombok.Getter; -import lombok.Setter; - import java.util.ArrayList; import java.util.List; - -import static com.fasterxml.jackson.annotation.JsonInclude.Include.NON_NULL; +import lombok.Getter; +import lombok.Setter; @Getter @Setter @@ -59,9 +58,8 @@ public class ExerciseFileExport { @JsonProperty("exercise_lessons_questions") private List lessonsQuestions = new ArrayList<>(); - @JsonIgnore - public static final String EXERCISE_VARIABLES = "exercise_variables"; + @JsonIgnore public static final String EXERCISE_VARIABLES = "exercise_variables"; + @JsonProperty(EXERCISE_VARIABLES) private List variables; - } diff --git a/openbas-api/src/main/java/io/openbas/rest/exercise/exports/VariableMixin.java b/openbas-api/src/main/java/io/openbas/rest/exercise/exports/VariableMixin.java index ad578424a6..e655ad559b 100644 --- a/openbas-api/src/main/java/io/openbas/rest/exercise/exports/VariableMixin.java +++ b/openbas-api/src/main/java/io/openbas/rest/exercise/exports/VariableMixin.java @@ -1,18 +1,18 @@ package io.openbas.rest.exercise.exports; -import com.fasterxml.jackson.annotation.JsonIncludeProperties; - import static io.openbas.rest.exercise.exports.VariableMixin.*; -@JsonIncludeProperties(value = { - VARIABLE_ID, - VARIABLE_KEY, - VARIABLE_DESCRIPTION, -}) +import com.fasterxml.jackson.annotation.JsonIncludeProperties; + +@JsonIncludeProperties( + value = { + VARIABLE_ID, + VARIABLE_KEY, + VARIABLE_DESCRIPTION, + }) public abstract class VariableMixin { static final String VARIABLE_ID = "variable_id"; static final String VARIABLE_KEY = "variable_key"; static final String VARIABLE_DESCRIPTION = "variable_description"; - } diff --git a/openbas-api/src/main/java/io/openbas/rest/exercise/exports/VariableWithValueMixin.java b/openbas-api/src/main/java/io/openbas/rest/exercise/exports/VariableWithValueMixin.java index 171c170fed..94c266903f 100644 --- a/openbas-api/src/main/java/io/openbas/rest/exercise/exports/VariableWithValueMixin.java +++ b/openbas-api/src/main/java/io/openbas/rest/exercise/exports/VariableWithValueMixin.java @@ -1,20 +1,20 @@ package io.openbas.rest.exercise.exports; +import static io.openbas.rest.exercise.exports.VariableMixin.*; +import static io.openbas.rest.exercise.exports.VariableWithValueMixin.VARIABLE_VALUE; + import com.fasterxml.jackson.annotation.JsonIncludeProperties; import com.fasterxml.jackson.databind.JsonNode; import io.openbas.database.model.Variable; - import jakarta.validation.constraints.NotNull; -import static io.openbas.rest.exercise.exports.VariableMixin.*; -import static io.openbas.rest.exercise.exports.VariableWithValueMixin.VARIABLE_VALUE; - -@JsonIncludeProperties(value = { - VARIABLE_ID, - VARIABLE_KEY, - VARIABLE_VALUE, - VARIABLE_DESCRIPTION, -}) +@JsonIncludeProperties( + value = { + VARIABLE_ID, + VARIABLE_KEY, + VARIABLE_VALUE, + VARIABLE_DESCRIPTION, + }) public abstract class VariableWithValueMixin { static final String VARIABLE_VALUE = "variable_value"; @@ -32,5 +32,4 @@ public static Variable build(@NotNull final JsonNode node) { variable.setDescription(node.get(VariableMixin.VARIABLE_DESCRIPTION).asText()); return variable; } - } diff --git a/openbas-api/src/main/java/io/openbas/rest/exercise/form/DryrunCreateInput.java b/openbas-api/src/main/java/io/openbas/rest/exercise/form/DryrunCreateInput.java index 8432e4815a..bfa53e9d3b 100644 --- a/openbas-api/src/main/java/io/openbas/rest/exercise/form/DryrunCreateInput.java +++ b/openbas-api/src/main/java/io/openbas/rest/exercise/form/DryrunCreateInput.java @@ -1,34 +1,33 @@ package io.openbas.rest.exercise.form; -import com.fasterxml.jackson.annotation.JsonProperty; +import static io.openbas.config.AppConfig.MANDATORY_MESSAGE; +import com.fasterxml.jackson.annotation.JsonProperty; import jakarta.validation.constraints.NotBlank; import java.util.ArrayList; import java.util.List; -import static io.openbas.config.AppConfig.MANDATORY_MESSAGE; - public class DryrunCreateInput { - @NotBlank(message = MANDATORY_MESSAGE) - @JsonProperty("dryrun_name") - private String name; + @NotBlank(message = MANDATORY_MESSAGE) + @JsonProperty("dryrun_name") + private String name; - @JsonProperty("dryrun_users") - private List userIds = new ArrayList<>(); + @JsonProperty("dryrun_users") + private List userIds = new ArrayList<>(); - public String getName() { - return name; - } + public String getName() { + return name; + } - public void setName(String name) { - this.name = name; - } + public void setName(String name) { + this.name = name; + } - public List getUserIds() { - return userIds; - } + public List getUserIds() { + return userIds; + } - public void setUserIds(List userIds) { - this.userIds = userIds; - } + public void setUserIds(List userIds) { + this.userIds = userIds; + } } diff --git a/openbas-api/src/main/java/io/openbas/rest/exercise/form/ExerciseCreateInput.java b/openbas-api/src/main/java/io/openbas/rest/exercise/form/ExerciseCreateInput.java index 5a7d431dab..30a80c7161 100644 --- a/openbas-api/src/main/java/io/openbas/rest/exercise/form/ExerciseCreateInput.java +++ b/openbas-api/src/main/java/io/openbas/rest/exercise/form/ExerciseCreateInput.java @@ -1,21 +1,20 @@ package io.openbas.rest.exercise.form; +import static io.openbas.config.AppConfig.MANDATORY_MESSAGE; +import static io.openbas.config.AppConfig.NOW_FUTURE_MESSAGE; +import static lombok.AccessLevel.NONE; + import com.fasterxml.jackson.annotation.JsonProperty; import io.swagger.v3.oas.annotations.media.Schema; import jakarta.annotation.Nullable; import jakarta.validation.constraints.FutureOrPresent; import jakarta.validation.constraints.NotBlank; -import lombok.Data; -import lombok.Getter; - import java.time.Instant; import java.time.temporal.ChronoUnit; import java.util.ArrayList; import java.util.List; - -import static io.openbas.config.AppConfig.MANDATORY_MESSAGE; -import static io.openbas.config.AppConfig.NOW_FUTURE_MESSAGE; -import static lombok.AccessLevel.NONE; +import lombok.Data; +import lombok.Getter; @Data public class ExerciseCreateInput { @@ -55,5 +54,4 @@ public class ExerciseCreateInput { public Instant getStart() { return start != null ? start.truncatedTo(ChronoUnit.MINUTES) : null; } - } diff --git a/openbas-api/src/main/java/io/openbas/rest/exercise/form/ExerciseDetails.java b/openbas-api/src/main/java/io/openbas/rest/exercise/form/ExerciseDetails.java index 1d66ed48f9..b7e16dc5f4 100644 --- a/openbas-api/src/main/java/io/openbas/rest/exercise/form/ExerciseDetails.java +++ b/openbas-api/src/main/java/io/openbas/rest/exercise/form/ExerciseDetails.java @@ -8,14 +8,13 @@ import jakarta.persistence.EnumType; import jakarta.persistence.Enumerated; import jakarta.validation.constraints.NotBlank; -import lombok.Getter; -import lombok.Setter; - import java.time.Instant; import java.util.HashSet; import java.util.List; import java.util.Map; import java.util.Set; +import lombok.Getter; +import lombok.Setter; @Setter @Getter @@ -164,23 +163,26 @@ public Map getInjectStatistics() { @JsonProperty("exercise_score") public Double getEvaluationAverage() { - double evaluationAverage = getObjectives().stream().mapToDouble(Objective::getEvaluationAverage).average() - .orElse(0D); + double evaluationAverage = + getObjectives().stream().mapToDouble(Objective::getEvaluationAverage).average().orElse(0D); return Math.round(evaluationAverage * 100.0) / 100.0; } - @JsonIgnore - private List injects; + @JsonIgnore private List injects; - @JsonIgnore - private List objectives; + @JsonIgnore private List objectives; /** * Create an Exercise Details object different from the one used in the lists from a Raw one + * * @param exercise the raw exercise * @return an Exercise Simple object */ - public static ExerciseDetails fromRawExercise(RawExercise exercise, List injects, List exerciseTeamsUsers, List objectives) { + public static ExerciseDetails fromRawExercise( + RawExercise exercise, + List injects, + List exerciseTeamsUsers, + List objectives) { ExerciseDetails details = new ExerciseDetails(); details.setId(exercise.getExercise_id()); @@ -196,7 +198,7 @@ public static ExerciseDetails fromRawExercise(RawExercise exercise, List details.setHeader(exercise.getExercise_message_header()); details.setFooter(exercise.getExercise_message_footer()); details.setFrom(exercise.getExercise_mail_from()); - if(exercise.getExercise_reply_to() != null) { + if (exercise.getExercise_reply_to() != null) { details.setReplyTo(exercise.getExercise_reply_to().stream().toList()); } details.setLessonsAnonymized(exercise.getExercise_lessons_anonymized()); @@ -205,7 +207,8 @@ public static ExerciseDetails fromRawExercise(RawExercise exercise, List details.setUpdatedAt(exercise.getExercise_updated_at()); details.setInjects(injects); details.setExerciseTeams(exercise.getExercise_teams()); - details.setExerciseTeamUsers(exerciseTeamsUsers != null ? new HashSet<>(exerciseTeamsUsers) : null); + details.setExerciseTeamUsers( + exerciseTeamsUsers != null ? new HashSet<>(exerciseTeamsUsers) : null); details.setPauses(exercise.getExercise_pauses()); details.setTags(new HashSet<>(exercise.getExercise_tags())); details.setExerciseInjects(new HashSet<>(exercise.getInject_ids())); @@ -216,13 +219,14 @@ public static ExerciseDetails fromRawExercise(RawExercise exercise, List details.setInjects(injects); details.setObjectives(objectives); - details.setLessonsAnswersNumber(exercise.getLessons_answers().stream().distinct().toList().size()); + details.setLessonsAnswersNumber( + exercise.getLessons_answers().stream().distinct().toList().size()); details.setAllUsersNumber(exercise.getUsers().stream().distinct().toList().size()); - details.setUsersNumber(details.getExerciseTeamUsers().stream().map(ExerciseTeamUser::getUser).distinct().count()); + details.setUsersNumber( + details.getExerciseTeamUsers().stream().map(ExerciseTeamUser::getUser).distinct().count()); details.setLogsNumber(exercise.getLogs().stream().distinct().toList().size()); return details; } - } diff --git a/openbas-api/src/main/java/io/openbas/rest/exercise/form/ExerciseSimple.java b/openbas-api/src/main/java/io/openbas/rest/exercise/form/ExerciseSimple.java index 84cb69c17f..d7a548085c 100644 --- a/openbas-api/src/main/java/io/openbas/rest/exercise/form/ExerciseSimple.java +++ b/openbas-api/src/main/java/io/openbas/rest/exercise/form/ExerciseSimple.java @@ -1,5 +1,7 @@ package io.openbas.rest.exercise.form; +import static java.time.Instant.now; + import com.fasterxml.jackson.annotation.JsonIgnore; import com.fasterxml.jackson.annotation.JsonProperty; import com.fasterxml.jackson.databind.annotation.JsonSerialize; @@ -12,16 +14,13 @@ import jakarta.persistence.Enumerated; import jakarta.validation.constraints.NotBlank; import jakarta.validation.constraints.NotNull; -import lombok.Getter; -import lombok.Setter; - import java.time.Instant; import java.util.ArrayList; import java.util.HashSet; import java.util.List; import java.util.Set; - -import static java.time.Instant.now; +import lombok.Getter; +import lombok.Setter; @Setter @Getter @@ -55,11 +54,11 @@ public class ExerciseSimple { @JsonProperty("exercise_tags") private Set tags = new HashSet<>(); - @JsonIgnore - private String[] injectIds; + @JsonIgnore private String[] injectIds; @JsonProperty("exercise_global_score") - private List expectationResultByTypes = new ArrayList<>(); + private List expectationResultByTypes = + new ArrayList<>(); @JsonProperty("exercise_targets") @NotNull diff --git a/openbas-api/src/main/java/io/openbas/rest/exercise/form/ExerciseTeamPlayersEnableInput.java b/openbas-api/src/main/java/io/openbas/rest/exercise/form/ExerciseTeamPlayersEnableInput.java index 03b0641f8b..c734ae985b 100644 --- a/openbas-api/src/main/java/io/openbas/rest/exercise/form/ExerciseTeamPlayersEnableInput.java +++ b/openbas-api/src/main/java/io/openbas/rest/exercise/form/ExerciseTeamPlayersEnableInput.java @@ -1,15 +1,13 @@ package io.openbas.rest.exercise.form; import com.fasterxml.jackson.annotation.JsonProperty; -import lombok.Data; - import java.util.ArrayList; import java.util.List; +import lombok.Data; @Data public class ExerciseTeamPlayersEnableInput { - @JsonProperty("exercise_team_players") - private List playersIds = new ArrayList<>(); - + @JsonProperty("exercise_team_players") + private List playersIds = new ArrayList<>(); } diff --git a/openbas-api/src/main/java/io/openbas/rest/exercise/form/ExerciseUpdateInput.java b/openbas-api/src/main/java/io/openbas/rest/exercise/form/ExerciseUpdateInput.java index 66d9f9e7f6..9e80752eec 100644 --- a/openbas-api/src/main/java/io/openbas/rest/exercise/form/ExerciseUpdateInput.java +++ b/openbas-api/src/main/java/io/openbas/rest/exercise/form/ExerciseUpdateInput.java @@ -1,54 +1,51 @@ package io.openbas.rest.exercise.form; -import com.fasterxml.jackson.annotation.JsonProperty; +import static io.openbas.config.AppConfig.*; -import jakarta.annotation.Nullable; +import com.fasterxml.jackson.annotation.JsonProperty; import jakarta.validation.constraints.Email; import jakarta.validation.constraints.NotBlank; -import lombok.Getter; -import lombok.Setter; - import java.util.ArrayList; import java.util.List; - -import static io.openbas.config.AppConfig.*; +import lombok.Getter; +import lombok.Setter; @Setter @Getter public class ExerciseUpdateInput { - @NotBlank(message = MANDATORY_MESSAGE) - @JsonProperty("exercise_name") - private String name; + @NotBlank(message = MANDATORY_MESSAGE) + @JsonProperty("exercise_name") + private String name; + + @JsonProperty("exercise_subtitle") + private String subtitle; - @JsonProperty("exercise_subtitle") - private String subtitle; + @JsonProperty("exercise_description") + private String description; - @JsonProperty("exercise_description") - private String description; + @JsonProperty("exercise_category") + private String category; - @JsonProperty("exercise_category") - private String category; + @JsonProperty("exercise_main_focus") + private String mainFocus; - @JsonProperty("exercise_main_focus") - private String mainFocus; + @JsonProperty("exercise_severity") + private String severity; - @JsonProperty("exercise_severity") - private String severity; - - @Email(message = EMAIL_FORMAT) - @JsonProperty("exercise_mail_from") - private String from; + @Email(message = EMAIL_FORMAT) + @JsonProperty("exercise_mail_from") + private String from; - @JsonProperty("exercise_mails_reply_to") - private List replyTos; + @JsonProperty("exercise_mails_reply_to") + private List replyTos; - @JsonProperty("exercise_message_header") - private String header; + @JsonProperty("exercise_message_header") + private String header; - @JsonProperty("exercise_message_footer") - private String footer; + @JsonProperty("exercise_message_footer") + private String footer; - @JsonProperty("exercise_tags") - private List tagIds = new ArrayList<>(); + @JsonProperty("exercise_tags") + private List tagIds = new ArrayList<>(); } diff --git a/openbas-api/src/main/java/io/openbas/rest/exercise/form/ExerciseUpdateLogoInput.java b/openbas-api/src/main/java/io/openbas/rest/exercise/form/ExerciseUpdateLogoInput.java index 303090294d..6c2817b392 100644 --- a/openbas-api/src/main/java/io/openbas/rest/exercise/form/ExerciseUpdateLogoInput.java +++ b/openbas-api/src/main/java/io/openbas/rest/exercise/form/ExerciseUpdateLogoInput.java @@ -4,25 +4,25 @@ public class ExerciseUpdateLogoInput { - @JsonProperty("exercise_logo_dark") - private String logoDark; + @JsonProperty("exercise_logo_dark") + private String logoDark; - @JsonProperty("exercise_logo_light") - private String logoLight; + @JsonProperty("exercise_logo_light") + private String logoLight; - public String getLogoDark() { - return logoDark; - } + public String getLogoDark() { + return logoDark; + } - public void setLogoDark(String logoDark) { - this.logoDark = logoDark; - } + public void setLogoDark(String logoDark) { + this.logoDark = logoDark; + } - public String getLogoLight() { - return logoLight; - } + public String getLogoLight() { + return logoLight; + } - public void setLogoLight(String logoLight) { - this.logoLight = logoLight; - } + public void setLogoLight(String logoLight) { + this.logoLight = logoLight; + } } diff --git a/openbas-api/src/main/java/io/openbas/rest/exercise/form/ExerciseUpdateStartDateInput.java b/openbas-api/src/main/java/io/openbas/rest/exercise/form/ExerciseUpdateStartDateInput.java index e94af2c8a6..c83ef7f3b6 100644 --- a/openbas-api/src/main/java/io/openbas/rest/exercise/form/ExerciseUpdateStartDateInput.java +++ b/openbas-api/src/main/java/io/openbas/rest/exercise/form/ExerciseUpdateStartDateInput.java @@ -1,23 +1,22 @@ package io.openbas.rest.exercise.form; -import com.fasterxml.jackson.annotation.JsonProperty; +import static io.openbas.config.AppConfig.*; +import com.fasterxml.jackson.annotation.JsonProperty; import jakarta.validation.constraints.FutureOrPresent; import java.time.Instant; import java.time.temporal.ChronoUnit; -import static io.openbas.config.AppConfig.*; - public class ExerciseUpdateStartDateInput { - @JsonProperty("exercise_start_date") - @FutureOrPresent(message = NOW_FUTURE_MESSAGE) - private Instant start; + @JsonProperty("exercise_start_date") + @FutureOrPresent(message = NOW_FUTURE_MESSAGE) + private Instant start; - public Instant getStart() { - return start != null ? start.truncatedTo(ChronoUnit.MINUTES) : null; - } + public Instant getStart() { + return start != null ? start.truncatedTo(ChronoUnit.MINUTES) : null; + } - public void setStart(Instant start) { - this.start = start; - } + public void setStart(Instant start) { + this.start = start; + } } diff --git a/openbas-api/src/main/java/io/openbas/rest/exercise/form/ExerciseUpdateStatusInput.java b/openbas-api/src/main/java/io/openbas/rest/exercise/form/ExerciseUpdateStatusInput.java index 436e2001db..9a2a974507 100644 --- a/openbas-api/src/main/java/io/openbas/rest/exercise/form/ExerciseUpdateStatusInput.java +++ b/openbas-api/src/main/java/io/openbas/rest/exercise/form/ExerciseUpdateStatusInput.java @@ -4,14 +4,14 @@ import io.openbas.database.model.ExerciseStatus; public class ExerciseUpdateStatusInput { - @JsonProperty("exercise_status") - private ExerciseStatus status; + @JsonProperty("exercise_status") + private ExerciseStatus status; - public ExerciseStatus getStatus() { - return status; - } + public ExerciseStatus getStatus() { + return status; + } - public void setStatus(ExerciseStatus status) { - this.status = status; - } + public void setStatus(ExerciseStatus status) { + this.status = status; + } } diff --git a/openbas-api/src/main/java/io/openbas/rest/exercise/form/ExerciseUpdateTagsInput.java b/openbas-api/src/main/java/io/openbas/rest/exercise/form/ExerciseUpdateTagsInput.java index 429f86d686..bfc1f7c834 100644 --- a/openbas-api/src/main/java/io/openbas/rest/exercise/form/ExerciseUpdateTagsInput.java +++ b/openbas-api/src/main/java/io/openbas/rest/exercise/form/ExerciseUpdateTagsInput.java @@ -1,17 +1,15 @@ package io.openbas.rest.exercise.form; import com.fasterxml.jackson.annotation.JsonProperty; -import lombok.Getter; -import lombok.Setter; - import java.util.ArrayList; import java.util.List; +import lombok.Getter; +import lombok.Setter; @Setter @Getter public class ExerciseUpdateTagsInput { - @JsonProperty("exercise_tags") - private List tagIds = new ArrayList<>(); - + @JsonProperty("exercise_tags") + private List tagIds = new ArrayList<>(); } diff --git a/openbas-api/src/main/java/io/openbas/rest/exercise/form/ExerciseUpdateTeamsInput.java b/openbas-api/src/main/java/io/openbas/rest/exercise/form/ExerciseUpdateTeamsInput.java index 055e17505e..8a305dea48 100644 --- a/openbas-api/src/main/java/io/openbas/rest/exercise/form/ExerciseUpdateTeamsInput.java +++ b/openbas-api/src/main/java/io/openbas/rest/exercise/form/ExerciseUpdateTeamsInput.java @@ -1,15 +1,13 @@ package io.openbas.rest.exercise.form; import com.fasterxml.jackson.annotation.JsonProperty; -import lombok.Data; - import java.util.ArrayList; import java.util.List; +import lombok.Data; @Data public class ExerciseUpdateTeamsInput { - @JsonProperty("exercise_teams") - private List teamIds = new ArrayList<>(); - + @JsonProperty("exercise_teams") + private List teamIds = new ArrayList<>(); } diff --git a/openbas-api/src/main/java/io/openbas/rest/exercise/form/ExpectationUpdateInput.java b/openbas-api/src/main/java/io/openbas/rest/exercise/form/ExpectationUpdateInput.java index 7064c6163f..1bd6817459 100644 --- a/openbas-api/src/main/java/io/openbas/rest/exercise/form/ExpectationUpdateInput.java +++ b/openbas-api/src/main/java/io/openbas/rest/exercise/form/ExpectationUpdateInput.java @@ -1,12 +1,10 @@ - package io.openbas.rest.exercise.form; import com.fasterxml.jackson.annotation.JsonProperty; +import jakarta.validation.constraints.NotNull; import lombok.Getter; import lombok.Setter; -import jakarta.validation.constraints.NotNull; - @Getter @Setter public class ExpectationUpdateInput { diff --git a/openbas-api/src/main/java/io/openbas/rest/exercise/form/LessonsInput.java b/openbas-api/src/main/java/io/openbas/rest/exercise/form/LessonsInput.java index ca5907bce2..ff33d26a42 100644 --- a/openbas-api/src/main/java/io/openbas/rest/exercise/form/LessonsInput.java +++ b/openbas-api/src/main/java/io/openbas/rest/exercise/form/LessonsInput.java @@ -7,8 +7,7 @@ @Setter @Getter public class LessonsInput { - - @JsonProperty("lessons_anonymized") - private boolean lessonsAnonymized; + @JsonProperty("lessons_anonymized") + private boolean lessonsAnonymized; } diff --git a/openbas-api/src/main/java/io/openbas/rest/exercise/form/LogCreateInput.java b/openbas-api/src/main/java/io/openbas/rest/exercise/form/LogCreateInput.java index 767ae9aaa1..8ff680a37f 100644 --- a/openbas-api/src/main/java/io/openbas/rest/exercise/form/LogCreateInput.java +++ b/openbas-api/src/main/java/io/openbas/rest/exercise/form/LogCreateInput.java @@ -1,42 +1,41 @@ package io.openbas.rest.exercise.form; import com.fasterxml.jackson.annotation.JsonProperty; - import java.util.ArrayList; import java.util.List; public class LogCreateInput { - @JsonProperty("log_title") - private String title; + @JsonProperty("log_title") + private String title; - @JsonProperty("log_content") - private String content; + @JsonProperty("log_content") + private String content; - @JsonProperty("log_tags") - private List tagIds = new ArrayList<>(); + @JsonProperty("log_tags") + private List tagIds = new ArrayList<>(); - public String getTitle() { - return title; - } + public String getTitle() { + return title; + } - public void setTitle(String title) { - this.title = title; - } + public void setTitle(String title) { + this.title = title; + } - public String getContent() { - return content; - } + public String getContent() { + return content; + } - public void setContent(String content) { - this.content = content; - } + public void setContent(String content) { + this.content = content; + } - public List getTagIds() { - return tagIds; - } + public List getTagIds() { + return tagIds; + } - public void setTagIds(List tagIds) { - this.tagIds = tagIds; - } + public void setTagIds(List tagIds) { + this.tagIds = tagIds; + } } diff --git a/openbas-api/src/main/java/io/openbas/rest/exercise/form/ScenarioTeamPlayersEnableInput.java b/openbas-api/src/main/java/io/openbas/rest/exercise/form/ScenarioTeamPlayersEnableInput.java index dcbae9a0f0..c8f239fa8b 100644 --- a/openbas-api/src/main/java/io/openbas/rest/exercise/form/ScenarioTeamPlayersEnableInput.java +++ b/openbas-api/src/main/java/io/openbas/rest/exercise/form/ScenarioTeamPlayersEnableInput.java @@ -1,15 +1,13 @@ package io.openbas.rest.exercise.form; import com.fasterxml.jackson.annotation.JsonProperty; -import lombok.Data; - import java.util.ArrayList; import java.util.List; +import lombok.Data; @Data public class ScenarioTeamPlayersEnableInput { - @JsonProperty("scenario_team_players") - private List playersIds = new ArrayList<>(); - + @JsonProperty("scenario_team_players") + private List playersIds = new ArrayList<>(); } diff --git a/openbas-api/src/main/java/io/openbas/rest/exercise/response/PublicExercise.java b/openbas-api/src/main/java/io/openbas/rest/exercise/response/PublicExercise.java index b7415a3bfe..4a36085f72 100644 --- a/openbas-api/src/main/java/io/openbas/rest/exercise/response/PublicExercise.java +++ b/openbas-api/src/main/java/io/openbas/rest/exercise/response/PublicExercise.java @@ -9,19 +9,18 @@ @Setter public class PublicExercise { - @JsonProperty("exercise_id") - private String id; + @JsonProperty("exercise_id") + private String id; - @JsonProperty("exercise_name") - private String name; + @JsonProperty("exercise_name") + private String name; - @JsonProperty("exercise_description") - private String description; - - public PublicExercise(Exercise exercise) { - this.id = exercise.getId(); - this.name = exercise.getName(); - this.description = exercise.getDescription(); - } + @JsonProperty("exercise_description") + private String description; + public PublicExercise(Exercise exercise) { + this.id = exercise.getId(); + this.name = exercise.getName(); + this.description = exercise.getDescription(); + } } diff --git a/openbas-api/src/main/java/io/openbas/rest/expectation/ExpectationApi.java b/openbas-api/src/main/java/io/openbas/rest/expectation/ExpectationApi.java index 8a30df72eb..9ebfd14419 100644 --- a/openbas-api/src/main/java/io/openbas/rest/expectation/ExpectationApi.java +++ b/openbas-api/src/main/java/io/openbas/rest/expectation/ExpectationApi.java @@ -13,129 +13,144 @@ import jakarta.validation.Valid; import jakarta.validation.constraints.NotBlank; import jakarta.validation.constraints.NotNull; +import java.util.List; +import java.util.stream.Stream; import lombok.RequiredArgsConstructor; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.web.bind.annotation.*; -import java.util.List; -import java.util.stream.Stream; - @RequiredArgsConstructor @RestController public class ExpectationApi extends RestBehavior { - private ExerciseExpectationService exerciseExpectationService; - private InjectExpectationService injectExpectationService; - private CollectorRepository collectorRepository; - - @Autowired - public void setExerciseExpectationService(final ExerciseExpectationService exerciseExpectationService) { - this.exerciseExpectationService = exerciseExpectationService; - } - - @Autowired - public void setInjectExpectationService(final InjectExpectationService injectExpectationService) { - this.injectExpectationService = injectExpectationService; - } - - @Autowired - public void setCollectorRepository(CollectorRepository collectorRepository) { - this.collectorRepository = collectorRepository; - } - - @Transactional(rollbackOn = Exception.class) - @PutMapping("/api/expectations/{expectationId}") - public InjectExpectation updateInjectExpectation( - @PathVariable @NotBlank final String expectationId, - @Valid @RequestBody final ExpectationUpdateInput input) { - return this.exerciseExpectationService.updateInjectExpectation(expectationId, input); - } - - @Transactional(rollbackOn = Exception.class) - @PutMapping("/api/expectations/{expectationId}/{sourceId}/delete") - public InjectExpectation deleteInjectExpectationResult( - @PathVariable @NotBlank final String expectationId, - @PathVariable @NotBlank final String sourceId) { - return this.exerciseExpectationService.deleteInjectExpectationResult(expectationId, sourceId); - } - - @GetMapping("/api/injects/expectations") - public List getInjectExpectationsNotFilled() { - return Stream.concat( - injectExpectationService.manualExpectationsNotFill().stream(), - Stream.concat( - injectExpectationService.preventionExpectationsNotFill().stream(), - injectExpectationService.detectionExpectationsNotFill().stream() - ) - ).toList(); - } - - @GetMapping("/api/injects/expectations/{sourceId}") - public List getInjectExpectationsNotFilledForSource(@PathVariable String sourceId) { - return Stream.concat( - injectExpectationService.manualExpectationsNotFill(sourceId).stream(), - Stream.concat( - injectExpectationService.preventionExpectationsNotFill(sourceId).stream(), - injectExpectationService.detectionExpectationsNotFill(sourceId).stream() - ) - ).toList(); - } - - @GetMapping("/api/injects/expectations/assets/{sourceId}") - public List getInjectExpectationsAssetsNotFilledForSource(@PathVariable String sourceId) { - return Stream.concat( + private ExerciseExpectationService exerciseExpectationService; + private InjectExpectationService injectExpectationService; + private CollectorRepository collectorRepository; + + @Autowired + public void setExerciseExpectationService( + final ExerciseExpectationService exerciseExpectationService) { + this.exerciseExpectationService = exerciseExpectationService; + } + + @Autowired + public void setInjectExpectationService(final InjectExpectationService injectExpectationService) { + this.injectExpectationService = injectExpectationService; + } + + @Autowired + public void setCollectorRepository(CollectorRepository collectorRepository) { + this.collectorRepository = collectorRepository; + } + + @Transactional(rollbackOn = Exception.class) + @PutMapping("/api/expectations/{expectationId}") + public InjectExpectation updateInjectExpectation( + @PathVariable @NotBlank final String expectationId, + @Valid @RequestBody final ExpectationUpdateInput input) { + return this.exerciseExpectationService.updateInjectExpectation(expectationId, input); + } + + @Transactional(rollbackOn = Exception.class) + @PutMapping("/api/expectations/{expectationId}/{sourceId}/delete") + public InjectExpectation deleteInjectExpectationResult( + @PathVariable @NotBlank final String expectationId, + @PathVariable @NotBlank final String sourceId) { + return this.exerciseExpectationService.deleteInjectExpectationResult(expectationId, sourceId); + } + + @GetMapping("/api/injects/expectations") + public List getInjectExpectationsNotFilled() { + return Stream.concat( + injectExpectationService.manualExpectationsNotFill().stream(), + Stream.concat( + injectExpectationService.preventionExpectationsNotFill().stream(), + injectExpectationService.detectionExpectationsNotFill().stream())) + .toList(); + } + + @GetMapping("/api/injects/expectations/{sourceId}") + public List getInjectExpectationsNotFilledForSource( + @PathVariable String sourceId) { + return Stream.concat( + injectExpectationService.manualExpectationsNotFill(sourceId).stream(), + Stream.concat( injectExpectationService.preventionExpectationsNotFill(sourceId).stream(), - injectExpectationService.detectionExpectationsNotFill(sourceId).stream() - ).toList(); - } - - @GetMapping("/api/injects/expectations/prevention") - public List getInjectPreventionExpectationsNotFilled() { - return injectExpectationService.preventionExpectationsNotFill().stream().toList(); - } - - @GetMapping("/api/injects/expectations/prevention/{sourceId}") - public List getInjectPreventionExpectationsNotFilledForSource(@PathVariable String sourceId) { - return injectExpectationService.preventionExpectationsNotFill(sourceId).stream().toList(); - } - - @GetMapping("/api/injects/expectations/detection") - public List getInjectDetectionExpectationsNotFilled() { - return injectExpectationService.detectionExpectationsNotFill().stream().toList(); - } - - @GetMapping("/api/injects/expectations/detection/{sourceId}") - public List getInjectDetectionExpectationsNotFilledForSource(@PathVariable String sourceId) { - return injectExpectationService.detectionExpectationsNotFill(sourceId).stream().toList(); - } - - @PutMapping("/api/injects/expectations/{expectationId}") - @Transactional(rollbackOn = Exception.class) - public InjectExpectation updateInjectExpectation(@PathVariable @NotBlank final String expectationId, @Valid @RequestBody @NotNull InjectExpectationUpdateInput input) { - InjectExpectation injectExpectation = this.injectExpectationService.findInjectExpectation(expectationId).orElseThrow(); - Collector collector = this.collectorRepository.findById(input.getCollectorId()).orElseThrow(); - injectExpectation = this.injectExpectationService.computeExpectation(injectExpectation, collector.getId(), "collector", collector.getName(), input.getResult(), input.getSuccess()); - - // Compute potential expectations for asset groups - Inject inject = injectExpectation.getInject(); - List expectationAssetGroups = inject.getExpectations().stream().filter(e -> e.getAssetGroup() != null).toList(); - expectationAssetGroups.forEach((expectationAssetGroup -> { - List expectationAssets = this.injectExpectationService.expectationsForAssets( - expectationAssetGroup.getInject(), expectationAssetGroup.getAssetGroup(), expectationAssetGroup.getType() - ); - // Every expectation assets are filled - if (expectationAssets.stream().noneMatch(e -> e.getResults().isEmpty())) { - this.injectExpectationService.computeExpectationGroup( - expectationAssetGroup, - expectationAssets, - collector.getId(), - "collector", - collector.getName() - ); - } + injectExpectationService.detectionExpectationsNotFill(sourceId).stream())) + .toList(); + } + + @GetMapping("/api/injects/expectations/assets/{sourceId}") + public List getInjectExpectationsAssetsNotFilledForSource( + @PathVariable String sourceId) { + return Stream.concat( + injectExpectationService.preventionExpectationsNotFill(sourceId).stream(), + injectExpectationService.detectionExpectationsNotFill(sourceId).stream()) + .toList(); + } + + @GetMapping("/api/injects/expectations/prevention") + public List getInjectPreventionExpectationsNotFilled() { + return injectExpectationService.preventionExpectationsNotFill().stream().toList(); + } + + @GetMapping("/api/injects/expectations/prevention/{sourceId}") + public List getInjectPreventionExpectationsNotFilledForSource( + @PathVariable String sourceId) { + return injectExpectationService.preventionExpectationsNotFill(sourceId).stream().toList(); + } + + @GetMapping("/api/injects/expectations/detection") + public List getInjectDetectionExpectationsNotFilled() { + return injectExpectationService.detectionExpectationsNotFill().stream().toList(); + } + + @GetMapping("/api/injects/expectations/detection/{sourceId}") + public List getInjectDetectionExpectationsNotFilledForSource( + @PathVariable String sourceId) { + return injectExpectationService.detectionExpectationsNotFill(sourceId).stream().toList(); + } + + @PutMapping("/api/injects/expectations/{expectationId}") + @Transactional(rollbackOn = Exception.class) + public InjectExpectation updateInjectExpectation( + @PathVariable @NotBlank final String expectationId, + @Valid @RequestBody @NotNull InjectExpectationUpdateInput input) { + InjectExpectation injectExpectation = + this.injectExpectationService.findInjectExpectation(expectationId).orElseThrow(); + Collector collector = this.collectorRepository.findById(input.getCollectorId()).orElseThrow(); + injectExpectation = + this.injectExpectationService.computeExpectation( + injectExpectation, + collector.getId(), + "collector", + collector.getName(), + input.getResult(), + input.getSuccess()); + + // Compute potential expectations for asset groups + Inject inject = injectExpectation.getInject(); + List expectationAssetGroups = + inject.getExpectations().stream().filter(e -> e.getAssetGroup() != null).toList(); + expectationAssetGroups.forEach( + (expectationAssetGroup -> { + List expectationAssets = + this.injectExpectationService.expectationsForAssets( + expectationAssetGroup.getInject(), + expectationAssetGroup.getAssetGroup(), + expectationAssetGroup.getType()); + // Every expectation assets are filled + if (expectationAssets.stream().noneMatch(e -> e.getResults().isEmpty())) { + this.injectExpectationService.computeExpectationGroup( + expectationAssetGroup, + expectationAssets, + collector.getId(), + "collector", + collector.getName()); + } })); - // end of computing + // end of computing - return injectExpectation; - } + return injectExpectation; + } } diff --git a/openbas-api/src/main/java/io/openbas/rest/group/GroupApi.java b/openbas-api/src/main/java/io/openbas/rest/group/GroupApi.java index 81bdfa62ba..b9f76495b4 100644 --- a/openbas-api/src/main/java/io/openbas/rest/group/GroupApi.java +++ b/openbas-api/src/main/java/io/openbas/rest/group/GroupApi.java @@ -1,5 +1,13 @@ package io.openbas.rest.group; +import static io.openbas.database.audit.ModelBaseListener.DATA_UPDATE; +import static io.openbas.database.model.User.ROLE_ADMIN; +import static io.openbas.database.model.User.ROLE_USER; +import static io.openbas.utils.pagination.PaginationUtils.buildPaginationJPA; +import static java.time.Instant.now; +import static java.util.stream.Collectors.toList; +import static java.util.stream.StreamSupport.stream; + import io.openbas.database.audit.BaseEvent; import io.openbas.database.model.*; import io.openbas.database.repository.*; @@ -13,6 +21,8 @@ import jakarta.transaction.Transactional; import jakarta.validation.Valid; import java.util.Objects; +import java.util.Optional; +import java.util.Spliterator; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.context.ApplicationEventPublisher; import org.springframework.data.domain.Page; @@ -21,207 +31,207 @@ import org.springframework.security.access.annotation.Secured; import org.springframework.web.bind.annotation.*; -import java.util.Optional; -import java.util.Spliterator; - -import static io.openbas.database.audit.ModelBaseListener.DATA_UPDATE; -import static io.openbas.database.model.User.ROLE_ADMIN; -import static io.openbas.database.model.User.ROLE_USER; -import static io.openbas.utils.pagination.PaginationUtils.buildPaginationJPA; -import static java.time.Instant.now; -import static java.util.stream.Collectors.toList; -import static java.util.stream.StreamSupport.stream; - @RestController @Secured(ROLE_USER) public class GroupApi extends RestBehavior { - private ExerciseRepository exerciseRepository; - private ScenarioRepository scenarioRepository; - private GrantRepository grantRepository; - private OrganizationRepository organizationRepository; - private GroupRepository groupRepository; - private UserRepository userRepository; - private ApplicationEventPublisher appPublisher; - - @Autowired - public void setOrganizationRepository(OrganizationRepository organizationRepository) { - this.organizationRepository = organizationRepository; - } - - @Autowired - public void setApplicationEventPublisher(ApplicationEventPublisher applicationEventPublisher) { - this.appPublisher = applicationEventPublisher; - } - - @Autowired - public void setGrantRepository(GrantRepository grantRepository) { - this.grantRepository = grantRepository; - } - - @Autowired - public void setExerciseRepository(ExerciseRepository exerciseRepository) { - this.exerciseRepository = exerciseRepository; - } - - @Autowired - public void setScenarioRepository(ScenarioRepository scenarioRepository) { - this.scenarioRepository = scenarioRepository; - } - - @Autowired - public void setUserRepository(UserRepository userRepository) { - this.userRepository = userRepository; - } - - @Autowired - public void setGroupRepository(GroupRepository groupRepository) { - this.groupRepository = groupRepository; - } - - @GetMapping("/api/groups") - public Iterable groups() { - return groupRepository.findAll(); - } - - @PostMapping("/api/groups/search") - public Page users(@RequestBody @Valid final SearchPaginationInput searchPaginationInput) { - return buildPaginationJPA( - (Specification specification, Pageable pageable) -> this.groupRepository.findAll( - specification, pageable), - searchPaginationInput, - Group.class - ); - } - - @GetMapping("/api/groups/{groupId}") - public Group group(@PathVariable String groupId) { - return groupRepository.findById(groupId).orElseThrow(ElementNotFoundException::new); - } - - @Secured(ROLE_ADMIN) - @PostMapping("/api/groups") - @Transactional(rollbackOn = Exception.class) - public Group createGroup(@Valid @RequestBody GroupCreateInput input) { - Group group = new Group(); - group.setUpdateAttributes(input); - group.setExercisesDefaultGrants(input.defaultExerciseGrants()); - group.setScenariosDefaultGrants(input.defaultScenarioGrants()); - return groupRepository.save(group); - } - - @Secured(ROLE_ADMIN) - @PutMapping("/api/groups/{groupId}/users") - @Transactional(rollbackOn = Exception.class) - public Group updateGroupUsers(@PathVariable String groupId, - @Valid @RequestBody GroupUpdateUsersInput input) { - Group group = groupRepository.findById(groupId).orElseThrow(ElementNotFoundException::new); - Spliterator userSpliterator = userRepository.findAllById(input.getUserIds()).spliterator(); - group.setUsers(stream(userSpliterator, false).collect(toList())); - Group savedGroup = groupRepository.save(group); - // Publish exercises impacted by this group change. - savedGroup.getGrants() - .stream() - .map(Grant::getExercise) - .filter(Objects::nonNull) - .forEach(exercise -> appPublisher.publishEvent(new BaseEvent(DATA_UPDATE, exercise, mapper))); - // Publish scenarios impacted by this group change. - savedGroup.getGrants() - .stream() - .map(Grant::getScenario) - .filter(Objects::nonNull) - .forEach(scenario -> appPublisher.publishEvent(new BaseEvent(DATA_UPDATE, scenario, mapper))); - return savedGroup; - } - - @Secured(ROLE_ADMIN) - @PutMapping("/api/groups/{groupId}/information") - @Transactional(rollbackOn = Exception.class) - public Group updateGroupInformation( - @PathVariable String groupId, - @Valid @RequestBody GroupCreateInput input) { - Group group = groupRepository.findById(groupId).orElseThrow(ElementNotFoundException::new); - group.setUpdateAttributes(input); - group.setExercisesDefaultGrants(input.defaultExerciseGrants()); - group.setScenariosDefaultGrants(input.defaultScenarioGrants()); - return groupRepository.save(group); - } - - @Secured(ROLE_ADMIN) - @PostMapping("/api/groups/{groupId}/grants") - @Transactional(rollbackOn = Exception.class) - public Grant groupGrant(@PathVariable String groupId, @Valid @RequestBody GroupGrantInput input) { - if (input.getExerciseId() == null && input.getScenarioId() == null) { - throw new IllegalArgumentException("At least one of exercise or scenario should be present"); - } - - // Resolve dependencies - Group group = groupRepository.findById(groupId).orElseThrow(ElementNotFoundException::new); - Optional exerciseOpt = input.getExerciseId() == null ? Optional.empty() : exerciseRepository.findById(input.getExerciseId()); - Optional scenarioOpt = input.getScenarioId() == null ? Optional.empty() : scenarioRepository.findById(input.getScenarioId()); - - // Create the grant - Grant grant = new Grant(); - grant.setName(input.getName()); - grant.setGroup(group); - if (exerciseOpt.isPresent()) { - grant.setExercise(exerciseOpt.get()); - } - if (scenarioOpt.isPresent()) { - grant.setScenario(scenarioOpt.get()); - } - Grant savedGrant = grantRepository.save(grant); - - // Exercise - if (exerciseOpt.isPresent()) { - Exercise exercise = exerciseOpt.get(); - exercise.getGrants().add(savedGrant); - exercise.setUpdatedAt(now()); - exerciseRepository.save(exercise); - } - - // Scenario - if (scenarioOpt.isPresent()) { - Scenario scenario = scenarioOpt.get(); - scenario.getGrants().add(savedGrant); - scenario.setUpdatedAt(now()); - scenarioRepository.save(scenario); - } - - return savedGrant; - } - - @Secured(ROLE_ADMIN) - @PostMapping("/api/groups/{groupId}/organizations") - @Transactional(rollbackOn = Exception.class) - public Group groupOrganization(@PathVariable String groupId, @Valid @RequestBody OrganizationGrantInput input) { - // Resolve dependencies - Group group = groupRepository.findById(groupId).orElseThrow(ElementNotFoundException::new); - Organization organization = organizationRepository.findById(input.getOrganizationId()).orElseThrow(ElementNotFoundException::new); - group.getOrganizations().add(organization); - return groupRepository.save(group); - } - - @Secured(ROLE_ADMIN) - @DeleteMapping("/api/groups/{groupId}/organizations/{organizationId}") - public Group deleteGroupOrganization(@PathVariable String groupId, @PathVariable String organizationId) { - Group group = groupRepository.findById(groupId).orElseThrow(ElementNotFoundException::new); - Organization organization = organizationRepository.findById(organizationId).orElseThrow(ElementNotFoundException::new); - group.getOrganizations().remove(organization); - return groupRepository.save(group); - } - - @Secured(ROLE_ADMIN) - @DeleteMapping("/api/grants/{grantId}") - @Transactional(rollbackOn = Exception.class) - public void deleteGrant(@PathVariable String grantId) { - grantRepository.deleteById(grantId); - } - - @Secured(ROLE_ADMIN) - @DeleteMapping("/api/groups/{groupId}") - @Transactional(rollbackOn = Exception.class) - public void deleteGroup(@PathVariable String groupId) { - groupRepository.deleteById(groupId); - } + private ExerciseRepository exerciseRepository; + private ScenarioRepository scenarioRepository; + private GrantRepository grantRepository; + private OrganizationRepository organizationRepository; + private GroupRepository groupRepository; + private UserRepository userRepository; + private ApplicationEventPublisher appPublisher; + + @Autowired + public void setOrganizationRepository(OrganizationRepository organizationRepository) { + this.organizationRepository = organizationRepository; + } + + @Autowired + public void setApplicationEventPublisher(ApplicationEventPublisher applicationEventPublisher) { + this.appPublisher = applicationEventPublisher; + } + + @Autowired + public void setGrantRepository(GrantRepository grantRepository) { + this.grantRepository = grantRepository; + } + + @Autowired + public void setExerciseRepository(ExerciseRepository exerciseRepository) { + this.exerciseRepository = exerciseRepository; + } + + @Autowired + public void setScenarioRepository(ScenarioRepository scenarioRepository) { + this.scenarioRepository = scenarioRepository; + } + + @Autowired + public void setUserRepository(UserRepository userRepository) { + this.userRepository = userRepository; + } + + @Autowired + public void setGroupRepository(GroupRepository groupRepository) { + this.groupRepository = groupRepository; + } + + @GetMapping("/api/groups") + public Iterable groups() { + return groupRepository.findAll(); + } + + @PostMapping("/api/groups/search") + public Page users(@RequestBody @Valid final SearchPaginationInput searchPaginationInput) { + return buildPaginationJPA( + (Specification specification, Pageable pageable) -> + this.groupRepository.findAll(specification, pageable), + searchPaginationInput, + Group.class); + } + + @GetMapping("/api/groups/{groupId}") + public Group group(@PathVariable String groupId) { + return groupRepository.findById(groupId).orElseThrow(ElementNotFoundException::new); + } + + @Secured(ROLE_ADMIN) + @PostMapping("/api/groups") + @Transactional(rollbackOn = Exception.class) + public Group createGroup(@Valid @RequestBody GroupCreateInput input) { + Group group = new Group(); + group.setUpdateAttributes(input); + group.setExercisesDefaultGrants(input.defaultExerciseGrants()); + group.setScenariosDefaultGrants(input.defaultScenarioGrants()); + return groupRepository.save(group); + } + + @Secured(ROLE_ADMIN) + @PutMapping("/api/groups/{groupId}/users") + @Transactional(rollbackOn = Exception.class) + public Group updateGroupUsers( + @PathVariable String groupId, @Valid @RequestBody GroupUpdateUsersInput input) { + Group group = groupRepository.findById(groupId).orElseThrow(ElementNotFoundException::new); + Spliterator userSpliterator = + userRepository.findAllById(input.getUserIds()).spliterator(); + group.setUsers(stream(userSpliterator, false).collect(toList())); + Group savedGroup = groupRepository.save(group); + // Publish exercises impacted by this group change. + savedGroup.getGrants().stream() + .map(Grant::getExercise) + .filter(Objects::nonNull) + .forEach( + exercise -> appPublisher.publishEvent(new BaseEvent(DATA_UPDATE, exercise, mapper))); + // Publish scenarios impacted by this group change. + savedGroup.getGrants().stream() + .map(Grant::getScenario) + .filter(Objects::nonNull) + .forEach( + scenario -> appPublisher.publishEvent(new BaseEvent(DATA_UPDATE, scenario, mapper))); + return savedGroup; + } + + @Secured(ROLE_ADMIN) + @PutMapping("/api/groups/{groupId}/information") + @Transactional(rollbackOn = Exception.class) + public Group updateGroupInformation( + @PathVariable String groupId, @Valid @RequestBody GroupCreateInput input) { + Group group = groupRepository.findById(groupId).orElseThrow(ElementNotFoundException::new); + group.setUpdateAttributes(input); + group.setExercisesDefaultGrants(input.defaultExerciseGrants()); + group.setScenariosDefaultGrants(input.defaultScenarioGrants()); + return groupRepository.save(group); + } + + @Secured(ROLE_ADMIN) + @PostMapping("/api/groups/{groupId}/grants") + @Transactional(rollbackOn = Exception.class) + public Grant groupGrant(@PathVariable String groupId, @Valid @RequestBody GroupGrantInput input) { + if (input.getExerciseId() == null && input.getScenarioId() == null) { + throw new IllegalArgumentException("At least one of exercise or scenario should be present"); + } + + // Resolve dependencies + Group group = groupRepository.findById(groupId).orElseThrow(ElementNotFoundException::new); + Optional exerciseOpt = + input.getExerciseId() == null + ? Optional.empty() + : exerciseRepository.findById(input.getExerciseId()); + Optional scenarioOpt = + input.getScenarioId() == null + ? Optional.empty() + : scenarioRepository.findById(input.getScenarioId()); + + // Create the grant + Grant grant = new Grant(); + grant.setName(input.getName()); + grant.setGroup(group); + if (exerciseOpt.isPresent()) { + grant.setExercise(exerciseOpt.get()); + } + if (scenarioOpt.isPresent()) { + grant.setScenario(scenarioOpt.get()); + } + Grant savedGrant = grantRepository.save(grant); + + // Exercise + if (exerciseOpt.isPresent()) { + Exercise exercise = exerciseOpt.get(); + exercise.getGrants().add(savedGrant); + exercise.setUpdatedAt(now()); + exerciseRepository.save(exercise); + } + + // Scenario + if (scenarioOpt.isPresent()) { + Scenario scenario = scenarioOpt.get(); + scenario.getGrants().add(savedGrant); + scenario.setUpdatedAt(now()); + scenarioRepository.save(scenario); + } + + return savedGrant; + } + + @Secured(ROLE_ADMIN) + @PostMapping("/api/groups/{groupId}/organizations") + @Transactional(rollbackOn = Exception.class) + public Group groupOrganization( + @PathVariable String groupId, @Valid @RequestBody OrganizationGrantInput input) { + // Resolve dependencies + Group group = groupRepository.findById(groupId).orElseThrow(ElementNotFoundException::new); + Organization organization = + organizationRepository + .findById(input.getOrganizationId()) + .orElseThrow(ElementNotFoundException::new); + group.getOrganizations().add(organization); + return groupRepository.save(group); + } + + @Secured(ROLE_ADMIN) + @DeleteMapping("/api/groups/{groupId}/organizations/{organizationId}") + public Group deleteGroupOrganization( + @PathVariable String groupId, @PathVariable String organizationId) { + Group group = groupRepository.findById(groupId).orElseThrow(ElementNotFoundException::new); + Organization organization = + organizationRepository.findById(organizationId).orElseThrow(ElementNotFoundException::new); + group.getOrganizations().remove(organization); + return groupRepository.save(group); + } + + @Secured(ROLE_ADMIN) + @DeleteMapping("/api/grants/{grantId}") + @Transactional(rollbackOn = Exception.class) + public void deleteGrant(@PathVariable String grantId) { + grantRepository.deleteById(grantId); + } + + @Secured(ROLE_ADMIN) + @DeleteMapping("/api/groups/{groupId}") + @Transactional(rollbackOn = Exception.class) + public void deleteGroup(@PathVariable String groupId) { + groupRepository.deleteById(groupId); + } } diff --git a/openbas-api/src/main/java/io/openbas/rest/group/form/GroupCreateInput.java b/openbas-api/src/main/java/io/openbas/rest/group/form/GroupCreateInput.java index d0d3d4245f..5d78626bde 100644 --- a/openbas-api/src/main/java/io/openbas/rest/group/form/GroupCreateInput.java +++ b/openbas-api/src/main/java/io/openbas/rest/group/form/GroupCreateInput.java @@ -1,15 +1,14 @@ package io.openbas.rest.group.form; +import static io.openbas.config.AppConfig.MANDATORY_MESSAGE; + import com.fasterxml.jackson.annotation.JsonProperty; import io.openbas.database.model.Grant; import jakarta.validation.constraints.NotBlank; -import lombok.Getter; -import lombok.Setter; - import java.util.ArrayList; import java.util.List; - -import static io.openbas.config.AppConfig.MANDATORY_MESSAGE; +import lombok.Getter; +import lombok.Setter; @Getter @Setter @@ -58,5 +57,4 @@ public List defaultScenarioGrants() { } return grants; } - } diff --git a/openbas-api/src/main/java/io/openbas/rest/group/form/GroupGrantInput.java b/openbas-api/src/main/java/io/openbas/rest/group/form/GroupGrantInput.java index dfbafe5d33..e8dc62dccc 100644 --- a/openbas-api/src/main/java/io/openbas/rest/group/form/GroupGrantInput.java +++ b/openbas-api/src/main/java/io/openbas/rest/group/form/GroupGrantInput.java @@ -9,13 +9,12 @@ @Getter public class GroupGrantInput { - @JsonProperty("grant_name") - private Grant.GRANT_TYPE name; + @JsonProperty("grant_name") + private Grant.GRANT_TYPE name; - @JsonProperty("grant_exercise") - private String exerciseId; - - @JsonProperty("grant_scenario") - private String scenarioId; + @JsonProperty("grant_exercise") + private String exerciseId; + @JsonProperty("grant_scenario") + private String scenarioId; } diff --git a/openbas-api/src/main/java/io/openbas/rest/group/form/GroupUpdateUsersInput.java b/openbas-api/src/main/java/io/openbas/rest/group/form/GroupUpdateUsersInput.java index 290e1991bc..b9d567a80a 100644 --- a/openbas-api/src/main/java/io/openbas/rest/group/form/GroupUpdateUsersInput.java +++ b/openbas-api/src/main/java/io/openbas/rest/group/form/GroupUpdateUsersInput.java @@ -1,16 +1,14 @@ package io.openbas.rest.group.form; import com.fasterxml.jackson.annotation.JsonProperty; +import java.util.List; import lombok.Getter; import lombok.Setter; -import java.util.List; - @Setter @Getter public class GroupUpdateUsersInput { - @JsonProperty("group_users") - private List userIds; - + @JsonProperty("group_users") + private List userIds; } diff --git a/openbas-api/src/main/java/io/openbas/rest/group/form/OrganizationGrantInput.java b/openbas-api/src/main/java/io/openbas/rest/group/form/OrganizationGrantInput.java index f5f0fd8a31..f075d2ae0b 100644 --- a/openbas-api/src/main/java/io/openbas/rest/group/form/OrganizationGrantInput.java +++ b/openbas-api/src/main/java/io/openbas/rest/group/form/OrganizationGrantInput.java @@ -1,19 +1,17 @@ package io.openbas.rest.group.form; -import com.fasterxml.jackson.annotation.JsonProperty; +import static io.openbas.config.AppConfig.MANDATORY_MESSAGE; +import com.fasterxml.jackson.annotation.JsonProperty; import jakarta.validation.constraints.NotBlank; import lombok.Getter; import lombok.Setter; -import static io.openbas.config.AppConfig.MANDATORY_MESSAGE; - @Setter @Getter public class OrganizationGrantInput { - @NotBlank(message = MANDATORY_MESSAGE) - @JsonProperty("organization_id") - private String organizationId; - + @NotBlank(message = MANDATORY_MESSAGE) + @JsonProperty("organization_id") + private String organizationId; } diff --git a/openbas-api/src/main/java/io/openbas/rest/helper/RestBehavior.java b/openbas-api/src/main/java/io/openbas/rest/helper/RestBehavior.java index 669a1ff860..40622d2f9e 100644 --- a/openbas-api/src/main/java/io/openbas/rest/helper/RestBehavior.java +++ b/openbas-api/src/main/java/io/openbas/rest/helper/RestBehavior.java @@ -1,5 +1,8 @@ package io.openbas.rest.helper; +import static io.openbas.config.OpenBASAnonymous.ANONYMOUS; +import static io.openbas.config.SessionHelper.currentUser; + import com.fasterxml.jackson.databind.BeanDescription; import com.fasterxml.jackson.databind.JavaType; import com.fasterxml.jackson.databind.ObjectMapper; @@ -10,6 +13,8 @@ import io.openbas.database.repository.UserRepository; import io.openbas.rest.exception.*; import jakarta.annotation.Resource; +import java.util.*; +import java.util.stream.Collectors; import lombok.extern.java.Log; import org.hibernate.exception.ConstraintViolationException; import org.springdoc.api.ErrorMessage; @@ -24,18 +29,11 @@ import org.springframework.web.bind.annotation.RestControllerAdvice; import org.springframework.web.reactive.function.UnsupportedMediaTypeException; -import java.util.*; -import java.util.stream.Collectors; - -import static io.openbas.config.OpenBASAnonymous.ANONYMOUS; -import static io.openbas.config.SessionHelper.currentUser; - @RestControllerAdvice @Log public class RestBehavior { - @Resource - protected ObjectMapper mapper; + @Resource protected ObjectMapper mapper; // Build the mapping between json specific name and the actual database field name private Map buildJsonMappingFields(MethodArgumentNotValidException ex) { @@ -43,7 +41,9 @@ private Map buildJsonMappingFields(MethodArgumentNotValidExcepti JavaType javaType = mapper.getTypeFactory().constructType(inputClass); BeanDescription beanDescription = mapper.getSerializationConfig().introspect(javaType); return beanDescription.findProperties().stream() - .collect(Collectors.toMap(BeanPropertyDefinition::getInternalName, BeanPropertyDefinition::getName)); + .collect( + Collectors.toMap( + BeanPropertyDefinition::getInternalName, BeanPropertyDefinition::getName)); } @ResponseStatus(HttpStatus.BAD_REQUEST) @@ -53,11 +53,14 @@ public ValidationErrorBag handleValidationExceptions(MethodArgumentNotValidExcep ValidationErrorBag bag = new ValidationErrorBag(); ValidationError errors = new ValidationError(); Map errorsBag = new HashMap<>(); - ex.getBindingResult().getAllErrors().forEach((error) -> { - String fieldName = ((FieldError) error).getField(); - String errorMessage = error.getDefaultMessage(); - errorsBag.put(jsonFieldsMapping.get(fieldName), new ValidationContent(errorMessage)); - }); + ex.getBindingResult() + .getAllErrors() + .forEach( + (error) -> { + String fieldName = ((FieldError) error).getField(); + String errorMessage = error.getDefaultMessage(); + errorsBag.put(jsonFieldsMapping.get(fieldName), new ValidationContent(errorMessage)); + }); errors.setChildren(errorsBag); bag.setErrors(errors); return bag; @@ -78,7 +81,8 @@ public ValidationErrorBag handleInputValidationExceptions(InputValidationExcepti @ResponseStatus(HttpStatus.BAD_REQUEST) @ExceptionHandler(ImportException.class) public ValidationErrorBag handleBadRequestExceptions(ImportException ex) { - ValidationErrorBag bag = new ValidationErrorBag(HttpStatus.BAD_REQUEST.value(), ex.getMessage()); + ValidationErrorBag bag = + new ValidationErrorBag(HttpStatus.BAD_REQUEST.value(), ex.getMessage()); ValidationError errors = new ValidationError(); Map errorsBag = new HashMap<>(); errorsBag.put(ex.getField(), new ValidationContent(ex.getMessage())); @@ -90,7 +94,8 @@ public ValidationErrorBag handleBadRequestExceptions(ImportException ex) { @ResponseStatus(HttpStatus.UNAUTHORIZED) @ExceptionHandler(AccessDeniedException.class) public ValidationErrorBag handleValidationExceptions() { - ValidationErrorBag bag = new ValidationErrorBag(HttpStatus.UNAUTHORIZED.value(), "ACCESS_DENIED"); + ValidationErrorBag bag = + new ValidationErrorBag(HttpStatus.UNAUTHORIZED.value(), "ACCESS_DENIED"); ValidationError errors = new ValidationError(); Map errorsBag = new HashMap<>(); errorsBag.put("username", new ValidationContent("Invalid user or password")); @@ -123,7 +128,8 @@ public ResponseEntity handleElementNotFoundException(ElementNotFou } @ExceptionHandler(UnsupportedMediaTypeException.class) - public ResponseEntity handleUnsupportedMediaTypeException(UnsupportedMediaTypeException ex) { + public ResponseEntity handleUnsupportedMediaTypeException( + UnsupportedMediaTypeException ex) { ErrorMessage message = new ErrorMessage(ex.getMessage()); log.warning("UnsupportedMediaTypeException: " + ex.getMessage()); return new ResponseEntity<>(message, HttpStatus.UNSUPPORTED_MEDIA_TYPE); @@ -160,10 +166,11 @@ public void checkUserAccess(UserRepository userRepository, String userId) { OpenBASPrincipal currentUser = currentUser(); if (!currentUser.isAdmin()) { User local = userRepository.findById(currentUser.getId()).orElseThrow(); - List localOrganizationIds = local.getGroups().stream() - .flatMap(group -> group.getOrganizations().stream()) - .map(Organization::getId) - .toList(); + List localOrganizationIds = + local.getGroups().stream() + .flatMap(group -> group.getOrganizations().stream()) + .map(Organization::getId) + .toList(); if (!localOrganizationIds.contains(askedUser.getOrganization().getId())) { throw new UnsupportedOperationException("User is restricted"); } @@ -176,10 +183,11 @@ public void checkOrganizationAccess(UserRepository userRepository, String organi OpenBASPrincipal currentUser = currentUser(); if (!currentUser.isAdmin()) { User local = userRepository.findById(currentUser.getId()).orElseThrow(); - List localOrganizationIds = local.getGroups().stream() - .flatMap(group -> group.getOrganizations().stream()) - .map(Organization::getId) - .toList(); + List localOrganizationIds = + local.getGroups().stream() + .flatMap(group -> group.getOrganizations().stream()) + .map(Organization::getId) + .toList(); if (!localOrganizationIds.contains(organizationId)) { throw new UnsupportedOperationException("User is restricted"); } diff --git a/openbas-api/src/main/java/io/openbas/rest/helper/TeamHelper.java b/openbas-api/src/main/java/io/openbas/rest/helper/TeamHelper.java index 9d757b21c2..fb704e8b74 100644 --- a/openbas-api/src/main/java/io/openbas/rest/helper/TeamHelper.java +++ b/openbas-api/src/main/java/io/openbas/rest/helper/TeamHelper.java @@ -7,7 +7,6 @@ import io.openbas.database.repository.InjectExpectationRepository; import io.openbas.database.repository.InjectRepository; import io.openbas.database.repository.ScenarioRepository; - import java.util.List; import java.util.Map; import java.util.Optional; @@ -17,128 +16,159 @@ public class TeamHelper { - public static List rawTeamToSimplerTeam(List teams, - InjectExpectationRepository injectExpectationRepository, - InjectRepository injectRepository, - CommunicationRepository communicationRepository, - ExerciseTeamUserRepository exerciseTeamUserRepository, - ScenarioRepository scenarioRepository) { - // Getting a map of inject expectations - Map mapInjectExpectation = injectExpectationRepository.rawByIds( - teams.stream().flatMap(rawTeam -> rawTeam.getTeam_expectations().stream()).toList() - ) - .stream().collect(Collectors.toMap(RawInjectExpectation::getInject_expectation_id, Function.identity())); - - // Getting a map of communications - Map mapCommunication = communicationRepository.rawByIds( - teams.stream().flatMap(rawTeam -> rawTeam.getTeam_communications().stream()).toList() - ) - .stream().collect(Collectors.toMap(RawCommunication::getCommunication_id, Function.identity())); - - // Getting a map of exercises team users by team id - Map> mapExerciseTeamUser = exerciseTeamUserRepository.rawByTeamIds( - teams.stream().map(RawTeam::getTeam_id).toList() - ) - .stream().collect(Collectors.groupingBy(RawExerciseTeamUser::getTeam_id)); - - // Getting a map of Injects by scenarios ids - Map> mapInjectsByScenarioIds = scenarioRepository.rawInjectsFromScenarios( - teams.stream().flatMap(rawTeam -> rawTeam.getTeam_scenarios().stream()).toList() - ).stream().collect(Collectors.toMap(RawScenario::getScenario_id, RawScenario::getScenario_injects)); - - // Then, for all the raw teams, we will create a simpler team object and then send it back to the front - return teams.stream().map(rawTeam -> { - // We create the simpler team object using the raw one - TeamSimple teamSimple = new TeamSimple(rawTeam); - - // We set the inject expectations - teamSimple.setInjectExpectations( - rawTeam.getTeam_expectations().stream().map( - expectation -> { - // We set the inject expectation using the map we generated earlier - InjectExpectation injectExpectation = new InjectExpectation(); - Optional raw = Optional.ofNullable(mapInjectExpectation.get(expectation)); - raw.ifPresent(toProcess -> { - injectExpectation.setScore(toProcess.getInject_expectation_score()); - injectExpectation.setExpectedScore(toProcess.getInject_expectation_expected_score()); - injectExpectation.setId(toProcess.getInject_expectation_id()); - injectExpectation.setExpectedScore(toProcess.getInject_expectation_expected_score()); - if (toProcess.getExercise_id() != null) { - injectExpectation.setExercise(new Exercise()); - injectExpectation.getExercise().setId(toProcess.getExercise_id()); - } - injectExpectation.setTeam(new Team()); - injectExpectation.getTeam().setId(rawTeam.getTeam_id()); - injectExpectation.setType(InjectExpectation.EXPECTATION_TYPE.valueOf(toProcess.getInject_expectation_type())); + public static List rawTeamToSimplerTeam( + List teams, + InjectExpectationRepository injectExpectationRepository, + InjectRepository injectRepository, + CommunicationRepository communicationRepository, + ExerciseTeamUserRepository exerciseTeamUserRepository, + ScenarioRepository scenarioRepository) { + // Getting a map of inject expectations + Map mapInjectExpectation = + injectExpectationRepository + .rawByIds( + teams.stream().flatMap(rawTeam -> rawTeam.getTeam_expectations().stream()).toList()) + .stream() + .collect( + Collectors.toMap( + RawInjectExpectation::getInject_expectation_id, Function.identity())); + + // Getting a map of communications + Map mapCommunication = + communicationRepository + .rawByIds( + teams.stream() + .flatMap(rawTeam -> rawTeam.getTeam_communications().stream()) + .toList()) + .stream() + .collect(Collectors.toMap(RawCommunication::getCommunication_id, Function.identity())); + + // Getting a map of exercises team users by team id + Map> mapExerciseTeamUser = + exerciseTeamUserRepository + .rawByTeamIds(teams.stream().map(RawTeam::getTeam_id).toList()) + .stream() + .collect(Collectors.groupingBy(RawExerciseTeamUser::getTeam_id)); + + // Getting a map of Injects by scenarios ids + Map> mapInjectsByScenarioIds = + scenarioRepository + .rawInjectsFromScenarios( + teams.stream().flatMap(rawTeam -> rawTeam.getTeam_scenarios().stream()).toList()) + .stream() + .collect( + Collectors.toMap(RawScenario::getScenario_id, RawScenario::getScenario_injects)); + + // Then, for all the raw teams, we will create a simpler team object and then send it back to + // the front + return teams.stream() + .map( + rawTeam -> { + // We create the simpler team object using the raw one + TeamSimple teamSimple = new TeamSimple(rawTeam); + + // We set the inject expectations + teamSimple.setInjectExpectations( + rawTeam.getTeam_expectations().stream() + .map( + expectation -> { + // We set the inject expectation using the map we generated earlier + InjectExpectation injectExpectation = new InjectExpectation(); + Optional raw = + Optional.ofNullable(mapInjectExpectation.get(expectation)); + raw.ifPresent( + toProcess -> { + injectExpectation.setScore( + toProcess.getInject_expectation_score()); + injectExpectation.setExpectedScore( + toProcess.getInject_expectation_expected_score()); + injectExpectation.setId(toProcess.getInject_expectation_id()); + injectExpectation.setExpectedScore( + toProcess.getInject_expectation_expected_score()); + if (toProcess.getExercise_id() != null) { + injectExpectation.setExercise(new Exercise()); + injectExpectation + .getExercise() + .setId(toProcess.getExercise_id()); + } + injectExpectation.setTeam(new Team()); + injectExpectation.getTeam().setId(rawTeam.getTeam_id()); + injectExpectation.setType( + InjectExpectation.EXPECTATION_TYPE.valueOf( + toProcess.getInject_expectation_type())); }); - return injectExpectation; - } - ).toList() - ); - - // We set the communications using the map we generated earlier - // This object has content, content_html and attachments ignored because WE DON'T WANT THE FULL EXTENT - teamSimple.setCommunications( - rawTeam.getTeam_communications().stream().map(communicationId -> { - RawCommunication raw = mapCommunication.get(communicationId); - Communication communication = new Communication(); - communication.setAck(raw.getCommunication_ack()); - communication.setId(raw.getCommunication_id()); - communication.setIdentifier(raw.getCommunication_message_id()); - communication.setReceivedAt(raw.getCommunication_received_at()); - communication.setSentAt(raw.getCommunication_sent_at()); - communication.setSubject(raw.getCommunication_subject()); - Inject inject = new Inject(); - inject.setId(raw.getCommunication_inject()); - Exercise exercise = new Exercise(); - exercise.setId(raw.getCommunication_exercise()); - inject.setExercise(exercise); - communication.setInject(inject); - communication.setUsers(raw.getCommunication_users().stream().map(id -> { - User user = new User(); - user.setId(id); - return user; - }).toList()); - communication.setAnimation(raw.getCommunication_animation()); - communication.setFrom(raw.getCommunication_from()); - communication.setTo(raw.getCommunication_to()); - return communication; - }).toList() - ); - - // We set the tuple of exercise/user/team - List exerciseTeamUsers = mapExerciseTeamUser.get(rawTeam); - if(exerciseTeamUsers != null) { - teamSimple.setExerciseTeamUsers(exerciseTeamUsers.stream().map( - ExerciseTeamUser::fromRawExerciseTeamUser - ).collect(Collectors.toSet())); - } - - // We set the injects linked to the scenarios - teamSimple.setScenariosInjects( - getInjectTeamsIds(teamSimple.getId(), - rawTeam.getTeam_scenarios().stream().flatMap( - scenario -> mapInjectsByScenarioIds.get(scenario).stream() - ).collect(Collectors.toSet()), - injectRepository) - ); - - // We set the injects linked to the exercises - teamSimple.setExercisesInjects( - getInjectTeamsIds(teamSimple.getId(), - rawTeam.getTeam_exercise_injects(), - injectRepository) - ); - - return teamSimple; - }).collect(Collectors.toList()); - } + return injectExpectation; + }) + .toList()); + + // We set the communications using the map we generated earlier + // This object has content, content_html and attachments ignored because WE DON'T WANT + // THE FULL EXTENT + teamSimple.setCommunications( + rawTeam.getTeam_communications().stream() + .map( + communicationId -> { + RawCommunication raw = mapCommunication.get(communicationId); + Communication communication = new Communication(); + communication.setAck(raw.getCommunication_ack()); + communication.setId(raw.getCommunication_id()); + communication.setIdentifier(raw.getCommunication_message_id()); + communication.setReceivedAt(raw.getCommunication_received_at()); + communication.setSentAt(raw.getCommunication_sent_at()); + communication.setSubject(raw.getCommunication_subject()); + Inject inject = new Inject(); + inject.setId(raw.getCommunication_inject()); + Exercise exercise = new Exercise(); + exercise.setId(raw.getCommunication_exercise()); + inject.setExercise(exercise); + communication.setInject(inject); + communication.setUsers( + raw.getCommunication_users().stream() + .map( + id -> { + User user = new User(); + user.setId(id); + return user; + }) + .toList()); + communication.setAnimation(raw.getCommunication_animation()); + communication.setFrom(raw.getCommunication_from()); + communication.setTo(raw.getCommunication_to()); + return communication; + }) + .toList()); + + // We set the tuple of exercise/user/team + List exerciseTeamUsers = mapExerciseTeamUser.get(rawTeam); + if (exerciseTeamUsers != null) { + teamSimple.setExerciseTeamUsers( + exerciseTeamUsers.stream() + .map(ExerciseTeamUser::fromRawExerciseTeamUser) + .collect(Collectors.toSet())); + } + + // We set the injects linked to the scenarios + teamSimple.setScenariosInjects( + getInjectTeamsIds( + teamSimple.getId(), + rawTeam.getTeam_scenarios().stream() + .flatMap(scenario -> mapInjectsByScenarioIds.get(scenario).stream()) + .collect(Collectors.toSet()), + injectRepository)); + + // We set the injects linked to the exercises + teamSimple.setExercisesInjects( + getInjectTeamsIds( + teamSimple.getId(), rawTeam.getTeam_exercise_injects(), injectRepository)); + + return teamSimple; + }) + .collect(Collectors.toList()); + } - private static Set getInjectTeamsIds(final String teamId, Set injectIds, final InjectRepository injectRepository) { + private static Set getInjectTeamsIds( + final String teamId, Set injectIds, final InjectRepository injectRepository) { Set rawInjectTeams = injectRepository.findRawInjectTeams(injectIds, teamId); - return rawInjectTeams.stream() - .map(RawInject::getInject_id) - .collect(Collectors.toSet()); + return rawInjectTeams.stream().map(RawInject::getInject_id).collect(Collectors.toSet()); } - } diff --git a/openbas-api/src/main/java/io/openbas/rest/helper/ValidationErrorBag.java b/openbas-api/src/main/java/io/openbas/rest/helper/ValidationErrorBag.java index 11c0fca005..fdacc1d291 100644 --- a/openbas-api/src/main/java/io/openbas/rest/helper/ValidationErrorBag.java +++ b/openbas-api/src/main/java/io/openbas/rest/helper/ValidationErrorBag.java @@ -4,68 +4,68 @@ import java.util.Map; class ValidationContent { - private List errors; + private List errors; - public ValidationContent(String error) { - this.errors = List.of(error); - } + public ValidationContent(String error) { + this.errors = List.of(error); + } - public List getErrors() { - return errors; - } + public List getErrors() { + return errors; + } - public void setErrors(List errors) { - this.errors = errors; - } + public void setErrors(List errors) { + this.errors = errors; + } } class ValidationError { - private Map children; + private Map children; - public Map getChildren() { - return children; - } + public Map getChildren() { + return children; + } - public void setChildren(Map children) { - this.children = children; - } + public void setChildren(Map children) { + this.children = children; + } } public class ValidationErrorBag { - private int code = 400; - private String message = "Validation Failed"; - private ValidationError errors; - - public ValidationErrorBag() { - // Default constructor - } - - public ValidationErrorBag(int code, String message) { - this.code = code; - this.message = message; - } - - public int getCode() { - return code; - } - - public void setCode(int code) { - this.code = code; - } - - public String getMessage() { - return message; - } - - public void setMessage(String message) { - this.message = message; - } - - public ValidationError getErrors() { - return errors; - } - - public void setErrors(ValidationError errors) { - this.errors = errors; - } + private int code = 400; + private String message = "Validation Failed"; + private ValidationError errors; + + public ValidationErrorBag() { + // Default constructor + } + + public ValidationErrorBag(int code, String message) { + this.code = code; + this.message = message; + } + + public int getCode() { + return code; + } + + public void setCode(int code) { + this.code = code; + } + + public String getMessage() { + return message; + } + + public void setMessage(String message) { + this.message = message; + } + + public ValidationError getErrors() { + return errors; + } + + public void setErrors(ValidationError errors) { + this.errors = errors; + } } diff --git a/openbas-api/src/main/java/io/openbas/rest/helper/ViolationErrorBag.java b/openbas-api/src/main/java/io/openbas/rest/helper/ViolationErrorBag.java index 6535a774d2..19a4371391 100644 --- a/openbas-api/src/main/java/io/openbas/rest/helper/ViolationErrorBag.java +++ b/openbas-api/src/main/java/io/openbas/rest/helper/ViolationErrorBag.java @@ -2,33 +2,33 @@ public class ViolationErrorBag { - private String type; + private String type; - private String message; + private String message; - private String error; + private String error; - public String getType() { - return type; - } + public String getType() { + return type; + } - public void setType(String type) { - this.type = type; - } + public void setType(String type) { + this.type = type; + } - public String getMessage() { - return message; - } + public String getMessage() { + return message; + } - public void setMessage(String message) { - this.message = message; - } + public void setMessage(String message) { + this.message = message; + } - public String getError() { - return error; - } + public String getError() { + return error; + } - public void setError(String error) { - this.error = error; - } + public void setError(String error) { + this.error = error; + } } diff --git a/openbas-api/src/main/java/io/openbas/rest/inject/ExerciseInjectApi.java b/openbas-api/src/main/java/io/openbas/rest/inject/ExerciseInjectApi.java index 32ea4b1177..f64f2bcbff 100644 --- a/openbas-api/src/main/java/io/openbas/rest/inject/ExerciseInjectApi.java +++ b/openbas-api/src/main/java/io/openbas/rest/inject/ExerciseInjectApi.java @@ -1,5 +1,9 @@ package io.openbas.rest.inject; +import static io.openbas.database.specification.InjectSpecification.fromExercise; +import static io.openbas.rest.exercise.ExerciseApi.EXERCISE_URI; +import static io.openbas.utils.pagination.PaginationUtils.buildPaginationCriteriaBuilder; + import io.openbas.database.model.Inject; import io.openbas.database.model.InjectTestStatus; import io.openbas.rest.helper.RestBehavior; @@ -14,6 +18,7 @@ import io.swagger.v3.oas.annotations.responses.ApiResponses; import jakarta.validation.Valid; import jakarta.validation.constraints.NotBlank; +import java.util.List; import lombok.RequiredArgsConstructor; import org.springframework.data.domain.Page; import org.springframework.data.domain.Pageable; @@ -22,12 +27,6 @@ import org.springframework.transaction.annotation.Transactional; import org.springframework.web.bind.annotation.*; -import java.util.List; - -import static io.openbas.database.specification.InjectSpecification.fromExercise; -import static io.openbas.rest.exercise.ExerciseApi.EXERCISE_URI; -import static io.openbas.utils.pagination.PaginationUtils.buildPaginationCriteriaBuilder; - @RestController @RequiredArgsConstructor public class ExerciseInjectApi extends RestBehavior { @@ -37,18 +36,22 @@ public class ExerciseInjectApi extends RestBehavior { private final InjectTestStatusService injectTestStatusService; @Operation(summary = "Retrieved injects for an exercise") - @ApiResponses(value = { - @ApiResponse( - responseCode = "200", description = "Retrieved injects for an exercise", - content = { - @Content(mediaType = "application/json", schema = @Schema(implementation = InjectOutput.class)) - } - ), - }) + @ApiResponses( + value = { + @ApiResponse( + responseCode = "200", + description = "Retrieved injects for an exercise", + content = { + @Content( + mediaType = "application/json", + schema = @Schema(implementation = InjectOutput.class)) + }), + }) @GetMapping(EXERCISE_URI + "/{exerciseId}/injects/simple") @PreAuthorize("isExerciseObserver(#exerciseId)") @Transactional(readOnly = true) - public Iterable exerciseInjectsSimple(@PathVariable @NotBlank final String exerciseId) { + public Iterable exerciseInjectsSimple( + @PathVariable @NotBlank final String exerciseId) { return injectService.injects(fromExercise(exerciseId)); } @@ -59,28 +62,29 @@ public Iterable exerciseInjectsSimple( @PathVariable @NotBlank final String exerciseId, @RequestBody @Valid final SearchPaginationInput searchPaginationInput) { return buildPaginationCriteriaBuilder( - (Specification specification, Specification specificationCount, Pageable pageable) -> this.injectService.injects( - fromExercise(exerciseId).and(specification), - fromExercise(exerciseId).and(specificationCount), - pageable - ), + (Specification specification, + Specification specificationCount, + Pageable pageable) -> + this.injectService.injects( + fromExercise(exerciseId).and(specification), + fromExercise(exerciseId).and(specificationCount), + pageable), searchPaginationInput, - Inject.class - ); + Inject.class); } @DeleteMapping(EXERCISE_URI + "/{exerciseId}/injects") @PreAuthorize("isExercisePlanner(#exerciseId)") - public void deleteListOfInjectsForExercise(@PathVariable final String exerciseId, - @RequestBody List injectIds) { + public void deleteListOfInjectsForExercise( + @PathVariable final String exerciseId, @RequestBody List injectIds) { injectService.deleteAllByIds(injectIds); } @PostMapping("/api/exercise/{exerciseId}/injects/test") - public Page findAllExerciseInjectTests(@PathVariable @NotBlank String exerciseId, - @RequestBody @Valid - SearchPaginationInput searchPaginationInput) { - return injectTestStatusService.findAllInjectTestsByExerciseId(exerciseId, searchPaginationInput); + public Page findAllExerciseInjectTests( + @PathVariable @NotBlank String exerciseId, + @RequestBody @Valid SearchPaginationInput searchPaginationInput) { + return injectTestStatusService.findAllInjectTestsByExerciseId( + exerciseId, searchPaginationInput); } - } diff --git a/openbas-api/src/main/java/io/openbas/rest/inject/InjectApi.java b/openbas-api/src/main/java/io/openbas/rest/inject/InjectApi.java index 690e765168..fc17ee7065 100644 --- a/openbas-api/src/main/java/io/openbas/rest/inject/InjectApi.java +++ b/openbas-api/src/main/java/io/openbas/rest/inject/InjectApi.java @@ -1,5 +1,18 @@ package io.openbas.rest.inject; +import static io.openbas.config.SessionHelper.currentUser; +import static io.openbas.database.model.User.ROLE_ADMIN; +import static io.openbas.database.specification.CommunicationSpecification.fromInject; +import static io.openbas.helper.DatabaseHelper.resolveOptionalRelation; +import static io.openbas.helper.DatabaseHelper.updateRelation; +import static io.openbas.helper.StreamHelper.fromIterable; +import static io.openbas.helper.StreamHelper.iterableToSet; +import static io.openbas.rest.exercise.ExerciseApi.EXERCISE_URI; +import static io.openbas.rest.scenario.ScenarioApi.SCENARIO_URI; +import static io.openbas.utils.AtomicTestingUtils.getTargets; +import static io.openbas.utils.pagination.PaginationUtils.buildPaginationJPA; +import static java.time.Instant.now; + import com.fasterxml.jackson.core.JsonProcessingException; import com.fasterxml.jackson.databind.JsonNode; import com.fasterxml.jackson.databind.node.ArrayNode; @@ -27,6 +40,12 @@ import jakarta.validation.Valid; import jakarta.validation.constraints.NotBlank; import jakarta.validation.constraints.NotNull; +import java.time.Duration; +import java.time.Instant; +import java.util.List; +import java.util.Optional; +import java.util.stream.Collectors; +import java.util.stream.StreamSupport; import lombok.RequiredArgsConstructor; import lombok.extern.java.Log; import org.springframework.data.domain.Page; @@ -39,26 +58,6 @@ import org.springframework.web.bind.annotation.*; import org.springframework.web.multipart.MultipartFile; -import java.time.Duration; -import java.time.Instant; -import java.util.List; -import java.util.Optional; -import java.util.stream.Collectors; -import java.util.stream.StreamSupport; - -import static io.openbas.config.SessionHelper.currentUser; -import static io.openbas.database.model.User.ROLE_ADMIN; -import static io.openbas.database.specification.CommunicationSpecification.fromInject; -import static io.openbas.helper.DatabaseHelper.resolveOptionalRelation; -import static io.openbas.helper.DatabaseHelper.updateRelation; -import static io.openbas.helper.StreamHelper.fromIterable; -import static io.openbas.helper.StreamHelper.iterableToSet; -import static io.openbas.rest.exercise.ExerciseApi.EXERCISE_URI; -import static io.openbas.rest.scenario.ScenarioApi.SCENARIO_URI; -import static io.openbas.utils.AtomicTestingUtils.getTargets; -import static io.openbas.utils.pagination.PaginationUtils.buildPaginationJPA; -import static java.time.Instant.now; - @Log @RestController @RequiredArgsConstructor @@ -97,8 +96,8 @@ public Inject inject(@PathVariable @NotBlank final String injectId) { @Secured(ROLE_ADMIN) @PostMapping(INJECT_URI + "/execution/reception/{injectId}") - public Inject injectExecutionReception(@PathVariable String injectId, - @Valid @RequestBody InjectReceptionInput input) { + public Inject injectExecutionReception( + @PathVariable String injectId, @Valid @RequestBody InjectReceptionInput input) { Inject inject = injectRepository.findById(injectId).orElseThrow(ElementNotFoundException::new); InjectStatus injectStatus = inject.getStatus().orElseThrow(ElementNotFoundException::new); injectStatus.setName(ExecutionStatus.PENDING); @@ -111,7 +110,8 @@ public Inject injectExecutionReception(@PathVariable String injectId, @Secured(ROLE_ADMIN) @PostMapping(INJECT_URI + "/execution/callback/{injectId}") - public Inject injectExecutionCallback(@PathVariable String injectId, @Valid @RequestBody InjectExecutionInput input) { + public Inject injectExecutionCallback( + @PathVariable String injectId, @Valid @RequestBody InjectExecutionInput input) { Inject inject = injectRepository.findById(injectId).orElseThrow(ElementNotFoundException::new); InjectStatus injectStatus = inject.getStatus().orElseThrow(ElementNotFoundException::new); ExecutionStatus executionStatus = ExecutionStatus.valueOf(input.getStatus()); @@ -127,20 +127,28 @@ public Inject injectExecutionCallback(@PathVariable String injectId, @Valid @Req } else { injectStatus.setTrackingTotalError(injectStatus.getTrackingTotalSuccess() + 1); } - int currentTotal = injectStatus.getTrackingTotalError() + injectStatus.getTrackingTotalSuccess(); + int currentTotal = + injectStatus.getTrackingTotalError() + injectStatus.getTrackingTotalSuccess(); if (injectStatus.getTrackingTotalCount() >= currentTotal) { injectStatus.setTrackingEndDate(trackingEndDate); injectStatus.setTrackingTotalExecutionTime( Duration.between(injectStatus.getTrackingSentDate(), trackingEndDate).getSeconds()); if (injectStatus.getTraces().stream() - .filter(injectStatusExecution -> injectStatusExecution.getStatus().equals(ExecutionStatus.ERROR)).count() + .filter( + injectStatusExecution -> + injectStatusExecution.getStatus().equals(ExecutionStatus.ERROR)) + .count() >= injectStatus.getTrackingTotalCount()) { injectStatus.setName(ExecutionStatus.ERROR); - } else if (injectStatus.getTraces().stream().anyMatch(trace -> trace.getStatus().equals(ExecutionStatus.ERROR))) { + } else if (injectStatus.getTraces().stream() + .anyMatch(trace -> trace.getStatus().equals(ExecutionStatus.ERROR))) { injectStatus.setName(ExecutionStatus.PARTIAL); } else if (injectStatus.getTraces().stream() - .filter(injectStatusExecution -> injectStatusExecution.getStatus().equals(ExecutionStatus.MAYBE_PREVENTED)) - .count() >= injectStatus.getTrackingTotalCount()) { + .filter( + injectStatusExecution -> + injectStatusExecution.getStatus().equals(ExecutionStatus.MAYBE_PREVENTED)) + .count() + >= injectStatus.getTrackingTotalCount()) { injectStatus.setName(ExecutionStatus.MAYBE_PREVENTED); } else if (injectStatus.getTraces().stream() .anyMatch(trace -> trace.getStatus().equals(ExecutionStatus.MAYBE_PREVENTED))) { @@ -164,15 +172,19 @@ public Inject updateInject( @PathVariable String exerciseId, @PathVariable String injectId, @Valid @RequestBody InjectInput input) { - Exercise exercise = exerciseRepository.findById(exerciseId).orElseThrow(ElementNotFoundException::new); + Exercise exercise = + exerciseRepository.findById(exerciseId).orElseThrow(ElementNotFoundException::new); Inject inject = updateInject(injectId, input); // If Documents not yet linked directly to the exercise, attached it - inject.getDocuments().forEach(document -> { - if (!document.getDocument().getExercises().contains(exercise)) { - exercise.getDocuments().add(document.getDocument()); - } - }); + inject + .getDocuments() + .forEach( + document -> { + if (!document.getDocument().getExercises().contains(exercise)) { + exercise.getDocuments().add(document.getDocument()); + } + }); this.exerciseRepository.save(exercise); return injectRepository.save(inject); } @@ -193,8 +205,7 @@ public Inject bulkUpdateInject( @GetMapping(EXERCISE_URI + "/{exerciseId}/injects") @PreAuthorize("isExerciseObserver(#exerciseId)") public Iterable exerciseInjects(@PathVariable @NotBlank final String exerciseId) { - return injectRepository.findByExerciseId(exerciseId) - .stream() + return injectRepository.findByExerciseId(exerciseId).stream() .sorted(Inject.executionComparator) .toList(); } @@ -206,32 +217,30 @@ public Page exerciseInjects( @PathVariable final String exerciseId, @RequestBody @Valid SearchPaginationInput searchPaginationInput) { return buildPaginationJPA( - (Specification specification, Pageable pageable) -> this.injectRepository.findAll( - InjectSpecification.fromExercise(exerciseId).and(specification), pageable), - searchPaginationInput, - Inject.class - ).map(inject -> AtomicTestingMapper.toDto( - inject, getTargets( - inject.getTeams(), - inject.getAssets(), - inject.getAssetGroups() - ) - )); + (Specification specification, Pageable pageable) -> + this.injectRepository.findAll( + InjectSpecification.fromExercise(exerciseId).and(specification), pageable), + searchPaginationInput, + Inject.class) + .map( + inject -> + AtomicTestingMapper.toDto( + inject, + getTargets(inject.getTeams(), inject.getAssets(), inject.getAssetGroups()))); } @GetMapping(EXERCISE_URI + "/{exerciseId}/injects/resultdto") @PreAuthorize("isExerciseObserver(#exerciseId)") @Transactional(readOnly = true) - public List exerciseInjectsWithExpectations(@PathVariable final String exerciseId) { + public List exerciseInjectsWithExpectations( + @PathVariable final String exerciseId) { return this.injectRepository.findAll(InjectSpecification.fromExercise(exerciseId)).stream() - .map(inject -> AtomicTestingMapper.toDto( - inject, getTargets( - inject.getTeams(), - inject.getAssets(), - inject.getAssetGroups() - ) - )) - .collect(Collectors.toList()); + .map( + inject -> + AtomicTestingMapper.toDto( + inject, + getTargets(inject.getTeams(), inject.getAssets(), inject.getAssetGroups()))) + .collect(Collectors.toList()); } @GetMapping(EXERCISE_URI + "/{exerciseId}/injects/{injectId}") @@ -242,16 +251,21 @@ public Inject exerciseInject(@PathVariable String exerciseId, @PathVariable Stri @GetMapping(EXERCISE_URI + "/{exerciseId}/injects/{injectId}/teams") @PreAuthorize("isExerciseObserver(#exerciseId)") - public Iterable exerciseInjectTeams(@PathVariable String exerciseId, @PathVariable String injectId) { - return injectRepository.findById(injectId).orElseThrow(ElementNotFoundException::new).getTeams(); + public Iterable exerciseInjectTeams( + @PathVariable String exerciseId, @PathVariable String injectId) { + return injectRepository + .findById(injectId) + .orElseThrow(ElementNotFoundException::new) + .getTeams(); } @GetMapping(EXERCISE_URI + "/{exerciseId}/injects/{injectId}/communications") @PreAuthorize("isExerciseObserver(#exerciseId)") - public Iterable exerciseInjectCommunications(@PathVariable String exerciseId, - @PathVariable String injectId) { - List coms = communicationRepository.findAll(fromInject(injectId), - Sort.by(Sort.Direction.DESC, "receivedAt")); + public Iterable exerciseInjectCommunications( + @PathVariable String exerciseId, @PathVariable String injectId) { + List coms = + communicationRepository.findAll( + fromInject(injectId), Sort.by(Sort.Direction.DESC, "receivedAt")); List ackComs = coms.stream().peek(com -> com.setAck(true)).toList(); return communicationRepository.saveAll(ackComs); } @@ -259,31 +273,43 @@ public Iterable exerciseInjectCommunications(@PathVariable String @PostMapping(EXERCISE_URI + "/{exerciseId}/injects") @PreAuthorize("isExercisePlanner(#exerciseId)") @Transactional(rollbackFor = Exception.class) - public Inject createInjectForExercise(@PathVariable String exerciseId, @Valid @RequestBody InjectInput input) { - Exercise exercise = exerciseRepository.findById(exerciseId).orElseThrow(ElementNotFoundException::new); - InjectorContract injectorContract = injectorContractRepository.findById(input.getInjectorContract()) - .orElseThrow(ElementNotFoundException::new); + public Inject createInjectForExercise( + @PathVariable String exerciseId, @Valid @RequestBody InjectInput input) { + Exercise exercise = + exerciseRepository.findById(exerciseId).orElseThrow(ElementNotFoundException::new); + InjectorContract injectorContract = + injectorContractRepository + .findById(input.getInjectorContract()) + .orElseThrow(ElementNotFoundException::new); // Set expectations ObjectNode finalContent = input.getContent(); - if (input.getContent() == null || input.getContent().get(EXPECTATIONS) == null || input.getContent() - .get(EXPECTATIONS).isEmpty()) { + if (input.getContent() == null + || input.getContent().get(EXPECTATIONS) == null + || input.getContent().get(EXPECTATIONS).isEmpty()) { try { JsonNode jsonNode = mapper.readTree(injectorContract.getContent()); - List contractElements = StreamSupport.stream(jsonNode.get("fields").spliterator(), false).filter( - contractElement -> contractElement.get("type").asText() - .equals(ContractType.Expectation.name().toLowerCase())).toList(); + List contractElements = + StreamSupport.stream(jsonNode.get("fields").spliterator(), false) + .filter( + contractElement -> + contractElement + .get("type") + .asText() + .equals(ContractType.Expectation.name().toLowerCase())) + .toList(); if (!contractElements.isEmpty()) { JsonNode contractElement = contractElements.getFirst(); - if (!contractElement.get(PREDEFINE_EXPECTATIONS).isNull() && !contractElement.get(PREDEFINE_EXPECTATIONS) - .isEmpty()) { + if (!contractElement.get(PREDEFINE_EXPECTATIONS).isNull() + && !contractElement.get(PREDEFINE_EXPECTATIONS).isEmpty()) { finalContent = finalContent != null ? finalContent : mapper.createObjectNode(); ArrayNode predefinedExpectations = mapper.createArrayNode(); StreamSupport.stream(contractElement.get(PREDEFINE_EXPECTATIONS).spliterator(), false) - .forEach(predefinedExpectation -> { - ObjectNode newExpectation = predefinedExpectation.deepCopy(); - newExpectation.put("expectation_score", 100); - predefinedExpectations.add(newExpectation); - }); + .forEach( + predefinedExpectation -> { + ObjectNode newExpectation = predefinedExpectation.deepCopy(); + newExpectation.put("expectation_score", 100); + predefinedExpectations.add(newExpectation); + }); finalContent.put(EXPECTATIONS, predefinedExpectations); } } @@ -294,7 +320,8 @@ public Inject createInjectForExercise(@PathVariable String exerciseId, @Valid @R input.setContent(finalContent); // Get common attributes Inject inject = input.toInject(injectorContract); - inject.setUser(userRepository.findById(currentUser().getId()).orElseThrow(ElementNotFoundException::new)); + inject.setUser( + userRepository.findById(currentUser().getId()).orElseThrow(ElementNotFoundException::new)); inject.setExercise(exercise); // Set dependencies inject.setDependsOn(resolveOptionalRelation(input.getDependsOn(), injectRepository)); @@ -302,28 +329,37 @@ public Inject createInjectForExercise(@PathVariable String exerciseId, @Valid @R inject.setAssets(fromIterable(assetService.assets(input.getAssets()))); inject.setAssetGroups(fromIterable(assetGroupService.assetGroups(input.getAssetGroups()))); inject.setTags(iterableToSet(tagRepository.findAllById(input.getTagIds()))); - List injectDocuments = input.getDocuments().stream() - .map(i -> { - InjectDocument injectDocument = new InjectDocument(); - injectDocument.setInject(inject); - injectDocument.setDocument( - documentRepository.findById(i.getDocumentId()).orElseThrow(ElementNotFoundException::new)); - injectDocument.setAttached(i.isAttached()); - return injectDocument; - }).toList(); + List injectDocuments = + input.getDocuments().stream() + .map( + i -> { + InjectDocument injectDocument = new InjectDocument(); + injectDocument.setInject(inject); + injectDocument.setDocument( + documentRepository + .findById(i.getDocumentId()) + .orElseThrow(ElementNotFoundException::new)); + injectDocument.setAttached(i.isAttached()); + return injectDocument; + }) + .toList(); inject.setDocuments(injectDocuments); // Linked documents directly to the exercise - inject.getDocuments().forEach(document -> { - if (!document.getDocument().getExercises().contains(exercise)) { - exercise.getDocuments().add(document.getDocument()); - } - }); + inject + .getDocuments() + .forEach( + document -> { + if (!document.getDocument().getExercises().contains(exercise)) { + exercise.getDocuments().add(document.getDocument()); + } + }); return injectRepository.save(inject); } @PostMapping(EXERCISE_URI + "/{exerciseId}/injects/{injectId}") @PreAuthorize("isExercisePlanner(#exerciseId)") - public Inject duplicateInjectForExercise(@PathVariable final String exerciseId, @PathVariable final String injectId) { + public Inject duplicateInjectForExercise( + @PathVariable final String exerciseId, @PathVariable final String injectId) { return injectDuplicateService.createInjectForExercise(exerciseId, injectId, true); } @@ -334,29 +370,38 @@ public InjectStatus executeInject( @PathVariable @NotBlank final String exerciseId, @Valid @RequestPart("input") DirectInjectInput input, @RequestPart("file") Optional file) { - Inject inject = input.toInject( - this.injectorContractRepository.findById(input.getInjectorContract()) - .orElseThrow(() -> new ElementNotFoundException("Injector contract not found")) - ); + Inject inject = + input.toInject( + this.injectorContractRepository + .findById(input.getInjectorContract()) + .orElseThrow(() -> new ElementNotFoundException("Injector contract not found"))); inject.setUser( - this.userRepository.findById(currentUser().getId()) - .orElseThrow(() -> new ElementNotFoundException("Current user not found")) - ); + this.userRepository + .findById(currentUser().getId()) + .orElseThrow(() -> new ElementNotFoundException("Current user not found"))); inject.setExercise( - this.exerciseRepository.findById(exerciseId) - .orElseThrow(() -> new ElementNotFoundException("Exercise not found")) - ); + this.exerciseRepository + .findById(exerciseId) + .orElseThrow(() -> new ElementNotFoundException("Exercise not found"))); inject.setDependsDuration(0L); Inject savedInject = this.injectRepository.save(inject); Iterable users = this.userRepository.findAllById(input.getUserIds()); - List userInjectContexts = fromIterable(users) - .stream() - .map(user -> this.executionContextService.executionContext(user, savedInject, "Direct execution")) - .collect(Collectors.toList()); - ExecutableInject injection = new ExecutableInject( - true, true, savedInject, List.of(), savedInject.getAssets(), - savedInject.getAssetGroups(), userInjectContexts - ); + List userInjectContexts = + fromIterable(users).stream() + .map( + user -> + this.executionContextService.executionContext( + user, savedInject, "Direct execution")) + .collect(Collectors.toList()); + ExecutableInject injection = + new ExecutableInject( + true, + true, + savedInject, + List.of(), + savedInject.getAssets(), + savedInject.getAssetGroups(), + userInjectContexts); file.ifPresent(injection::addDirectAttachment); return executor.execute(injection); } @@ -381,8 +426,7 @@ public Inject updateInjectActivationForExercise( @PutMapping(EXERCISE_URI + "/{exerciseId}/injects/{injectId}/trigger") @PreAuthorize("isExercisePlanner(#exerciseId)") public Inject updateInjectTrigger( - @PathVariable String exerciseId, - @PathVariable String injectId) { + @PathVariable String exerciseId, @PathVariable String injectId) { Inject inject = injectRepository.findById(injectId).orElseThrow(ElementNotFoundException::new); inject.setTriggerNowDate(now()); inject.setUpdatedAt(now()); @@ -392,14 +436,18 @@ public Inject updateInjectTrigger( @Transactional(rollbackFor = Exception.class) @PostMapping(EXERCISE_URI + "/{exerciseId}/injects/{injectId}/status") @PreAuthorize("isExercisePlanner(#exerciseId)") - public Inject setInjectStatus(@PathVariable String exerciseId, @PathVariable String injectId, + public Inject setInjectStatus( + @PathVariable String exerciseId, + @PathVariable String injectId, @Valid @RequestBody InjectUpdateStatusInput input) { return injectService.updateInjectStatus(injectId, input); } @PutMapping(EXERCISE_URI + "/{exerciseId}/injects/{injectId}/teams") @PreAuthorize("isExercisePlanner(#exerciseId)") - public Inject updateInjectTeams(@PathVariable String exerciseId, @PathVariable String injectId, + public Inject updateInjectTeams( + @PathVariable String exerciseId, + @PathVariable String injectId, @Valid @RequestBody InjectTeamsInput input) { Inject inject = injectRepository.findById(injectId).orElseThrow(ElementNotFoundException::new); Iterable injectTeams = teamRepository.findAllById(input.getTeamIds()); @@ -412,8 +460,14 @@ public List nextInjectsToExecute(@RequestParam Optional size) { return injectRepository.findAll(InjectSpecification.next()).stream() // Keep only injects visible by the user .filter(inject -> inject.getDate().isPresent()) - .filter(inject -> inject.getExercise() - .isUserHasAccess(userRepository.findById(currentUser().getId()).orElseThrow(ElementNotFoundException::new))) + .filter( + inject -> + inject + .getExercise() + .isUserHasAccess( + userRepository + .findById(currentUser().getId()) + .orElseThrow(ElementNotFoundException::new))) // Order by near execution .sorted(Inject.executionComparator) // Keep only the expected size @@ -428,32 +482,41 @@ public List nextInjectsToExecute(@RequestParam Optional size) { @PreAuthorize("isScenarioPlanner(#scenarioId)") @Transactional(rollbackFor = Exception.class) public Inject createInjectForScenario( - @PathVariable @NotBlank final String scenarioId, - @Valid @RequestBody InjectInput input) { + @PathVariable @NotBlank final String scenarioId, @Valid @RequestBody InjectInput input) { Scenario scenario = this.scenarioService.scenario(scenarioId); - InjectorContract injectorContract = injectorContractRepository.findById(input.getInjectorContract()) - .orElseThrow(ElementNotFoundException::new); + InjectorContract injectorContract = + injectorContractRepository + .findById(input.getInjectorContract()) + .orElseThrow(ElementNotFoundException::new); // Set expectations ObjectNode finalContent = input.getContent(); - if (input.getContent() == null || input.getContent().get(EXPECTATIONS) == null || input.getContent() - .get(EXPECTATIONS).isEmpty()) { + if (input.getContent() == null + || input.getContent().get(EXPECTATIONS) == null + || input.getContent().get(EXPECTATIONS).isEmpty()) { try { JsonNode jsonNode = mapper.readTree(injectorContract.getContent()); - List contractElements = StreamSupport.stream(jsonNode.get("fields").spliterator(), false).filter( - contractElement -> contractElement.get("type").asText() - .equals(ContractType.Expectation.name().toLowerCase())).toList(); + List contractElements = + StreamSupport.stream(jsonNode.get("fields").spliterator(), false) + .filter( + contractElement -> + contractElement + .get("type") + .asText() + .equals(ContractType.Expectation.name().toLowerCase())) + .toList(); if (!contractElements.isEmpty()) { JsonNode contractElement = contractElements.getFirst(); - if (!contractElement.get(PREDEFINE_EXPECTATIONS).isNull() && !contractElement.get(PREDEFINE_EXPECTATIONS) - .isEmpty()) { + if (!contractElement.get(PREDEFINE_EXPECTATIONS).isNull() + && !contractElement.get(PREDEFINE_EXPECTATIONS).isEmpty()) { finalContent = finalContent != null ? finalContent : mapper.createObjectNode(); ArrayNode predefinedExpectations = mapper.createArrayNode(); StreamSupport.stream(contractElement.get(PREDEFINE_EXPECTATIONS).spliterator(), false) - .forEach(predefinedExpectation -> { - ObjectNode newExpectation = predefinedExpectation.deepCopy(); - newExpectation.put("expectation_score", 100); - predefinedExpectations.add(newExpectation); - }); + .forEach( + predefinedExpectation -> { + ObjectNode newExpectation = predefinedExpectation.deepCopy(); + newExpectation.put("expectation_score", 100); + predefinedExpectations.add(newExpectation); + }); finalContent.put(EXPECTATIONS, predefinedExpectations); } } @@ -464,7 +527,10 @@ public Inject createInjectForScenario( input.setContent(finalContent); // Get common attributes Inject inject = input.toInject(injectorContract); - inject.setUser(this.userRepository.findById(currentUser().getId()).orElseThrow(ElementNotFoundException::new)); + inject.setUser( + this.userRepository + .findById(currentUser().getId()) + .orElseThrow(ElementNotFoundException::new)); inject.setScenario(scenario); // Set dependencies inject.setDependsOn(resolveOptionalRelation(input.getDependsOn(), this.injectRepository)); @@ -472,36 +538,44 @@ public Inject createInjectForScenario( inject.setAssets(fromIterable(assetService.assets(input.getAssets()))); inject.setAssetGroups(fromIterable(assetGroupService.assetGroups(input.getAssetGroups()))); inject.setTags(iterableToSet(tagRepository.findAllById(input.getTagIds()))); - List injectDocuments = input.getDocuments().stream() - .map(i -> { - InjectDocument injectDocument = new InjectDocument(); - injectDocument.setInject(inject); - injectDocument.setDocument( - documentRepository.findById(i.getDocumentId()).orElseThrow(ElementNotFoundException::new)); - injectDocument.setAttached(i.isAttached()); - return injectDocument; - }).toList(); + List injectDocuments = + input.getDocuments().stream() + .map( + i -> { + InjectDocument injectDocument = new InjectDocument(); + injectDocument.setInject(inject); + injectDocument.setDocument( + documentRepository + .findById(i.getDocumentId()) + .orElseThrow(ElementNotFoundException::new)); + injectDocument.setAttached(i.isAttached()); + return injectDocument; + }) + .toList(); inject.setDocuments(injectDocuments); // Linked documents directly to the exercise - inject.getDocuments().forEach(document -> { - if (!document.getDocument().getScenarios().contains(scenario)) { - scenario.getDocuments().add(document.getDocument()); - } - }); + inject + .getDocuments() + .forEach( + document -> { + if (!document.getDocument().getScenarios().contains(scenario)) { + scenario.getDocuments().add(document.getDocument()); + } + }); return injectRepository.save(inject); } @PostMapping(SCENARIO_URI + "/{scenarioId}/injects/{injectId}") @PreAuthorize("isScenarioPlanner(#scenarioId)") - public Inject duplicateInjectForScenario(@PathVariable final String scenarioId, @PathVariable final String injectId) { + public Inject duplicateInjectForScenario( + @PathVariable final String scenarioId, @PathVariable final String injectId) { return injectDuplicateService.createInjectForScenario(scenarioId, injectId, true); } @GetMapping(SCENARIO_URI + "/{scenarioId}/injects") @PreAuthorize("isScenarioObserver(#scenarioId)") public Iterable scenarioInjects(@PathVariable @NotBlank final String scenarioId) { - return this.injectRepository.findByScenarioId(scenarioId) - .stream() + return this.injectRepository.findByScenarioId(scenarioId).stream() .sorted(Inject.executionComparator) .toList(); } @@ -538,11 +612,14 @@ public Inject updateInjectForScenario( Inject inject = updateInject(injectId, input); // If Documents not yet linked directly to the exercise, attached it - inject.getDocuments().forEach(document -> { - if (!document.getDocument().getScenarios().contains(scenario)) { - scenario.getDocuments().add(document.getDocument()); - } - }); + inject + .getDocuments() + .forEach( + document -> { + if (!document.getDocument().getScenarios().contains(scenario)) { + scenario.getDocuments().add(document.getDocument()); + } + }); this.scenarioService.updateScenario(scenario); return injectRepository.save(inject); } @@ -571,11 +648,13 @@ public void deleteInjectForScenario( // -- PRIVATE -- private Inject updateInject(@NotBlank final String injectId, @NotNull InjectInput input) { - Inject inject = this.injectRepository.findById(injectId).orElseThrow(ElementNotFoundException::new); + Inject inject = + this.injectRepository.findById(injectId).orElseThrow(ElementNotFoundException::new); inject.setUpdateAttributes(input); // Set dependencies - inject.setDependsOn(updateRelation(input.getDependsOn(), inject.getDependsOn(), this.injectRepository)); + inject.setDependsOn( + updateRelation(input.getDependsOn(), inject.getDependsOn(), this.injectRepository)); inject.setTeams(fromIterable(this.teamRepository.findAllById(input.getTeams()))); inject.setAssets(fromIterable(this.assetService.assets(input.getAssets()))); inject.setAssetGroups(fromIterable(this.assetGroupService.assetGroups(input.getAssetGroups()))); @@ -585,41 +664,50 @@ private Inject updateInject(@NotBlank final String injectId, @NotNull InjectInpu List inputDocuments = input.getDocuments(); List injectDocuments = inject.getDocuments(); - List askedDocumentIds = inputDocuments.stream().map(InjectDocumentInput::getDocumentId).toList(); - List currentDocumentIds = inject.getDocuments().stream().map(document -> document.getDocument().getId()) - .toList(); + List askedDocumentIds = + inputDocuments.stream().map(InjectDocumentInput::getDocumentId).toList(); + List currentDocumentIds = + inject.getDocuments().stream().map(document -> document.getDocument().getId()).toList(); // To delete - List toRemoveDocuments = injectDocuments.stream() - .filter(injectDoc -> !askedDocumentIds.contains(injectDoc.getDocument().getId())) - .toList(); + List toRemoveDocuments = + injectDocuments.stream() + .filter(injectDoc -> !askedDocumentIds.contains(injectDoc.getDocument().getId())) + .toList(); injectDocuments.removeAll(toRemoveDocuments); // To add - inputDocuments.stream().filter(doc -> !currentDocumentIds.contains(doc.getDocumentId())).forEach(in -> { - Optional doc = this.documentRepository.findById(in.getDocumentId()); - if (doc.isPresent()) { - InjectDocument injectDocument = new InjectDocument(); - injectDocument.setInject(inject); - Document document = doc.get(); - injectDocument.setDocument(document); - injectDocument.setAttached(in.isAttached()); - InjectDocument savedInjectDoc = this.injectDocumentRepository.save(injectDocument); - injectDocuments.add(savedInjectDoc); - } - }); + inputDocuments.stream() + .filter(doc -> !currentDocumentIds.contains(doc.getDocumentId())) + .forEach( + in -> { + Optional doc = this.documentRepository.findById(in.getDocumentId()); + if (doc.isPresent()) { + InjectDocument injectDocument = new InjectDocument(); + injectDocument.setInject(inject); + Document document = doc.get(); + injectDocument.setDocument(document); + injectDocument.setAttached(in.isAttached()); + InjectDocument savedInjectDoc = this.injectDocumentRepository.save(injectDocument); + injectDocuments.add(savedInjectDoc); + } + }); // Remap the attached boolean - injectDocuments.forEach(injectDoc -> { - Optional inputInjectDoc = input.getDocuments().stream() - .filter(id -> id.getDocumentId().equals(injectDoc.getDocument().getId())).findFirst(); - Boolean attached = inputInjectDoc.map(InjectDocumentInput::isAttached).orElse(false); - injectDoc.setAttached(attached); - }); + injectDocuments.forEach( + injectDoc -> { + Optional inputInjectDoc = + input.getDocuments().stream() + .filter(id -> id.getDocumentId().equals(injectDoc.getDocument().getId())) + .findFirst(); + Boolean attached = inputInjectDoc.map(InjectDocumentInput::isAttached).orElse(false); + injectDoc.setAttached(attached); + }); inject.setDocuments(injectDocuments); return inject; } private Inject bulkUpdateInject(@NotBlank final String injectId, @NotNull InjectInput input) { - Inject inject = this.injectRepository.findById(injectId).orElseThrow(ElementNotFoundException::new); + Inject inject = + this.injectRepository.findById(injectId).orElseThrow(ElementNotFoundException::new); // Set dependencies inject.setTeams(fromIterable(this.teamRepository.findAllById(input.getTeams()))); @@ -629,12 +717,12 @@ private Inject bulkUpdateInject(@NotBlank final String injectId, @NotNull Inject return inject; } - private Inject updateInjectActivation(@NotBlank final String injectId, - @NotNull final InjectUpdateActivationInput input) { - Inject inject = this.injectRepository.findById(injectId).orElseThrow(ElementNotFoundException::new); + private Inject updateInjectActivation( + @NotBlank final String injectId, @NotNull final InjectUpdateActivationInput input) { + Inject inject = + this.injectRepository.findById(injectId).orElseThrow(ElementNotFoundException::new); inject.setEnabled(input.isEnabled()); inject.setUpdatedAt(now()); return injectRepository.save(inject); } - } diff --git a/openbas-api/src/main/java/io/openbas/rest/inject/ScenarioInjectApi.java b/openbas-api/src/main/java/io/openbas/rest/inject/ScenarioInjectApi.java index 5ecc5f81d8..3d55f9a241 100644 --- a/openbas-api/src/main/java/io/openbas/rest/inject/ScenarioInjectApi.java +++ b/openbas-api/src/main/java/io/openbas/rest/inject/ScenarioInjectApi.java @@ -1,5 +1,9 @@ package io.openbas.rest.inject; +import static io.openbas.database.specification.InjectSpecification.fromScenario; +import static io.openbas.rest.scenario.ScenarioApi.SCENARIO_URI; +import static io.openbas.utils.pagination.PaginationUtils.buildPaginationCriteriaBuilder; + import io.openbas.database.model.Inject; import io.openbas.database.model.InjectTestStatus; import io.openbas.rest.helper.RestBehavior; @@ -10,6 +14,7 @@ import io.openbas.utils.pagination.SearchPaginationInput; import jakarta.validation.Valid; import jakarta.validation.constraints.NotBlank; +import java.util.List; import lombok.RequiredArgsConstructor; import org.springframework.data.domain.Page; import org.springframework.data.domain.Pageable; @@ -18,12 +23,6 @@ import org.springframework.transaction.annotation.Transactional; import org.springframework.web.bind.annotation.*; -import java.util.List; - -import static io.openbas.database.specification.InjectSpecification.fromScenario; -import static io.openbas.rest.scenario.ScenarioApi.SCENARIO_URI; -import static io.openbas.utils.pagination.PaginationUtils.buildPaginationCriteriaBuilder; - @RestController @RequiredArgsConstructor public class ScenarioInjectApi extends RestBehavior { @@ -36,7 +35,8 @@ public class ScenarioInjectApi extends RestBehavior { @PreAuthorize("isScenarioObserver(#scenarioId)") @Transactional(readOnly = true) @Tracing(name = "Fetch injects for scenario", layer = "api", operation = "GET") - public Iterable scenarioInjectsSimple(@PathVariable @NotBlank final String scenarioId) { + public Iterable scenarioInjectsSimple( + @PathVariable @NotBlank final String scenarioId) { return injectService.injects(fromScenario(scenarioId)); } @@ -47,28 +47,29 @@ public Iterable scenarioInjectsSimple( @PathVariable @NotBlank final String scenarioId, @RequestBody @Valid final SearchPaginationInput searchPaginationInput) { return buildPaginationCriteriaBuilder( - (Specification specification, Specification specificationCount, Pageable pageable) -> this.injectService.injects( - fromScenario(scenarioId).and(specification), - fromScenario(scenarioId).and(specificationCount), - pageable - ), + (Specification specification, + Specification specificationCount, + Pageable pageable) -> + this.injectService.injects( + fromScenario(scenarioId).and(specification), + fromScenario(scenarioId).and(specificationCount), + pageable), searchPaginationInput, - Inject.class - ); + Inject.class); } @DeleteMapping(SCENARIO_URI + "/{scenarioId}/injects") @PreAuthorize("isScenarioPlanner(#scenarioId)") - public void deleteListOfInjectsForScenario(@PathVariable final String scenarioId, - @RequestBody List injectIds) { + public void deleteListOfInjectsForScenario( + @PathVariable final String scenarioId, @RequestBody List injectIds) { injectService.deleteAllByIds(injectIds); } @PostMapping("/api/scenario/{scenarioId}/injects/test") - public Page findAllScenarioInjectTests(@PathVariable @NotBlank String scenarioId, - @RequestBody @Valid - SearchPaginationInput searchPaginationInput) { - return injectTestStatusService.findAllInjectTestsByScenarioId(scenarioId, searchPaginationInput); + public Page findAllScenarioInjectTests( + @PathVariable @NotBlank String scenarioId, + @RequestBody @Valid SearchPaginationInput searchPaginationInput) { + return injectTestStatusService.findAllInjectTestsByScenarioId( + scenarioId, searchPaginationInput); } - } diff --git a/openbas-api/src/main/java/io/openbas/rest/inject/form/DirectInjectInput.java b/openbas-api/src/main/java/io/openbas/rest/inject/form/DirectInjectInput.java index 97e14fec45..1281905ccf 100644 --- a/openbas-api/src/main/java/io/openbas/rest/inject/form/DirectInjectInput.java +++ b/openbas-api/src/main/java/io/openbas/rest/inject/form/DirectInjectInput.java @@ -5,14 +5,13 @@ import io.openbas.database.model.Inject; import io.openbas.database.model.InjectorContract; import jakarta.validation.constraints.NotNull; +import java.util.ArrayList; +import java.util.List; import lombok.AllArgsConstructor; import lombok.Getter; import lombok.NoArgsConstructor; import lombok.Setter; -import java.util.ArrayList; -import java.util.List; - @Setter @Getter @NoArgsConstructor diff --git a/openbas-api/src/main/java/io/openbas/rest/inject/form/InjectDocumentInput.java b/openbas-api/src/main/java/io/openbas/rest/inject/form/InjectDocumentInput.java index d9b4ebb4ba..b4d1b74501 100644 --- a/openbas-api/src/main/java/io/openbas/rest/inject/form/InjectDocumentInput.java +++ b/openbas-api/src/main/java/io/openbas/rest/inject/form/InjectDocumentInput.java @@ -8,10 +8,9 @@ @Getter public class InjectDocumentInput { - @JsonProperty("document_id") - private String documentId; - - @JsonProperty("document_attached") - private boolean attached = true; + @JsonProperty("document_id") + private String documentId; + @JsonProperty("document_attached") + private boolean attached = true; } diff --git a/openbas-api/src/main/java/io/openbas/rest/inject/form/InjectExecutionInput.java b/openbas-api/src/main/java/io/openbas/rest/inject/form/InjectExecutionInput.java index 7a57a5efba..627cbb3968 100644 --- a/openbas-api/src/main/java/io/openbas/rest/inject/form/InjectExecutionInput.java +++ b/openbas-api/src/main/java/io/openbas/rest/inject/form/InjectExecutionInput.java @@ -1,29 +1,28 @@ package io.openbas.rest.inject.form; +import static io.openbas.config.AppConfig.MANDATORY_MESSAGE; + import com.fasterxml.jackson.annotation.JsonProperty; import jakarta.validation.constraints.NotBlank; -import lombok.Getter; -import lombok.Setter; - import java.util.ArrayList; import java.util.List; - -import static io.openbas.config.AppConfig.MANDATORY_MESSAGE; +import lombok.Getter; +import lombok.Setter; @Setter @Getter public class InjectExecutionInput { - @JsonProperty("execution_message") - private String message; + @JsonProperty("execution_message") + private String message; - @NotBlank(message = MANDATORY_MESSAGE) - @JsonProperty("execution_status") - private String status; + @NotBlank(message = MANDATORY_MESSAGE) + @JsonProperty("execution_status") + private String status; - @JsonProperty("execution_duration") - private int duration; + @JsonProperty("execution_duration") + private int duration; - @JsonProperty("execution_context_identifiers") - private List identifiers = new ArrayList<>(); + @JsonProperty("execution_context_identifiers") + private List identifiers = new ArrayList<>(); } diff --git a/openbas-api/src/main/java/io/openbas/rest/inject/form/InjectExpectationResultsByAttackPattern.java b/openbas-api/src/main/java/io/openbas/rest/inject/form/InjectExpectationResultsByAttackPattern.java index 86723e2855..253b59f4ed 100644 --- a/openbas-api/src/main/java/io/openbas/rest/inject/form/InjectExpectationResultsByAttackPattern.java +++ b/openbas-api/src/main/java/io/openbas/rest/inject/form/InjectExpectationResultsByAttackPattern.java @@ -8,10 +8,9 @@ import io.openbas.utils.AtomicTestingMapper.ExpectationResultsByType; import io.openbas.utils.AtomicTestingUtils; import jakarta.validation.constraints.NotNull; -import lombok.Data; - import java.util.List; import java.util.stream.Collectors; +import lombok.Data; @Data public class InjectExpectationResultsByAttackPattern { @@ -34,20 +33,20 @@ public static class InjectExpectationResultsByType { } public InjectExpectationResultsByAttackPattern( - final AttackPattern attackPattern, - @NotNull final List injects) { - this.results = injects.stream() - .map(inject -> { - InjectExpectationResultsByType result = new InjectExpectationResultsByType(); - result.setInjectTitle(inject.getTitle()); - result.setResults(AtomicTestingUtils.getExpectationResultByTypes(inject.getExpectations())); - return result; - }) - .collect(Collectors.toList()); + final AttackPattern attackPattern, @NotNull final List injects) { + this.results = + injects.stream() + .map( + inject -> { + InjectExpectationResultsByType result = new InjectExpectationResultsByType(); + result.setInjectTitle(inject.getTitle()); + result.setResults( + AtomicTestingUtils.getExpectationResultByTypes(inject.getExpectations())); + return result; + }) + .collect(Collectors.toList()); this.attackPattern = attackPattern; } - public InjectExpectationResultsByAttackPattern() { - } - + public InjectExpectationResultsByAttackPattern() {} } diff --git a/openbas-api/src/main/java/io/openbas/rest/inject/form/InjectExpectationUpdateInput.java b/openbas-api/src/main/java/io/openbas/rest/inject/form/InjectExpectationUpdateInput.java index 3fa069cf9a..8cb03ea537 100644 --- a/openbas-api/src/main/java/io/openbas/rest/inject/form/InjectExpectationUpdateInput.java +++ b/openbas-api/src/main/java/io/openbas/rest/inject/form/InjectExpectationUpdateInput.java @@ -4,39 +4,39 @@ import jakarta.validation.constraints.NotNull; public class InjectExpectationUpdateInput { - @NotNull - @JsonProperty("collector_id") - private String collectorId; + @NotNull + @JsonProperty("collector_id") + private String collectorId; - @NotNull - @JsonProperty("result") - private String result; + @NotNull + @JsonProperty("result") + private String result; - @NotNull - @JsonProperty("is_success") - private Boolean isSuccess; + @NotNull + @JsonProperty("is_success") + private Boolean isSuccess; - public String getCollectorId() { - return collectorId; - } + public String getCollectorId() { + return collectorId; + } - public void setCollectorId(String collectorId) { - this.collectorId = collectorId; - } + public void setCollectorId(String collectorId) { + this.collectorId = collectorId; + } - public String getResult() { - return result; - } + public String getResult() { + return result; + } - public void setResult(String result) { - this.result = result; - } + public void setResult(String result) { + this.result = result; + } - public Boolean getSuccess() { - return isSuccess; - } + public Boolean getSuccess() { + return isSuccess; + } - public void setSuccess(Boolean success) { - isSuccess = success; - } + public void setSuccess(Boolean success) { + isSuccess = success; + } } diff --git a/openbas-api/src/main/java/io/openbas/rest/inject/form/InjectInput.java b/openbas-api/src/main/java/io/openbas/rest/inject/form/InjectInput.java index 8571fc4003..dbdb780872 100644 --- a/openbas-api/src/main/java/io/openbas/rest/inject/form/InjectInput.java +++ b/openbas-api/src/main/java/io/openbas/rest/inject/form/InjectInput.java @@ -5,68 +5,67 @@ import io.openbas.database.model.Inject; import io.openbas.database.model.InjectorContract; import jakarta.validation.constraints.NotNull; -import lombok.Getter; -import lombok.Setter; - import java.util.ArrayList; import java.util.List; +import lombok.Getter; +import lombok.Setter; @Setter @Getter public class InjectInput { - @JsonProperty("inject_title") - private String title; + @JsonProperty("inject_title") + private String title; - @JsonProperty("inject_description") - private String description; + @JsonProperty("inject_description") + private String description; - @JsonProperty("inject_injector_contract") - private String injectorContract; + @JsonProperty("inject_injector_contract") + private String injectorContract; - @JsonProperty("inject_content") - private ObjectNode content; + @JsonProperty("inject_content") + private ObjectNode content; - @JsonProperty("inject_depends_on") - private String dependsOn; + @JsonProperty("inject_depends_on") + private String dependsOn; - @JsonProperty("inject_depends_duration") - private Long dependsDuration; + @JsonProperty("inject_depends_duration") + private Long dependsDuration; - @JsonProperty("inject_teams") - private List teams = new ArrayList<>(); + @JsonProperty("inject_teams") + private List teams = new ArrayList<>(); - @JsonProperty("inject_assets") - private List assets = new ArrayList<>(); + @JsonProperty("inject_assets") + private List assets = new ArrayList<>(); - @JsonProperty("inject_asset_groups") - private List assetGroups = new ArrayList<>(); + @JsonProperty("inject_asset_groups") + private List assetGroups = new ArrayList<>(); - @JsonProperty("inject_documents") - private List documents = new ArrayList<>(); + @JsonProperty("inject_documents") + private List documents = new ArrayList<>(); - @JsonProperty("inject_all_teams") - private boolean allTeams = false; + @JsonProperty("inject_all_teams") + private boolean allTeams = false; - @JsonProperty("inject_country") - private String country; + @JsonProperty("inject_country") + private String country; - @JsonProperty("inject_city") - private String city; + @JsonProperty("inject_city") + private String city; - @JsonProperty("inject_tags") - private List tagIds = new ArrayList<>(); + @JsonProperty("inject_tags") + private List tagIds = new ArrayList<>(); - public Inject toInject(@NotNull final InjectorContract injectorContract) { - Inject inject = new Inject(); - inject.setTitle(getTitle()); - inject.setDescription(getDescription()); - inject.setContent(getContent()); - inject.setInjectorContract(injectorContract); - inject.setDependsDuration(getDependsDuration()); - inject.setAllTeams(isAllTeams()); - inject.setCountry(getCountry()); - inject.setCity(getCity()); - return inject; - } + public Inject toInject(@NotNull final InjectorContract injectorContract) { + Inject inject = new Inject(); + inject.setTitle(getTitle()); + inject.setDescription(getDescription()); + inject.setContent(getContent()); + inject.setInjectorContract(injectorContract); + inject.setDependsDuration(getDependsDuration()); + inject.setAllTeams(isAllTeams()); + inject.setCountry(getCountry()); + inject.setCity(getCity()); + return inject; + } } diff --git a/openbas-api/src/main/java/io/openbas/rest/inject/form/InjectReceptionInput.java b/openbas-api/src/main/java/io/openbas/rest/inject/form/InjectReceptionInput.java index 62bbac8c0e..684fdd3cf8 100644 --- a/openbas-api/src/main/java/io/openbas/rest/inject/form/InjectReceptionInput.java +++ b/openbas-api/src/main/java/io/openbas/rest/inject/form/InjectReceptionInput.java @@ -1,16 +1,13 @@ package io.openbas.rest.inject.form; import com.fasterxml.jackson.annotation.JsonProperty; -import jakarta.validation.constraints.NotBlank; import lombok.Getter; import lombok.Setter; -import static io.openbas.config.AppConfig.MANDATORY_MESSAGE; - @Setter @Getter public class InjectReceptionInput { - @JsonProperty("tracking_total_count") - private int trackingTotalCount; + @JsonProperty("tracking_total_count") + private int trackingTotalCount; } diff --git a/openbas-api/src/main/java/io/openbas/rest/inject/form/InjectTeamsInput.java b/openbas-api/src/main/java/io/openbas/rest/inject/form/InjectTeamsInput.java index 3df786fdf1..93edb96eed 100644 --- a/openbas-api/src/main/java/io/openbas/rest/inject/form/InjectTeamsInput.java +++ b/openbas-api/src/main/java/io/openbas/rest/inject/form/InjectTeamsInput.java @@ -1,19 +1,18 @@ package io.openbas.rest.inject.form; import com.fasterxml.jackson.annotation.JsonProperty; - import java.util.List; public class InjectTeamsInput { - @JsonProperty("inject_teams") - private List teamIds; + @JsonProperty("inject_teams") + private List teamIds; - public List getTeamIds() { - return teamIds; - } + public List getTeamIds() { + return teamIds; + } - public void setTeamIds(List teamIds) { - this.teamIds = teamIds; - } + public void setTeamIds(List teamIds) { + this.teamIds = teamIds; + } } diff --git a/openbas-api/src/main/java/io/openbas/rest/inject/form/InjectUpdateActivationInput.java b/openbas-api/src/main/java/io/openbas/rest/inject/form/InjectUpdateActivationInput.java index 5226ea2724..c495cd15a1 100644 --- a/openbas-api/src/main/java/io/openbas/rest/inject/form/InjectUpdateActivationInput.java +++ b/openbas-api/src/main/java/io/openbas/rest/inject/form/InjectUpdateActivationInput.java @@ -4,14 +4,14 @@ public class InjectUpdateActivationInput { - @JsonProperty("inject_enabled") - private boolean enabled; + @JsonProperty("inject_enabled") + private boolean enabled; - public boolean isEnabled() { - return enabled; - } + public boolean isEnabled() { + return enabled; + } - public void setEnabled(boolean enabled) { - this.enabled = enabled; - } + public void setEnabled(boolean enabled) { + this.enabled = enabled; + } } diff --git a/openbas-api/src/main/java/io/openbas/rest/inject/form/InjectUpdateStatusInput.java b/openbas-api/src/main/java/io/openbas/rest/inject/form/InjectUpdateStatusInput.java index f2edbb698e..30f95f2962 100644 --- a/openbas-api/src/main/java/io/openbas/rest/inject/form/InjectUpdateStatusInput.java +++ b/openbas-api/src/main/java/io/openbas/rest/inject/form/InjectUpdateStatusInput.java @@ -4,25 +4,25 @@ public class InjectUpdateStatusInput { - @JsonProperty("status") - private String status; + @JsonProperty("status") + private String status; - @JsonProperty("message") - private String message; + @JsonProperty("message") + private String message; - public String getStatus() { - return status; - } + public String getStatus() { + return status; + } - public void setStatus(String status) { - this.status = status; - } + public void setStatus(String status) { + this.status = status; + } - public String getMessage() { - return message; - } + public String getMessage() { + return message; + } - public void setMessage(String message) { - this.message = message; - } + public void setMessage(String message) { + this.message = message; + } } diff --git a/openbas-api/src/main/java/io/openbas/rest/inject/output/AtomicTestingOutput.java b/openbas-api/src/main/java/io/openbas/rest/inject/output/AtomicTestingOutput.java index d434db7114..82b9c7169a 100644 --- a/openbas-api/src/main/java/io/openbas/rest/inject/output/AtomicTestingOutput.java +++ b/openbas-api/src/main/java/io/openbas/rest/inject/output/AtomicTestingOutput.java @@ -1,5 +1,8 @@ package io.openbas.rest.inject.output; +import static io.openbas.database.model.InjectStatus.draftInjectStatus; +import static lombok.AccessLevel.NONE; + import com.fasterxml.jackson.annotation.JsonProperty; import io.openbas.database.model.InjectStatus; import io.openbas.database.model.InjectorContract; @@ -7,16 +10,12 @@ import io.openbas.utils.AtomicTestingMapper; import jakarta.validation.constraints.NotBlank; import jakarta.validation.constraints.NotNull; -import lombok.Data; -import lombok.Getter; - import java.time.Instant; import java.util.ArrayList; import java.util.Arrays; import java.util.List; - -import static io.openbas.database.model.InjectStatus.draftInjectStatus; -import static lombok.AccessLevel.NONE; +import lombok.Data; +import lombok.Getter; @Data public class AtomicTestingOutput { @@ -72,7 +71,8 @@ public InjectStatus getStatus() { private List targets; @JsonProperty("inject_expectation_results") - private List expectationResultByTypes = new ArrayList<>(); + private List expectationResultByTypes = + new ArrayList<>(); public AtomicTestingOutput( String id, @@ -91,11 +91,14 @@ public AtomicTestingOutput( this.injectType = injectType; this.injectorContract = injectorContract; this.status = injectStatus; - this.expectations = injectExpectations != null ? new ArrayList<>(Arrays.asList(injectExpectations)) : new ArrayList<>(); + this.expectations = + injectExpectations != null + ? new ArrayList<>(Arrays.asList(injectExpectations)) + : new ArrayList<>(); this.teams = teams != null ? new ArrayList<>(Arrays.asList(teams)) : new ArrayList<>(); this.assets = assets != null ? new ArrayList<>(Arrays.asList(assets)) : new ArrayList<>(); - this.assetGroups = assetGroups != null ? new ArrayList<>(Arrays.asList(assetGroups)) : new ArrayList<>(); + this.assetGroups = + assetGroups != null ? new ArrayList<>(Arrays.asList(assetGroups)) : new ArrayList<>(); } - } diff --git a/openbas-api/src/main/java/io/openbas/rest/inject/output/InjectOutput.java b/openbas-api/src/main/java/io/openbas/rest/inject/output/InjectOutput.java index 38278ae5df..410f629670 100644 --- a/openbas-api/src/main/java/io/openbas/rest/inject/output/InjectOutput.java +++ b/openbas-api/src/main/java/io/openbas/rest/inject/output/InjectOutput.java @@ -9,9 +9,8 @@ import jakarta.validation.constraints.Min; import jakarta.validation.constraints.NotBlank; import jakarta.validation.constraints.NotNull; -import lombok.Data; - import java.util.*; +import lombok.Data; @Data public class InjectOutput { @@ -67,7 +66,8 @@ public class InjectOutput { @JsonProperty("inject_testable") public boolean canBeTested() { - return EmailContract.TYPE.equals(this.getInjectType()) || OvhSmsContract.TYPE.equals(this.getInjectType()); + return EmailContract.TYPE.equals(this.getInjectType()) + || OvhSmsContract.TYPE.equals(this.getInjectType()); } public InjectOutput( @@ -98,16 +98,12 @@ public InjectOutput( this.teams = teams != null ? new ArrayList<>(Arrays.asList(teams)) : new ArrayList<>(); this.assets = assets != null ? new ArrayList<>(Arrays.asList(assets)) : new ArrayList<>(); - this.assetGroups = assetGroups != null ? new ArrayList<>(Arrays.asList(assetGroups)) : new ArrayList<>(); - - this.isReady = InjectModelHelper.isReady( - injectorContract, - content, - allTeams, - this.teams, - this.assets, - this.assetGroups - ); + this.assetGroups = + assetGroups != null ? new ArrayList<>(Arrays.asList(assetGroups)) : new ArrayList<>(); + + this.isReady = + InjectModelHelper.isReady( + injectorContract, content, allTeams, this.teams, this.assets, this.assetGroups); this.injectType = injectType; this.teams = teams != null ? new ArrayList<>(Arrays.asList(teams)) : new ArrayList<>(); this.content = content; diff --git a/openbas-api/src/main/java/io/openbas/rest/inject/service/InjectDuplicateService.java b/openbas-api/src/main/java/io/openbas/rest/inject/service/InjectDuplicateService.java index d40dcce4a0..c90e4db243 100644 --- a/openbas-api/src/main/java/io/openbas/rest/inject/service/InjectDuplicateService.java +++ b/openbas-api/src/main/java/io/openbas/rest/inject/service/InjectDuplicateService.java @@ -21,39 +21,47 @@ @Validated public class InjectDuplicateService { - private final ExerciseRepository exerciseRepository; - private final ScenarioRepository scenarioRepository; - private final InjectRepository injectRepository; - private final InjectDocumentRepository injectDocumentRepository; - private final AtomicTestingService atomicTestingService; + private final ExerciseRepository exerciseRepository; + private final ScenarioRepository scenarioRepository; + private final InjectRepository injectRepository; + private final InjectDocumentRepository injectDocumentRepository; + private final AtomicTestingService atomicTestingService; - @Transactional - public Inject createInjectForScenario(@NotBlank final String scenarioId, @NotBlank final String injectId, boolean isChild) { - Scenario scenario = scenarioRepository.findById(scenarioId).orElseThrow(); - Inject injectOrigin = injectRepository.findById(injectId).orElseThrow(); - Inject injectDuplicate = atomicTestingService.copyInject(injectOrigin, isChild); - injectDuplicate.setScenario(scenario); - Inject saved = injectRepository.save(injectDuplicate); - getDocumentList(saved, injectId); - return saved; - } + @Transactional + public Inject createInjectForScenario( + @NotBlank final String scenarioId, @NotBlank final String injectId, boolean isChild) { + Scenario scenario = scenarioRepository.findById(scenarioId).orElseThrow(); + Inject injectOrigin = injectRepository.findById(injectId).orElseThrow(); + Inject injectDuplicate = atomicTestingService.copyInject(injectOrigin, isChild); + injectDuplicate.setScenario(scenario); + Inject saved = injectRepository.save(injectDuplicate); + getDocumentList(saved, injectId); + return saved; + } - @Transactional - public Inject createInjectForExercise(@NotBlank final String exerciseId, @NotBlank final String injectId, boolean isChild) { - Exercise exercise = exerciseRepository.findById(exerciseId).orElseThrow(ElementNotFoundException::new); - Inject injectOrigin = injectRepository.findById(injectId).orElseThrow(); - Inject inject = atomicTestingService.copyInject(injectOrigin, isChild); - inject.setExercise(exercise); - Inject saved = injectRepository.save(inject); - getDocumentList(saved, injectId); - return saved; - } + @Transactional + public Inject createInjectForExercise( + @NotBlank final String exerciseId, @NotBlank final String injectId, boolean isChild) { + Exercise exercise = + exerciseRepository.findById(exerciseId).orElseThrow(ElementNotFoundException::new); + Inject injectOrigin = injectRepository.findById(injectId).orElseThrow(); + Inject inject = atomicTestingService.copyInject(injectOrigin, isChild); + inject.setExercise(exercise); + Inject saved = injectRepository.save(inject); + getDocumentList(saved, injectId); + return saved; + } - private void getDocumentList(@NotNull final Inject injectDuplicate, @NotNull final String injectId) { - Inject injectOrigin = injectRepository.findById(injectId).orElseThrow(); - injectOrigin.getDocuments().forEach(injectDocument -> { - String documentId = injectDocument.getDocument().getId(); - injectDocumentRepository.addInjectDoc(injectDuplicate.getId(), documentId, injectDocument.isAttached()); - }); - } + private void getDocumentList( + @NotNull final Inject injectDuplicate, @NotNull final String injectId) { + Inject injectOrigin = injectRepository.findById(injectId).orElseThrow(); + injectOrigin + .getDocuments() + .forEach( + injectDocument -> { + String documentId = injectDocument.getDocument().getId(); + injectDocumentRepository.addInjectDoc( + injectDuplicate.getId(), documentId, injectDocument.isAttached()); + }); + } } diff --git a/openbas-api/src/main/java/io/openbas/rest/inject_test_status/InjectTestStatusApi.java b/openbas-api/src/main/java/io/openbas/rest/inject_test_status/InjectTestStatusApi.java index 0e15b38479..6bc1836bf5 100644 --- a/openbas-api/src/main/java/io/openbas/rest/inject_test_status/InjectTestStatusApi.java +++ b/openbas-api/src/main/java/io/openbas/rest/inject_test_status/InjectTestStatusApi.java @@ -1,17 +1,15 @@ package io.openbas.rest.inject_test_status; import io.openbas.database.model.InjectTestStatus; -import io.openbas.database.repository.InjectTestStatusRepository; import io.openbas.rest.helper.RestBehavior; import io.openbas.service.InjectTestStatusService; import jakarta.transaction.Transactional; import jakarta.validation.constraints.NotBlank; +import java.util.List; import lombok.RequiredArgsConstructor; import org.springframework.security.access.prepost.PreAuthorize; import org.springframework.web.bind.annotation.*; -import java.util.List; - @RestController @PreAuthorize("isAdmin()") @RequiredArgsConstructor @@ -39,5 +37,4 @@ public InjectTestStatus findInjectTestStatus(@PathVariable @NotBlank String test public void deleteInjectTest(@PathVariable String testId) { injectTestStatusService.deleteInjectTest(testId); } - } diff --git a/openbas-api/src/main/java/io/openbas/rest/injector/InjectorApi.java b/openbas-api/src/main/java/io/openbas/rest/injector/InjectorApi.java index 476e32a950..fecd23621b 100644 --- a/openbas-api/src/main/java/io/openbas/rest/injector/InjectorApi.java +++ b/openbas-api/src/main/java/io/openbas/rest/injector/InjectorApi.java @@ -1,5 +1,12 @@ package io.openbas.rest.injector; +import static io.openbas.asset.EndpointService.JFROG_BASE; +import static io.openbas.asset.QueueService.EXCHANGE_KEY; +import static io.openbas.asset.QueueService.ROUTING_KEY; +import static io.openbas.database.model.User.ROLE_ADMIN; +import static io.openbas.database.specification.InjectorSpecification.byName; +import static io.openbas.helper.StreamHelper.fromIterable; + import com.fasterxml.jackson.core.JsonProcessingException; import com.fasterxml.jackson.databind.JsonNode; import com.rabbitmq.client.Channel; @@ -24,6 +31,12 @@ import jakarta.annotation.Resource; import jakarta.transaction.Transactional; import jakarta.validation.Valid; +import java.io.BufferedInputStream; +import java.io.IOException; +import java.io.InputStream; +import java.net.URL; +import java.time.Instant; +import java.util.*; import lombok.extern.java.Log; import org.apache.commons.io.IOUtils; import org.springframework.beans.factory.annotation.Autowired; @@ -36,121 +49,117 @@ import org.springframework.web.bind.annotation.*; import org.springframework.web.multipart.MultipartFile; -import java.io.BufferedInputStream; -import java.io.IOException; -import java.io.InputStream; -import java.net.URL; -import java.time.Instant; -import java.util.*; - -import static io.openbas.asset.EndpointService.JFROG_BASE; -import static io.openbas.asset.QueueService.EXCHANGE_KEY; -import static io.openbas.asset.QueueService.ROUTING_KEY; -import static io.openbas.database.model.User.ROLE_ADMIN; -import static io.openbas.database.specification.InjectorSpecification.byName; -import static io.openbas.helper.StreamHelper.fromIterable; - @Log @RestController public class InjectorApi extends RestBehavior { - public static final String INJECT0R_URI = "/api/injectors"; + public static final String INJECT0R_URI = "/api/injectors"; - @Value("${info.app.version:unknown}") String version; + @Value("${info.app.version:unknown}") + String version; - @Resource - private RabbitmqConfig rabbitmqConfig; + @Resource private RabbitmqConfig rabbitmqConfig; - private AttackPatternRepository attackPatternRepository; + private AttackPatternRepository attackPatternRepository; - private InjectorRepository injectorRepository; + private InjectorRepository injectorRepository; - private InjectorContractRepository injectorContractRepository; + private InjectorContractRepository injectorContractRepository; - private FileService fileService; + private FileService fileService; - @Autowired - public void setFileService(FileService fileService) { - this.fileService = fileService; - } + @Autowired + public void setFileService(FileService fileService) { + this.fileService = fileService; + } - @Autowired - public void setAttackPatternRepository(AttackPatternRepository attackPatternRepository) { - this.attackPatternRepository = attackPatternRepository; - } + @Autowired + public void setAttackPatternRepository(AttackPatternRepository attackPatternRepository) { + this.attackPatternRepository = attackPatternRepository; + } - @Autowired - public void setInjectorRepository(InjectorRepository injectorRepository) { - this.injectorRepository = injectorRepository; - } + @Autowired + public void setInjectorRepository(InjectorRepository injectorRepository) { + this.injectorRepository = injectorRepository; + } - @Autowired - public void setInjectorContractRepository(InjectorContractRepository injectorContractRepository) { - this.injectorContractRepository = injectorContractRepository; - } + @Autowired + public void setInjectorContractRepository(InjectorContractRepository injectorContractRepository) { + this.injectorContractRepository = injectorContractRepository; + } - @GetMapping("/api/injectors") - public Iterable injectors() { - return injectorRepository.findAll(); - } + @GetMapping("/api/injectors") + public Iterable injectors() { + return injectorRepository.findAll(); + } - @GetMapping("/api/injectors/{injectorId}/injector_contracts") - public Collection injectorInjectTypes(@PathVariable String injectorId) { - Injector injector = injectorRepository.findById(injectorId).orElseThrow(ElementNotFoundException::new); - return fromIterable(injectorContractRepository.findInjectorContractsByInjector(injector)).stream() - .map(contract -> { - try { - return mapper.readTree(contract.getContent()); - } catch (JsonProcessingException e) { - throw new RuntimeException(e); - } - }).toList(); - } + @GetMapping("/api/injectors/{injectorId}/injector_contracts") + public Collection injectorInjectTypes(@PathVariable String injectorId) { + Injector injector = + injectorRepository.findById(injectorId).orElseThrow(ElementNotFoundException::new); + return fromIterable(injectorContractRepository.findInjectorContractsByInjector(injector)) + .stream() + .map( + contract -> { + try { + return mapper.readTree(contract.getContent()); + } catch (JsonProcessingException e) { + throw new RuntimeException(e); + } + }) + .toList(); + } - // TODO JRI => REFACTOR TO RELY ON INJECTOR SERVICE - private InjectorContract convertInjectorFromInput(InjectorContractInput in, Injector injector) { - InjectorContract injectorContract = new InjectorContract(); - injectorContract.setId(in.getId()); - injectorContract.setManual(in.isManual()); - injectorContract.setLabels(in.getLabels()); - injectorContract.setInjector(injector); - injectorContract.setContent(in.getContent()); - injectorContract.setAtomicTesting(in.isAtomicTesting()); - injectorContract.setPlatforms(in.getPlatforms()); - if (!in.getAttackPatternsExternalIds().isEmpty()) { - List attackPatterns = fromIterable(attackPatternRepository.findAllByExternalIdInIgnoreCase(in.getAttackPatternsExternalIds())); - injectorContract.setAttackPatterns(attackPatterns); - } else { - injectorContract.setAttackPatterns(new ArrayList<>()); - } - return injectorContract; + // TODO JRI => REFACTOR TO RELY ON INJECTOR SERVICE + private InjectorContract convertInjectorFromInput(InjectorContractInput in, Injector injector) { + InjectorContract injectorContract = new InjectorContract(); + injectorContract.setId(in.getId()); + injectorContract.setManual(in.isManual()); + injectorContract.setLabels(in.getLabels()); + injectorContract.setInjector(injector); + injectorContract.setContent(in.getContent()); + injectorContract.setAtomicTesting(in.isAtomicTesting()); + injectorContract.setPlatforms(in.getPlatforms()); + if (!in.getAttackPatternsExternalIds().isEmpty()) { + List attackPatterns = + fromIterable( + attackPatternRepository.findAllByExternalIdInIgnoreCase( + in.getAttackPatternsExternalIds())); + injectorContract.setAttackPatterns(attackPatterns); + } else { + injectorContract.setAttackPatterns(new ArrayList<>()); } + return injectorContract; + } - private Injector updateInjector( - Injector injector, - String type, - String name, - List contracts, - Boolean customContracts, - String category, - Map executorCommands, - Map executorClearCommands, - Boolean payloads) { - injector.setUpdatedAt(Instant.now()); - injector.setType(type); - injector.setName(name); - injector.setExternal(true); - injector.setCustomContracts(customContracts); - injector.setCategory(category); - injector.setExecutorCommands(executorCommands); - injector.setExecutorClearCommands(executorClearCommands); - injector.setPayloads(payloads); - List existing = new ArrayList<>(); - List toDeletes = new ArrayList<>(); - injector.getContracts().forEach(contract -> { - Optional current = contracts.stream() - .filter(c -> c.getId().equals(contract.getId())).findFirst(); - if (current.isPresent()) { + private Injector updateInjector( + Injector injector, + String type, + String name, + List contracts, + Boolean customContracts, + String category, + Map executorCommands, + Map executorClearCommands, + Boolean payloads) { + injector.setUpdatedAt(Instant.now()); + injector.setType(type); + injector.setName(name); + injector.setExternal(true); + injector.setCustomContracts(customContracts); + injector.setCategory(category); + injector.setExecutorCommands(executorCommands); + injector.setExecutorClearCommands(executorClearCommands); + injector.setPayloads(payloads); + List existing = new ArrayList<>(); + List toDeletes = new ArrayList<>(); + injector + .getContracts() + .forEach( + contract -> { + Optional current = + contracts.stream().filter(c -> c.getId().equals(contract.getId())).findFirst(); + if (current.isPresent()) { existing.add(contract.getId()); contract.setManual(current.get().isManual()); contract.setLabels(current.get().getLabels()); @@ -158,195 +167,219 @@ private Injector updateInjector( contract.setAtomicTesting(current.get().isAtomicTesting()); contract.setPlatforms(current.get().getPlatforms()); if (!current.get().getAttackPatternsExternalIds().isEmpty()) { - List attackPatterns = fromIterable(attackPatternRepository.findAllByExternalIdInIgnoreCase(current.get().getAttackPatternsExternalIds())); - contract.setAttackPatterns(attackPatterns); + List attackPatterns = + fromIterable( + attackPatternRepository.findAllByExternalIdInIgnoreCase( + current.get().getAttackPatternsExternalIds())); + contract.setAttackPatterns(attackPatterns); } else { - contract.setAttackPatterns(new ArrayList<>()); + contract.setAttackPatterns(new ArrayList<>()); } - } else if (!contract.getCustom()) { + } else if (!contract.getCustom()) { toDeletes.add(contract.getId()); - } - }); - List toCreates = contracts.stream() - .filter(c -> !existing.contains(c.getId())) - .map(in -> convertInjectorFromInput(in, injector)).toList(); - injectorContractRepository.deleteAllById(toDeletes); - injectorContractRepository.saveAll(toCreates); - return injectorRepository.save(injector); - } + } + }); + List toCreates = + contracts.stream() + .filter(c -> !existing.contains(c.getId())) + .map(in -> convertInjectorFromInput(in, injector)) + .toList(); + injectorContractRepository.deleteAllById(toDeletes); + injectorContractRepository.saveAll(toCreates); + return injectorRepository.save(injector); + } - @Secured(ROLE_ADMIN) - @PutMapping("/api/injectors/{injectorId}") - public Injector updateInjector(@PathVariable String injectorId, @Valid @RequestBody InjectorUpdateInput input) { - Injector injector = injectorRepository.findById(injectorId).orElseThrow(ElementNotFoundException::new); - return updateInjector( - injector, - injector.getType(), - input.getName(), - input.getContracts(), - input.getCustomContracts(), - input.getCategory(), - input.getExecutorCommands(), - input.getExecutorClearCommands(), - input.getPayloads() - ); - } + @Secured(ROLE_ADMIN) + @PutMapping("/api/injectors/{injectorId}") + public Injector updateInjector( + @PathVariable String injectorId, @Valid @RequestBody InjectorUpdateInput input) { + Injector injector = + injectorRepository.findById(injectorId).orElseThrow(ElementNotFoundException::new); + return updateInjector( + injector, + injector.getType(), + input.getName(), + input.getContracts(), + input.getCustomContracts(), + input.getCategory(), + input.getExecutorCommands(), + input.getExecutorClearCommands(), + input.getPayloads()); + } - @Secured(ROLE_ADMIN) - @GetMapping("/api/injectors/{injectorId}") - public Injector injector(@PathVariable String injectorId) { - return injectorRepository.findById(injectorId).orElseThrow(ElementNotFoundException::new); - } + @Secured(ROLE_ADMIN) + @GetMapping("/api/injectors/{injectorId}") + public Injector injector(@PathVariable String injectorId) { + return injectorRepository.findById(injectorId).orElseThrow(ElementNotFoundException::new); + } - @Secured(ROLE_ADMIN) - @PostMapping(value = "/api/injectors", - produces = {MediaType.APPLICATION_JSON_VALUE}, - consumes = {MediaType.APPLICATION_JSON_VALUE, MediaType.MULTIPART_FORM_DATA_VALUE}) - @Transactional(rollbackOn = Exception.class) - public InjectorRegistration registerInjector(@Valid @RequestPart("input") InjectorCreateInput input, - @RequestPart("icon") Optional file) { - ConnectionFactory factory = new ConnectionFactory(); - factory.setHost(rabbitmqConfig.getHostname()); - factory.setPort(rabbitmqConfig.getPort()); - factory.setUsername(rabbitmqConfig.getUser()); - factory.setPassword(rabbitmqConfig.getPass()); - factory.setVirtualHost(rabbitmqConfig.getVhost()); - // Declare queueing - Connection connection = null; + @Secured(ROLE_ADMIN) + @PostMapping( + value = "/api/injectors", + produces = {MediaType.APPLICATION_JSON_VALUE}, + consumes = {MediaType.APPLICATION_JSON_VALUE, MediaType.MULTIPART_FORM_DATA_VALUE}) + @Transactional(rollbackOn = Exception.class) + public InjectorRegistration registerInjector( + @Valid @RequestPart("input") InjectorCreateInput input, + @RequestPart("icon") Optional file) { + ConnectionFactory factory = new ConnectionFactory(); + factory.setHost(rabbitmqConfig.getHostname()); + factory.setPort(rabbitmqConfig.getPort()); + factory.setUsername(rabbitmqConfig.getUser()); + factory.setPassword(rabbitmqConfig.getPass()); + factory.setVirtualHost(rabbitmqConfig.getVhost()); + // Declare queueing + Connection connection = null; + try { + // Upload icon + if (file.isPresent() && "image/png".equals(file.get().getContentType())) { + fileService.uploadFile( + FileService.INJECTORS_IMAGES_BASE_PATH + input.getType() + ".png", file.get()); + } + connection = factory.newConnection(); + Channel channel = connection.createChannel(); + String queueName = rabbitmqConfig.getPrefix() + "_injector_" + input.getType(); + Map queueOptions = new HashMap<>(); + queueOptions.put("x-queue-type", rabbitmqConfig.getQueueType()); + channel.queueDeclare(queueName, true, false, false, queueOptions); + String routingKey = rabbitmqConfig.getPrefix() + ROUTING_KEY + input.getType(); + String exchangeKey = rabbitmqConfig.getPrefix() + EXCHANGE_KEY; + channel.exchangeDeclare(exchangeKey, "direct", true); + channel.queueBind(queueName, exchangeKey, routingKey); + // We need to support upsert for registration + Injector injector = injectorRepository.findById(input.getId()).orElse(null); + if (injector == null) { + Injector injectorChecking = injectorRepository.findByType(input.getType()).orElse(null); + if (injectorChecking != null) { + throw new Exception( + "The injector " + + input.getType() + + " already exists with a different ID, please delete it or contact your administrator."); + } + } + if (injector != null) { + updateInjector( + injector, + input.getType(), + input.getName(), + input.getContracts(), + input.getCustomContracts(), + input.getCategory(), + input.getExecutorCommands(), + input.getExecutorClearCommands(), + input.getPayloads()); + } else { + // save the injector + Injector newInjector = new Injector(); + newInjector.setId(input.getId()); + newInjector.setExternal(true); + newInjector.setName(input.getName()); + newInjector.setType(input.getType()); + newInjector.setCategory(input.getCategory()); + newInjector.setCustomContracts(input.getCustomContracts()); + newInjector.setExecutorCommands(input.getExecutorCommands()); + newInjector.setExecutorClearCommands(input.getExecutorClearCommands()); + newInjector.setPayloads(input.getPayloads()); + Injector savedInjector = injectorRepository.save(newInjector); + // Save the contracts + List injectorContracts = + input.getContracts().stream() + .map(in -> convertInjectorFromInput(in, savedInjector)) + .toList(); + injectorContractRepository.saveAll(injectorContracts); + } + InjectorConnection conn = + new InjectorConnection( + rabbitmqConfig.getHostname(), + rabbitmqConfig.getVhost(), + rabbitmqConfig.isSsl(), + rabbitmqConfig.getPort(), + rabbitmqConfig.getUser(), + rabbitmqConfig.getPass()); + return new InjectorRegistration(conn, queueName); + } catch (Exception e) { + throw new RuntimeException(e); + } finally { + if (connection != null) { try { - // Upload icon - if (file.isPresent() && "image/png".equals(file.get().getContentType())) { - fileService.uploadFile(FileService.INJECTORS_IMAGES_BASE_PATH + input.getType() + ".png", file.get()); - } - connection = factory.newConnection(); - Channel channel = connection.createChannel(); - String queueName = rabbitmqConfig.getPrefix() + "_injector_" + input.getType(); - Map queueOptions = new HashMap<>(); - queueOptions.put("x-queue-type", rabbitmqConfig.getQueueType()); - channel.queueDeclare(queueName, true, false, false, queueOptions); - String routingKey = rabbitmqConfig.getPrefix() + ROUTING_KEY + input.getType(); - String exchangeKey = rabbitmqConfig.getPrefix() + EXCHANGE_KEY; - channel.exchangeDeclare(exchangeKey, "direct", true); - channel.queueBind(queueName, exchangeKey, routingKey); - // We need to support upsert for registration - Injector injector = injectorRepository.findById(input.getId()).orElse(null); - if( injector == null ) { - Injector injectorChecking = injectorRepository.findByType(input.getType()).orElse(null); - if (injectorChecking != null ) { - throw new Exception("The injector " + input.getType() + " already exists with a different ID, please delete it or contact your administrator."); - } - } - if (injector != null) { - updateInjector( - injector, - input.getType(), - input.getName(), - input.getContracts(), - input.getCustomContracts(), - input.getCategory(), - input.getExecutorCommands(), - input.getExecutorClearCommands(), - input.getPayloads() - ); - } else { - // save the injector - Injector newInjector = new Injector(); - newInjector.setId(input.getId()); - newInjector.setExternal(true); - newInjector.setName(input.getName()); - newInjector.setType(input.getType()); - newInjector.setCategory(input.getCategory()); - newInjector.setCustomContracts(input.getCustomContracts()); - newInjector.setExecutorCommands(input.getExecutorCommands()); - newInjector.setExecutorClearCommands(input.getExecutorClearCommands()); - newInjector.setPayloads(input.getPayloads()); - Injector savedInjector = injectorRepository.save(newInjector); - // Save the contracts - List injectorContracts = input.getContracts().stream() - .map(in -> convertInjectorFromInput(in, savedInjector)).toList(); - injectorContractRepository.saveAll(injectorContracts); - } - InjectorConnection conn = new InjectorConnection( - rabbitmqConfig.getHostname(), - rabbitmqConfig.getVhost(), - rabbitmqConfig.isSsl(), - rabbitmqConfig.getPort(), - rabbitmqConfig.getUser(), - rabbitmqConfig.getPass() - ); - return new InjectorRegistration(conn, queueName); - } catch (Exception e) { - throw new RuntimeException(e); - } finally { - if (connection != null) { - try { - connection.close(); - } catch (IOException e) { - log.severe("Unable to close RabbitMQ connection. You should worry as this could impact performance"); - } - } + connection.close(); + } catch (IOException e) { + log.severe( + "Unable to close RabbitMQ connection. You should worry as this could impact performance"); } + } } + } - @GetMapping(value = "/api/implant/caldera/{platform}/{arch}", produces = MediaType.APPLICATION_OCTET_STREAM_VALUE) - public @ResponseBody byte[] getCalderaImplant(@PathVariable String platform, @PathVariable String arch) throws IOException { - InputStream in = getClass().getResourceAsStream("/implants/caldera/" + platform + "/" + arch + "/obas-implant-caldera-" + platform); - if (in != null) { - return IOUtils.toByteArray(in); - } - return null; + @GetMapping( + value = "/api/implant/caldera/{platform}/{arch}", + produces = MediaType.APPLICATION_OCTET_STREAM_VALUE) + public @ResponseBody byte[] getCalderaImplant( + @PathVariable String platform, @PathVariable String arch) throws IOException { + InputStream in = + getClass() + .getResourceAsStream( + "/implants/caldera/" + platform + "/" + arch + "/obas-implant-caldera-" + platform); + if (in != null) { + return IOUtils.toByteArray(in); } + return null; + } - // Public API - @GetMapping(value = "/api/implant/openbas/{platform}/{architecture}", produces = MediaType.APPLICATION_OCTET_STREAM_VALUE) - public @ResponseBody ResponseEntity getOpenBasImplant(@PathVariable String platform, @PathVariable String architecture) throws IOException { - InputStream in = null; - String filename = null; - if (platform.equals("windows") && architecture.equals("x86_64")) { - filename = "openbas-implant-" + version + ".exe"; - String resourcePath = "/openbas-implant/windows/x86_64/"; - in = getClass().getResourceAsStream("/implants" + resourcePath + filename); - if (in == null) { // Dev mode, get from artifactory - filename = "openbas-implant-latest.exe"; - in = new BufferedInputStream(new URL(JFROG_BASE + resourcePath + filename).openStream()); - } - } - if (platform.equals("linux") || platform.equals("macos")) { - filename = "openbas-agent-" + version; - String resourcePath = "/openbas-implant/" + platform + "/" + architecture + "/"; - in = getClass().getResourceAsStream("/implants" + resourcePath + filename); - if (in == null) { // Dev mode, get from artifactory - filename = "openbas-implant-latest"; - in = new BufferedInputStream(new URL(JFROG_BASE + resourcePath + filename).openStream()); - } - } - if (in != null) { - HttpHeaders headers = new HttpHeaders(); - headers.add(HttpHeaders.CONTENT_DISPOSITION, "attachment; filename=" + filename); - return ResponseEntity.ok() - .headers(headers) - .contentType(MediaType.APPLICATION_OCTET_STREAM) - .body(IOUtils.toByteArray(in)); - } - throw new UnsupportedOperationException("Implant " + platform + " executable not supported"); + // Public API + @GetMapping( + value = "/api/implant/openbas/{platform}/{architecture}", + produces = MediaType.APPLICATION_OCTET_STREAM_VALUE) + public @ResponseBody ResponseEntity getOpenBasImplant( + @PathVariable String platform, @PathVariable String architecture) throws IOException { + InputStream in = null; + String filename = null; + if (platform.equals("windows") && architecture.equals("x86_64")) { + filename = "openbas-implant-" + version + ".exe"; + String resourcePath = "/openbas-implant/windows/x86_64/"; + in = getClass().getResourceAsStream("/implants" + resourcePath + filename); + if (in == null) { // Dev mode, get from artifactory + filename = "openbas-implant-latest.exe"; + in = new BufferedInputStream(new URL(JFROG_BASE + resourcePath + filename).openStream()); + } } - - // -- OPTION -- - - @GetMapping(INJECT0R_URI + "/options") - public List optionsByName(@RequestParam(required = false) final String searchText) { - return fromIterable(this.injectorRepository.findAll(byName(searchText), Sort.by(Sort.Direction.ASC, "name"))) - .stream() - .map(i -> new FilterUtilsJpa.Option(i.getId(), i.getName())) - .toList(); + if (platform.equals("linux") || platform.equals("macos")) { + filename = "openbas-agent-" + version; + String resourcePath = "/openbas-implant/" + platform + "/" + architecture + "/"; + in = getClass().getResourceAsStream("/implants" + resourcePath + filename); + if (in == null) { // Dev mode, get from artifactory + filename = "openbas-implant-latest"; + in = new BufferedInputStream(new URL(JFROG_BASE + resourcePath + filename).openStream()); + } } - - @PostMapping(INJECT0R_URI + "/options") - public List optionsById(@RequestBody final List ids) { - return fromIterable(this.injectorRepository.findAllById(ids)) - .stream() - .map(i -> new FilterUtilsJpa.Option(i.getId(), i.getName())) - .toList(); + if (in != null) { + HttpHeaders headers = new HttpHeaders(); + headers.add(HttpHeaders.CONTENT_DISPOSITION, "attachment; filename=" + filename); + return ResponseEntity.ok() + .headers(headers) + .contentType(MediaType.APPLICATION_OCTET_STREAM) + .body(IOUtils.toByteArray(in)); } + throw new UnsupportedOperationException("Implant " + platform + " executable not supported"); + } + + // -- OPTION -- + + @GetMapping(INJECT0R_URI + "/options") + public List optionsByName( + @RequestParam(required = false) final String searchText) { + return fromIterable( + this.injectorRepository.findAll( + byName(searchText), Sort.by(Sort.Direction.ASC, "name"))) + .stream() + .map(i -> new FilterUtilsJpa.Option(i.getId(), i.getName())) + .toList(); + } + @PostMapping(INJECT0R_URI + "/options") + public List optionsById(@RequestBody final List ids) { + return fromIterable(this.injectorRepository.findAllById(ids)).stream() + .map(i -> new FilterUtilsJpa.Option(i.getId(), i.getName())) + .toList(); + } } diff --git a/openbas-api/src/main/java/io/openbas/rest/injector/form/InjectorCreateInput.java b/openbas-api/src/main/java/io/openbas/rest/injector/form/InjectorCreateInput.java index 185fbab49c..97916bc636 100644 --- a/openbas-api/src/main/java/io/openbas/rest/injector/form/InjectorCreateInput.java +++ b/openbas-api/src/main/java/io/openbas/rest/injector/form/InjectorCreateInput.java @@ -1,115 +1,114 @@ package io.openbas.rest.injector.form; +import static io.openbas.config.AppConfig.MANDATORY_MESSAGE; + import com.fasterxml.jackson.annotation.JsonProperty; import io.openbas.rest.injector_contract.form.InjectorContractInput; import jakarta.validation.constraints.NotBlank; - import java.util.List; import java.util.Map; -import static io.openbas.config.AppConfig.MANDATORY_MESSAGE; - public class InjectorCreateInput { - @NotBlank(message = MANDATORY_MESSAGE) - @JsonProperty("injector_id") - private String id; + @NotBlank(message = MANDATORY_MESSAGE) + @JsonProperty("injector_id") + private String id; - @NotBlank(message = MANDATORY_MESSAGE) - @JsonProperty("injector_name") - private String name; + @NotBlank(message = MANDATORY_MESSAGE) + @JsonProperty("injector_name") + private String name; - @NotBlank(message = MANDATORY_MESSAGE) - @JsonProperty("injector_type") - private String type; + @NotBlank(message = MANDATORY_MESSAGE) + @JsonProperty("injector_type") + private String type; - @JsonProperty("injector_contracts") - private List contracts; + @JsonProperty("injector_contracts") + private List contracts; - @JsonProperty("injector_custom_contracts") - private Boolean customContracts = false; + @JsonProperty("injector_custom_contracts") + private Boolean customContracts = false; - @JsonProperty("injector_category") - private String category; + @JsonProperty("injector_category") + private String category; - @JsonProperty("injector_executor_commands") - private Map executorCommands; + @JsonProperty("injector_executor_commands") + private Map executorCommands; - @JsonProperty("injector_executor_clear_commands") - private Map executorClearCommands; + @JsonProperty("injector_executor_clear_commands") + private Map executorClearCommands; - @JsonProperty("injector_payloads") - private Boolean payloads = false; + @JsonProperty("injector_payloads") + private Boolean payloads = false; - public String getId() { - return id; - } + public String getId() { + return id; + } - public void setId(String id) { - this.id = id; - } + public void setId(String id) { + this.id = id; + } - public String getType() { - return type; - } + public String getType() { + return type; + } - public void setType(String type) { - this.type = type; - } + public void setType(String type) { + this.type = type; + } - public String getName() { - return name; - } + public String getName() { + return name; + } - public void setName(String name) { - this.name = name; - } + public void setName(String name) { + this.name = name; + } - public List getContracts() { - return contracts; - } + public List getContracts() { + return contracts; + } - public void setContracts(List contracts) { - this.contracts = contracts; - } + public void setContracts(List contracts) { + this.contracts = contracts; + } - public Boolean getCustomContracts() { - return customContracts; - } + public Boolean getCustomContracts() { + return customContracts; + } - public void setCustomContracts(Boolean customContracts) { - this.customContracts = customContracts; - } + public void setCustomContracts(Boolean customContracts) { + this.customContracts = customContracts; + } - public String getCategory() { - return category; - } + public String getCategory() { + return category; + } - public void setCategory(String category) { - this.category = category; - } + public void setCategory(String category) { + this.category = category; + } - public Map getExecutorCommands() { - return executorCommands; - } + public Map getExecutorCommands() { + return executorCommands; + } - public void setExecutorCommands(Map executorCommands) { - this.executorCommands = executorCommands; - } + public void setExecutorCommands(Map executorCommands) { + this.executorCommands = executorCommands; + } - public Map getExecutorClearCommands() { - return executorClearCommands; - } + public Map getExecutorClearCommands() { + return executorClearCommands; + } - public void setExecutorClearCommands(Map executorClearCommands) { - this.executorClearCommands = executorClearCommands; - } + public void setExecutorClearCommands(Map executorClearCommands) { + this.executorClearCommands = executorClearCommands; + } - public Boolean getPayloads() { - return payloads; - } + public Boolean getPayloads() { + return payloads; + } - public void setPayloads(Boolean payloads) { - this.payloads = payloads; - } + public void setPayloads(Boolean payloads) { + this.payloads = payloads; + } } diff --git a/openbas-api/src/main/java/io/openbas/rest/injector/form/InjectorUpdateInput.java b/openbas-api/src/main/java/io/openbas/rest/injector/form/InjectorUpdateInput.java index 27f1d4e144..d1ea4491b5 100644 --- a/openbas-api/src/main/java/io/openbas/rest/injector/form/InjectorUpdateInput.java +++ b/openbas-api/src/main/java/io/openbas/rest/injector/form/InjectorUpdateInput.java @@ -1,39 +1,38 @@ package io.openbas.rest.injector.form; +import static io.openbas.config.AppConfig.MANDATORY_MESSAGE; + import com.fasterxml.jackson.annotation.JsonProperty; import io.openbas.rest.injector_contract.form.InjectorContractInput; import jakarta.validation.constraints.NotBlank; -import lombok.Getter; -import lombok.Setter; - import java.util.List; import java.util.Map; - -import static io.openbas.config.AppConfig.MANDATORY_MESSAGE; +import lombok.Getter; +import lombok.Setter; @Getter @Setter public class InjectorUpdateInput { - @NotBlank(message = MANDATORY_MESSAGE) - @JsonProperty("injector_name") - private String name; + @NotBlank(message = MANDATORY_MESSAGE) + @JsonProperty("injector_name") + private String name; - @JsonProperty("injector_contracts") - private List contracts; + @JsonProperty("injector_contracts") + private List contracts; - @JsonProperty("injector_custom_contracts") - private Boolean customContracts = false; + @JsonProperty("injector_custom_contracts") + private Boolean customContracts = false; - @JsonProperty("injector_category") - private String category; + @JsonProperty("injector_category") + private String category; - @JsonProperty("injector_executor_commands") - private Map executorCommands; + @JsonProperty("injector_executor_commands") + private Map executorCommands; - @JsonProperty("injector_executor_clear_commands") - private Map executorClearCommands; + @JsonProperty("injector_executor_clear_commands") + private Map executorClearCommands; - @JsonProperty("injector_payloads") - private Boolean payloads = false; + @JsonProperty("injector_payloads") + private Boolean payloads = false; } diff --git a/openbas-api/src/main/java/io/openbas/rest/injector/response/InjectorConnection.java b/openbas-api/src/main/java/io/openbas/rest/injector/response/InjectorConnection.java index c1e756c6d6..2f1b58e678 100644 --- a/openbas-api/src/main/java/io/openbas/rest/injector/response/InjectorConnection.java +++ b/openbas-api/src/main/java/io/openbas/rest/injector/response/InjectorConnection.java @@ -8,30 +8,31 @@ @Setter public class InjectorConnection { - @JsonProperty("host") - private String host; + @JsonProperty("host") + private String host; - @JsonProperty("vhost") - private String vhost; + @JsonProperty("vhost") + private String vhost; - @JsonProperty("use_ssl") - private boolean useSsl; + @JsonProperty("use_ssl") + private boolean useSsl; - @JsonProperty("port") - private int port; + @JsonProperty("port") + private int port; - @JsonProperty("user") - private String user; + @JsonProperty("user") + private String user; - @JsonProperty("pass") - private String pass; + @JsonProperty("pass") + private String pass; - public InjectorConnection(String host, String vhost, boolean useSsl, int port, String user, String pass) { - this.host = host; - this.vhost = vhost; - this.useSsl = useSsl; - this.port = port; - this.user = user; - this.pass = pass; - } + public InjectorConnection( + String host, String vhost, boolean useSsl, int port, String user, String pass) { + this.host = host; + this.vhost = vhost; + this.useSsl = useSsl; + this.port = port; + this.user = user; + this.pass = pass; + } } diff --git a/openbas-api/src/main/java/io/openbas/rest/injector/response/InjectorRegistration.java b/openbas-api/src/main/java/io/openbas/rest/injector/response/InjectorRegistration.java index 1eea67c1ed..e6e0f5a8e3 100644 --- a/openbas-api/src/main/java/io/openbas/rest/injector/response/InjectorRegistration.java +++ b/openbas-api/src/main/java/io/openbas/rest/injector/response/InjectorRegistration.java @@ -8,14 +8,14 @@ @Setter public class InjectorRegistration { - @JsonProperty("connection") - private InjectorConnection connection; + @JsonProperty("connection") + private InjectorConnection connection; - @JsonProperty("listen") - private String listen; + @JsonProperty("listen") + private String listen; - public InjectorRegistration(InjectorConnection connection, String listen) { - this.connection = connection; - this.listen = listen; - } + public InjectorRegistration(InjectorConnection connection, String listen) { + this.connection = connection; + this.listen = listen; + } } diff --git a/openbas-api/src/main/java/io/openbas/rest/injector_contract/InjectorContractApi.java b/openbas-api/src/main/java/io/openbas/rest/injector_contract/InjectorContractApi.java index 46a1af9ae5..d25d36ee8b 100644 --- a/openbas-api/src/main/java/io/openbas/rest/injector_contract/InjectorContractApi.java +++ b/openbas-api/src/main/java/io/openbas/rest/injector_contract/InjectorContractApi.java @@ -1,5 +1,10 @@ package io.openbas.rest.injector_contract; +import static io.openbas.database.model.User.ROLE_ADMIN; +import static io.openbas.helper.DatabaseHelper.updateRelation; +import static io.openbas.helper.StreamHelper.fromIterable; +import static io.openbas.utils.pagination.PaginationUtils.buildPaginationCriteriaBuilder; + import io.openbas.database.model.InjectorContract; import io.openbas.database.raw.RawInjectorsContrats; import io.openbas.database.repository.AttackPatternRepository; @@ -14,88 +19,102 @@ import io.openbas.utils.pagination.SearchPaginationInput; import jakarta.transaction.Transactional; import jakarta.validation.Valid; +import java.time.Instant; import lombok.RequiredArgsConstructor; import org.springframework.data.domain.Page; import org.springframework.security.access.annotation.Secured; import org.springframework.web.bind.annotation.*; -import java.time.Instant; - -import static io.openbas.database.model.User.ROLE_ADMIN; -import static io.openbas.helper.DatabaseHelper.updateRelation; -import static io.openbas.helper.StreamHelper.fromIterable; -import static io.openbas.utils.pagination.PaginationUtils.buildPaginationCriteriaBuilder; - @RequiredArgsConstructor @RestController public class InjectorContractApi extends RestBehavior { - private final AttackPatternRepository attackPatternRepository; + private final AttackPatternRepository attackPatternRepository; - private final InjectorRepository injectorRepository; + private final InjectorRepository injectorRepository; - private final InjectorContractRepository injectorContractRepository; + private final InjectorContractRepository injectorContractRepository; - private final InjectorContractService injectorContractService; + private final InjectorContractService injectorContractService; - @GetMapping("/api/injector_contracts") - public Iterable injectContracts() { - return injectorContractRepository.getAllRawInjectorsContracts(); - } + @GetMapping("/api/injector_contracts") + public Iterable injectContracts() { + return injectorContractRepository.getAllRawInjectorsContracts(); + } - @PostMapping("/api/injector_contracts/search") - public Page injectorContracts(@RequestBody @Valid final SearchPaginationInput searchPaginationInput) { - return buildPaginationCriteriaBuilder( - this.injectorContractService::injectorContracts, - searchPaginationInput, - InjectorContract.class - ); - } + @PostMapping("/api/injector_contracts/search") + public Page injectorContracts( + @RequestBody @Valid final SearchPaginationInput searchPaginationInput) { + return buildPaginationCriteriaBuilder( + this.injectorContractService::injectorContracts, + searchPaginationInput, + InjectorContract.class); + } - @Secured(ROLE_ADMIN) - @GetMapping("/api/injector_contracts/{injectorContractId}") - public InjectorContract injectorContract(@PathVariable String injectorContractId) { - return injectorContractRepository.findById(injectorContractId).orElseThrow(ElementNotFoundException::new); - } + @Secured(ROLE_ADMIN) + @GetMapping("/api/injector_contracts/{injectorContractId}") + public InjectorContract injectorContract(@PathVariable String injectorContractId) { + return injectorContractRepository + .findById(injectorContractId) + .orElseThrow(ElementNotFoundException::new); + } - @Secured(ROLE_ADMIN) - @PostMapping("/api/injector_contracts") - @Transactional(rollbackOn = Exception.class) - public InjectorContract createInjectorContract(@Valid @RequestBody InjectorContractAddInput input) { - InjectorContract injectorContract = new InjectorContract(); - injectorContract.setCustom(true); - injectorContract.setUpdateAttributes(input); - if (!input.getAttackPatternsExternalIds().isEmpty()) { - injectorContract.setAttackPatterns(fromIterable(attackPatternRepository.findAllByExternalIdInIgnoreCase(input.getAttackPatternsExternalIds()))); - } else if (!input.getAttackPatternsIds().isEmpty()) { - injectorContract.setAttackPatterns(fromIterable(attackPatternRepository.findAllById(input.getAttackPatternsIds()))); - } - injectorContract.setInjector(updateRelation(input.getInjectorId(), injectorContract.getInjector(), injectorRepository)); - return injectorContractRepository.save(injectorContract); + @Secured(ROLE_ADMIN) + @PostMapping("/api/injector_contracts") + @Transactional(rollbackOn = Exception.class) + public InjectorContract createInjectorContract( + @Valid @RequestBody InjectorContractAddInput input) { + InjectorContract injectorContract = new InjectorContract(); + injectorContract.setCustom(true); + injectorContract.setUpdateAttributes(input); + if (!input.getAttackPatternsExternalIds().isEmpty()) { + injectorContract.setAttackPatterns( + fromIterable( + attackPatternRepository.findAllByExternalIdInIgnoreCase( + input.getAttackPatternsExternalIds()))); + } else if (!input.getAttackPatternsIds().isEmpty()) { + injectorContract.setAttackPatterns( + fromIterable(attackPatternRepository.findAllById(input.getAttackPatternsIds()))); } + injectorContract.setInjector( + updateRelation(input.getInjectorId(), injectorContract.getInjector(), injectorRepository)); + return injectorContractRepository.save(injectorContract); + } - @Secured(ROLE_ADMIN) - @PutMapping("/api/injector_contracts/{injectorContractId}") - public InjectorContract updateInjectorContract(@PathVariable String injectorContractId, @Valid @RequestBody InjectorContractUpdateInput input) { - InjectorContract injectorContract = injectorContractRepository.findById(injectorContractId).orElseThrow(ElementNotFoundException::new); - injectorContract.setUpdateAttributes(input); - injectorContract.setAttackPatterns(fromIterable(attackPatternRepository.findAllById(input.getAttackPatternsIds()))); - injectorContract.setUpdatedAt(Instant.now()); - return injectorContractRepository.save(injectorContract); - } + @Secured(ROLE_ADMIN) + @PutMapping("/api/injector_contracts/{injectorContractId}") + public InjectorContract updateInjectorContract( + @PathVariable String injectorContractId, + @Valid @RequestBody InjectorContractUpdateInput input) { + InjectorContract injectorContract = + injectorContractRepository + .findById(injectorContractId) + .orElseThrow(ElementNotFoundException::new); + injectorContract.setUpdateAttributes(input); + injectorContract.setAttackPatterns( + fromIterable(attackPatternRepository.findAllById(input.getAttackPatternsIds()))); + injectorContract.setUpdatedAt(Instant.now()); + return injectorContractRepository.save(injectorContract); + } - @Secured(ROLE_ADMIN) - @PutMapping("/api/injector_contracts/{injectorContractId}/mapping") - public InjectorContract updateInjectorContractMapping(@PathVariable String injectorContractId, @Valid @RequestBody InjectorContractUpdateMappingInput input) { - InjectorContract injectorContract = injectorContractRepository.findById(injectorContractId).orElseThrow(ElementNotFoundException::new); - injectorContract.setAttackPatterns(fromIterable(attackPatternRepository.findAllById(input.getAttackPatternsIds()))); - injectorContract.setUpdatedAt(Instant.now()); - return injectorContractRepository.save(injectorContract); - } + @Secured(ROLE_ADMIN) + @PutMapping("/api/injector_contracts/{injectorContractId}/mapping") + public InjectorContract updateInjectorContractMapping( + @PathVariable String injectorContractId, + @Valid @RequestBody InjectorContractUpdateMappingInput input) { + InjectorContract injectorContract = + injectorContractRepository + .findById(injectorContractId) + .orElseThrow(ElementNotFoundException::new); + injectorContract.setAttackPatterns( + fromIterable(attackPatternRepository.findAllById(input.getAttackPatternsIds()))); + injectorContract.setUpdatedAt(Instant.now()); + return injectorContractRepository.save(injectorContract); + } - @Secured(ROLE_ADMIN) - @DeleteMapping("/api/injector_contracts/{injectorContractId}") - public void deleteInjectorContract(@PathVariable String injectorContractId) { - injectorContractRepository.deleteById(injectorContractId); - } + @Secured(ROLE_ADMIN) + @DeleteMapping("/api/injector_contracts/{injectorContractId}") + public void deleteInjectorContract(@PathVariable String injectorContractId) { + injectorContractRepository.deleteById(injectorContractId); + } } diff --git a/openbas-api/src/main/java/io/openbas/rest/injector_contract/InjectorContractService.java b/openbas-api/src/main/java/io/openbas/rest/injector_contract/InjectorContractService.java index bf88ad53b0..d0cd15e1a8 100644 --- a/openbas-api/src/main/java/io/openbas/rest/injector_contract/InjectorContractService.java +++ b/openbas-api/src/main/java/io/openbas/rest/injector_contract/InjectorContractService.java @@ -1,5 +1,10 @@ package io.openbas.rest.injector_contract; +import static io.openbas.database.criteria.GenericCriteria.countQuery; +import static io.openbas.utils.JpaUtils.createJoinArrayAggOnId; +import static io.openbas.utils.JpaUtils.createLeftJoin; +import static io.openbas.utils.pagination.SortUtilsCriteriaBuilder.toSortCriteriaBuilder; + import io.openbas.database.model.*; import io.openbas.database.repository.InjectorContractRepository; import io.openbas.injectors.email.EmailContract; @@ -10,6 +15,10 @@ import jakarta.persistence.Tuple; import jakarta.persistence.TypedQuery; import jakarta.persistence.criteria.*; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; +import java.util.Map; import lombok.RequiredArgsConstructor; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; @@ -22,22 +31,11 @@ import org.springframework.data.jpa.domain.Specification; import org.springframework.stereotype.Service; -import java.util.ArrayList; -import java.util.Arrays; -import java.util.List; -import java.util.Map; - -import static io.openbas.database.criteria.GenericCriteria.countQuery; -import static io.openbas.utils.JpaUtils.createJoinArrayAggOnId; -import static io.openbas.utils.JpaUtils.createLeftJoin; -import static io.openbas.utils.pagination.SortUtilsCriteriaBuilder.toSortCriteriaBuilder; - @RequiredArgsConstructor @Service public class InjectorContractService { - @PersistenceContext - private EntityManager entityManager; + @PersistenceContext private EntityManager entityManager; private final InjectorContractRepository injectorContractRepository; @@ -50,14 +48,18 @@ public class InjectorContractService { @EventListener(ApplicationReadyEvent.class) public void initImportAvailableOnStartup() { List listOfInjectorImportAvailable = new ArrayList<>(); - if (mailImportEnabled) listOfInjectorImportAvailable.addAll(Arrays.asList(EmailContract.EMAIL_GLOBAL, EmailContract.EMAIL_DEFAULT)); + if (mailImportEnabled) + listOfInjectorImportAvailable.addAll( + Arrays.asList(EmailContract.EMAIL_GLOBAL, EmailContract.EMAIL_DEFAULT)); if (smsImportEnabled) listOfInjectorImportAvailable.add(OvhSmsContract.OVH_DEFAULT); List listInjectorContract = new ArrayList<>(); injectorContractRepository.findAll().spliterator().forEachRemaining(listInjectorContract::add); - listInjectorContract.forEach(injectorContract -> { - injectorContract.setImportAvailable(listOfInjectorImportAvailable.contains(injectorContract.getId())); - }); + listInjectorContract.forEach( + injectorContract -> { + injectorContract.setImportAvailable( + listOfInjectorImportAvailable.contains(injectorContract.getId())); + }); injectorContractRepository.saveAll(listInjectorContract); } @@ -99,7 +101,6 @@ public Page injectorContracts( return new PageImpl<>(injectorContractOutputs, pageable, total); } - // -- CRITERIA BUILDER -- private void selectForInjectorContract( @@ -107,50 +108,52 @@ private void selectForInjectorContract( @NotNull final CriteriaQuery cq, @NotNull final Root injectorContractRoot) { // Joins - Join injectorContractPayloadJoin = createLeftJoin(injectorContractRoot, "payload"); - Join payloadCollectorJoin = injectorContractPayloadJoin.join("collector", JoinType.LEFT); - Join injectorContractInjectorJoin = createLeftJoin(injectorContractRoot, "injector"); + Join injectorContractPayloadJoin = + createLeftJoin(injectorContractRoot, "payload"); + Join payloadCollectorJoin = + injectorContractPayloadJoin.join("collector", JoinType.LEFT); + Join injectorContractInjectorJoin = + createLeftJoin(injectorContractRoot, "injector"); // Array aggregations - Expression attackPatternIdsExpression = createJoinArrayAggOnId(cb, injectorContractRoot, "attackPatterns"); + Expression attackPatternIdsExpression = + createJoinArrayAggOnId(cb, injectorContractRoot, "attackPatterns"); // SELECT cq.multiselect( - injectorContractRoot.get("id").alias("injector_contract_id"), - injectorContractRoot.get("labels").alias("injector_contract_labels"), - injectorContractRoot.get("content").alias("injector_contract_content"), - injectorContractRoot.get("platforms").alias("injector_contract_platforms"), - injectorContractPayloadJoin.get("type").alias("payload_type"), - payloadCollectorJoin.get("type").alias("collector_type"), - injectorContractInjectorJoin.get("type").alias("injector_contract_injector_type"), - attackPatternIdsExpression.alias("injector_contract_attack_patterns"), - injectorContractPayloadJoin.get("executableArch").alias("payload_executable_arch") - ).distinct(true); + injectorContractRoot.get("id").alias("injector_contract_id"), + injectorContractRoot.get("labels").alias("injector_contract_labels"), + injectorContractRoot.get("content").alias("injector_contract_content"), + injectorContractRoot.get("platforms").alias("injector_contract_platforms"), + injectorContractPayloadJoin.get("type").alias("payload_type"), + payloadCollectorJoin.get("type").alias("collector_type"), + injectorContractInjectorJoin.get("type").alias("injector_contract_injector_type"), + attackPatternIdsExpression.alias("injector_contract_attack_patterns"), + injectorContractPayloadJoin.get("executableArch").alias("payload_executable_arch")) + .distinct(true); // GROUP BY - cq.groupBy(Arrays.asList( - injectorContractRoot.get("id"), - injectorContractPayloadJoin.get("id"), - payloadCollectorJoin.get("id"), - injectorContractInjectorJoin.get("id") - )); + cq.groupBy( + Arrays.asList( + injectorContractRoot.get("id"), + injectorContractPayloadJoin.get("id"), + payloadCollectorJoin.get("id"), + injectorContractInjectorJoin.get("id"))); } - private List execInjectorContract(TypedQuery query) { - return query.getResultList() - .stream() - .map(tuple -> new InjectorContractOutput( - tuple.get("injector_contract_id", String.class), - tuple.get("injector_contract_labels", Map.class), - tuple.get("injector_contract_content", String.class), - tuple.get("injector_contract_platforms", Endpoint.PLATFORM_TYPE[].class), - tuple.get("payload_type", String.class), - tuple.get("collector_type", String.class), - tuple.get("injector_contract_injector_type", String.class), - tuple.get("injector_contract_attack_patterns", String[].class), - tuple.get("payload_executable_arch", Endpoint.PLATFORM_ARCH.class) - )) + return query.getResultList().stream() + .map( + tuple -> + new InjectorContractOutput( + tuple.get("injector_contract_id", String.class), + tuple.get("injector_contract_labels", Map.class), + tuple.get("injector_contract_content", String.class), + tuple.get("injector_contract_platforms", Endpoint.PLATFORM_TYPE[].class), + tuple.get("payload_type", String.class), + tuple.get("collector_type", String.class), + tuple.get("injector_contract_injector_type", String.class), + tuple.get("injector_contract_attack_patterns", String[].class), + tuple.get("payload_executable_arch", Endpoint.PLATFORM_ARCH.class))) .toList(); } - } diff --git a/openbas-api/src/main/java/io/openbas/rest/injector_contract/form/InjectorContractAddInput.java b/openbas-api/src/main/java/io/openbas/rest/injector_contract/form/InjectorContractAddInput.java index 02f8b51eb3..c3062d6f79 100644 --- a/openbas-api/src/main/java/io/openbas/rest/injector_contract/form/InjectorContractAddInput.java +++ b/openbas-api/src/main/java/io/openbas/rest/injector_contract/form/InjectorContractAddInput.java @@ -1,125 +1,124 @@ package io.openbas.rest.injector_contract.form; +import static io.openbas.config.AppConfig.MANDATORY_MESSAGE; + import com.fasterxml.jackson.annotation.JsonProperty; import jakarta.validation.constraints.NotBlank; -import lombok.Getter; -import lombok.Setter; - import java.util.ArrayList; import java.util.List; import java.util.Map; - -import static io.openbas.config.AppConfig.MANDATORY_MESSAGE; +import lombok.Getter; +import lombok.Setter; @Getter @Setter public class InjectorContractAddInput { - @NotBlank(message = MANDATORY_MESSAGE) - @JsonProperty("contract_id") - private String id; + @NotBlank(message = MANDATORY_MESSAGE) + @JsonProperty("contract_id") + private String id; - @NotBlank(message = MANDATORY_MESSAGE) - @JsonProperty("injector_id") - private String injectorId; + @NotBlank(message = MANDATORY_MESSAGE) + @JsonProperty("injector_id") + private String injectorId; - @Getter - @JsonProperty("contract_manual") - private boolean manual = false; + @Getter + @JsonProperty("contract_manual") + private boolean manual = false; - @Getter - @JsonProperty("contract_labels") - private Map labels; + @Getter + @JsonProperty("contract_labels") + private Map labels; - @Getter - @JsonProperty("contract_attack_patterns_ids") - private List attackPatternsIds = new ArrayList<>(); + @Getter + @JsonProperty("contract_attack_patterns_ids") + private List attackPatternsIds = new ArrayList<>(); - @Getter - @JsonProperty("contract_attack_patterns_external_ids") - private List attackPatternsExternalIds = new ArrayList<>(); + @Getter + @JsonProperty("contract_attack_patterns_external_ids") + private List attackPatternsExternalIds = new ArrayList<>(); - @Getter - @NotBlank(message = MANDATORY_MESSAGE) - @JsonProperty("contract_content") - private String content; + @Getter + @NotBlank(message = MANDATORY_MESSAGE) + @JsonProperty("contract_content") + private String content; - @JsonProperty("is_atomic_testing") - private boolean isAtomicTesting = true; + @JsonProperty("is_atomic_testing") + private boolean isAtomicTesting = true; - @Getter - @JsonProperty("contract_platforms") - private String[] platforms = new String[0]; + @Getter + @JsonProperty("contract_platforms") + private String[] platforms = new String[0]; - public String getId() { - return id; - } + public String getId() { + return id; + } - public void setId(String id) { - this.id = id; - } + public void setId(String id) { + this.id = id; + } - public String getInjectorId() { - return injectorId; - } + public String getInjectorId() { + return injectorId; + } - public void setInjectorId(String injectorId) { - this.injectorId = injectorId; - } + public void setInjectorId(String injectorId) { + this.injectorId = injectorId; + } - public boolean isManual() { - return manual; - } + public boolean isManual() { + return manual; + } - public void setManual(boolean manual) { - this.manual = manual; - } + public void setManual(boolean manual) { + this.manual = manual; + } - public Map getLabels() { - return labels; - } + public Map getLabels() { + return labels; + } - public void setLabels(Map labels) { - this.labels = labels; - } + public void setLabels(Map labels) { + this.labels = labels; + } - public List getAttackPatternsIds() { - return attackPatternsIds; - } + public List getAttackPatternsIds() { + return attackPatternsIds; + } - public void setAttackPatternsIds(List attackPatternsIds) { - this.attackPatternsIds = attackPatternsIds; - } + public void setAttackPatternsIds(List attackPatternsIds) { + this.attackPatternsIds = attackPatternsIds; + } - public List getAttackPatternsExternalIds() { - return attackPatternsExternalIds; - } + public List getAttackPatternsExternalIds() { + return attackPatternsExternalIds; + } - public void setAttackPatternsExternalIds(List attackPatternsExternalIds) { - this.attackPatternsExternalIds = attackPatternsExternalIds; - } + public void setAttackPatternsExternalIds(List attackPatternsExternalIds) { + this.attackPatternsExternalIds = attackPatternsExternalIds; + } - public String getContent() { - return content; - } + public String getContent() { + return content; + } - public void setContent(String content) { - this.content = content; - } + public void setContent(String content) { + this.content = content; + } - public boolean isAtomicTesting() { - return isAtomicTesting; - } + public boolean isAtomicTesting() { + return isAtomicTesting; + } - public void setAtomicTesting(boolean atomicTesting) { - isAtomicTesting = atomicTesting; - } + public void setAtomicTesting(boolean atomicTesting) { + isAtomicTesting = atomicTesting; + } - public String[] getPlatforms() { - return platforms; - } + public String[] getPlatforms() { + return platforms; + } - public void setPlatforms(String[] platforms) { - this.platforms = platforms; - } + public void setPlatforms(String[] platforms) { + this.platforms = platforms; + } } diff --git a/openbas-api/src/main/java/io/openbas/rest/injector_contract/form/InjectorContractInput.java b/openbas-api/src/main/java/io/openbas/rest/injector_contract/form/InjectorContractInput.java index e029b17782..fd1408ef73 100644 --- a/openbas-api/src/main/java/io/openbas/rest/injector_contract/form/InjectorContractInput.java +++ b/openbas-api/src/main/java/io/openbas/rest/injector_contract/form/InjectorContractInput.java @@ -1,78 +1,77 @@ package io.openbas.rest.injector_contract.form; +import static io.openbas.config.AppConfig.MANDATORY_MESSAGE; + import com.fasterxml.jackson.annotation.JsonProperty; import io.openbas.database.model.Endpoint.PLATFORM_TYPE; import jakarta.validation.constraints.NotBlank; -import lombok.Getter; -import lombok.Setter; - import java.util.ArrayList; import java.util.List; import java.util.Map; - -import static io.openbas.config.AppConfig.MANDATORY_MESSAGE; +import lombok.Getter; +import lombok.Setter; @Getter @Setter public class InjectorContractInput { - @NotBlank(message = MANDATORY_MESSAGE) - @JsonProperty("contract_id") - private String id; + @NotBlank(message = MANDATORY_MESSAGE) + @JsonProperty("contract_id") + private String id; - @Getter - @JsonProperty("contract_manual") - private boolean manual = false; + @Getter + @JsonProperty("contract_manual") + private boolean manual = false; - @Getter - @JsonProperty("contract_labels") - private Map labels; + @Getter + @JsonProperty("contract_labels") + private Map labels; - @Getter - @JsonProperty("contract_attack_patterns_external_ids") - private List attackPatternsExternalIds = new ArrayList<>(); + @Getter + @JsonProperty("contract_attack_patterns_external_ids") + private List attackPatternsExternalIds = new ArrayList<>(); - @Getter - @NotBlank(message = MANDATORY_MESSAGE) - @JsonProperty("contract_content") - private String content; + @Getter + @NotBlank(message = MANDATORY_MESSAGE) + @JsonProperty("contract_content") + private String content; - @JsonProperty("is_atomic_testing") - private boolean isAtomicTesting = true; + @JsonProperty("is_atomic_testing") + private boolean isAtomicTesting = true; - @Getter - @JsonProperty("contract_platforms") - private PLATFORM_TYPE[] platforms = new PLATFORM_TYPE[0]; + @Getter + @JsonProperty("contract_platforms") + private PLATFORM_TYPE[] platforms = new PLATFORM_TYPE[0]; - public void setId(String id) { - this.id = id; - } + public void setId(String id) { + this.id = id; + } - public void setManual(boolean manual) { - this.manual = manual; - } + public void setManual(boolean manual) { + this.manual = manual; + } - public void setLabels(Map labels) { - this.labels = labels; - } + public void setLabels(Map labels) { + this.labels = labels; + } - public void setAttackPatternsExternalIds(List attackPatternsExternalIds) { - this.attackPatternsExternalIds = attackPatternsExternalIds; - } + public void setAttackPatternsExternalIds(List attackPatternsExternalIds) { + this.attackPatternsExternalIds = attackPatternsExternalIds; + } - public void setContent(String content) { - this.content = content; - } + public void setContent(String content) { + this.content = content; + } - public boolean isAtomicTesting() { - return isAtomicTesting; - } + public boolean isAtomicTesting() { + return isAtomicTesting; + } - public void setAtomicTesting(boolean atomicTesting) { - isAtomicTesting = atomicTesting; - } + public void setAtomicTesting(boolean atomicTesting) { + isAtomicTesting = atomicTesting; + } - public void setPlatforms(PLATFORM_TYPE[] platforms) { - this.platforms = platforms; - } + public void setPlatforms(PLATFORM_TYPE[] platforms) { + this.platforms = platforms; + } } diff --git a/openbas-api/src/main/java/io/openbas/rest/injector_contract/form/InjectorContractUpdateInput.java b/openbas-api/src/main/java/io/openbas/rest/injector_contract/form/InjectorContractUpdateInput.java index 39313bf7b5..391e4c898c 100644 --- a/openbas-api/src/main/java/io/openbas/rest/injector_contract/form/InjectorContractUpdateInput.java +++ b/openbas-api/src/main/java/io/openbas/rest/injector_contract/form/InjectorContractUpdateInput.java @@ -1,72 +1,71 @@ package io.openbas.rest.injector_contract.form; +import static io.openbas.config.AppConfig.MANDATORY_MESSAGE; + import com.fasterxml.jackson.annotation.JsonProperty; import jakarta.validation.constraints.NotBlank; -import lombok.Getter; -import lombok.Setter; - import java.util.ArrayList; import java.util.List; import java.util.Map; - -import static io.openbas.config.AppConfig.MANDATORY_MESSAGE; +import lombok.Getter; +import lombok.Setter; @Getter @Setter public class InjectorContractUpdateInput { - @Getter - @JsonProperty("contract_manual") - private boolean manual = false; + @Getter + @JsonProperty("contract_manual") + private boolean manual = false; - @Getter - @JsonProperty("contract_labels") - private Map labels; + @Getter + @JsonProperty("contract_labels") + private Map labels; - @Getter - @JsonProperty("contract_attack_patterns_ids") - private List attackPatternsIds = new ArrayList<>(); + @Getter + @JsonProperty("contract_attack_patterns_ids") + private List attackPatternsIds = new ArrayList<>(); - @Getter - @NotBlank(message = MANDATORY_MESSAGE) - @JsonProperty("contract_content") - private String content; + @Getter + @NotBlank(message = MANDATORY_MESSAGE) + @JsonProperty("contract_content") + private String content; - @JsonProperty("is_atomic_testing") - private boolean isAtomicTesting = true; + @JsonProperty("is_atomic_testing") + private boolean isAtomicTesting = true; - @Getter - @JsonProperty("contract_platforms") - private String[] platforms = new String[0]; + @Getter + @JsonProperty("contract_platforms") + private String[] platforms = new String[0]; - public void setManual(boolean manual) { - this.manual = manual; - } + public void setManual(boolean manual) { + this.manual = manual; + } - public void setLabels(Map labels) { - this.labels = labels; - } + public void setLabels(Map labels) { + this.labels = labels; + } - public void setAttackPatternsIds(List attackPatternsIds) { - this.attackPatternsIds = attackPatternsIds; - } + public void setAttackPatternsIds(List attackPatternsIds) { + this.attackPatternsIds = attackPatternsIds; + } - public void setContent(String content) { - this.content = content; - } + public void setContent(String content) { + this.content = content; + } - public boolean isAtomicTesting() { - return isAtomicTesting; - } + public boolean isAtomicTesting() { + return isAtomicTesting; + } - public void setAtomicTesting(boolean atomicTesting) { - isAtomicTesting = atomicTesting; - } + public void setAtomicTesting(boolean atomicTesting) { + isAtomicTesting = atomicTesting; + } - public String[] getPlatforms() { - return platforms; - } + public String[] getPlatforms() { + return platforms; + } - public void setPlatforms(String[] platforms) { - this.platforms = platforms; - } + public void setPlatforms(String[] platforms) { + this.platforms = platforms; + } } diff --git a/openbas-api/src/main/java/io/openbas/rest/injector_contract/form/InjectorContractUpdateMappingInput.java b/openbas-api/src/main/java/io/openbas/rest/injector_contract/form/InjectorContractUpdateMappingInput.java index 4cdbeebb3b..556b1a8fa6 100644 --- a/openbas-api/src/main/java/io/openbas/rest/injector_contract/form/InjectorContractUpdateMappingInput.java +++ b/openbas-api/src/main/java/io/openbas/rest/injector_contract/form/InjectorContractUpdateMappingInput.java @@ -1,28 +1,23 @@ package io.openbas.rest.injector_contract.form; import com.fasterxml.jackson.annotation.JsonProperty; -import jakarta.validation.constraints.NotBlank; -import lombok.Getter; -import lombok.Setter; - import java.util.ArrayList; import java.util.List; -import java.util.Map; - -import static io.openbas.config.AppConfig.MANDATORY_MESSAGE; +import lombok.Getter; +import lombok.Setter; @Getter @Setter public class InjectorContractUpdateMappingInput { - @Getter - @JsonProperty("contract_attack_patterns_ids") - private List attackPatternsIds = new ArrayList<>(); + @Getter + @JsonProperty("contract_attack_patterns_ids") + private List attackPatternsIds = new ArrayList<>(); - public List getAttackPatternsIds() { - return attackPatternsIds; - } + public List getAttackPatternsIds() { + return attackPatternsIds; + } - public void setAttackPatternsIds(List attackPatternsIds) { - this.attackPatternsIds = attackPatternsIds; - } + public void setAttackPatternsIds(List attackPatternsIds) { + this.attackPatternsIds = attackPatternsIds; + } } diff --git a/openbas-api/src/main/java/io/openbas/rest/injector_contract/output/InjectorContractOutput.java b/openbas-api/src/main/java/io/openbas/rest/injector_contract/output/InjectorContractOutput.java index b09af1b0c5..70a619e070 100644 --- a/openbas-api/src/main/java/io/openbas/rest/injector_contract/output/InjectorContractOutput.java +++ b/openbas-api/src/main/java/io/openbas/rest/injector_contract/output/InjectorContractOutput.java @@ -4,9 +4,8 @@ import io.openbas.database.model.Endpoint; import io.openbas.database.model.Endpoint.PLATFORM_TYPE; import jakarta.validation.constraints.NotBlank; -import lombok.Data; - import java.util.*; +import lombok.Data; @Data public class InjectorContractOutput { @@ -54,7 +53,8 @@ public InjectorContractOutput( this.payloadType = Optional.ofNullable(collectorType).orElse(payloadType); this.injectorType = injectorType; - this.attackPatterns = attackPatterns != null ? new ArrayList<>(Arrays.asList(attackPatterns)) : new ArrayList<>(); + this.attackPatterns = + attackPatterns != null ? new ArrayList<>(Arrays.asList(attackPatterns)) : new ArrayList<>(); this.arch = arch; } } diff --git a/openbas-api/src/main/java/io/openbas/rest/kill_chain_phase/KillChainPhaseApi.java b/openbas-api/src/main/java/io/openbas/rest/kill_chain_phase/KillChainPhaseApi.java index 7806c57dfe..fafd842080 100644 --- a/openbas-api/src/main/java/io/openbas/rest/kill_chain_phase/KillChainPhaseApi.java +++ b/openbas-api/src/main/java/io/openbas/rest/kill_chain_phase/KillChainPhaseApi.java @@ -1,5 +1,11 @@ package io.openbas.rest.kill_chain_phase; +import static io.openbas.database.model.User.ROLE_ADMIN; +import static io.openbas.database.model.User.ROLE_USER; +import static io.openbas.database.specification.KillChainPhaseSpecification.byName; +import static io.openbas.helper.StreamHelper.fromIterable; +import static io.openbas.utils.pagination.PaginationUtils.buildPaginationJPA; + import io.openbas.database.model.KillChainPhase; import io.openbas.database.repository.KillChainPhaseRepository; import io.openbas.rest.exception.ElementNotFoundException; @@ -11,6 +17,10 @@ import io.openbas.utils.pagination.SearchPaginationInput; import jakarta.transaction.Transactional; import jakarta.validation.Valid; +import java.time.Instant; +import java.util.ArrayList; +import java.util.List; +import java.util.Optional; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.data.domain.Page; import org.springframework.data.domain.Pageable; @@ -19,17 +29,6 @@ import org.springframework.security.access.annotation.Secured; import org.springframework.web.bind.annotation.*; -import java.time.Instant; -import java.util.ArrayList; -import java.util.List; -import java.util.Optional; - -import static io.openbas.database.model.User.ROLE_ADMIN; -import static io.openbas.database.model.User.ROLE_USER; -import static io.openbas.database.specification.KillChainPhaseSpecification.byName; -import static io.openbas.helper.StreamHelper.fromIterable; -import static io.openbas.utils.pagination.PaginationUtils.buildPaginationJPA; - @RestController @Secured(ROLE_USER) public class KillChainPhaseApi extends RestBehavior { @@ -49,26 +48,31 @@ public Iterable killChainPhases() { } @PostMapping("/api/kill_chain_phases/search") - public Page killChainPhases(@RequestBody @Valid SearchPaginationInput searchPaginationInput) { + public Page killChainPhases( + @RequestBody @Valid SearchPaginationInput searchPaginationInput) { return buildPaginationJPA( - (Specification specification, Pageable pageable) -> this.killChainPhaseRepository.findAll( - specification, pageable), + (Specification specification, Pageable pageable) -> + this.killChainPhaseRepository.findAll(specification, pageable), searchPaginationInput, - KillChainPhase.class - ); + KillChainPhase.class); } @GetMapping("/api/kill_chain_phases/{killChainPhaseId}") public KillChainPhase killChainPhase(@PathVariable String killChainPhaseId) { - return killChainPhaseRepository.findById(killChainPhaseId).orElseThrow(ElementNotFoundException::new); + return killChainPhaseRepository + .findById(killChainPhaseId) + .orElseThrow(ElementNotFoundException::new); } @Secured(ROLE_ADMIN) @PutMapping("/api/kill_chain_phases/{killChainPhaseId}") @Transactional(rollbackOn = Exception.class) - public KillChainPhase updateKillChainPhase(@PathVariable String killChainPhaseId, - @Valid @RequestBody KillChainPhaseUpdateInput input) { - KillChainPhase killchainPhase = killChainPhaseRepository.findById(killChainPhaseId).orElseThrow(ElementNotFoundException::new); + public KillChainPhase updateKillChainPhase( + @PathVariable String killChainPhaseId, @Valid @RequestBody KillChainPhaseUpdateInput input) { + KillChainPhase killchainPhase = + killChainPhaseRepository + .findById(killChainPhaseId) + .orElseThrow(ElementNotFoundException::new); killchainPhase.setUpdateAttributes(input); killchainPhase.setUpdatedAt(Instant.now()); return killChainPhaseRepository.save(killchainPhase); @@ -86,35 +90,38 @@ public KillChainPhase createKillChainPhase(@Valid @RequestBody KillChainPhaseCre @Secured(ROLE_ADMIN) @PostMapping("/api/kill_chain_phases/upsert") @Transactional(rollbackOn = Exception.class) - public Iterable upsertKillChainPhases(@Valid @RequestBody KillChainPhaseUpsertInput input) { + public Iterable upsertKillChainPhases( + @Valid @RequestBody KillChainPhaseUpsertInput input) { List upserted = new ArrayList<>(); List inputKillChainPhases = input.getKillChainPhases(); - inputKillChainPhases.forEach(killChainPhaseCreateInput -> { - String killChainName = killChainPhaseCreateInput.getKillChainName(); - String shortName = killChainPhaseCreateInput.getShortName(); - Optional optionalKillChainPhase = killChainPhaseRepository.findByKillChainNameAndShortName( - killChainName, shortName); - if (optionalKillChainPhase.isEmpty()) { - KillChainPhase newKillChainPhase = new KillChainPhase(); - newKillChainPhase.setKillChainName(killChainName); - newKillChainPhase.setStixId(killChainPhaseCreateInput.getStixId()); - newKillChainPhase.setExternalId(killChainPhaseCreateInput.getExternalId()); - newKillChainPhase.setShortName(shortName); - newKillChainPhase.setName(killChainPhaseCreateInput.getName()); - newKillChainPhase.setDescription(killChainPhaseCreateInput.getDescription()); - newKillChainPhase.setOrder( - Optional.ofNullable(KillChainPhaseUtils.orderFromMitreAttack().get(shortName)).orElse(0L)); - upserted.add(newKillChainPhase); - } else { - KillChainPhase killChainPhase = optionalKillChainPhase.get(); - killChainPhase.setStixId(killChainPhaseCreateInput.getStixId()); - killChainPhase.setShortName(killChainPhaseCreateInput.getShortName()); - killChainPhase.setName(killChainPhaseCreateInput.getName()); - killChainPhase.setExternalId(killChainPhaseCreateInput.getExternalId()); - killChainPhase.setDescription(killChainPhaseCreateInput.getDescription()); - upserted.add(killChainPhase); - } - }); + inputKillChainPhases.forEach( + killChainPhaseCreateInput -> { + String killChainName = killChainPhaseCreateInput.getKillChainName(); + String shortName = killChainPhaseCreateInput.getShortName(); + Optional optionalKillChainPhase = + killChainPhaseRepository.findByKillChainNameAndShortName(killChainName, shortName); + if (optionalKillChainPhase.isEmpty()) { + KillChainPhase newKillChainPhase = new KillChainPhase(); + newKillChainPhase.setKillChainName(killChainName); + newKillChainPhase.setStixId(killChainPhaseCreateInput.getStixId()); + newKillChainPhase.setExternalId(killChainPhaseCreateInput.getExternalId()); + newKillChainPhase.setShortName(shortName); + newKillChainPhase.setName(killChainPhaseCreateInput.getName()); + newKillChainPhase.setDescription(killChainPhaseCreateInput.getDescription()); + newKillChainPhase.setOrder( + Optional.ofNullable(KillChainPhaseUtils.orderFromMitreAttack().get(shortName)) + .orElse(0L)); + upserted.add(newKillChainPhase); + } else { + KillChainPhase killChainPhase = optionalKillChainPhase.get(); + killChainPhase.setStixId(killChainPhaseCreateInput.getStixId()); + killChainPhase.setShortName(killChainPhaseCreateInput.getShortName()); + killChainPhase.setName(killChainPhaseCreateInput.getName()); + killChainPhase.setExternalId(killChainPhaseCreateInput.getExternalId()); + killChainPhase.setDescription(killChainPhaseCreateInput.getDescription()); + upserted.add(killChainPhase); + } + }); return this.killChainPhaseRepository.saveAll(upserted); } @@ -127,8 +134,11 @@ public void deleteKillChainPhase(@PathVariable String killChainPhaseId) { // -- OPTION -- @GetMapping(KILL_CHAIN_PHASE_URI + "/options") - public List optionsByName(@RequestParam(required = false) final String searchText) { - return fromIterable(this.killChainPhaseRepository.findAll(byName(searchText), Sort.by(Sort.Direction.ASC, "name"))) + public List optionsByName( + @RequestParam(required = false) final String searchText) { + return fromIterable( + this.killChainPhaseRepository.findAll( + byName(searchText), Sort.by(Sort.Direction.ASC, "name"))) .stream() .map(i -> new FilterUtilsJpa.Option(i.getId(), i.getName())) .toList(); @@ -136,10 +146,8 @@ public List optionsByName(@RequestParam(required = false) @PostMapping(KILL_CHAIN_PHASE_URI + "/options") public List optionsById(@RequestBody final List ids) { - return fromIterable(this.killChainPhaseRepository.findAllById(ids)) - .stream() + return fromIterable(this.killChainPhaseRepository.findAllById(ids)).stream() .map(i -> new FilterUtilsJpa.Option(i.getId(), i.getName())) .toList(); } - } diff --git a/openbas-api/src/main/java/io/openbas/rest/kill_chain_phase/KillChainPhaseUtils.java b/openbas-api/src/main/java/io/openbas/rest/kill_chain_phase/KillChainPhaseUtils.java index eeaa20f6b9..47666a8a00 100644 --- a/openbas-api/src/main/java/io/openbas/rest/kill_chain_phase/KillChainPhaseUtils.java +++ b/openbas-api/src/main/java/io/openbas/rest/kill_chain_phase/KillChainPhaseUtils.java @@ -23,5 +23,4 @@ public static Map orderFromMitreAttack() { map.put("initial-access", 2L); return map; } - } diff --git a/openbas-api/src/main/java/io/openbas/rest/kill_chain_phase/form/KillChainPhaseCreateInput.java b/openbas-api/src/main/java/io/openbas/rest/kill_chain_phase/form/KillChainPhaseCreateInput.java index 6b998f13e9..275af54e18 100644 --- a/openbas-api/src/main/java/io/openbas/rest/kill_chain_phase/form/KillChainPhaseCreateInput.java +++ b/openbas-api/src/main/java/io/openbas/rest/kill_chain_phase/form/KillChainPhaseCreateInput.java @@ -1,38 +1,37 @@ package io.openbas.rest.kill_chain_phase.form; +import static io.openbas.config.AppConfig.MANDATORY_MESSAGE; + import com.fasterxml.jackson.annotation.JsonProperty; import jakarta.validation.constraints.NotBlank; import lombok.Getter; import lombok.Setter; -import static io.openbas.config.AppConfig.MANDATORY_MESSAGE; - @Setter @Getter public class KillChainPhaseCreateInput { - @NotBlank(message = MANDATORY_MESSAGE) - @JsonProperty("phase_kill_chain_name") - private String killChainName; - - @NotBlank(message = MANDATORY_MESSAGE) - @JsonProperty("phase_name") - private String name; + @NotBlank(message = MANDATORY_MESSAGE) + @JsonProperty("phase_kill_chain_name") + private String killChainName; - @NotBlank(message = MANDATORY_MESSAGE) - @JsonProperty("phase_shortname") - private String shortName; + @NotBlank(message = MANDATORY_MESSAGE) + @JsonProperty("phase_name") + private String name; - @JsonProperty("phase_stix_id") - private String stixId; + @NotBlank(message = MANDATORY_MESSAGE) + @JsonProperty("phase_shortname") + private String shortName; - @JsonProperty("phase_external_id") - private String externalId; + @JsonProperty("phase_stix_id") + private String stixId; - @JsonProperty("phase_description") - private String description; + @JsonProperty("phase_external_id") + private String externalId; - @JsonProperty("phase_order") - private Long order = 0L; + @JsonProperty("phase_description") + private String description; + @JsonProperty("phase_order") + private Long order = 0L; } diff --git a/openbas-api/src/main/java/io/openbas/rest/kill_chain_phase/form/KillChainPhaseUpdateInput.java b/openbas-api/src/main/java/io/openbas/rest/kill_chain_phase/form/KillChainPhaseUpdateInput.java index e3f15a5e62..44d0991b98 100644 --- a/openbas-api/src/main/java/io/openbas/rest/kill_chain_phase/form/KillChainPhaseUpdateInput.java +++ b/openbas-api/src/main/java/io/openbas/rest/kill_chain_phase/form/KillChainPhaseUpdateInput.java @@ -1,26 +1,24 @@ package io.openbas.rest.kill_chain_phase.form; +import static io.openbas.config.AppConfig.MANDATORY_MESSAGE; + import com.fasterxml.jackson.annotation.JsonProperty; import jakarta.validation.constraints.NotBlank; import lombok.Getter; import lombok.Setter; -import static io.openbas.config.AppConfig.MANDATORY_MESSAGE; - @Setter @Getter public class KillChainPhaseUpdateInput { - @NotBlank(message = MANDATORY_MESSAGE) - @JsonProperty("phase_kill_chain_name") - private String killChainName; - - @NotBlank(message = MANDATORY_MESSAGE) - @JsonProperty("phase_name") - private String name; - - @JsonProperty("phase_order") - private Long order; + @NotBlank(message = MANDATORY_MESSAGE) + @JsonProperty("phase_kill_chain_name") + private String killChainName; + @NotBlank(message = MANDATORY_MESSAGE) + @JsonProperty("phase_name") + private String name; + @JsonProperty("phase_order") + private Long order; } diff --git a/openbas-api/src/main/java/io/openbas/rest/kill_chain_phase/form/KillChainPhaseUpsertInput.java b/openbas-api/src/main/java/io/openbas/rest/kill_chain_phase/form/KillChainPhaseUpsertInput.java index f98f14b5db..cd4faa2689 100644 --- a/openbas-api/src/main/java/io/openbas/rest/kill_chain_phase/form/KillChainPhaseUpsertInput.java +++ b/openbas-api/src/main/java/io/openbas/rest/kill_chain_phase/form/KillChainPhaseUpsertInput.java @@ -1,20 +1,19 @@ package io.openbas.rest.kill_chain_phase.form; import com.fasterxml.jackson.annotation.JsonProperty; - import java.util.ArrayList; import java.util.List; public class KillChainPhaseUpsertInput { - @JsonProperty("kill_chain_phases") - private List killChainPhases = new ArrayList<>(); + @JsonProperty("kill_chain_phases") + private List killChainPhases = new ArrayList<>(); - public List getKillChainPhases() { - return killChainPhases; - } + public List getKillChainPhases() { + return killChainPhases; + } - public void setKillChainPhases(List killChainPhases) { - this.killChainPhases = killChainPhases; - } + public void setKillChainPhases(List killChainPhases) { + this.killChainPhases = killChainPhases; + } } diff --git a/openbas-api/src/main/java/io/openbas/rest/lessons/ExerciseLessonsApi.java b/openbas-api/src/main/java/io/openbas/rest/lessons/ExerciseLessonsApi.java index 86aeaeae4b..02b6a6edb0 100644 --- a/openbas-api/src/main/java/io/openbas/rest/lessons/ExerciseLessonsApi.java +++ b/openbas-api/src/main/java/io/openbas/rest/lessons/ExerciseLessonsApi.java @@ -1,5 +1,8 @@ package io.openbas.rest.lessons; +import static io.openbas.helper.StreamHelper.fromIterable; +import static java.time.Instant.now; + import io.openbas.database.model.*; import io.openbas.database.repository.*; import io.openbas.database.specification.LessonsAnswerSpecification; @@ -11,257 +14,351 @@ import io.openbas.service.MailingService; import jakarta.transaction.Transactional; import jakarta.validation.Valid; +import java.util.List; +import java.util.Optional; import lombok.RequiredArgsConstructor; import org.springframework.security.access.prepost.PreAuthorize; import org.springframework.web.bind.annotation.*; -import java.util.List; -import java.util.Optional; - -import static io.openbas.helper.StreamHelper.fromIterable; -import static java.time.Instant.now; - @RestController @RequiredArgsConstructor public class ExerciseLessonsApi extends RestBehavior { - public static final String EXERCISE_URL = "/api/exercises/"; + public static final String EXERCISE_URL = "/api/exercises/"; - private final ExerciseRepository exerciseRepository; - private final TeamRepository teamRepository; - private final LessonsTemplateRepository lessonsTemplateRepository; - private final LessonsCategoryRepository lessonsCategoryRepository; - private final LessonsQuestionRepository lessonsQuestionRepository; - private final LessonsAnswerRepository lessonsAnswerRepository; - private final UserRepository userRepository; - private final MailingService mailingService; + private final ExerciseRepository exerciseRepository; + private final TeamRepository teamRepository; + private final LessonsTemplateRepository lessonsTemplateRepository; + private final LessonsCategoryRepository lessonsCategoryRepository; + private final LessonsQuestionRepository lessonsQuestionRepository; + private final LessonsAnswerRepository lessonsAnswerRepository; + private final UserRepository userRepository; + private final MailingService mailingService; + @GetMapping(EXERCISE_URL + "{exerciseId}/lessons_categories") + @PreAuthorize("isExerciseObserver(#exerciseId)") + public Iterable exerciseLessonsCategories(@PathVariable String exerciseId) { + return lessonsCategoryRepository.findAll(LessonsCategorySpecification.fromExercise(exerciseId)); + } - @GetMapping(EXERCISE_URL + "{exerciseId}/lessons_categories") - @PreAuthorize("isExerciseObserver(#exerciseId)") - public Iterable exerciseLessonsCategories(@PathVariable String exerciseId) { - return lessonsCategoryRepository.findAll(LessonsCategorySpecification.fromExercise(exerciseId)); + @PostMapping(EXERCISE_URL + "{exerciseId}/lessons_apply_template/{lessonsTemplateId}") + @PreAuthorize("isExercisePlanner(#exerciseId)") + @Transactional(rollbackOn = Exception.class) + public Iterable applyExerciseLessonsTemplate( + @PathVariable String exerciseId, @PathVariable String lessonsTemplateId) { + Exercise exercise = + exerciseRepository.findById(exerciseId).orElseThrow(ElementNotFoundException::new); + LessonsTemplate lessonsTemplate = + lessonsTemplateRepository + .findById(lessonsTemplateId) + .orElseThrow(ElementNotFoundException::new); + List lessonsTemplateCategories = + lessonsTemplate.getCategories().stream().toList(); + for (LessonsTemplateCategory lessonsTemplateCategory : lessonsTemplateCategories) { + LessonsCategory lessonsCategory = new LessonsCategory(); + lessonsCategory.setExercise(exercise); + lessonsCategory.setName(lessonsTemplateCategory.getName()); + lessonsCategory.setDescription(lessonsTemplateCategory.getDescription()); + lessonsCategory.setOrder(lessonsTemplateCategory.getOrder()); + lessonsCategoryRepository.save(lessonsCategory); + List lessonsQuestions = + lessonsTemplateCategory.getQuestions().stream() + .map( + lessonsTemplateQuestion -> { + LessonsQuestion lessonsQuestion = new LessonsQuestion(); + lessonsQuestion.setCategory(lessonsCategory); + lessonsQuestion.setContent(lessonsTemplateQuestion.getContent()); + lessonsQuestion.setExplanation(lessonsTemplateQuestion.getExplanation()); + lessonsQuestion.setOrder(lessonsTemplateQuestion.getOrder()); + return lessonsQuestion; + }) + .toList(); + lessonsQuestionRepository.saveAll(lessonsQuestions); } + return lessonsCategoryRepository.findAll(LessonsCategorySpecification.fromExercise(exerciseId)); + } - @PostMapping(EXERCISE_URL + "{exerciseId}/lessons_apply_template/{lessonsTemplateId}") - @PreAuthorize("isExercisePlanner(#exerciseId)") - @Transactional(rollbackOn = Exception.class) - public Iterable applyExerciseLessonsTemplate(@PathVariable String exerciseId, - @PathVariable String lessonsTemplateId) { - Exercise exercise = exerciseRepository.findById(exerciseId).orElseThrow(ElementNotFoundException::new); - LessonsTemplate lessonsTemplate = lessonsTemplateRepository.findById(lessonsTemplateId) - .orElseThrow(ElementNotFoundException::new); - List lessonsTemplateCategories = lessonsTemplate.getCategories().stream().toList(); - for (LessonsTemplateCategory lessonsTemplateCategory : lessonsTemplateCategories) { - LessonsCategory lessonsCategory = new LessonsCategory(); - lessonsCategory.setExercise(exercise); - lessonsCategory.setName(lessonsTemplateCategory.getName()); - lessonsCategory.setDescription(lessonsTemplateCategory.getDescription()); - lessonsCategory.setOrder(lessonsTemplateCategory.getOrder()); - lessonsCategoryRepository.save(lessonsCategory); - List lessonsQuestions = lessonsTemplateCategory.getQuestions().stream() - .map(lessonsTemplateQuestion -> { - LessonsQuestion lessonsQuestion = new LessonsQuestion(); - lessonsQuestion.setCategory(lessonsCategory); - lessonsQuestion.setContent(lessonsTemplateQuestion.getContent()); - lessonsQuestion.setExplanation(lessonsTemplateQuestion.getExplanation()); - lessonsQuestion.setOrder(lessonsTemplateQuestion.getOrder()); - return lessonsQuestion; - }).toList(); - lessonsQuestionRepository.saveAll(lessonsQuestions); - } - return lessonsCategoryRepository.findAll(LessonsCategorySpecification.fromExercise(exerciseId)); - } + @PostMapping(EXERCISE_URL + "{exerciseId}/lessons_categories") + @PreAuthorize("isExercisePlanner(#exerciseId)") + @Transactional(rollbackOn = Exception.class) + public LessonsCategory createExerciseLessonsCategory( + @PathVariable String exerciseId, @Valid @RequestBody LessonsCategoryCreateInput input) { + Exercise exercise = + exerciseRepository.findById(exerciseId).orElseThrow(ElementNotFoundException::new); + LessonsCategory lessonsCategory = new LessonsCategory(); + lessonsCategory.setUpdateAttributes(input); + lessonsCategory.setExercise(exercise); + return lessonsCategoryRepository.save(lessonsCategory); + } - @PostMapping(EXERCISE_URL + "{exerciseId}/lessons_categories") - @PreAuthorize("isExercisePlanner(#exerciseId)") - @Transactional(rollbackOn = Exception.class) - public LessonsCategory createExerciseLessonsCategory(@PathVariable String exerciseId, - @Valid @RequestBody LessonsCategoryCreateInput input) { - Exercise exercise = exerciseRepository.findById(exerciseId).orElseThrow(ElementNotFoundException::new); - LessonsCategory lessonsCategory = new LessonsCategory(); - lessonsCategory.setUpdateAttributes(input); - lessonsCategory.setExercise(exercise); - return lessonsCategoryRepository.save(lessonsCategory); - } - - @PostMapping(EXERCISE_URL + "{exerciseId}/lessons_answers_reset") - @PreAuthorize("isExercisePlanner(#exerciseId)") - @Transactional(rollbackOn = Exception.class) - public Iterable resetExerciseLessonsAnswers(@PathVariable String exerciseId) { - List lessonsAnswers = lessonsCategoryRepository.findAll( - LessonsCategorySpecification.fromExercise(exerciseId)).stream() - .flatMap(lessonsCategory -> lessonsQuestionRepository.findAll( - LessonsQuestionSpecification.fromCategory(lessonsCategory.getId())).stream() - .flatMap(lessonsQuestion -> lessonsAnswerRepository.findAll( - LessonsAnswerSpecification.fromQuestion(lessonsQuestion.getId())).stream())) - .toList(); - lessonsAnswerRepository.deleteAll(lessonsAnswers); - return lessonsCategoryRepository.findAll(LessonsCategorySpecification.fromExercise(exerciseId)).stream().toList(); - } + @PostMapping(EXERCISE_URL + "{exerciseId}/lessons_answers_reset") + @PreAuthorize("isExercisePlanner(#exerciseId)") + @Transactional(rollbackOn = Exception.class) + public Iterable resetExerciseLessonsAnswers(@PathVariable String exerciseId) { + List lessonsAnswers = + lessonsCategoryRepository + .findAll(LessonsCategorySpecification.fromExercise(exerciseId)) + .stream() + .flatMap( + lessonsCategory -> + lessonsQuestionRepository + .findAll(LessonsQuestionSpecification.fromCategory(lessonsCategory.getId())) + .stream() + .flatMap( + lessonsQuestion -> + lessonsAnswerRepository + .findAll( + LessonsAnswerSpecification.fromQuestion( + lessonsQuestion.getId())) + .stream())) + .toList(); + lessonsAnswerRepository.deleteAll(lessonsAnswers); + return lessonsCategoryRepository + .findAll(LessonsCategorySpecification.fromExercise(exerciseId)) + .stream() + .toList(); + } - @PostMapping(EXERCISE_URL + "{exerciseId}/lessons_empty") - @PreAuthorize("isExercisePlanner(#exerciseId)") - @Transactional(rollbackOn = Exception.class) - public Iterable emptyExerciseLessons(@PathVariable String exerciseId) { - List lessonsCategories = lessonsCategoryRepository.findAll( - LessonsCategorySpecification.fromExercise(exerciseId)).stream().toList(); - lessonsCategoryRepository.deleteAll(lessonsCategories); - lessonsCategories = lessonsCategoryRepository.findAll(LessonsCategorySpecification.fromExercise(exerciseId)) - .stream().toList(); - return lessonsCategories; - } + @PostMapping(EXERCISE_URL + "{exerciseId}/lessons_empty") + @PreAuthorize("isExercisePlanner(#exerciseId)") + @Transactional(rollbackOn = Exception.class) + public Iterable emptyExerciseLessons(@PathVariable String exerciseId) { + List lessonsCategories = + lessonsCategoryRepository + .findAll(LessonsCategorySpecification.fromExercise(exerciseId)) + .stream() + .toList(); + lessonsCategoryRepository.deleteAll(lessonsCategories); + lessonsCategories = + lessonsCategoryRepository + .findAll(LessonsCategorySpecification.fromExercise(exerciseId)) + .stream() + .toList(); + return lessonsCategories; + } - @PutMapping(EXERCISE_URL + "{exerciseId}/lessons_categories/{lessonsCategoryId}") - @PreAuthorize("isExercisePlanner(#exerciseId)") - @Transactional(rollbackOn = Exception.class) - public LessonsCategory updateExerciseLessonsCategory(@PathVariable String exerciseId, - @PathVariable String lessonsCategoryId, @Valid @RequestBody LessonsCategoryUpdateInput input) { - LessonsCategory lessonsTemplateCategory = lessonsCategoryRepository.findById(lessonsCategoryId) - .orElseThrow(ElementNotFoundException::new); - lessonsTemplateCategory.setUpdateAttributes(input); - lessonsTemplateCategory.setUpdated(now()); - return lessonsCategoryRepository.save(lessonsTemplateCategory); - } + @PutMapping(EXERCISE_URL + "{exerciseId}/lessons_categories/{lessonsCategoryId}") + @PreAuthorize("isExercisePlanner(#exerciseId)") + @Transactional(rollbackOn = Exception.class) + public LessonsCategory updateExerciseLessonsCategory( + @PathVariable String exerciseId, + @PathVariable String lessonsCategoryId, + @Valid @RequestBody LessonsCategoryUpdateInput input) { + LessonsCategory lessonsTemplateCategory = + lessonsCategoryRepository + .findById(lessonsCategoryId) + .orElseThrow(ElementNotFoundException::new); + lessonsTemplateCategory.setUpdateAttributes(input); + lessonsTemplateCategory.setUpdated(now()); + return lessonsCategoryRepository.save(lessonsTemplateCategory); + } - @DeleteMapping(EXERCISE_URL + "{exerciseId}/lessons_categories/{lessonsCategoryId}") - @PreAuthorize("isExercisePlanner(#exerciseId)") - @Transactional(rollbackOn = Exception.class) - public void deleteExerciseLessonsCategory(@PathVariable String exerciseId, @PathVariable String lessonsCategoryId) { - lessonsCategoryRepository.deleteById(lessonsCategoryId); - } + @DeleteMapping(EXERCISE_URL + "{exerciseId}/lessons_categories/{lessonsCategoryId}") + @PreAuthorize("isExercisePlanner(#exerciseId)") + @Transactional(rollbackOn = Exception.class) + public void deleteExerciseLessonsCategory( + @PathVariable String exerciseId, @PathVariable String lessonsCategoryId) { + lessonsCategoryRepository.deleteById(lessonsCategoryId); + } - @PutMapping(EXERCISE_URL + "{exerciseId}/lessons_categories/{lessonsCategoryId}/teams") - @PreAuthorize("isExercisePlanner(#exerciseId)") - @Transactional(rollbackOn = Exception.class) - public LessonsCategory updateExerciseLessonsCategoryTeams(@PathVariable String exerciseId, - @PathVariable String lessonsCategoryId, @Valid @RequestBody LessonsCategoryTeamsInput input) { - LessonsCategory lessonsCategory = lessonsCategoryRepository.findById(lessonsCategoryId) - .orElseThrow(ElementNotFoundException::new); - Iterable lessonsCategoryTeams = teamRepository.findAllById(input.getTeamIds()); - lessonsCategory.setTeams(fromIterable(lessonsCategoryTeams)); - return lessonsCategoryRepository.save(lessonsCategory); - } + @PutMapping(EXERCISE_URL + "{exerciseId}/lessons_categories/{lessonsCategoryId}/teams") + @PreAuthorize("isExercisePlanner(#exerciseId)") + @Transactional(rollbackOn = Exception.class) + public LessonsCategory updateExerciseLessonsCategoryTeams( + @PathVariable String exerciseId, + @PathVariable String lessonsCategoryId, + @Valid @RequestBody LessonsCategoryTeamsInput input) { + LessonsCategory lessonsCategory = + lessonsCategoryRepository + .findById(lessonsCategoryId) + .orElseThrow(ElementNotFoundException::new); + Iterable lessonsCategoryTeams = teamRepository.findAllById(input.getTeamIds()); + lessonsCategory.setTeams(fromIterable(lessonsCategoryTeams)); + return lessonsCategoryRepository.save(lessonsCategory); + } - @GetMapping(EXERCISE_URL + "{exerciseId}/lessons_questions") - @PreAuthorize("isExerciseObserver(#exerciseId)") - public Iterable exerciseLessonsQuestions(@PathVariable String exerciseId) { - return lessonsCategoryRepository.findAll(LessonsCategorySpecification.fromExercise(exerciseId)).stream() - .flatMap(lessonsCategory -> lessonsQuestionRepository.findAll( - LessonsQuestionSpecification.fromCategory(lessonsCategory.getId())).stream()).toList(); - } + @GetMapping(EXERCISE_URL + "{exerciseId}/lessons_questions") + @PreAuthorize("isExerciseObserver(#exerciseId)") + public Iterable exerciseLessonsQuestions(@PathVariable String exerciseId) { + return lessonsCategoryRepository + .findAll(LessonsCategorySpecification.fromExercise(exerciseId)) + .stream() + .flatMap( + lessonsCategory -> + lessonsQuestionRepository + .findAll(LessonsQuestionSpecification.fromCategory(lessonsCategory.getId())) + .stream()) + .toList(); + } - @GetMapping(EXERCISE_URL + "{exerciseId}/lessons_categories/{lessonsCategoryId}/lessons_questions") - @PreAuthorize("isExerciseObserver(#exerciseId)") - public Iterable exerciseLessonsCategoryQuestions(@PathVariable String exerciseId, - @PathVariable String lessonsCategoryId) { - return lessonsQuestionRepository.findAll(LessonsQuestionSpecification.fromCategory(lessonsCategoryId)); - } + @GetMapping( + EXERCISE_URL + "{exerciseId}/lessons_categories/{lessonsCategoryId}/lessons_questions") + @PreAuthorize("isExerciseObserver(#exerciseId)") + public Iterable exerciseLessonsCategoryQuestions( + @PathVariable String exerciseId, @PathVariable String lessonsCategoryId) { + return lessonsQuestionRepository.findAll( + LessonsQuestionSpecification.fromCategory(lessonsCategoryId)); + } - @PostMapping(EXERCISE_URL + "{exerciseId}/lessons_categories/{lessonsCategoryId}/lessons_questions") - @PreAuthorize("isExercisePlanner(#exerciseId)") - public LessonsQuestion createExerciseLessonsQuestion(@PathVariable String exerciseId, - @PathVariable String lessonsCategoryId, @Valid @RequestBody LessonsQuestionCreateInput input) { - LessonsCategory lessonsCategory = lessonsCategoryRepository.findById(lessonsCategoryId) - .orElseThrow(ElementNotFoundException::new); - LessonsQuestion lessonsQuestion = new LessonsQuestion(); - lessonsQuestion.setUpdateAttributes(input); - lessonsQuestion.setCategory(lessonsCategory); - return lessonsQuestionRepository.save(lessonsQuestion); - } + @PostMapping( + EXERCISE_URL + "{exerciseId}/lessons_categories/{lessonsCategoryId}/lessons_questions") + @PreAuthorize("isExercisePlanner(#exerciseId)") + public LessonsQuestion createExerciseLessonsQuestion( + @PathVariable String exerciseId, + @PathVariable String lessonsCategoryId, + @Valid @RequestBody LessonsQuestionCreateInput input) { + LessonsCategory lessonsCategory = + lessonsCategoryRepository + .findById(lessonsCategoryId) + .orElseThrow(ElementNotFoundException::new); + LessonsQuestion lessonsQuestion = new LessonsQuestion(); + lessonsQuestion.setUpdateAttributes(input); + lessonsQuestion.setCategory(lessonsCategory); + return lessonsQuestionRepository.save(lessonsQuestion); + } - @PutMapping( - EXERCISE_URL + "{exerciseId}/lessons_categories/{lessonsCategoryId}/lessons_questions/{lessonsQuestionId}") - @PreAuthorize("isExercisePlanner(#exerciseId)") - public LessonsQuestion updateExerciseLessonsQuestion(@PathVariable String exerciseId, - @PathVariable String lessonsQuestionId, @Valid @RequestBody LessonsQuestionUpdateInput input) { - LessonsQuestion lessonsQuestion = lessonsQuestionRepository.findById(lessonsQuestionId) - .orElseThrow(ElementNotFoundException::new); - lessonsQuestion.setUpdateAttributes(input); - lessonsQuestion.setUpdated(now()); - return lessonsQuestionRepository.save(lessonsQuestion); - } + @PutMapping( + EXERCISE_URL + + "{exerciseId}/lessons_categories/{lessonsCategoryId}/lessons_questions/{lessonsQuestionId}") + @PreAuthorize("isExercisePlanner(#exerciseId)") + public LessonsQuestion updateExerciseLessonsQuestion( + @PathVariable String exerciseId, + @PathVariable String lessonsQuestionId, + @Valid @RequestBody LessonsQuestionUpdateInput input) { + LessonsQuestion lessonsQuestion = + lessonsQuestionRepository + .findById(lessonsQuestionId) + .orElseThrow(ElementNotFoundException::new); + lessonsQuestion.setUpdateAttributes(input); + lessonsQuestion.setUpdated(now()); + return lessonsQuestionRepository.save(lessonsQuestion); + } - @DeleteMapping( - EXERCISE_URL + "{exerciseId}/lessons_categories/{lessonsCategoryId}/lessons_questions/{lessonsQuestionId}") - @PreAuthorize("isExercisePlanner(#exerciseId)") - @Transactional(rollbackOn = Exception.class) - public void deleteExerciseLessonsQuestion(@PathVariable String exerciseId, @PathVariable String lessonsQuestionId) { - lessonsQuestionRepository.deleteById(lessonsQuestionId); - } + @DeleteMapping( + EXERCISE_URL + + "{exerciseId}/lessons_categories/{lessonsCategoryId}/lessons_questions/{lessonsQuestionId}") + @PreAuthorize("isExercisePlanner(#exerciseId)") + @Transactional(rollbackOn = Exception.class) + public void deleteExerciseLessonsQuestion( + @PathVariable String exerciseId, @PathVariable String lessonsQuestionId) { + lessonsQuestionRepository.deleteById(lessonsQuestionId); + } - @PostMapping(EXERCISE_URL + "{exerciseId}/lessons_send") - @PreAuthorize("isExercisePlanner(#exerciseId)") - @Transactional(rollbackOn = Exception.class) - public void sendExerciseLessons(@PathVariable String exerciseId, @Valid @RequestBody LessonsSendInput input) { - Exercise exercise = exerciseRepository.findById(exerciseId).orElseThrow(ElementNotFoundException::new); - List lessonsCategories = lessonsCategoryRepository.findAll( - LessonsCategorySpecification.fromExercise(exerciseId)).stream().toList(); - List users = lessonsCategories.stream().flatMap(lessonsCategory -> lessonsCategory.getTeams().stream() - .flatMap(team -> team.getUsers().stream())).distinct().toList(); - mailingService.sendEmail(input.getSubject(), input.getBody(), users, Optional.of(exercise)); - } + @PostMapping(EXERCISE_URL + "{exerciseId}/lessons_send") + @PreAuthorize("isExercisePlanner(#exerciseId)") + @Transactional(rollbackOn = Exception.class) + public void sendExerciseLessons( + @PathVariable String exerciseId, @Valid @RequestBody LessonsSendInput input) { + Exercise exercise = + exerciseRepository.findById(exerciseId).orElseThrow(ElementNotFoundException::new); + List lessonsCategories = + lessonsCategoryRepository + .findAll(LessonsCategorySpecification.fromExercise(exerciseId)) + .stream() + .toList(); + List users = + lessonsCategories.stream() + .flatMap( + lessonsCategory -> + lessonsCategory.getTeams().stream().flatMap(team -> team.getUsers().stream())) + .distinct() + .toList(); + mailingService.sendEmail(input.getSubject(), input.getBody(), users, Optional.of(exercise)); + } - @GetMapping(EXERCISE_URL + "{exerciseId}/lessons_answers") - @PreAuthorize("isExerciseObserver(#exerciseId)") - public List exerciseLessonsAnswers(@PathVariable String exerciseId, - @RequestParam Optional userId) { - return lessonsCategoryRepository.findAll(LessonsCategorySpecification.fromExercise(exerciseId)).stream() - .flatMap(lessonsCategory -> lessonsQuestionRepository.findAll( - LessonsQuestionSpecification.fromCategory(lessonsCategory.getId())).stream() - .flatMap(lessonsQuestion -> lessonsAnswerRepository.findAll( - LessonsAnswerSpecification.fromQuestion(lessonsQuestion.getId())).stream())) - .toList(); - } + @GetMapping(EXERCISE_URL + "{exerciseId}/lessons_answers") + @PreAuthorize("isExerciseObserver(#exerciseId)") + public List exerciseLessonsAnswers( + @PathVariable String exerciseId, @RequestParam Optional userId) { + return lessonsCategoryRepository + .findAll(LessonsCategorySpecification.fromExercise(exerciseId)) + .stream() + .flatMap( + lessonsCategory -> + lessonsQuestionRepository + .findAll(LessonsQuestionSpecification.fromCategory(lessonsCategory.getId())) + .stream() + .flatMap( + lessonsQuestion -> + lessonsAnswerRepository + .findAll( + LessonsAnswerSpecification.fromQuestion( + lessonsQuestion.getId())) + .stream())) + .toList(); + } - @GetMapping("/api/player/lessons/exercise/{exerciseId}/lessons_categories") - public List playerLessonsCategories(@PathVariable String exerciseId, - @RequestParam Optional userId) { - impersonateUser(userRepository, userId); // Protection for ? - return lessonsCategoryRepository.findAll(LessonsCategorySpecification.fromExercise(exerciseId)); - } + @GetMapping("/api/player/lessons/exercise/{exerciseId}/lessons_categories") + public List playerLessonsCategories( + @PathVariable String exerciseId, @RequestParam Optional userId) { + impersonateUser(userRepository, userId); // Protection for ? + return lessonsCategoryRepository.findAll(LessonsCategorySpecification.fromExercise(exerciseId)); + } - @GetMapping("/api/player/lessons/exercise/{exerciseId}/lessons_questions") - public List playerLessonsQuestions(@PathVariable String exerciseId, - @RequestParam Optional userId) { - impersonateUser(userRepository, userId); // Protection for ? - return lessonsCategoryRepository.findAll(LessonsCategorySpecification.fromExercise(exerciseId)).stream() - .flatMap(lessonsCategory -> lessonsQuestionRepository.findAll( - LessonsQuestionSpecification.fromCategory(lessonsCategory.getId())).stream()).toList(); - } + @GetMapping("/api/player/lessons/exercise/{exerciseId}/lessons_questions") + public List playerLessonsQuestions( + @PathVariable String exerciseId, @RequestParam Optional userId) { + impersonateUser(userRepository, userId); // Protection for ? + return lessonsCategoryRepository + .findAll(LessonsCategorySpecification.fromExercise(exerciseId)) + .stream() + .flatMap( + lessonsCategory -> + lessonsQuestionRepository + .findAll(LessonsQuestionSpecification.fromCategory(lessonsCategory.getId())) + .stream()) + .toList(); + } - @GetMapping("/api/player/lessons/exercise/{exerciseId}/lessons_answers") - public List playerLessonsAnswers(@PathVariable String exerciseId, - @RequestParam Optional userId) { - impersonateUser(userRepository, userId); // Protection for ? - return lessonsCategoryRepository.findAll(LessonsCategorySpecification.fromExercise(exerciseId)).stream() - .flatMap(lessonsCategory -> lessonsQuestionRepository.findAll( - LessonsQuestionSpecification.fromCategory(lessonsCategory.getId())).stream() - .flatMap(lessonsQuestion -> lessonsAnswerRepository.findAll( - LessonsAnswerSpecification.fromQuestion(lessonsQuestion.getId())).stream())) - .toList(); - } + @GetMapping("/api/player/lessons/exercise/{exerciseId}/lessons_answers") + public List playerLessonsAnswers( + @PathVariable String exerciseId, @RequestParam Optional userId) { + impersonateUser(userRepository, userId); // Protection for ? + return lessonsCategoryRepository + .findAll(LessonsCategorySpecification.fromExercise(exerciseId)) + .stream() + .flatMap( + lessonsCategory -> + lessonsQuestionRepository + .findAll(LessonsQuestionSpecification.fromCategory(lessonsCategory.getId())) + .stream() + .flatMap( + lessonsQuestion -> + lessonsAnswerRepository + .findAll( + LessonsAnswerSpecification.fromQuestion( + lessonsQuestion.getId())) + .stream())) + .toList(); + } - @PostMapping("/api/player/lessons/exercise/{exerciseId}/lessons_categories/{lessonsCategoryId}/lessons_questions/{lessonsQuestionId}/lessons_answers") - public LessonsAnswer createExerciseLessonsQuestion(@PathVariable String exerciseId, - @PathVariable String lessonsQuestionId, @Valid @RequestBody LessonsAnswerCreateInput input, - @RequestParam Optional userId) { - User user = impersonateUser(userRepository, userId); - LessonsQuestion lessonsQuestion = lessonsQuestionRepository.findById(lessonsQuestionId) - .orElseThrow(ElementNotFoundException::new); + @PostMapping( + "/api/player/lessons/exercise/{exerciseId}/lessons_categories/{lessonsCategoryId}/lessons_questions/{lessonsQuestionId}/lessons_answers") + public LessonsAnswer createExerciseLessonsQuestion( + @PathVariable String exerciseId, + @PathVariable String lessonsQuestionId, + @Valid @RequestBody LessonsAnswerCreateInput input, + @RequestParam Optional userId) { + User user = impersonateUser(userRepository, userId); + LessonsQuestion lessonsQuestion = + lessonsQuestionRepository + .findById(lessonsQuestionId) + .orElseThrow(ElementNotFoundException::new); - Optional optionalAnswer = lessonsAnswerRepository.findByUserIdAndQuestionId(user.getId(), - lessonsQuestionId); - LessonsAnswer lessonsAnswer = optionalAnswer.orElseGet(() -> { - LessonsAnswer newAnswer = new LessonsAnswer(); - newAnswer.setQuestion(lessonsQuestion); - newAnswer.setUser(user); - return newAnswer; - }); - lessonsAnswer.setScore(input.getScore()); - lessonsAnswer.setPositive(input.getPositive()); - lessonsAnswer.setNegative(input.getNegative()); + Optional optionalAnswer = + lessonsAnswerRepository.findByUserIdAndQuestionId(user.getId(), lessonsQuestionId); + LessonsAnswer lessonsAnswer = + optionalAnswer.orElseGet( + () -> { + LessonsAnswer newAnswer = new LessonsAnswer(); + newAnswer.setQuestion(lessonsQuestion); + newAnswer.setUser(user); + return newAnswer; + }); + lessonsAnswer.setScore(input.getScore()); + lessonsAnswer.setPositive(input.getPositive()); + lessonsAnswer.setNegative(input.getNegative()); - return lessonsAnswerRepository.save(lessonsAnswer); - } + return lessonsAnswerRepository.save(lessonsAnswer); + } } diff --git a/openbas-api/src/main/java/io/openbas/rest/lessons/ScenarioLessonsApi.java b/openbas-api/src/main/java/io/openbas/rest/lessons/ScenarioLessonsApi.java index b9608a433a..d7573dd2fd 100644 --- a/openbas-api/src/main/java/io/openbas/rest/lessons/ScenarioLessonsApi.java +++ b/openbas-api/src/main/java/io/openbas/rest/lessons/ScenarioLessonsApi.java @@ -1,5 +1,8 @@ package io.openbas.rest.lessons; +import static io.openbas.helper.StreamHelper.fromIterable; +import static java.time.Instant.now; + import io.openbas.database.model.*; import io.openbas.database.repository.*; import io.openbas.database.specification.LessonsCategorySpecification; @@ -9,169 +12,203 @@ import io.openbas.rest.lessons.form.*; import jakarta.transaction.Transactional; import jakarta.validation.Valid; +import java.util.List; import lombok.RequiredArgsConstructor; import org.springframework.security.access.prepost.PreAuthorize; import org.springframework.web.bind.annotation.*; -import java.util.List; - -import static io.openbas.helper.StreamHelper.fromIterable; -import static java.time.Instant.now; - @RestController @RequiredArgsConstructor public class ScenarioLessonsApi extends RestBehavior { - public static final String SCENARIO_URI = "/api/scenarios/"; - - private final ScenarioRepository scenarioRepository; - private final TeamRepository teamRepository; - private final LessonsTemplateRepository lessonsTemplateRepository; - private final LessonsCategoryRepository lessonsCategoryRepository; - private final LessonsQuestionRepository lessonsQuestionRepository; - private final LessonsAnswerRepository lessonsAnswerRepository; - private final UserRepository userRepository; - - - @GetMapping(SCENARIO_URI + "{scenarioId}/lessons_categories") - @PreAuthorize("isScenarioObserver(#scenarioId)") - public Iterable scenarioLessonsCategories(@PathVariable String scenarioId) { - return lessonsCategoryRepository.findAll(LessonsCategorySpecification.fromScenario(scenarioId)); - } - - @PostMapping(SCENARIO_URI + "{scenarioId}/lessons_apply_template/{lessonsTemplateId}") - @PreAuthorize("isScenarioPlanner(#scenarioId)") - @Transactional(rollbackOn = Exception.class) - public Iterable applyScenarioLessonsTemplate(@PathVariable String scenarioId, - @PathVariable String lessonsTemplateId) { - Scenario scenario = scenarioRepository.findById(scenarioId).orElseThrow(ElementNotFoundException::new); - LessonsTemplate lessonsTemplate = lessonsTemplateRepository.findById(lessonsTemplateId) - .orElseThrow(ElementNotFoundException::new); - List lessonsTemplateCategories = lessonsTemplate.getCategories().stream().toList(); - for (LessonsTemplateCategory lessonsTemplateCategory : lessonsTemplateCategories) { - LessonsCategory lessonsCategory = new LessonsCategory(); - lessonsCategory.setScenario(scenario); - lessonsCategory.setName(lessonsTemplateCategory.getName()); - lessonsCategory.setDescription(lessonsTemplateCategory.getDescription()); - lessonsCategory.setOrder(lessonsTemplateCategory.getOrder()); - lessonsCategoryRepository.save(lessonsCategory); - List lessonsQuestions = lessonsTemplateCategory.getQuestions().stream() - .map(lessonsTemplateQuestion -> { - LessonsQuestion lessonsQuestion = new LessonsQuestion(); - lessonsQuestion.setCategory(lessonsCategory); - lessonsQuestion.setContent(lessonsTemplateQuestion.getContent()); - lessonsQuestion.setExplanation(lessonsTemplateQuestion.getExplanation()); - lessonsQuestion.setOrder(lessonsTemplateQuestion.getOrder()); - return lessonsQuestion; - }).toList(); - lessonsQuestionRepository.saveAll(lessonsQuestions); - } - return lessonsCategoryRepository.findAll(LessonsCategorySpecification.fromScenario(scenarioId)); - } - - @PostMapping(SCENARIO_URI + "{scenarioId}/lessons_categories") - @PreAuthorize("isScenarioPlanner(#scenarioId)") - @Transactional(rollbackOn = Exception.class) - public LessonsCategory createScenarioLessonsCategory(@PathVariable String scenarioId, - @Valid @RequestBody LessonsCategoryCreateInput input) { - Scenario scenario = scenarioRepository.findById(scenarioId).orElseThrow(ElementNotFoundException::new); - LessonsCategory lessonsCategory = new LessonsCategory(); - lessonsCategory.setUpdateAttributes(input); - lessonsCategory.setScenario(scenario); - return lessonsCategoryRepository.save(lessonsCategory); - } - - @PostMapping(SCENARIO_URI + "{scenarioId}/lessons_empty") - @PreAuthorize("isScenarioPlanner(#scenarioId)") - @Transactional(rollbackOn = Exception.class) - public Iterable emptyScenarioLessons(@PathVariable String scenarioId) { - List lessonsCategories = lessonsCategoryRepository.findAll( - LessonsCategorySpecification.fromScenario(scenarioId)).stream().toList(); - lessonsCategoryRepository.deleteAll(lessonsCategories); - lessonsCategories = lessonsCategoryRepository.findAll(LessonsCategorySpecification.fromScenario(scenarioId)) - .stream().toList(); - return lessonsCategories; + public static final String SCENARIO_URI = "/api/scenarios/"; + + private final ScenarioRepository scenarioRepository; + private final TeamRepository teamRepository; + private final LessonsTemplateRepository lessonsTemplateRepository; + private final LessonsCategoryRepository lessonsCategoryRepository; + private final LessonsQuestionRepository lessonsQuestionRepository; + private final LessonsAnswerRepository lessonsAnswerRepository; + private final UserRepository userRepository; + + @GetMapping(SCENARIO_URI + "{scenarioId}/lessons_categories") + @PreAuthorize("isScenarioObserver(#scenarioId)") + public Iterable scenarioLessonsCategories(@PathVariable String scenarioId) { + return lessonsCategoryRepository.findAll(LessonsCategorySpecification.fromScenario(scenarioId)); + } + + @PostMapping(SCENARIO_URI + "{scenarioId}/lessons_apply_template/{lessonsTemplateId}") + @PreAuthorize("isScenarioPlanner(#scenarioId)") + @Transactional(rollbackOn = Exception.class) + public Iterable applyScenarioLessonsTemplate( + @PathVariable String scenarioId, @PathVariable String lessonsTemplateId) { + Scenario scenario = + scenarioRepository.findById(scenarioId).orElseThrow(ElementNotFoundException::new); + LessonsTemplate lessonsTemplate = + lessonsTemplateRepository + .findById(lessonsTemplateId) + .orElseThrow(ElementNotFoundException::new); + List lessonsTemplateCategories = + lessonsTemplate.getCategories().stream().toList(); + for (LessonsTemplateCategory lessonsTemplateCategory : lessonsTemplateCategories) { + LessonsCategory lessonsCategory = new LessonsCategory(); + lessonsCategory.setScenario(scenario); + lessonsCategory.setName(lessonsTemplateCategory.getName()); + lessonsCategory.setDescription(lessonsTemplateCategory.getDescription()); + lessonsCategory.setOrder(lessonsTemplateCategory.getOrder()); + lessonsCategoryRepository.save(lessonsCategory); + List lessonsQuestions = + lessonsTemplateCategory.getQuestions().stream() + .map( + lessonsTemplateQuestion -> { + LessonsQuestion lessonsQuestion = new LessonsQuestion(); + lessonsQuestion.setCategory(lessonsCategory); + lessonsQuestion.setContent(lessonsTemplateQuestion.getContent()); + lessonsQuestion.setExplanation(lessonsTemplateQuestion.getExplanation()); + lessonsQuestion.setOrder(lessonsTemplateQuestion.getOrder()); + return lessonsQuestion; + }) + .toList(); + lessonsQuestionRepository.saveAll(lessonsQuestions); } - - @PutMapping(SCENARIO_URI + "{scenarioId}/lessons_categories/{lessonsCategoryId}") - @PreAuthorize("isScenarioPlanner(#scenarioId)") - @Transactional(rollbackOn = Exception.class) - public LessonsCategory updateScenarioLessonsCategory(@PathVariable String scenarioId, - @PathVariable String lessonsCategoryId, @Valid @RequestBody LessonsCategoryUpdateInput input) { - LessonsCategory lessonsTemplateCategory = lessonsCategoryRepository.findById(lessonsCategoryId) - .orElseThrow(ElementNotFoundException::new); - lessonsTemplateCategory.setUpdateAttributes(input); - lessonsTemplateCategory.setUpdated(now()); - return lessonsCategoryRepository.save(lessonsTemplateCategory); - } - - @DeleteMapping(SCENARIO_URI + "{scenarioId}/lessons_categories/{lessonsCategoryId}") - @PreAuthorize("isScenarioPlanner(#scenarioId)") - @Transactional(rollbackOn = Exception.class) - public void deleteScenarioLessonsCategory(@PathVariable String scenarioId, @PathVariable String lessonsCategoryId) { - lessonsCategoryRepository.deleteById(lessonsCategoryId); - } - - @PutMapping(SCENARIO_URI + "{scenarioId}/lessons_categories/{lessonsCategoryId}/teams") - @PreAuthorize("isScenarioPlanner(#scenarioId)") - @Transactional(rollbackOn = Exception.class) - public LessonsCategory updateScenarioLessonsCategoryTeams(@PathVariable String scenarioId, - @PathVariable String lessonsCategoryId, - @Valid @RequestBody LessonsCategoryTeamsInput input) { - LessonsCategory lessonsCategory = lessonsCategoryRepository.findById(lessonsCategoryId) - .orElseThrow(ElementNotFoundException::new); - Iterable lessonsCategoryTeams = teamRepository.findAllById(input.getTeamIds()); - lessonsCategory.setTeams(fromIterable(lessonsCategoryTeams)); - return lessonsCategoryRepository.save(lessonsCategory); - } - - @GetMapping(SCENARIO_URI + "{scenarioId}/lessons_questions") - @PreAuthorize("isScenarioObserver(#scenarioId)") - public Iterable scenarioLessonsQuestions(@PathVariable String scenarioId) { - return lessonsCategoryRepository.findAll(LessonsCategorySpecification.fromScenario(scenarioId)).stream() - .flatMap(lessonsCategory -> lessonsQuestionRepository.findAll( - LessonsQuestionSpecification.fromCategory(lessonsCategory.getId())).stream()).toList(); - } - - @GetMapping(SCENARIO_URI + "{scenarioId}/lessons_categories/{lessonsCategoryId}/lessons_questions") - @PreAuthorize("isScenarioObserver(#scenarioId)") - public Iterable scenarioLessonsCategoryQuestions(@PathVariable String scenarioId, - @PathVariable String lessonsCategoryId) { - return lessonsQuestionRepository.findAll(LessonsQuestionSpecification.fromCategory(lessonsCategoryId)); - } - - @PostMapping(SCENARIO_URI + "{scenarioId}/lessons_categories/{lessonsCategoryId}/lessons_questions") - @PreAuthorize("isScenarioPlanner(#scenarioId)") - public LessonsQuestion createScenarioLessonsQuestion(@PathVariable String scenarioId, - @PathVariable String lessonsCategoryId, - @Valid @RequestBody LessonsQuestionCreateInput input) { - LessonsCategory lessonsCategory = lessonsCategoryRepository.findById(lessonsCategoryId) - .orElseThrow(ElementNotFoundException::new); - LessonsQuestion lessonsQuestion = new LessonsQuestion(); - lessonsQuestion.setUpdateAttributes(input); - lessonsQuestion.setCategory(lessonsCategory); - return lessonsQuestionRepository.save(lessonsQuestion); - } - - @PutMapping( - SCENARIO_URI + "{scenarioId}/lessons_categories/{lessonsCategoryId}/lessons_questions/{lessonsQuestionId}") - @PreAuthorize("isScenarioPlanner(#scenarioId)") - public LessonsQuestion updateScenarioLessonsQuestion(@PathVariable String scenarioId, - @PathVariable String lessonsQuestionId, - @Valid @RequestBody LessonsQuestionUpdateInput input) { - LessonsQuestion lessonsQuestion = lessonsQuestionRepository.findById(lessonsQuestionId) - .orElseThrow(ElementNotFoundException::new); - lessonsQuestion.setUpdateAttributes(input); - lessonsQuestion.setUpdated(now()); - return lessonsQuestionRepository.save(lessonsQuestion); - } - - @DeleteMapping( - SCENARIO_URI + "{scenarioId}/lessons_categories/{lessonsCategoryId}/lessons_questions/{lessonsQuestionId}") - @PreAuthorize("isScenarioPlanner(#scenarioId)") - @Transactional(rollbackOn = Exception.class) - public void deleteScenarioLessonsQuestion(@PathVariable String scenarioId, @PathVariable String lessonsQuestionId) { - lessonsQuestionRepository.deleteById(lessonsQuestionId); - } - + return lessonsCategoryRepository.findAll(LessonsCategorySpecification.fromScenario(scenarioId)); + } + + @PostMapping(SCENARIO_URI + "{scenarioId}/lessons_categories") + @PreAuthorize("isScenarioPlanner(#scenarioId)") + @Transactional(rollbackOn = Exception.class) + public LessonsCategory createScenarioLessonsCategory( + @PathVariable String scenarioId, @Valid @RequestBody LessonsCategoryCreateInput input) { + Scenario scenario = + scenarioRepository.findById(scenarioId).orElseThrow(ElementNotFoundException::new); + LessonsCategory lessonsCategory = new LessonsCategory(); + lessonsCategory.setUpdateAttributes(input); + lessonsCategory.setScenario(scenario); + return lessonsCategoryRepository.save(lessonsCategory); + } + + @PostMapping(SCENARIO_URI + "{scenarioId}/lessons_empty") + @PreAuthorize("isScenarioPlanner(#scenarioId)") + @Transactional(rollbackOn = Exception.class) + public Iterable emptyScenarioLessons(@PathVariable String scenarioId) { + List lessonsCategories = + lessonsCategoryRepository + .findAll(LessonsCategorySpecification.fromScenario(scenarioId)) + .stream() + .toList(); + lessonsCategoryRepository.deleteAll(lessonsCategories); + lessonsCategories = + lessonsCategoryRepository + .findAll(LessonsCategorySpecification.fromScenario(scenarioId)) + .stream() + .toList(); + return lessonsCategories; + } + + @PutMapping(SCENARIO_URI + "{scenarioId}/lessons_categories/{lessonsCategoryId}") + @PreAuthorize("isScenarioPlanner(#scenarioId)") + @Transactional(rollbackOn = Exception.class) + public LessonsCategory updateScenarioLessonsCategory( + @PathVariable String scenarioId, + @PathVariable String lessonsCategoryId, + @Valid @RequestBody LessonsCategoryUpdateInput input) { + LessonsCategory lessonsTemplateCategory = + lessonsCategoryRepository + .findById(lessonsCategoryId) + .orElseThrow(ElementNotFoundException::new); + lessonsTemplateCategory.setUpdateAttributes(input); + lessonsTemplateCategory.setUpdated(now()); + return lessonsCategoryRepository.save(lessonsTemplateCategory); + } + + @DeleteMapping(SCENARIO_URI + "{scenarioId}/lessons_categories/{lessonsCategoryId}") + @PreAuthorize("isScenarioPlanner(#scenarioId)") + @Transactional(rollbackOn = Exception.class) + public void deleteScenarioLessonsCategory( + @PathVariable String scenarioId, @PathVariable String lessonsCategoryId) { + lessonsCategoryRepository.deleteById(lessonsCategoryId); + } + + @PutMapping(SCENARIO_URI + "{scenarioId}/lessons_categories/{lessonsCategoryId}/teams") + @PreAuthorize("isScenarioPlanner(#scenarioId)") + @Transactional(rollbackOn = Exception.class) + public LessonsCategory updateScenarioLessonsCategoryTeams( + @PathVariable String scenarioId, + @PathVariable String lessonsCategoryId, + @Valid @RequestBody LessonsCategoryTeamsInput input) { + LessonsCategory lessonsCategory = + lessonsCategoryRepository + .findById(lessonsCategoryId) + .orElseThrow(ElementNotFoundException::new); + Iterable lessonsCategoryTeams = teamRepository.findAllById(input.getTeamIds()); + lessonsCategory.setTeams(fromIterable(lessonsCategoryTeams)); + return lessonsCategoryRepository.save(lessonsCategory); + } + + @GetMapping(SCENARIO_URI + "{scenarioId}/lessons_questions") + @PreAuthorize("isScenarioObserver(#scenarioId)") + public Iterable scenarioLessonsQuestions(@PathVariable String scenarioId) { + return lessonsCategoryRepository + .findAll(LessonsCategorySpecification.fromScenario(scenarioId)) + .stream() + .flatMap( + lessonsCategory -> + lessonsQuestionRepository + .findAll(LessonsQuestionSpecification.fromCategory(lessonsCategory.getId())) + .stream()) + .toList(); + } + + @GetMapping( + SCENARIO_URI + "{scenarioId}/lessons_categories/{lessonsCategoryId}/lessons_questions") + @PreAuthorize("isScenarioObserver(#scenarioId)") + public Iterable scenarioLessonsCategoryQuestions( + @PathVariable String scenarioId, @PathVariable String lessonsCategoryId) { + return lessonsQuestionRepository.findAll( + LessonsQuestionSpecification.fromCategory(lessonsCategoryId)); + } + + @PostMapping( + SCENARIO_URI + "{scenarioId}/lessons_categories/{lessonsCategoryId}/lessons_questions") + @PreAuthorize("isScenarioPlanner(#scenarioId)") + public LessonsQuestion createScenarioLessonsQuestion( + @PathVariable String scenarioId, + @PathVariable String lessonsCategoryId, + @Valid @RequestBody LessonsQuestionCreateInput input) { + LessonsCategory lessonsCategory = + lessonsCategoryRepository + .findById(lessonsCategoryId) + .orElseThrow(ElementNotFoundException::new); + LessonsQuestion lessonsQuestion = new LessonsQuestion(); + lessonsQuestion.setUpdateAttributes(input); + lessonsQuestion.setCategory(lessonsCategory); + return lessonsQuestionRepository.save(lessonsQuestion); + } + + @PutMapping( + SCENARIO_URI + + "{scenarioId}/lessons_categories/{lessonsCategoryId}/lessons_questions/{lessonsQuestionId}") + @PreAuthorize("isScenarioPlanner(#scenarioId)") + public LessonsQuestion updateScenarioLessonsQuestion( + @PathVariable String scenarioId, + @PathVariable String lessonsQuestionId, + @Valid @RequestBody LessonsQuestionUpdateInput input) { + LessonsQuestion lessonsQuestion = + lessonsQuestionRepository + .findById(lessonsQuestionId) + .orElseThrow(ElementNotFoundException::new); + lessonsQuestion.setUpdateAttributes(input); + lessonsQuestion.setUpdated(now()); + return lessonsQuestionRepository.save(lessonsQuestion); + } + + @DeleteMapping( + SCENARIO_URI + + "{scenarioId}/lessons_categories/{lessonsCategoryId}/lessons_questions/{lessonsQuestionId}") + @PreAuthorize("isScenarioPlanner(#scenarioId)") + @Transactional(rollbackOn = Exception.class) + public void deleteScenarioLessonsQuestion( + @PathVariable String scenarioId, @PathVariable String lessonsQuestionId) { + lessonsQuestionRepository.deleteById(lessonsQuestionId); + } } diff --git a/openbas-api/src/main/java/io/openbas/rest/lessons/form/LessonsAnswerCreateInput.java b/openbas-api/src/main/java/io/openbas/rest/lessons/form/LessonsAnswerCreateInput.java index 9b5fd78019..fb8064cc00 100644 --- a/openbas-api/src/main/java/io/openbas/rest/lessons/form/LessonsAnswerCreateInput.java +++ b/openbas-api/src/main/java/io/openbas/rest/lessons/form/LessonsAnswerCreateInput.java @@ -8,12 +8,12 @@ @Setter public class LessonsAnswerCreateInput { - @JsonProperty("lessons_answer_score") - private int score; + @JsonProperty("lessons_answer_score") + private int score; - @JsonProperty("lessons_answer_positive") - private String positive; + @JsonProperty("lessons_answer_positive") + private String positive; - @JsonProperty("lessons_answer_negative") - private String negative; + @JsonProperty("lessons_answer_negative") + private String negative; } diff --git a/openbas-api/src/main/java/io/openbas/rest/lessons/form/LessonsCategoryCreateInput.java b/openbas-api/src/main/java/io/openbas/rest/lessons/form/LessonsCategoryCreateInput.java index 6fd45a41fa..dac7458bdf 100644 --- a/openbas-api/src/main/java/io/openbas/rest/lessons/form/LessonsCategoryCreateInput.java +++ b/openbas-api/src/main/java/io/openbas/rest/lessons/form/LessonsCategoryCreateInput.java @@ -1,44 +1,43 @@ package io.openbas.rest.lessons.form; -import com.fasterxml.jackson.annotation.JsonProperty; +import static io.openbas.config.AppConfig.MANDATORY_MESSAGE; +import com.fasterxml.jackson.annotation.JsonProperty; import jakarta.validation.constraints.NotBlank; -import static io.openbas.config.AppConfig.MANDATORY_MESSAGE; - public class LessonsCategoryCreateInput { - @NotBlank(message = MANDATORY_MESSAGE) - @JsonProperty("lessons_category_name") - private String name; + @NotBlank(message = MANDATORY_MESSAGE) + @JsonProperty("lessons_category_name") + private String name; - @JsonProperty("lessons_category_description") - private String description; + @JsonProperty("lessons_category_description") + private String description; - @JsonProperty("lessons_category_order") - private int order; + @JsonProperty("lessons_category_order") + private int order; - public String getName() { - return name; - } + public String getName() { + return name; + } - public void setName(String name) { - this.name = name; - } + public void setName(String name) { + this.name = name; + } - public String getDescription() { - return description; - } + public String getDescription() { + return description; + } - public void setDescription(String description) { - this.description = description; - } + public void setDescription(String description) { + this.description = description; + } - public int getOrder() { - return order; - } + public int getOrder() { + return order; + } - public void setOrder(int order) { - this.order = order; - } + public void setOrder(int order) { + this.order = order; + } } diff --git a/openbas-api/src/main/java/io/openbas/rest/lessons/form/LessonsCategoryTeamsInput.java b/openbas-api/src/main/java/io/openbas/rest/lessons/form/LessonsCategoryTeamsInput.java index 9f1587b822..0f5c342865 100644 --- a/openbas-api/src/main/java/io/openbas/rest/lessons/form/LessonsCategoryTeamsInput.java +++ b/openbas-api/src/main/java/io/openbas/rest/lessons/form/LessonsCategoryTeamsInput.java @@ -1,19 +1,18 @@ package io.openbas.rest.lessons.form; import com.fasterxml.jackson.annotation.JsonProperty; - import java.util.List; public class LessonsCategoryTeamsInput { - @JsonProperty("lessons_category_teams") - private List teamIds; + @JsonProperty("lessons_category_teams") + private List teamIds; - public List getTeamIds() { - return teamIds; - } + public List getTeamIds() { + return teamIds; + } - public void setTeamIds(List teamIds) { - this.teamIds = teamIds; - } + public void setTeamIds(List teamIds) { + this.teamIds = teamIds; + } } diff --git a/openbas-api/src/main/java/io/openbas/rest/lessons/form/LessonsCategoryUpdateInput.java b/openbas-api/src/main/java/io/openbas/rest/lessons/form/LessonsCategoryUpdateInput.java index 555393bf2d..c19df967fb 100644 --- a/openbas-api/src/main/java/io/openbas/rest/lessons/form/LessonsCategoryUpdateInput.java +++ b/openbas-api/src/main/java/io/openbas/rest/lessons/form/LessonsCategoryUpdateInput.java @@ -1,44 +1,43 @@ package io.openbas.rest.lessons.form; -import com.fasterxml.jackson.annotation.JsonProperty; +import static io.openbas.config.AppConfig.MANDATORY_MESSAGE; +import com.fasterxml.jackson.annotation.JsonProperty; import jakarta.validation.constraints.NotBlank; -import static io.openbas.config.AppConfig.MANDATORY_MESSAGE; - public class LessonsCategoryUpdateInput { - @NotBlank(message = MANDATORY_MESSAGE) - @JsonProperty("lessons_category_name") - private String name; + @NotBlank(message = MANDATORY_MESSAGE) + @JsonProperty("lessons_category_name") + private String name; - @JsonProperty("lessons_category_description") - private String description; + @JsonProperty("lessons_category_description") + private String description; - @JsonProperty("lessons_category_order") - private int order; + @JsonProperty("lessons_category_order") + private int order; - public String getName() { - return name; - } + public String getName() { + return name; + } - public void setName(String name) { - this.name = name; - } + public void setName(String name) { + this.name = name; + } - public String getDescription() { - return description; - } + public String getDescription() { + return description; + } - public void setDescription(String description) { - this.description = description; - } + public void setDescription(String description) { + this.description = description; + } - public int getOrder() { - return order; - } + public int getOrder() { + return order; + } - public void setOrder(int order) { - this.order = order; - } + public void setOrder(int order) { + this.order = order; + } } diff --git a/openbas-api/src/main/java/io/openbas/rest/lessons/form/LessonsQuestionCreateInput.java b/openbas-api/src/main/java/io/openbas/rest/lessons/form/LessonsQuestionCreateInput.java index 0980d70d52..85a70bcf88 100644 --- a/openbas-api/src/main/java/io/openbas/rest/lessons/form/LessonsQuestionCreateInput.java +++ b/openbas-api/src/main/java/io/openbas/rest/lessons/form/LessonsQuestionCreateInput.java @@ -1,44 +1,43 @@ package io.openbas.rest.lessons.form; -import com.fasterxml.jackson.annotation.JsonProperty; +import static io.openbas.config.AppConfig.MANDATORY_MESSAGE; +import com.fasterxml.jackson.annotation.JsonProperty; import jakarta.validation.constraints.NotBlank; -import static io.openbas.config.AppConfig.MANDATORY_MESSAGE; - public class LessonsQuestionCreateInput { - @NotBlank(message = MANDATORY_MESSAGE) - @JsonProperty("lessons_question_content") - private String content; + @NotBlank(message = MANDATORY_MESSAGE) + @JsonProperty("lessons_question_content") + private String content; - @JsonProperty("lessons_question_explanation") - private String explanation; + @JsonProperty("lessons_question_explanation") + private String explanation; - @JsonProperty("lessons_question_order") - private int order; + @JsonProperty("lessons_question_order") + private int order; - public String getContent() { - return content; - } + public String getContent() { + return content; + } - public void setContent(String content) { - this.content = content; - } + public void setContent(String content) { + this.content = content; + } - public String getExplanation() { - return explanation; - } + public String getExplanation() { + return explanation; + } - public void setExplanation(String explanation) { - this.explanation = explanation; - } + public void setExplanation(String explanation) { + this.explanation = explanation; + } - public int getOrder() { - return order; - } + public int getOrder() { + return order; + } - public void setOrder(int order) { - this.order = order; - } + public void setOrder(int order) { + this.order = order; + } } diff --git a/openbas-api/src/main/java/io/openbas/rest/lessons/form/LessonsQuestionUpdateInput.java b/openbas-api/src/main/java/io/openbas/rest/lessons/form/LessonsQuestionUpdateInput.java index fd3751e70b..82601a9dad 100644 --- a/openbas-api/src/main/java/io/openbas/rest/lessons/form/LessonsQuestionUpdateInput.java +++ b/openbas-api/src/main/java/io/openbas/rest/lessons/form/LessonsQuestionUpdateInput.java @@ -1,44 +1,43 @@ package io.openbas.rest.lessons.form; -import com.fasterxml.jackson.annotation.JsonProperty; +import static io.openbas.config.AppConfig.MANDATORY_MESSAGE; +import com.fasterxml.jackson.annotation.JsonProperty; import jakarta.validation.constraints.NotBlank; -import static io.openbas.config.AppConfig.MANDATORY_MESSAGE; - public class LessonsQuestionUpdateInput { - @NotBlank(message = MANDATORY_MESSAGE) - @JsonProperty("lessons_question_content") - private String content; + @NotBlank(message = MANDATORY_MESSAGE) + @JsonProperty("lessons_question_content") + private String content; - @JsonProperty("lessons_question_explanation") - private String explanation; + @JsonProperty("lessons_question_explanation") + private String explanation; - @JsonProperty("lessons_question_order") - private int order; + @JsonProperty("lessons_question_order") + private int order; - public String getContent() { - return content; - } + public String getContent() { + return content; + } - public void setContent(String content) { - this.content = content; - } + public void setContent(String content) { + this.content = content; + } - public String getExplanation() { - return explanation; - } + public String getExplanation() { + return explanation; + } - public void setExplanation(String explanation) { - this.explanation = explanation; - } + public void setExplanation(String explanation) { + this.explanation = explanation; + } - public int getOrder() { - return order; - } + public int getOrder() { + return order; + } - public void setOrder(int order) { - this.order = order; - } + public void setOrder(int order) { + this.order = order; + } } diff --git a/openbas-api/src/main/java/io/openbas/rest/lessons/form/LessonsSendInput.java b/openbas-api/src/main/java/io/openbas/rest/lessons/form/LessonsSendInput.java index 19e49f44ef..c43bdf1a95 100644 --- a/openbas-api/src/main/java/io/openbas/rest/lessons/form/LessonsSendInput.java +++ b/openbas-api/src/main/java/io/openbas/rest/lessons/form/LessonsSendInput.java @@ -4,25 +4,25 @@ public class LessonsSendInput { - @JsonProperty("subject") - private String subject; + @JsonProperty("subject") + private String subject; - @JsonProperty("body") - private String body; + @JsonProperty("body") + private String body; - public String getSubject() { - return subject; - } + public String getSubject() { + return subject; + } - public void setSubject(String subject) { - this.subject = subject; - } + public void setSubject(String subject) { + this.subject = subject; + } - public String getBody() { - return body; - } + public String getBody() { + return body; + } - public void setBody(String body) { - this.body = body; - } + public void setBody(String body) { + this.body = body; + } } diff --git a/openbas-api/src/main/java/io/openbas/rest/lessons_template/LessonsTemplateApi.java b/openbas-api/src/main/java/io/openbas/rest/lessons_template/LessonsTemplateApi.java index 18e5827639..f6639a5da2 100644 --- a/openbas-api/src/main/java/io/openbas/rest/lessons_template/LessonsTemplateApi.java +++ b/openbas-api/src/main/java/io/openbas/rest/lessons_template/LessonsTemplateApi.java @@ -1,5 +1,10 @@ package io.openbas.rest.lessons_template; +import static io.openbas.database.model.User.ROLE_ADMIN; +import static io.openbas.helper.StreamHelper.fromIterable; +import static io.openbas.utils.pagination.PaginationUtils.buildPaginationJPA; +import static java.time.Instant.now; + import io.openbas.database.model.LessonsTemplate; import io.openbas.database.model.LessonsTemplateCategory; import io.openbas.database.model.LessonsTemplateQuestion; @@ -21,11 +26,6 @@ import org.springframework.security.access.annotation.Secured; import org.springframework.web.bind.annotation.*; -import static io.openbas.database.model.User.ROLE_ADMIN; -import static io.openbas.helper.StreamHelper.fromIterable; -import static io.openbas.utils.pagination.PaginationUtils.buildPaginationJPA; -import static java.time.Instant.now; - @RestController @RequiredArgsConstructor public class LessonsTemplateApi extends RestBehavior { @@ -53,21 +53,20 @@ public Iterable lessonsTemplates() { } @PostMapping(LESSON_TEMPLATE_URI + "/search") - public Page lessonsTemplates(@RequestBody @Valid SearchPaginationInput searchPaginationInput) { + public Page lessonsTemplates( + @RequestBody @Valid SearchPaginationInput searchPaginationInput) { return buildPaginationJPA( - this.lessonsTemplateRepository::findAll, - searchPaginationInput, - LessonsTemplate.class - ); + this.lessonsTemplateRepository::findAll, searchPaginationInput, LessonsTemplate.class); } @Secured(ROLE_ADMIN) @PutMapping(LESSON_TEMPLATE_URI + "/{lessonsTemplateId}") public LessonsTemplate updateLessonsTemplate( - @PathVariable String lessonsTemplateId, - @Valid @RequestBody LessonsTemplateInput input) { - LessonsTemplate lessonsTemplate = lessonsTemplateRepository.findById(lessonsTemplateId) - .orElseThrow(ElementNotFoundException::new); + @PathVariable String lessonsTemplateId, @Valid @RequestBody LessonsTemplateInput input) { + LessonsTemplate lessonsTemplate = + lessonsTemplateRepository + .findById(lessonsTemplateId) + .orElseThrow(ElementNotFoundException::new); lessonsTemplate.setUpdateAttributes(input); lessonsTemplate.setUpdated(now()); return lessonsTemplateRepository.save(lessonsTemplate); @@ -90,8 +89,10 @@ public void deleteLessonsTemplate(@PathVariable String lessonsTemplateId) { public LessonsTemplateCategory createLessonsTemplateCategory( @PathVariable String lessonsTemplateId, @Valid @RequestBody LessonsTemplateCategoryInput input) { - LessonsTemplate lessonsTemplate = lessonsTemplateRepository.findById(lessonsTemplateId) - .orElseThrow(ElementNotFoundException::new); + LessonsTemplate lessonsTemplate = + lessonsTemplateRepository + .findById(lessonsTemplateId) + .orElseThrow(ElementNotFoundException::new); LessonsTemplateCategory lessonsTemplateCategory = new LessonsTemplateCategory(); lessonsTemplateCategory.setUpdateAttributes(input); lessonsTemplateCategory.setTemplate(lessonsTemplate); @@ -99,7 +100,8 @@ public LessonsTemplateCategory createLessonsTemplateCategory( } @GetMapping(LESSON_CATEGORY_URI) - public Iterable lessonsTemplateCategories(@PathVariable String lessonsTemplateId) { + public Iterable lessonsTemplateCategories( + @PathVariable String lessonsTemplateId) { return lessonsTemplateCategoryRepository.findAll( LessonsTemplateCategorySpecification.fromTemplate(lessonsTemplateId)); } @@ -111,8 +113,10 @@ public LessonsTemplateCategory updateLessonsTemplateCategory( @PathVariable String lessonsTemplateId, @PathVariable String lessonsTemplateCategoryId, @Valid @RequestBody LessonsTemplateCategoryInput input) { - LessonsTemplateCategory lessonsTemplateCategory = lessonsTemplateCategoryRepository.findById( - lessonsTemplateCategoryId).orElseThrow(ElementNotFoundException::new); + LessonsTemplateCategory lessonsTemplateCategory = + lessonsTemplateCategoryRepository + .findById(lessonsTemplateCategoryId) + .orElseThrow(ElementNotFoundException::new); lessonsTemplateCategory.setUpdateAttributes(input); lessonsTemplateCategory.setUpdated(now()); return lessonsTemplateCategoryRepository.save(lessonsTemplateCategory); @@ -121,33 +125,41 @@ public LessonsTemplateCategory updateLessonsTemplateCategory( @Secured(ROLE_ADMIN) @DeleteMapping(LESSON_CATEGORY_URI + "/{lessonsTemplateCategoryId}") public void deleteLessonsTemplateCategory( - @PathVariable String lessonsTemplateId, - @PathVariable String lessonsTemplateCategoryId) { + @PathVariable String lessonsTemplateId, @PathVariable String lessonsTemplateCategoryId) { lessonsTemplateCategoryRepository.deleteById(lessonsTemplateCategoryId); } // -- LESSONS TEMPLATES QUESTIONS -- @GetMapping(LESSON_TEMPLATE_URI + "/{lessonsTemplateId}/lessons_template_questions") - public Iterable lessonsTemplateQuestions(@PathVariable String lessonsTemplateId) { - return lessonsTemplateCategoryRepository.findAll( - LessonsTemplateCategorySpecification.fromTemplate(lessonsTemplateId)).stream(). - flatMap(lessonsTemplateCategory -> lessonsTemplateQuestionRepository.findAll( - LessonsTemplateQuestionSpecification.fromCategory(lessonsTemplateCategory.getId())).stream()).toList(); + public Iterable lessonsTemplateQuestions( + @PathVariable String lessonsTemplateId) { + return lessonsTemplateCategoryRepository + .findAll(LessonsTemplateCategorySpecification.fromTemplate(lessonsTemplateId)) + .stream() + .flatMap( + lessonsTemplateCategory -> + lessonsTemplateQuestionRepository + .findAll( + LessonsTemplateQuestionSpecification.fromCategory( + lessonsTemplateCategory.getId())) + .stream()) + .toList(); } public static final String LESSON_QUESTION_URI = LESSON_CATEGORY_URI + "/{lessonsTemplateCategoryId}/lessons_template_questions"; - @Secured(ROLE_ADMIN) @PostMapping(LESSON_QUESTION_URI) public LessonsTemplateQuestion createLessonsTemplateQuestion( @PathVariable String lessonsTemplateId, @PathVariable String lessonsTemplateCategoryId, @Valid @RequestBody LessonsTemplateQuestionInput input) { - LessonsTemplateCategory lessonsTemplateCategory = lessonsTemplateCategoryRepository.findById( - lessonsTemplateCategoryId).orElseThrow(ElementNotFoundException::new); + LessonsTemplateCategory lessonsTemplateCategory = + lessonsTemplateCategoryRepository + .findById(lessonsTemplateCategoryId) + .orElseThrow(ElementNotFoundException::new); LessonsTemplateQuestion lessonsTemplateQuestion = new LessonsTemplateQuestion(); lessonsTemplateQuestion.setUpdateAttributes(input); lessonsTemplateQuestion.setCategory(lessonsTemplateCategory); @@ -156,8 +168,7 @@ public LessonsTemplateQuestion createLessonsTemplateQuestion( @GetMapping(LESSON_QUESTION_URI) public Iterable lessonsTemplateCategoryQuestions( - @PathVariable String lessonsTemplateId, - @PathVariable String lessonsTemplateCategoryId) { + @PathVariable String lessonsTemplateId, @PathVariable String lessonsTemplateCategoryId) { return lessonsTemplateQuestionRepository.findAll( LessonsTemplateQuestionSpecification.fromCategory(lessonsTemplateCategoryId)); } @@ -169,8 +180,10 @@ public LessonsTemplateQuestion updateLessonsTemplateQuestion( @PathVariable String lessonsTemplateCategoryId, @PathVariable String lessonsTemplateQuestionId, @Valid @RequestBody LessonsTemplateQuestionInput input) { - LessonsTemplateQuestion lessonsTemplateQuestion = lessonsTemplateQuestionRepository.findById( - lessonsTemplateQuestionId).orElseThrow(ElementNotFoundException::new); + LessonsTemplateQuestion lessonsTemplateQuestion = + lessonsTemplateQuestionRepository + .findById(lessonsTemplateQuestionId) + .orElseThrow(ElementNotFoundException::new); lessonsTemplateQuestion.setUpdateAttributes(input); lessonsTemplateQuestion.setUpdated(now()); return lessonsTemplateQuestionRepository.save(lessonsTemplateQuestion); diff --git a/openbas-api/src/main/java/io/openbas/rest/lessons_template/form/LessonsTemplateCategoryInput.java b/openbas-api/src/main/java/io/openbas/rest/lessons_template/form/LessonsTemplateCategoryInput.java index fb373d29d9..3bade04e96 100644 --- a/openbas-api/src/main/java/io/openbas/rest/lessons_template/form/LessonsTemplateCategoryInput.java +++ b/openbas-api/src/main/java/io/openbas/rest/lessons_template/form/LessonsTemplateCategoryInput.java @@ -1,25 +1,23 @@ package io.openbas.rest.lessons_template.form; -import com.fasterxml.jackson.annotation.JsonProperty; +import static io.openbas.config.AppConfig.MANDATORY_MESSAGE; +import com.fasterxml.jackson.annotation.JsonProperty; import jakarta.validation.constraints.NotBlank; import jakarta.validation.constraints.NotNull; import lombok.Data; -import static io.openbas.config.AppConfig.MANDATORY_MESSAGE; - @Data public class LessonsTemplateCategoryInput { - @NotBlank(message = MANDATORY_MESSAGE) - @JsonProperty("lessons_template_category_name") - private String name; - - @JsonProperty("lessons_template_category_description") - private String description; + @NotBlank(message = MANDATORY_MESSAGE) + @JsonProperty("lessons_template_category_name") + private String name; - @JsonProperty("lessons_template_category_order") - @NotNull - private int order; + @JsonProperty("lessons_template_category_description") + private String description; + @JsonProperty("lessons_template_category_order") + @NotNull + private int order; } diff --git a/openbas-api/src/main/java/io/openbas/rest/lessons_template/form/LessonsTemplateInput.java b/openbas-api/src/main/java/io/openbas/rest/lessons_template/form/LessonsTemplateInput.java index 0c26dc0e22..d065d2a7eb 100644 --- a/openbas-api/src/main/java/io/openbas/rest/lessons_template/form/LessonsTemplateInput.java +++ b/openbas-api/src/main/java/io/openbas/rest/lessons_template/form/LessonsTemplateInput.java @@ -1,11 +1,11 @@ package io.openbas.rest.lessons_template.form; +import static io.openbas.config.AppConfig.MANDATORY_MESSAGE; + import com.fasterxml.jackson.annotation.JsonProperty; import jakarta.validation.constraints.NotBlank; import lombok.Data; -import static io.openbas.config.AppConfig.MANDATORY_MESSAGE; - @Data public class LessonsTemplateInput { @@ -15,5 +15,4 @@ public class LessonsTemplateInput { @JsonProperty("lessons_template_description") private String description; - } diff --git a/openbas-api/src/main/java/io/openbas/rest/lessons_template/form/LessonsTemplateQuestionInput.java b/openbas-api/src/main/java/io/openbas/rest/lessons_template/form/LessonsTemplateQuestionInput.java index b1a50a0f02..47954cbbf6 100644 --- a/openbas-api/src/main/java/io/openbas/rest/lessons_template/form/LessonsTemplateQuestionInput.java +++ b/openbas-api/src/main/java/io/openbas/rest/lessons_template/form/LessonsTemplateQuestionInput.java @@ -1,25 +1,23 @@ package io.openbas.rest.lessons_template.form; -import com.fasterxml.jackson.annotation.JsonProperty; +import static io.openbas.config.AppConfig.MANDATORY_MESSAGE; +import com.fasterxml.jackson.annotation.JsonProperty; import jakarta.validation.constraints.NotBlank; import jakarta.validation.constraints.NotNull; import lombok.Data; -import static io.openbas.config.AppConfig.MANDATORY_MESSAGE; - @Data public class LessonsTemplateQuestionInput { - @NotBlank(message = MANDATORY_MESSAGE) - @JsonProperty("lessons_template_question_content") - private String content; - - @JsonProperty("lessons_template_question_explanation") - private String explanation; + @NotBlank(message = MANDATORY_MESSAGE) + @JsonProperty("lessons_template_question_content") + private String content; - @JsonProperty("lessons_template_question_order") - @NotNull - private int order; + @JsonProperty("lessons_template_question_explanation") + private String explanation; + @JsonProperty("lessons_template_question_order") + @NotNull + private int order; } diff --git a/openbas-api/src/main/java/io/openbas/rest/mapper/MapperApi.java b/openbas-api/src/main/java/io/openbas/rest/mapper/MapperApi.java index fcd299d663..d18e67ef8f 100644 --- a/openbas-api/src/main/java/io/openbas/rest/mapper/MapperApi.java +++ b/openbas-api/src/main/java/io/openbas/rest/mapper/MapperApi.java @@ -1,5 +1,9 @@ package io.openbas.rest.mapper; +import static io.openbas.database.model.User.ROLE_ADMIN; +import static io.openbas.database.model.User.ROLE_USER; +import static io.openbas.utils.pagination.PaginationUtils.buildPaginationJPA; + import com.fasterxml.jackson.core.type.TypeReference; import io.openbas.database.model.ImportMapper; import io.openbas.database.model.Scenario; @@ -24,6 +28,14 @@ import jakarta.validation.Valid; import jakarta.validation.constraints.NotBlank; import jakarta.validation.constraints.NotNull; +import java.io.IOException; +import java.nio.charset.StandardCharsets; +import java.text.MessageFormat; +import java.time.Instant; +import java.time.LocalDateTime; +import java.time.format.DateTimeFormatter; +import java.util.List; +import java.util.UUID; import lombok.RequiredArgsConstructor; import org.apache.commons.io.FilenameUtils; import org.springframework.data.domain.Page; @@ -34,152 +46,149 @@ import org.springframework.web.multipart.MultipartFile; import org.springframework.web.reactive.function.UnsupportedMediaTypeException; -import java.io.IOException; -import java.nio.charset.StandardCharsets; -import java.text.MessageFormat; -import java.time.Instant; -import java.time.LocalDateTime; -import java.time.format.DateTimeFormatter; -import java.util.List; -import java.util.UUID; - -import static io.openbas.database.model.User.ROLE_ADMIN; -import static io.openbas.database.model.User.ROLE_USER; -import static io.openbas.utils.pagination.PaginationUtils.buildPaginationJPA; - @RestController @RequiredArgsConstructor public class MapperApi extends RestBehavior { - private final ImportMapperRepository importMapperRepository; - - private final MapperService mapperService; - - private final InjectService injectService; - - // 25mb in byte - private static final int MAXIMUM_FILE_SIZE_ALLOWED = 25 * 1000 * 1000; - private static final List ACCEPTED_FILE_TYPES = List.of("xls", "xlsx"); - - @Secured(ROLE_USER) - @PostMapping("/api/mappers/search") - public Page getImportMapper(@RequestBody @Valid final SearchPaginationInput searchPaginationInput) { - return buildPaginationJPA( - this.importMapperRepository::findAll, - searchPaginationInput, - ImportMapper.class - ).map(RawPaginationImportMapper::new); - } - - @Secured(ROLE_USER) - @GetMapping("/api/mappers/{mapperId}") - public ImportMapper getImportMapperById(@PathVariable String mapperId) { - return importMapperRepository.findById(UUID.fromString(mapperId)).orElseThrow(ElementNotFoundException::new); - } - - @Secured(ROLE_ADMIN) - @PostMapping("/api/mappers") - public ImportMapper createImportMapper(@RequestBody @Valid final ImportMapperAddInput importMapperAddInput) { - return mapperService.createAndSaveImportMapper(importMapperAddInput); - } - - @Secured(ROLE_ADMIN) - @PostMapping(value="/api/mappers/export") - public void exportMappers( - @RequestBody @Valid final ExportMapperInput exportMapperInput, - HttpServletResponse response) { - try { - String jsonMappers = mapperService.exportMappers(exportMapperInput.getIdsToExport()); - - String rightNow = DateTimeFormatter.ofPattern("yyyyMMdd").format(LocalDateTime.now()); - String name = exportMapperInput.getName().replace("(Import)", "").replace(" ", ""); - String exportFileName = name.length() > 15 ? name.substring(0, 15) : name; - String filename = MessageFormat.format("{0}-{1}.json", exportFileName, rightNow); - - response.addHeader(HttpHeaders.CONTENT_DISPOSITION, "attachment; filename=" + filename); - response.addHeader(HttpHeaders.CONTENT_TYPE, MediaType.APPLICATION_JSON_VALUE); - response.setStatus(HttpServletResponse.SC_OK); - - response.getOutputStream().write(jsonMappers.getBytes(StandardCharsets.UTF_8)); - response.getOutputStream().flush(); - response.getOutputStream().close(); - } catch (IOException e) { - throw new RuntimeException("Error during export", e); - } - } - - @Secured(ROLE_ADMIN) - @PostMapping("/api/mappers/import") - public void importMappers(@RequestPart("file") @NotNull MultipartFile file) throws ImportException { - try { - mapperService.importMappers(mapper.readValue(file.getInputStream().readAllBytes(), new TypeReference<>() { - })); - } catch (Exception e) { - throw new ImportException("Mapper import", "Error during import"); - } + private final ImportMapperRepository importMapperRepository; + + private final MapperService mapperService; + + private final InjectService injectService; + + // 25mb in byte + private static final int MAXIMUM_FILE_SIZE_ALLOWED = 25 * 1000 * 1000; + private static final List ACCEPTED_FILE_TYPES = List.of("xls", "xlsx"); + + @Secured(ROLE_USER) + @PostMapping("/api/mappers/search") + public Page getImportMapper( + @RequestBody @Valid final SearchPaginationInput searchPaginationInput) { + return buildPaginationJPA( + this.importMapperRepository::findAll, searchPaginationInput, ImportMapper.class) + .map(RawPaginationImportMapper::new); + } + + @Secured(ROLE_USER) + @GetMapping("/api/mappers/{mapperId}") + public ImportMapper getImportMapperById(@PathVariable String mapperId) { + return importMapperRepository + .findById(UUID.fromString(mapperId)) + .orElseThrow(ElementNotFoundException::new); + } + + @Secured(ROLE_ADMIN) + @PostMapping("/api/mappers") + public ImportMapper createImportMapper( + @RequestBody @Valid final ImportMapperAddInput importMapperAddInput) { + return mapperService.createAndSaveImportMapper(importMapperAddInput); + } + + @Secured(ROLE_ADMIN) + @PostMapping(value = "/api/mappers/export") + public void exportMappers( + @RequestBody @Valid final ExportMapperInput exportMapperInput, HttpServletResponse response) { + try { + String jsonMappers = mapperService.exportMappers(exportMapperInput.getIdsToExport()); + + String rightNow = DateTimeFormatter.ofPattern("yyyyMMdd").format(LocalDateTime.now()); + String name = exportMapperInput.getName().replace("(Import)", "").replace(" ", ""); + String exportFileName = name.length() > 15 ? name.substring(0, 15) : name; + String filename = MessageFormat.format("{0}-{1}.json", exportFileName, rightNow); + + response.addHeader(HttpHeaders.CONTENT_DISPOSITION, "attachment; filename=" + filename); + response.addHeader(HttpHeaders.CONTENT_TYPE, MediaType.APPLICATION_JSON_VALUE); + response.setStatus(HttpServletResponse.SC_OK); + + response.getOutputStream().write(jsonMappers.getBytes(StandardCharsets.UTF_8)); + response.getOutputStream().flush(); + response.getOutputStream().close(); + } catch (IOException e) { + throw new RuntimeException("Error during export", e); } - - @Secured(ROLE_ADMIN) - @PostMapping("/api/mappers/{mapperId}") - @Operation(summary = "Duplicate XLS mapper by id") - public ImportMapper duplicateMapper(@PathVariable @NotBlank final String mapperId) { - return mapperService.getDuplicateImportMapper(mapperId); - } - - @Secured(ROLE_ADMIN) - @PutMapping("/api/mappers/{mapperId}") - public ImportMapper updateImportMapper(@PathVariable String mapperId, @Valid @RequestBody ImportMapperUpdateInput importMapperUpdateInput) { - return mapperService.updateImportMapper(mapperId, importMapperUpdateInput); - } - - @Secured(ROLE_ADMIN) - @DeleteMapping("/api/mappers/{mapperId}") - public void deleteImportMapper(@PathVariable String mapperId) { - importMapperRepository.deleteById(UUID.fromString(mapperId)); - } - - @PostMapping("/api/mappers/store") - @Transactional(rollbackOn = Exception.class) - @Operation(summary = "Import injects into an xls file") - @Secured(ROLE_USER) - public ImportPostSummary importXLSFile(@RequestPart("file") @NotNull MultipartFile file) { - validateUploadedFile(file); - return injectService.storeXlsFileForImport(file); - } - - @PostMapping("/api/mappers/store/{importId}") - @Transactional(rollbackOn = Exception.class) - @Operation(summary = "Test the import of injects from an xls file") - @Secured(ROLE_USER) - public ImportTestSummary testImportXLSFile(@PathVariable @NotBlank final String importId, - @Valid @RequestBody final InjectsImportTestInput input) { - ImportMapper importMapper = mapperService.createImportMapper(input.getImportMapper()); - importMapper.getInjectImporters().forEach( - injectImporter -> { - injectImporter.setId(UUID.randomUUID().toString()); - injectImporter.getRuleAttributes().forEach(ruleAttribute -> ruleAttribute.setId(UUID.randomUUID().toString())); - } - ); - Scenario scenario = new Scenario(); - scenario.setRecurrenceStart(Instant.now()); - return injectService.importInjectIntoScenarioFromXLS(scenario, importMapper, importId, input.getName(), input.getTimezoneOffset(), false); + } + + @Secured(ROLE_ADMIN) + @PostMapping("/api/mappers/import") + public void importMappers(@RequestPart("file") @NotNull MultipartFile file) + throws ImportException { + try { + mapperService.importMappers( + mapper.readValue(file.getInputStream().readAllBytes(), new TypeReference<>() {})); + } catch (Exception e) { + throw new ImportException("Mapper import", "Error during import"); } - - private void validateUploadedFile(MultipartFile file) { - validateExtension(file); - validateFileSize(file); - } - - private void validateExtension(MultipartFile file) { - String extension = FilenameUtils.getExtension(file.getOriginalFilename()); - if (!ACCEPTED_FILE_TYPES.contains(extension)) { - throw new UnsupportedMediaTypeException("Only the following file types are accepted : " + String.join(", ", ACCEPTED_FILE_TYPES)); - } + } + + @Secured(ROLE_ADMIN) + @PostMapping("/api/mappers/{mapperId}") + @Operation(summary = "Duplicate XLS mapper by id") + public ImportMapper duplicateMapper(@PathVariable @NotBlank final String mapperId) { + return mapperService.getDuplicateImportMapper(mapperId); + } + + @Secured(ROLE_ADMIN) + @PutMapping("/api/mappers/{mapperId}") + public ImportMapper updateImportMapper( + @PathVariable String mapperId, + @Valid @RequestBody ImportMapperUpdateInput importMapperUpdateInput) { + return mapperService.updateImportMapper(mapperId, importMapperUpdateInput); + } + + @Secured(ROLE_ADMIN) + @DeleteMapping("/api/mappers/{mapperId}") + public void deleteImportMapper(@PathVariable String mapperId) { + importMapperRepository.deleteById(UUID.fromString(mapperId)); + } + + @PostMapping("/api/mappers/store") + @Transactional(rollbackOn = Exception.class) + @Operation(summary = "Import injects into an xls file") + @Secured(ROLE_USER) + public ImportPostSummary importXLSFile(@RequestPart("file") @NotNull MultipartFile file) { + validateUploadedFile(file); + return injectService.storeXlsFileForImport(file); + } + + @PostMapping("/api/mappers/store/{importId}") + @Transactional(rollbackOn = Exception.class) + @Operation(summary = "Test the import of injects from an xls file") + @Secured(ROLE_USER) + public ImportTestSummary testImportXLSFile( + @PathVariable @NotBlank final String importId, + @Valid @RequestBody final InjectsImportTestInput input) { + ImportMapper importMapper = mapperService.createImportMapper(input.getImportMapper()); + importMapper + .getInjectImporters() + .forEach( + injectImporter -> { + injectImporter.setId(UUID.randomUUID().toString()); + injectImporter + .getRuleAttributes() + .forEach(ruleAttribute -> ruleAttribute.setId(UUID.randomUUID().toString())); + }); + Scenario scenario = new Scenario(); + scenario.setRecurrenceStart(Instant.now()); + return injectService.importInjectIntoScenarioFromXLS( + scenario, importMapper, importId, input.getName(), input.getTimezoneOffset(), false); + } + + private void validateUploadedFile(MultipartFile file) { + validateExtension(file); + validateFileSize(file); + } + + private void validateExtension(MultipartFile file) { + String extension = FilenameUtils.getExtension(file.getOriginalFilename()); + if (!ACCEPTED_FILE_TYPES.contains(extension)) { + throw new UnsupportedMediaTypeException( + "Only the following file types are accepted : " + String.join(", ", ACCEPTED_FILE_TYPES)); } + } - private void validateFileSize(MultipartFile file){ - if (file.getSize() >= MAXIMUM_FILE_SIZE_ALLOWED) { - throw new FileTooBigException("File size cannot be greater than 25 Mb"); - } + private void validateFileSize(MultipartFile file) { + if (file.getSize() >= MAXIMUM_FILE_SIZE_ALLOWED) { + throw new FileTooBigException("File size cannot be greater than 25 Mb"); } + } } diff --git a/openbas-api/src/main/java/io/openbas/rest/mapper/export/MapperExportMixins.java b/openbas-api/src/main/java/io/openbas/rest/mapper/export/MapperExportMixins.java index 605824d33f..213d1753e3 100644 --- a/openbas-api/src/main/java/io/openbas/rest/mapper/export/MapperExportMixins.java +++ b/openbas-api/src/main/java/io/openbas/rest/mapper/export/MapperExportMixins.java @@ -4,33 +4,30 @@ public class MapperExportMixins { - private MapperExportMixins() { - - } - - @JsonIncludeProperties(value = { - "import_mapper_name", - "import_mapper_inject_type_column", - "import_mapper_inject_importers", - }) - public static class ImportMapper { - } - - @JsonIncludeProperties(value = { - "inject_importer_type_value", - "inject_importer_injector_contract", - "inject_importer_rule_attributes", - }) - public static class InjectImporter { - } - - @JsonIncludeProperties(value = { - "rule_attribute_columns", - "rule_attribute_name", - "rule_attribute_default_value", - "rule_attribute_additional_config", - }) - public static class RuleAttribute { - } - + private MapperExportMixins() {} + + @JsonIncludeProperties( + value = { + "import_mapper_name", + "import_mapper_inject_type_column", + "import_mapper_inject_importers", + }) + public static class ImportMapper {} + + @JsonIncludeProperties( + value = { + "inject_importer_type_value", + "inject_importer_injector_contract", + "inject_importer_rule_attributes", + }) + public static class InjectImporter {} + + @JsonIncludeProperties( + value = { + "rule_attribute_columns", + "rule_attribute_name", + "rule_attribute_default_value", + "rule_attribute_additional_config", + }) + public static class RuleAttribute {} } diff --git a/openbas-api/src/main/java/io/openbas/rest/mapper/form/ExportMapperInput.java b/openbas-api/src/main/java/io/openbas/rest/mapper/form/ExportMapperInput.java index 91ccc25d44..2d7b0a634b 100644 --- a/openbas-api/src/main/java/io/openbas/rest/mapper/form/ExportMapperInput.java +++ b/openbas-api/src/main/java/io/openbas/rest/mapper/form/ExportMapperInput.java @@ -1,21 +1,19 @@ package io.openbas.rest.mapper.form; +import static io.openbas.config.AppConfig.MANDATORY_MESSAGE; + import com.fasterxml.jackson.annotation.JsonProperty; import jakarta.validation.constraints.NotNull; -import lombok.Data; - import java.util.List; - -import static io.openbas.config.AppConfig.MANDATORY_MESSAGE; +import lombok.Data; @Data public class ExportMapperInput { - @JsonProperty("export_mapper_name") - private String name; - - @NotNull(message = MANDATORY_MESSAGE) - @JsonProperty("ids_to_export") - private List idsToExport; + @JsonProperty("export_mapper_name") + private String name; + @NotNull(message = MANDATORY_MESSAGE) + @JsonProperty("ids_to_export") + private List idsToExport; } diff --git a/openbas-api/src/main/java/io/openbas/rest/mapper/form/ImportMapperAddInput.java b/openbas-api/src/main/java/io/openbas/rest/mapper/form/ImportMapperAddInput.java index 4bff96888e..b194197eec 100644 --- a/openbas-api/src/main/java/io/openbas/rest/mapper/form/ImportMapperAddInput.java +++ b/openbas-api/src/main/java/io/openbas/rest/mapper/form/ImportMapperAddInput.java @@ -1,30 +1,28 @@ package io.openbas.rest.mapper.form; +import static io.openbas.config.AppConfig.MANDATORY_MESSAGE; + import com.fasterxml.jackson.annotation.JsonProperty; import jakarta.validation.constraints.NotBlank; import jakarta.validation.constraints.NotNull; import jakarta.validation.constraints.Pattern; -import lombok.Data; - import java.util.ArrayList; import java.util.List; - -import static io.openbas.config.AppConfig.MANDATORY_MESSAGE; +import lombok.Data; @Data public class ImportMapperAddInput { - @NotBlank(message = MANDATORY_MESSAGE) - @JsonProperty("import_mapper_name") - private String name; - - @Pattern(regexp="^[A-Z]{1,2}$") - @JsonProperty("import_mapper_inject_type_column") - @NotBlank - private String injectTypeColumn; + @NotBlank(message = MANDATORY_MESSAGE) + @JsonProperty("import_mapper_name") + private String name; - @JsonProperty("import_mapper_inject_importers") - @NotNull - private List importers = new ArrayList<>(); + @Pattern(regexp = "^[A-Z]{1,2}$") + @JsonProperty("import_mapper_inject_type_column") + @NotBlank + private String injectTypeColumn; + @JsonProperty("import_mapper_inject_importers") + @NotNull + private List importers = new ArrayList<>(); } diff --git a/openbas-api/src/main/java/io/openbas/rest/mapper/form/ImportMapperUpdateInput.java b/openbas-api/src/main/java/io/openbas/rest/mapper/form/ImportMapperUpdateInput.java index 5d7461a0b9..8c6c9bdea6 100644 --- a/openbas-api/src/main/java/io/openbas/rest/mapper/form/ImportMapperUpdateInput.java +++ b/openbas-api/src/main/java/io/openbas/rest/mapper/form/ImportMapperUpdateInput.java @@ -1,29 +1,28 @@ package io.openbas.rest.mapper.form; +import static io.openbas.config.AppConfig.MANDATORY_MESSAGE; + import com.fasterxml.jackson.annotation.JsonProperty; import jakarta.validation.constraints.NotBlank; import jakarta.validation.constraints.NotNull; import jakarta.validation.constraints.Pattern; -import lombok.Data; - import java.util.ArrayList; import java.util.List; - -import static io.openbas.config.AppConfig.MANDATORY_MESSAGE; +import lombok.Data; @Data public class ImportMapperUpdateInput { - @NotBlank(message = MANDATORY_MESSAGE) - @JsonProperty("import_mapper_name") - private String name; + @NotBlank(message = MANDATORY_MESSAGE) + @JsonProperty("import_mapper_name") + private String name; - @Pattern(regexp="^[A-Z]{1,2}$") - @JsonProperty("import_mapper_inject_type_column") - @NotBlank - private String injectTypeColumn; + @Pattern(regexp = "^[A-Z]{1,2}$") + @JsonProperty("import_mapper_inject_type_column") + @NotBlank + private String injectTypeColumn; - @JsonProperty("import_mapper_inject_importers") - @NotNull - private List importers = new ArrayList<>(); + @JsonProperty("import_mapper_inject_importers") + @NotNull + private List importers = new ArrayList<>(); } diff --git a/openbas-api/src/main/java/io/openbas/rest/mapper/form/InjectImporterAddInput.java b/openbas-api/src/main/java/io/openbas/rest/mapper/form/InjectImporterAddInput.java index 496acfba33..545e87e8c8 100644 --- a/openbas-api/src/main/java/io/openbas/rest/mapper/form/InjectImporterAddInput.java +++ b/openbas-api/src/main/java/io/openbas/rest/mapper/form/InjectImporterAddInput.java @@ -1,25 +1,24 @@ package io.openbas.rest.mapper.form; +import static io.openbas.config.AppConfig.MANDATORY_MESSAGE; + import com.fasterxml.jackson.annotation.JsonProperty; import jakarta.validation.constraints.NotBlank; -import lombok.Data; - import java.util.ArrayList; import java.util.List; - -import static io.openbas.config.AppConfig.MANDATORY_MESSAGE; +import lombok.Data; @Data public class InjectImporterAddInput { - @NotBlank(message = MANDATORY_MESSAGE) - @JsonProperty("inject_importer_type_value") - private String injectTypeValue; + @NotBlank(message = MANDATORY_MESSAGE) + @JsonProperty("inject_importer_type_value") + private String injectTypeValue; - @NotBlank(message = MANDATORY_MESSAGE) - @JsonProperty("inject_importer_injector_contract") - private String injectorContractId; + @NotBlank(message = MANDATORY_MESSAGE) + @JsonProperty("inject_importer_injector_contract") + private String injectorContractId; - @JsonProperty("inject_importer_rule_attributes") - private List ruleAttributes = new ArrayList<>(); + @JsonProperty("inject_importer_rule_attributes") + private List ruleAttributes = new ArrayList<>(); } diff --git a/openbas-api/src/main/java/io/openbas/rest/mapper/form/InjectImporterUpdateInput.java b/openbas-api/src/main/java/io/openbas/rest/mapper/form/InjectImporterUpdateInput.java index 1c7301e078..9ca10e7032 100644 --- a/openbas-api/src/main/java/io/openbas/rest/mapper/form/InjectImporterUpdateInput.java +++ b/openbas-api/src/main/java/io/openbas/rest/mapper/form/InjectImporterUpdateInput.java @@ -1,28 +1,27 @@ package io.openbas.rest.mapper.form; +import static io.openbas.config.AppConfig.MANDATORY_MESSAGE; + import com.fasterxml.jackson.annotation.JsonProperty; import jakarta.validation.constraints.NotBlank; -import lombok.Data; - import java.util.ArrayList; import java.util.List; - -import static io.openbas.config.AppConfig.MANDATORY_MESSAGE; +import lombok.Data; @Data public class InjectImporterUpdateInput { - @JsonProperty("inject_importer_id") - private String id; + @JsonProperty("inject_importer_id") + private String id; - @NotBlank(message = MANDATORY_MESSAGE) - @JsonProperty("inject_importer_type_value") - private String injectTypeValue; + @NotBlank(message = MANDATORY_MESSAGE) + @JsonProperty("inject_importer_type_value") + private String injectTypeValue; - @NotBlank(message = MANDATORY_MESSAGE) - @JsonProperty("inject_importer_injector_contract") - private String injectorContractId; + @NotBlank(message = MANDATORY_MESSAGE) + @JsonProperty("inject_importer_injector_contract") + private String injectorContractId; - @JsonProperty("inject_importer_rule_attributes") - private List ruleAttributes = new ArrayList<>(); + @JsonProperty("inject_importer_rule_attributes") + private List ruleAttributes = new ArrayList<>(); } diff --git a/openbas-api/src/main/java/io/openbas/rest/mapper/form/RuleAttributeAddInput.java b/openbas-api/src/main/java/io/openbas/rest/mapper/form/RuleAttributeAddInput.java index 531ac10a21..2eebbe4fcf 100644 --- a/openbas-api/src/main/java/io/openbas/rest/mapper/form/RuleAttributeAddInput.java +++ b/openbas-api/src/main/java/io/openbas/rest/mapper/form/RuleAttributeAddInput.java @@ -1,30 +1,28 @@ package io.openbas.rest.mapper.form; +import static io.openbas.config.AppConfig.MANDATORY_MESSAGE; + import com.fasterxml.jackson.annotation.JsonProperty; import io.swagger.v3.oas.annotations.media.Schema; import jakarta.validation.constraints.NotBlank; -import lombok.Data; - import java.util.HashMap; import java.util.Map; - -import static io.openbas.config.AppConfig.MANDATORY_MESSAGE; +import lombok.Data; @Data public class RuleAttributeAddInput { - @NotBlank(message = MANDATORY_MESSAGE) - @JsonProperty("rule_attribute_name") - private String name; - - @JsonProperty("rule_attribute_columns") - @Schema(nullable = true) - private String columns; + @NotBlank(message = MANDATORY_MESSAGE) + @JsonProperty("rule_attribute_name") + private String name; - @JsonProperty("rule_attribute_default_value") - private String defaultValue; + @JsonProperty("rule_attribute_columns") + @Schema(nullable = true) + private String columns; - @JsonProperty("rule_attribute_additional_config") - private Map additionalConfig = new HashMap<>(); + @JsonProperty("rule_attribute_default_value") + private String defaultValue; + @JsonProperty("rule_attribute_additional_config") + private Map additionalConfig = new HashMap<>(); } diff --git a/openbas-api/src/main/java/io/openbas/rest/mapper/form/RuleAttributeUpdateInput.java b/openbas-api/src/main/java/io/openbas/rest/mapper/form/RuleAttributeUpdateInput.java index 7d7f94a3bc..4380422847 100644 --- a/openbas-api/src/main/java/io/openbas/rest/mapper/form/RuleAttributeUpdateInput.java +++ b/openbas-api/src/main/java/io/openbas/rest/mapper/form/RuleAttributeUpdateInput.java @@ -1,33 +1,31 @@ package io.openbas.rest.mapper.form; +import static io.openbas.config.AppConfig.MANDATORY_MESSAGE; + import com.fasterxml.jackson.annotation.JsonProperty; import io.swagger.v3.oas.annotations.media.Schema; import jakarta.validation.constraints.NotBlank; -import lombok.Data; - import java.util.HashMap; import java.util.Map; - -import static io.openbas.config.AppConfig.MANDATORY_MESSAGE; +import lombok.Data; @Data public class RuleAttributeUpdateInput { - @JsonProperty("rule_attribute_id") - private String id; - - @NotBlank(message = MANDATORY_MESSAGE) - @JsonProperty("rule_attribute_name") - private String name; + @JsonProperty("rule_attribute_id") + private String id; - @JsonProperty("rule_attribute_columns") - @Schema(nullable = true) - private String columns; + @NotBlank(message = MANDATORY_MESSAGE) + @JsonProperty("rule_attribute_name") + private String name; - @JsonProperty("rule_attribute_default_value") - private String defaultValue; + @JsonProperty("rule_attribute_columns") + @Schema(nullable = true) + private String columns; - @JsonProperty("rule_attribute_additional_config") - private Map additionalConfig = new HashMap<>(); + @JsonProperty("rule_attribute_default_value") + private String defaultValue; + @JsonProperty("rule_attribute_additional_config") + private Map additionalConfig = new HashMap<>(); } diff --git a/openbas-api/src/main/java/io/openbas/rest/mitigation/MitigationApi.java b/openbas-api/src/main/java/io/openbas/rest/mitigation/MitigationApi.java index 69964b12a7..ae1f7f886b 100644 --- a/openbas-api/src/main/java/io/openbas/rest/mitigation/MitigationApi.java +++ b/openbas-api/src/main/java/io/openbas/rest/mitigation/MitigationApi.java @@ -1,5 +1,10 @@ package io.openbas.rest.mitigation; +import static io.openbas.database.model.User.ROLE_ADMIN; +import static io.openbas.database.model.User.ROLE_USER; +import static io.openbas.helper.StreamHelper.fromIterable; +import static io.openbas.utils.pagination.PaginationUtils.buildPaginationJPA; + import io.openbas.database.model.AttackPattern; import io.openbas.database.model.Mitigation; import io.openbas.database.repository.AttackPatternRepository; @@ -14,6 +19,10 @@ import jakarta.transaction.Transactional; import jakarta.validation.Valid; import jakarta.validation.constraints.NotBlank; +import java.time.Instant; +import java.util.ArrayList; +import java.util.List; +import java.util.Optional; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.data.domain.Page; import org.springframework.data.domain.Pageable; @@ -21,16 +30,6 @@ import org.springframework.security.access.annotation.Secured; import org.springframework.web.bind.annotation.*; -import java.time.Instant; -import java.util.ArrayList; -import java.util.List; -import java.util.Optional; - -import static io.openbas.database.model.User.ROLE_ADMIN; -import static io.openbas.database.model.User.ROLE_USER; -import static io.openbas.helper.StreamHelper.fromIterable; -import static io.openbas.utils.pagination.PaginationUtils.buildPaginationJPA; - @RestController @Secured(ROLE_USER) public class MitigationApi extends RestBehavior { @@ -55,13 +54,13 @@ public Iterable mitigations() { } @PostMapping("/api/mitigations/search") - public Page mitigations(@RequestBody @Valid final SearchPaginationInput searchPaginationInput) { + public Page mitigations( + @RequestBody @Valid final SearchPaginationInput searchPaginationInput) { return buildPaginationJPA( - (Specification specification, Pageable pageable) -> this.mitigationRepository.findAll( - specification, pageable), + (Specification specification, Pageable pageable) -> + this.mitigationRepository.findAll(specification, pageable), searchPaginationInput, - Mitigation.class - ); + Mitigation.class); } @GetMapping("/api/mitigations/{mitigationId}") @@ -75,14 +74,16 @@ public Mitigation mitigation(@PathVariable String mitigationId) { public Mitigation createMitigation(@Valid @RequestBody MitigationCreateInput input) { Mitigation mitigation = new Mitigation(); mitigation.setUpdateAttributes(input); - mitigation.setAttackPatterns(fromIterable(attackPatternRepository.findAllById(input.getAttackPatternsIds()))); + mitigation.setAttackPatterns( + fromIterable(attackPatternRepository.findAllById(input.getAttackPatternsIds()))); return mitigationRepository.save(mitigation); } @GetMapping("/api/mitigations/{mitigationId}/attack_patterns") public Iterable injectorContracts(@PathVariable String mitigationId) { mitigationRepository.findById(mitigationId).orElseThrow(ElementNotFoundException::new); - return attackPatternRepository.findAll(AttackPatternSpecification.fromAttackPattern(mitigationId)); + return attackPatternRepository.findAll( + AttackPatternSpecification.fromAttackPattern(mitigationId)); } @Secured(ROLE_ADMIN) @@ -90,22 +91,27 @@ public Iterable injectorContracts(@PathVariable String mitigation public Mitigation updateMitigation( @NotBlank @PathVariable final String mitigationId, @Valid @RequestBody MitigationUpdateInput input) { - Mitigation mitigation = this.mitigationRepository.findById(mitigationId).orElseThrow(ElementNotFoundException::new); + Mitigation mitigation = + this.mitigationRepository.findById(mitigationId).orElseThrow(ElementNotFoundException::new); mitigation.setUpdateAttributes(input); - mitigation.setAttackPatterns(fromIterable(this.attackPatternRepository.findAllById(input.getAttackPatternsIds()))); + mitigation.setAttackPatterns( + fromIterable(this.attackPatternRepository.findAllById(input.getAttackPatternsIds()))); mitigation.setUpdatedAt(Instant.now()); return mitigationRepository.save(mitigation); } private List upsertMitigations(List mitigations) { List upserted = new ArrayList<>(); - mitigations.forEach(mitigationInput -> { + mitigations.forEach( + mitigationInput -> { String mitigationExternalId = mitigationInput.getExternalId(); - Optional optionalMitigation = mitigationRepository.findByExternalId( - mitigationExternalId); - List attackPatterns = !mitigationInput.getAttackPatternsIds().isEmpty() ? - fromIterable(attackPatternRepository.findAllById(mitigationInput.getAttackPatternsIds())) - : List.of(); + Optional optionalMitigation = + mitigationRepository.findByExternalId(mitigationExternalId); + List attackPatterns = + !mitigationInput.getAttackPatternsIds().isEmpty() + ? fromIterable( + attackPatternRepository.findAllById(mitigationInput.getAttackPatternsIds())) + : List.of(); if (optionalMitigation.isEmpty()) { Mitigation newMitigation = new Mitigation(); newMitigation.setStixId(mitigationInput.getStixId()); @@ -133,9 +139,10 @@ private List upsertMitigations(List mitigatio @Secured(ROLE_ADMIN) @PostMapping("/api/mitigations/upsert") @Transactional(rollbackOn = Exception.class) - public Iterable upsertKillChainPhases(@Valid @RequestBody MitigationUpsertInput input) { - List mitigations = input.getMitigations(); - return new ArrayList<>(upsertMitigations(mitigations)); + public Iterable upsertKillChainPhases( + @Valid @RequestBody MitigationUpsertInput input) { + List mitigations = input.getMitigations(); + return new ArrayList<>(upsertMitigations(mitigations)); } @Secured(ROLE_ADMIN) diff --git a/openbas-api/src/main/java/io/openbas/rest/mitigation/form/MitigationCreateInput.java b/openbas-api/src/main/java/io/openbas/rest/mitigation/form/MitigationCreateInput.java index 05cdfbaec7..cac35ef174 100644 --- a/openbas-api/src/main/java/io/openbas/rest/mitigation/form/MitigationCreateInput.java +++ b/openbas-api/src/main/java/io/openbas/rest/mitigation/form/MitigationCreateInput.java @@ -1,42 +1,41 @@ package io.openbas.rest.mitigation.form; +import static io.openbas.config.AppConfig.MANDATORY_MESSAGE; + import com.fasterxml.jackson.annotation.JsonProperty; import jakarta.validation.constraints.NotBlank; -import lombok.Getter; -import lombok.Setter; - import java.util.ArrayList; import java.util.List; import java.util.UUID; - -import static io.openbas.config.AppConfig.MANDATORY_MESSAGE; +import lombok.Getter; +import lombok.Setter; @Getter @Setter public class MitigationCreateInput { - @JsonProperty("mitigation_stix_id") - private String stixId = "course-of-action--" + UUID.randomUUID();; + @JsonProperty("mitigation_stix_id") + private String stixId = "course-of-action--" + UUID.randomUUID(); - @NotBlank(message = MANDATORY_MESSAGE) - @JsonProperty("mitigation_name") - private String name; + ; - @JsonProperty("mitigation_description") - private String description; + @NotBlank(message = MANDATORY_MESSAGE) + @JsonProperty("mitigation_name") + private String name; - @NotBlank(message = MANDATORY_MESSAGE) - @JsonProperty("mitigation_external_id") - private String externalId; + @JsonProperty("mitigation_description") + private String description; - @JsonProperty("mitigation_log_sources") - private String[] logSources = new String[0]; + @NotBlank(message = MANDATORY_MESSAGE) + @JsonProperty("mitigation_external_id") + private String externalId; - @JsonProperty("mitigation_threat_hunting_techniques") - private String threatHuntingTechniques; - - @JsonProperty("mitigation_attack_patterns") - private List attackPatternsIds = new ArrayList<>(); -} + @JsonProperty("mitigation_log_sources") + private String[] logSources = new String[0]; + @JsonProperty("mitigation_threat_hunting_techniques") + private String threatHuntingTechniques; + @JsonProperty("mitigation_attack_patterns") + private List attackPatternsIds = new ArrayList<>(); +} diff --git a/openbas-api/src/main/java/io/openbas/rest/mitigation/form/MitigationUpdateInput.java b/openbas-api/src/main/java/io/openbas/rest/mitigation/form/MitigationUpdateInput.java index 50d2efce9a..6291f5ced9 100644 --- a/openbas-api/src/main/java/io/openbas/rest/mitigation/form/MitigationUpdateInput.java +++ b/openbas-api/src/main/java/io/openbas/rest/mitigation/form/MitigationUpdateInput.java @@ -1,33 +1,29 @@ package io.openbas.rest.mitigation.form; +import static io.openbas.config.AppConfig.MANDATORY_MESSAGE; + import com.fasterxml.jackson.annotation.JsonProperty; import jakarta.validation.constraints.NotBlank; -import lombok.Getter; -import lombok.Setter; - import java.util.ArrayList; import java.util.List; - -import static io.openbas.config.AppConfig.MANDATORY_MESSAGE; +import lombok.Getter; +import lombok.Setter; @Getter @Setter public class MitigationUpdateInput { - @NotBlank(message = MANDATORY_MESSAGE) - @JsonProperty("mitigation_name") - private String name; + @NotBlank(message = MANDATORY_MESSAGE) + @JsonProperty("mitigation_name") + private String name; - @JsonProperty("mitigation_description") - private String description; + @JsonProperty("mitigation_description") + private String description; - @NotBlank(message = MANDATORY_MESSAGE) - @JsonProperty("mitigation_external_id") - private String externalId; - - @JsonProperty("mitigation_attack_patterns") - private List attackPatternsIds = new ArrayList<>(); + @NotBlank(message = MANDATORY_MESSAGE) + @JsonProperty("mitigation_external_id") + private String externalId; + @JsonProperty("mitigation_attack_patterns") + private List attackPatternsIds = new ArrayList<>(); } - - diff --git a/openbas-api/src/main/java/io/openbas/rest/mitigation/form/MitigationUpsertInput.java b/openbas-api/src/main/java/io/openbas/rest/mitigation/form/MitigationUpsertInput.java index 0c4a078c87..ec877c4edb 100644 --- a/openbas-api/src/main/java/io/openbas/rest/mitigation/form/MitigationUpsertInput.java +++ b/openbas-api/src/main/java/io/openbas/rest/mitigation/form/MitigationUpsertInput.java @@ -1,15 +1,13 @@ package io.openbas.rest.mitigation.form; import com.fasterxml.jackson.annotation.JsonProperty; -import lombok.Data; - import java.util.ArrayList; import java.util.List; +import lombok.Data; @Data public class MitigationUpsertInput { @JsonProperty("mitigations") private List mitigations = new ArrayList<>(); - } diff --git a/openbas-api/src/main/java/io/openbas/rest/objective/ExerciseObjectiveApi.java b/openbas-api/src/main/java/io/openbas/rest/objective/ExerciseObjectiveApi.java index 00ee13a650..547eaf77df 100644 --- a/openbas-api/src/main/java/io/openbas/rest/objective/ExerciseObjectiveApi.java +++ b/openbas-api/src/main/java/io/openbas/rest/objective/ExerciseObjectiveApi.java @@ -1,5 +1,9 @@ package io.openbas.rest.objective; +import static io.openbas.config.SessionHelper.currentUser; +import static io.openbas.helper.DatabaseHelper.resolveRelation; +import static java.time.Instant.now; + import io.openbas.database.model.Evaluation; import io.openbas.database.model.Exercise; import io.openbas.database.model.Objective; @@ -19,112 +23,121 @@ import org.springframework.security.access.prepost.PreAuthorize; import org.springframework.web.bind.annotation.*; -import static io.openbas.config.SessionHelper.currentUser; -import static io.openbas.helper.DatabaseHelper.resolveRelation; -import static java.time.Instant.now; - @RestController @RequiredArgsConstructor public class ExerciseObjectiveApi extends RestBehavior { - public static final String EXERCISE_URI = "/api/exercises/"; + public static final String EXERCISE_URI = "/api/exercises/"; + + private final ExerciseRepository exerciseRepository; + private final ObjectiveRepository objectiveRepository; + private final EvaluationRepository evaluationRepository; + private final UserRepository userRepository; - private final ExerciseRepository exerciseRepository; - private final ObjectiveRepository objectiveRepository; - private final EvaluationRepository evaluationRepository; - private final UserRepository userRepository; + // region objectives + @GetMapping(EXERCISE_URI + "{exerciseId}/objectives") + @PreAuthorize("isExerciseObserver(#exerciseId)") + public Iterable getMainObjectives(@PathVariable String exerciseId) { + return objectiveRepository.findAll(ObjectiveSpecification.fromExercise(exerciseId)); + } - // region objectives - @GetMapping(EXERCISE_URI + "{exerciseId}/objectives") - @PreAuthorize("isExerciseObserver(#exerciseId)") - public Iterable getMainObjectives(@PathVariable String exerciseId) { - return objectiveRepository.findAll(ObjectiveSpecification.fromExercise(exerciseId)); - } + @PostMapping(EXERCISE_URI + "{exerciseId}/objectives") + @PreAuthorize("isExercisePlanner(#exerciseId)") + @Transactional(rollbackOn = Exception.class) + public Objective createObjective( + @PathVariable String exerciseId, @Valid @RequestBody ObjectiveInput input) { + Exercise exercise = + exerciseRepository.findById(exerciseId).orElseThrow(ElementNotFoundException::new); + Objective objective = new Objective(); + objective.setUpdateAttributes(input); + objective.setExercise(exercise); + return objectiveRepository.save(objective); + } - @PostMapping(EXERCISE_URI + "{exerciseId}/objectives") - @PreAuthorize("isExercisePlanner(#exerciseId)") - @Transactional(rollbackOn = Exception.class) - public Objective createObjective(@PathVariable String exerciseId, - @Valid @RequestBody ObjectiveInput input) { - Exercise exercise = exerciseRepository.findById(exerciseId).orElseThrow(ElementNotFoundException::new); - Objective objective = new Objective(); - objective.setUpdateAttributes(input); - objective.setExercise(exercise); - return objectiveRepository.save(objective); - } + @PutMapping(EXERCISE_URI + "{exerciseId}/objectives/{objectiveId}") + @PreAuthorize("isExercisePlanner(#exerciseId)") + public Objective updateObjective( + @PathVariable String exerciseId, + @PathVariable String objectiveId, + @Valid @RequestBody ObjectiveInput input) { + Objective objective = + objectiveRepository.findById(objectiveId).orElseThrow(ElementNotFoundException::new); + objective.setUpdateAttributes(input); + return objectiveRepository.save(objective); + } - @PutMapping(EXERCISE_URI + "{exerciseId}/objectives/{objectiveId}") - @PreAuthorize("isExercisePlanner(#exerciseId)") - public Objective updateObjective(@PathVariable String exerciseId, - @PathVariable String objectiveId, - @Valid @RequestBody ObjectiveInput input) { - Objective objective = objectiveRepository.findById(objectiveId).orElseThrow(ElementNotFoundException::new); - objective.setUpdateAttributes(input); - return objectiveRepository.save(objective); - } + @DeleteMapping(EXERCISE_URI + "{exerciseId}/objectives/{objectiveId}") + @PreAuthorize("isExercisePlanner(#exerciseId)") + public void deleteObjective(@PathVariable String exerciseId, @PathVariable String objectiveId) { + objectiveRepository.deleteById(objectiveId); + } - @DeleteMapping(EXERCISE_URI + "{exerciseId}/objectives/{objectiveId}") - @PreAuthorize("isExercisePlanner(#exerciseId)") - public void deleteObjective(@PathVariable String exerciseId, @PathVariable String objectiveId) { - objectiveRepository.deleteById(objectiveId); - } - // endregion + // endregion - // region evaluations - @GetMapping(EXERCISE_URI + "{exerciseId}/objectives/{objectiveId}/evaluations/{evaluationId}") - @PreAuthorize("isExerciseObserver(#exerciseId)") - public Evaluation getEvaluation(@PathVariable String exerciseId, @PathVariable String evaluationId) { - return evaluationRepository.findById(evaluationId).orElseThrow(ElementNotFoundException::new); - } + // region evaluations + @GetMapping(EXERCISE_URI + "{exerciseId}/objectives/{objectiveId}/evaluations/{evaluationId}") + @PreAuthorize("isExerciseObserver(#exerciseId)") + public Evaluation getEvaluation( + @PathVariable String exerciseId, @PathVariable String evaluationId) { + return evaluationRepository.findById(evaluationId).orElseThrow(ElementNotFoundException::new); + } - @GetMapping(EXERCISE_URI + "{exerciseId}/objectives/{objectiveId}/evaluations") - @PreAuthorize("isExerciseObserver(#exerciseId)") - public Iterable getEvaluations(@PathVariable String exerciseId, @PathVariable String objectiveId) { - return evaluationRepository.findAll(EvaluationSpecification.fromObjective(objectiveId)); - } + @GetMapping(EXERCISE_URI + "{exerciseId}/objectives/{objectiveId}/evaluations") + @PreAuthorize("isExerciseObserver(#exerciseId)") + public Iterable getEvaluations( + @PathVariable String exerciseId, @PathVariable String objectiveId) { + return evaluationRepository.findAll(EvaluationSpecification.fromObjective(objectiveId)); + } - @PostMapping(EXERCISE_URI + "{exerciseId}/objectives/{objectiveId}/evaluations") - @PreAuthorize("isExercisePlanner(#exerciseId)") - @Transactional(rollbackOn = Exception.class) - public Evaluation createEvaluation(@PathVariable String exerciseId, - @PathVariable String objectiveId, - @Valid @RequestBody EvaluationInput input) { - Evaluation evaluation = new Evaluation(); - evaluation.setUpdateAttributes(input); - Objective objective = resolveRelation(objectiveId, objectiveRepository); - evaluation.setObjective(objective); - evaluation.setUser(userRepository.findById(currentUser().getId()).orElseThrow(ElementNotFoundException::new)); - Evaluation result = evaluationRepository.save(evaluation); - objective.setUpdatedAt(now()); - objectiveRepository.save(objective); - Exercise exercise = exerciseRepository.findById(exerciseId).orElseThrow(ElementNotFoundException::new); - exercise.setUpdatedAt(now()); - exerciseRepository.save(exercise); - return result; - } + @PostMapping(EXERCISE_URI + "{exerciseId}/objectives/{objectiveId}/evaluations") + @PreAuthorize("isExercisePlanner(#exerciseId)") + @Transactional(rollbackOn = Exception.class) + public Evaluation createEvaluation( + @PathVariable String exerciseId, + @PathVariable String objectiveId, + @Valid @RequestBody EvaluationInput input) { + Evaluation evaluation = new Evaluation(); + evaluation.setUpdateAttributes(input); + Objective objective = resolveRelation(objectiveId, objectiveRepository); + evaluation.setObjective(objective); + evaluation.setUser( + userRepository.findById(currentUser().getId()).orElseThrow(ElementNotFoundException::new)); + Evaluation result = evaluationRepository.save(evaluation); + objective.setUpdatedAt(now()); + objectiveRepository.save(objective); + Exercise exercise = + exerciseRepository.findById(exerciseId).orElseThrow(ElementNotFoundException::new); + exercise.setUpdatedAt(now()); + exerciseRepository.save(exercise); + return result; + } - @PutMapping(EXERCISE_URI + "{exerciseId}/objectives/{objectiveId}/evaluations/{evaluationId}") - @PreAuthorize("isExercisePlanner(#exerciseId)") - public Evaluation updateEvaluation(@PathVariable String exerciseId, - @PathVariable String objectiveId, - @PathVariable String evaluationId, - @Valid @RequestBody EvaluationInput input) { - Evaluation evaluation = evaluationRepository.findById(evaluationId).orElseThrow(ElementNotFoundException::new); - evaluation.setUpdateAttributes(input); - Evaluation result = evaluationRepository.save(evaluation); - Objective objective = objectiveRepository.findById(objectiveId).orElseThrow(ElementNotFoundException::new); - objective.setUpdatedAt(now()); - objectiveRepository.save(objective); - Exercise exercise = exerciseRepository.findById(exerciseId).orElseThrow(ElementNotFoundException::new); - exercise.setUpdatedAt(now()); - exerciseRepository.save(exercise); - return result; - } + @PutMapping(EXERCISE_URI + "{exerciseId}/objectives/{objectiveId}/evaluations/{evaluationId}") + @PreAuthorize("isExercisePlanner(#exerciseId)") + public Evaluation updateEvaluation( + @PathVariable String exerciseId, + @PathVariable String objectiveId, + @PathVariable String evaluationId, + @Valid @RequestBody EvaluationInput input) { + Evaluation evaluation = + evaluationRepository.findById(evaluationId).orElseThrow(ElementNotFoundException::new); + evaluation.setUpdateAttributes(input); + Evaluation result = evaluationRepository.save(evaluation); + Objective objective = + objectiveRepository.findById(objectiveId).orElseThrow(ElementNotFoundException::new); + objective.setUpdatedAt(now()); + objectiveRepository.save(objective); + Exercise exercise = + exerciseRepository.findById(exerciseId).orElseThrow(ElementNotFoundException::new); + exercise.setUpdatedAt(now()); + exerciseRepository.save(exercise); + return result; + } - @DeleteMapping(EXERCISE_URI + "{exerciseId}/objectives/{objectiveId}/evaluations/{evaluationId}") - @PreAuthorize("isExercisePlanner(#exerciseId)") - public void deleteEvaluation(@PathVariable String exerciseId, @PathVariable String evaluationId) { - evaluationRepository.deleteById(evaluationId); - } - // endregion + @DeleteMapping(EXERCISE_URI + "{exerciseId}/objectives/{objectiveId}/evaluations/{evaluationId}") + @PreAuthorize("isExercisePlanner(#exerciseId)") + public void deleteEvaluation(@PathVariable String exerciseId, @PathVariable String evaluationId) { + evaluationRepository.deleteById(evaluationId); + } + // endregion } diff --git a/openbas-api/src/main/java/io/openbas/rest/objective/ScenarioObjectiveApi.java b/openbas-api/src/main/java/io/openbas/rest/objective/ScenarioObjectiveApi.java index 3467a41a5f..e142d997e5 100644 --- a/openbas-api/src/main/java/io/openbas/rest/objective/ScenarioObjectiveApi.java +++ b/openbas-api/src/main/java/io/openbas/rest/objective/ScenarioObjectiveApi.java @@ -1,5 +1,9 @@ package io.openbas.rest.objective; +import static io.openbas.config.SessionHelper.currentUser; +import static io.openbas.helper.DatabaseHelper.resolveRelation; +import static java.time.Instant.now; + import io.openbas.database.model.Evaluation; import io.openbas.database.model.Objective; import io.openbas.database.model.Scenario; @@ -19,112 +23,121 @@ import org.springframework.security.access.prepost.PreAuthorize; import org.springframework.web.bind.annotation.*; -import static io.openbas.config.SessionHelper.currentUser; -import static io.openbas.helper.DatabaseHelper.resolveRelation; -import static java.time.Instant.now; - @RestController @RequiredArgsConstructor public class ScenarioObjectiveApi extends RestBehavior { - public static final String SCENARIO_URI = "/api/scenarios/"; + public static final String SCENARIO_URI = "/api/scenarios/"; + + private final ScenarioRepository scenarioRepository; + private final ObjectiveRepository objectiveRepository; + private final EvaluationRepository evaluationRepository; + private final UserRepository userRepository; - private final ScenarioRepository scenarioRepository; - private final ObjectiveRepository objectiveRepository; - private final EvaluationRepository evaluationRepository; - private final UserRepository userRepository; + // region objectives + @GetMapping(SCENARIO_URI + "{scenarioId}/objectives") + @PreAuthorize("isScenarioObserver(#scenarioId)") + public Iterable getMainObjectives(@PathVariable String scenarioId) { + return objectiveRepository.findAll(ObjectiveSpecification.fromScenario(scenarioId)); + } - // region objectives - @GetMapping(SCENARIO_URI + "{scenarioId}/objectives") - @PreAuthorize("isScenarioObserver(#scenarioId)") - public Iterable getMainObjectives(@PathVariable String scenarioId) { - return objectiveRepository.findAll(ObjectiveSpecification.fromScenario(scenarioId)); - } + @PostMapping(SCENARIO_URI + "{scenarioId}/objectives") + @PreAuthorize("isScenarioPlanner(#scenarioId)") + @Transactional(rollbackOn = Exception.class) + public Objective createObjective( + @PathVariable String scenarioId, @Valid @RequestBody ObjectiveInput input) { + Scenario scenario = + scenarioRepository.findById(scenarioId).orElseThrow(ElementNotFoundException::new); + Objective objective = new Objective(); + objective.setUpdateAttributes(input); + objective.setScenario(scenario); + return objectiveRepository.save(objective); + } - @PostMapping(SCENARIO_URI + "{scenarioId}/objectives") - @PreAuthorize("isScenarioPlanner(#scenarioId)") - @Transactional(rollbackOn = Exception.class) - public Objective createObjective(@PathVariable String scenarioId, - @Valid @RequestBody ObjectiveInput input) { - Scenario scenario = scenarioRepository.findById(scenarioId).orElseThrow(ElementNotFoundException::new); - Objective objective = new Objective(); - objective.setUpdateAttributes(input); - objective.setScenario(scenario); - return objectiveRepository.save(objective); - } + @PutMapping(SCENARIO_URI + "{scenarioId}/objectives/{objectiveId}") + @PreAuthorize("isScenarioPlanner(#scenarioId)") + public Objective updateObjective( + @PathVariable String scenarioId, + @PathVariable String objectiveId, + @Valid @RequestBody ObjectiveInput input) { + Objective objective = + objectiveRepository.findById(objectiveId).orElseThrow(ElementNotFoundException::new); + objective.setUpdateAttributes(input); + return objectiveRepository.save(objective); + } - @PutMapping(SCENARIO_URI + "{scenarioId}/objectives/{objectiveId}") - @PreAuthorize("isScenarioPlanner(#scenarioId)") - public Objective updateObjective(@PathVariable String scenarioId, - @PathVariable String objectiveId, - @Valid @RequestBody ObjectiveInput input) { - Objective objective = objectiveRepository.findById(objectiveId).orElseThrow(ElementNotFoundException::new); - objective.setUpdateAttributes(input); - return objectiveRepository.save(objective); - } + @DeleteMapping(SCENARIO_URI + "{scenarioId}/objectives/{objectiveId}") + @PreAuthorize("isScenarioPlanner(#scenarioId)") + public void deleteObjective(@PathVariable String scenarioId, @PathVariable String objectiveId) { + objectiveRepository.deleteById(objectiveId); + } - @DeleteMapping(SCENARIO_URI + "{scenarioId}/objectives/{objectiveId}") - @PreAuthorize("isScenarioPlanner(#scenarioId)") - public void deleteObjective(@PathVariable String scenarioId, @PathVariable String objectiveId) { - objectiveRepository.deleteById(objectiveId); - } - // endregion + // endregion - // region evaluations - @GetMapping(SCENARIO_URI + "{scenarioId}/objectives/{objectiveId}/evaluations/{evaluationId}") - @PreAuthorize("isScenarioObserver(#scenarioId)") - public Evaluation getEvaluation(@PathVariable String scenarioId, @PathVariable String evaluationId) { - return evaluationRepository.findById(evaluationId).orElseThrow(ElementNotFoundException::new); - } + // region evaluations + @GetMapping(SCENARIO_URI + "{scenarioId}/objectives/{objectiveId}/evaluations/{evaluationId}") + @PreAuthorize("isScenarioObserver(#scenarioId)") + public Evaluation getEvaluation( + @PathVariable String scenarioId, @PathVariable String evaluationId) { + return evaluationRepository.findById(evaluationId).orElseThrow(ElementNotFoundException::new); + } - @GetMapping(SCENARIO_URI + "{scenarioId}/objectives/{objectiveId}/evaluations") - @PreAuthorize("isScenarioObserver(#scenarioId)") - public Iterable getEvaluations(@PathVariable String scenarioId, @PathVariable String objectiveId) { - return evaluationRepository.findAll(EvaluationSpecification.fromObjective(objectiveId)); - } + @GetMapping(SCENARIO_URI + "{scenarioId}/objectives/{objectiveId}/evaluations") + @PreAuthorize("isScenarioObserver(#scenarioId)") + public Iterable getEvaluations( + @PathVariable String scenarioId, @PathVariable String objectiveId) { + return evaluationRepository.findAll(EvaluationSpecification.fromObjective(objectiveId)); + } - @PostMapping(SCENARIO_URI + "{scenarioId}/objectives/{objectiveId}/evaluations") - @PreAuthorize("isScenarioPlanner(#scenarioId)") - @Transactional(rollbackOn = Exception.class) - public Evaluation createEvaluation(@PathVariable String scenarioId, - @PathVariable String objectiveId, - @Valid @RequestBody EvaluationInput input) { - Evaluation evaluation = new Evaluation(); - evaluation.setUpdateAttributes(input); - Objective objective = resolveRelation(objectiveId, objectiveRepository); - evaluation.setObjective(objective); - evaluation.setUser(userRepository.findById(currentUser().getId()).orElseThrow(ElementNotFoundException::new)); - Evaluation result = evaluationRepository.save(evaluation); - objective.setUpdatedAt(now()); - objectiveRepository.save(objective); - Scenario scenario = scenarioRepository.findById(scenarioId).orElseThrow(ElementNotFoundException::new); - scenario.setUpdatedAt(now()); - scenarioRepository.save(scenario); - return result; - } + @PostMapping(SCENARIO_URI + "{scenarioId}/objectives/{objectiveId}/evaluations") + @PreAuthorize("isScenarioPlanner(#scenarioId)") + @Transactional(rollbackOn = Exception.class) + public Evaluation createEvaluation( + @PathVariable String scenarioId, + @PathVariable String objectiveId, + @Valid @RequestBody EvaluationInput input) { + Evaluation evaluation = new Evaluation(); + evaluation.setUpdateAttributes(input); + Objective objective = resolveRelation(objectiveId, objectiveRepository); + evaluation.setObjective(objective); + evaluation.setUser( + userRepository.findById(currentUser().getId()).orElseThrow(ElementNotFoundException::new)); + Evaluation result = evaluationRepository.save(evaluation); + objective.setUpdatedAt(now()); + objectiveRepository.save(objective); + Scenario scenario = + scenarioRepository.findById(scenarioId).orElseThrow(ElementNotFoundException::new); + scenario.setUpdatedAt(now()); + scenarioRepository.save(scenario); + return result; + } - @PutMapping(SCENARIO_URI + "{scenarioId}/objectives/{objectiveId}/evaluations/{evaluationId}") - @PreAuthorize("isScenarioPlanner(#scenarioId)") - public Evaluation updateEvaluation(@PathVariable String scenarioId, - @PathVariable String objectiveId, - @PathVariable String evaluationId, - @Valid @RequestBody EvaluationInput input) { - Evaluation evaluation = evaluationRepository.findById(evaluationId).orElseThrow(ElementNotFoundException::new); - evaluation.setUpdateAttributes(input); - Evaluation result = evaluationRepository.save(evaluation); - Objective objective = objectiveRepository.findById(objectiveId).orElseThrow(ElementNotFoundException::new); - objective.setUpdatedAt(now()); - objectiveRepository.save(objective); - Scenario scenario = scenarioRepository.findById(scenarioId).orElseThrow(ElementNotFoundException::new); - scenario.setUpdatedAt(now()); - scenarioRepository.save(scenario); - return result; - } + @PutMapping(SCENARIO_URI + "{scenarioId}/objectives/{objectiveId}/evaluations/{evaluationId}") + @PreAuthorize("isScenarioPlanner(#scenarioId)") + public Evaluation updateEvaluation( + @PathVariable String scenarioId, + @PathVariable String objectiveId, + @PathVariable String evaluationId, + @Valid @RequestBody EvaluationInput input) { + Evaluation evaluation = + evaluationRepository.findById(evaluationId).orElseThrow(ElementNotFoundException::new); + evaluation.setUpdateAttributes(input); + Evaluation result = evaluationRepository.save(evaluation); + Objective objective = + objectiveRepository.findById(objectiveId).orElseThrow(ElementNotFoundException::new); + objective.setUpdatedAt(now()); + objectiveRepository.save(objective); + Scenario scenario = + scenarioRepository.findById(scenarioId).orElseThrow(ElementNotFoundException::new); + scenario.setUpdatedAt(now()); + scenarioRepository.save(scenario); + return result; + } - @DeleteMapping(SCENARIO_URI + "{scenarioId}/objectives/{objectiveId}/evaluations/{evaluationId}") - @PreAuthorize("isScenarioPlanner(#scenarioId)") - public void deleteEvaluation(@PathVariable String scenarioId, @PathVariable String evaluationId) { - evaluationRepository.deleteById(evaluationId); - } - // endregion + @DeleteMapping(SCENARIO_URI + "{scenarioId}/objectives/{objectiveId}/evaluations/{evaluationId}") + @PreAuthorize("isScenarioPlanner(#scenarioId)") + public void deleteEvaluation(@PathVariable String scenarioId, @PathVariable String evaluationId) { + evaluationRepository.deleteById(evaluationId); + } + // endregion } diff --git a/openbas-api/src/main/java/io/openbas/rest/objective/form/EvaluationInput.java b/openbas-api/src/main/java/io/openbas/rest/objective/form/EvaluationInput.java index a9367b8cef..391bbe8e83 100644 --- a/openbas-api/src/main/java/io/openbas/rest/objective/form/EvaluationInput.java +++ b/openbas-api/src/main/java/io/openbas/rest/objective/form/EvaluationInput.java @@ -4,14 +4,14 @@ public class EvaluationInput { - @JsonProperty("evaluation_score") - private Long score; + @JsonProperty("evaluation_score") + private Long score; - public Long getScore() { - return score; - } + public Long getScore() { + return score; + } - public void setScore(Long score) { - this.score = score; - } + public void setScore(Long score) { + this.score = score; + } } diff --git a/openbas-api/src/main/java/io/openbas/rest/objective/form/ObjectiveInput.java b/openbas-api/src/main/java/io/openbas/rest/objective/form/ObjectiveInput.java index 506076fc15..4821751e1b 100644 --- a/openbas-api/src/main/java/io/openbas/rest/objective/form/ObjectiveInput.java +++ b/openbas-api/src/main/java/io/openbas/rest/objective/form/ObjectiveInput.java @@ -4,36 +4,36 @@ public class ObjectiveInput { - @JsonProperty("objective_title") - private String title; + @JsonProperty("objective_title") + private String title; - @JsonProperty("objective_description") - private String description; + @JsonProperty("objective_description") + private String description; - @JsonProperty("objective_priority") - private Short priority; + @JsonProperty("objective_priority") + private Short priority; - public String getTitle() { - return title; - } + public String getTitle() { + return title; + } - public void setTitle(String title) { - this.title = title; - } + public void setTitle(String title) { + this.title = title; + } - public String getDescription() { - return description; - } + public String getDescription() { + return description; + } - public void setDescription(String description) { - this.description = description; - } + public void setDescription(String description) { + this.description = description; + } - public Short getPriority() { - return priority; - } + public Short getPriority() { + return priority; + } - public void setPriority(Short priority) { - this.priority = priority; - } + public void setPriority(Short priority) { + this.priority = priority; + } } diff --git a/openbas-api/src/main/java/io/openbas/rest/organization/OrganizationApi.java b/openbas-api/src/main/java/io/openbas/rest/organization/OrganizationApi.java index 5086fed3a2..1a24cbc52e 100644 --- a/openbas-api/src/main/java/io/openbas/rest/organization/OrganizationApi.java +++ b/openbas-api/src/main/java/io/openbas/rest/organization/OrganizationApi.java @@ -1,5 +1,12 @@ package io.openbas.rest.organization; +import static io.openbas.config.SessionHelper.currentUser; +import static io.openbas.database.model.User.ROLE_ADMIN; +import static io.openbas.database.specification.OrganizationSpecification.byName; +import static io.openbas.helper.StreamHelper.fromIterable; +import static io.openbas.helper.StreamHelper.iterableToSet; +import static java.time.Instant.now; + import io.openbas.config.OpenBASPrincipal; import io.openbas.database.model.Organization; import io.openbas.database.raw.RawOrganization; @@ -13,21 +20,13 @@ import io.openbas.utils.FilterUtilsJpa; import jakarta.transaction.Transactional; import jakarta.validation.Valid; +import java.util.List; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.data.domain.Sort; import org.springframework.security.access.annotation.Secured; import org.springframework.security.access.prepost.PreAuthorize; import org.springframework.web.bind.annotation.*; -import java.util.List; - -import static io.openbas.config.SessionHelper.currentUser; -import static io.openbas.database.model.User.ROLE_ADMIN; -import static io.openbas.database.specification.OrganizationSpecification.byName; -import static io.openbas.helper.StreamHelper.fromIterable; -import static io.openbas.helper.StreamHelper.iterableToSet; -import static java.time.Instant.now; - @RestController public class OrganizationApi extends RestBehavior { @@ -77,17 +76,17 @@ public Organization createOrganization(@Valid @RequestBody OrganizationCreateInp @Secured(ROLE_ADMIN) @PutMapping(ORGANIZATION_URI + "/{organizationId}") - public Organization updateOrganization(@PathVariable String organizationId, - @Valid @RequestBody OrganizationUpdateInput input) { + public Organization updateOrganization( + @PathVariable String organizationId, @Valid @RequestBody OrganizationUpdateInput input) { checkOrganizationAccess(userRepository, organizationId); - Organization organization = organizationRepository.findById(organizationId).orElseThrow(ElementNotFoundException::new); + Organization organization = + organizationRepository.findById(organizationId).orElseThrow(ElementNotFoundException::new); organization.setUpdateAttributes(input); organization.setUpdatedAt(now()); organization.setTags(iterableToSet(tagRepository.findAllById(input.getTagIds()))); return organizationRepository.save(organization); } - @Secured(ROLE_ADMIN) @DeleteMapping(ORGANIZATION_URI + "/{organizationId}") public void deleteOrganization(@PathVariable String organizationId) { @@ -98,8 +97,11 @@ public void deleteOrganization(@PathVariable String organizationId) { // -- OPTION -- @GetMapping(ORGANIZATION_URI + "/options") - public List optionsByName(@RequestParam(required = false) final String searchText) { - return fromIterable(this.organizationRepository.findAll(byName(searchText), Sort.by(Sort.Direction.ASC, "name"))) + public List optionsByName( + @RequestParam(required = false) final String searchText) { + return fromIterable( + this.organizationRepository.findAll( + byName(searchText), Sort.by(Sort.Direction.ASC, "name"))) .stream() .map(i -> new FilterUtilsJpa.Option(i.getId(), i.getName())) .toList(); @@ -107,8 +109,7 @@ public List optionsByName(@RequestParam(required = false) @PostMapping(ORGANIZATION_URI + "/options") public List optionsById(@RequestBody final List ids) { - return fromIterable(this.organizationRepository.findAllById(ids)) - .stream() + return fromIterable(this.organizationRepository.findAllById(ids)).stream() .map(i -> new FilterUtilsJpa.Option(i.getId(), i.getName())) .toList(); } diff --git a/openbas-api/src/main/java/io/openbas/rest/organization/form/OrganizationCreateInput.java b/openbas-api/src/main/java/io/openbas/rest/organization/form/OrganizationCreateInput.java index 9ed25c92b7..44916d8c7a 100644 --- a/openbas-api/src/main/java/io/openbas/rest/organization/form/OrganizationCreateInput.java +++ b/openbas-api/src/main/java/io/openbas/rest/organization/form/OrganizationCreateInput.java @@ -1,47 +1,45 @@ package io.openbas.rest.organization.form; -import com.fasterxml.jackson.annotation.JsonProperty; +import static io.openbas.config.AppConfig.MANDATORY_MESSAGE; +import com.fasterxml.jackson.annotation.JsonProperty; import jakarta.validation.constraints.NotBlank; - import java.util.ArrayList; import java.util.List; -import static io.openbas.config.AppConfig.MANDATORY_MESSAGE; - public class OrganizationCreateInput { - @NotBlank(message = MANDATORY_MESSAGE) - @JsonProperty("organization_name") - private String name; + @NotBlank(message = MANDATORY_MESSAGE) + @JsonProperty("organization_name") + private String name; - @JsonProperty("organization_description") - private String description; + @JsonProperty("organization_description") + private String description; - @JsonProperty("organization_tags") - private List tagIds = new ArrayList<>(); + @JsonProperty("organization_tags") + private List tagIds = new ArrayList<>(); - public String getName() { - return name; - } + public String getName() { + return name; + } - public void setName(String name) { - this.name = name; - } + public void setName(String name) { + this.name = name; + } - public String getDescription() { - return description; - } + public String getDescription() { + return description; + } - public void setDescription(String description) { - this.description = description; - } + public void setDescription(String description) { + this.description = description; + } - public List getTagIds() { - return tagIds; - } + public List getTagIds() { + return tagIds; + } - public void setTagIds(List tagIds) { - this.tagIds = tagIds; - } + public void setTagIds(List tagIds) { + this.tagIds = tagIds; + } } diff --git a/openbas-api/src/main/java/io/openbas/rest/organization/form/OrganizationUpdateInput.java b/openbas-api/src/main/java/io/openbas/rest/organization/form/OrganizationUpdateInput.java index 1b55b5899a..6b8fa523a0 100644 --- a/openbas-api/src/main/java/io/openbas/rest/organization/form/OrganizationUpdateInput.java +++ b/openbas-api/src/main/java/io/openbas/rest/organization/form/OrganizationUpdateInput.java @@ -1,46 +1,45 @@ package io.openbas.rest.organization.form; -import com.fasterxml.jackson.annotation.JsonProperty; +import static io.openbas.config.AppConfig.MANDATORY_MESSAGE; +import com.fasterxml.jackson.annotation.JsonProperty; import jakarta.validation.constraints.NotBlank; import java.util.ArrayList; import java.util.List; -import static io.openbas.config.AppConfig.MANDATORY_MESSAGE; - public class OrganizationUpdateInput { - @NotBlank(message = MANDATORY_MESSAGE) - @JsonProperty("organization_name") - private String name; + @NotBlank(message = MANDATORY_MESSAGE) + @JsonProperty("organization_name") + private String name; - @JsonProperty("organization_description") - private String description; + @JsonProperty("organization_description") + private String description; - @JsonProperty("organization_tags") - private List tagIds = new ArrayList<>(); + @JsonProperty("organization_tags") + private List tagIds = new ArrayList<>(); - public String getName() { - return name; - } + public String getName() { + return name; + } - public void setName(String name) { - this.name = name; - } + public void setName(String name) { + this.name = name; + } - public String getDescription() { - return description; - } + public String getDescription() { + return description; + } - public void setDescription(String description) { - this.description = description; - } + public void setDescription(String description) { + this.description = description; + } - public List getTagIds() { - return tagIds; - } + public List getTagIds() { + return tagIds; + } - public void setTagIds(List tagIds) { - this.tagIds = tagIds; - } + public void setTagIds(List tagIds) { + this.tagIds = tagIds; + } } diff --git a/openbas-api/src/main/java/io/openbas/rest/payload/PayloadApi.java b/openbas-api/src/main/java/io/openbas/rest/payload/PayloadApi.java index 81fefcd883..6c541f2413 100644 --- a/openbas-api/src/main/java/io/openbas/rest/payload/PayloadApi.java +++ b/openbas-api/src/main/java/io/openbas/rest/payload/PayloadApi.java @@ -1,5 +1,11 @@ package io.openbas.rest.payload; +import static io.openbas.database.model.User.ROLE_ADMIN; +import static io.openbas.database.model.User.ROLE_USER; +import static io.openbas.helper.StreamHelper.fromIterable; +import static io.openbas.helper.StreamHelper.iterableToSet; +import static io.openbas.utils.pagination.PaginationUtils.buildPaginationJPA; + import io.openbas.database.model.*; import io.openbas.database.repository.*; import io.openbas.integrations.PayloadService; @@ -13,6 +19,8 @@ import jakarta.transaction.Transactional; import jakarta.validation.Valid; import jakarta.validation.constraints.NotBlank; +import java.time.Instant; +import java.util.Optional; import org.hibernate.Hibernate; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.data.domain.Page; @@ -22,316 +30,354 @@ import org.springframework.security.access.prepost.PreAuthorize; import org.springframework.web.bind.annotation.*; -import java.time.Instant; -import java.util.Optional; - -import static io.openbas.database.model.User.ROLE_ADMIN; -import static io.openbas.database.model.User.ROLE_USER; -import static io.openbas.helper.StreamHelper.fromIterable; -import static io.openbas.helper.StreamHelper.iterableToSet; -import static io.openbas.utils.pagination.PaginationUtils.buildPaginationJPA; - @RestController @Secured(ROLE_USER) public class PayloadApi extends RestBehavior { - public static final String PAYLOAD_URI = "/api/payloads"; + public static final String PAYLOAD_URI = "/api/payloads"; - private PayloadRepository payloadRepository; - private TagRepository tagRepository; - private PayloadService payloadService; - private AttackPatternRepository attackPatternRepository; - private DocumentRepository documentRepository; - private final CollectorRepository collectorRepository; + private PayloadRepository payloadRepository; + private TagRepository tagRepository; + private PayloadService payloadService; + private AttackPatternRepository attackPatternRepository; + private DocumentRepository documentRepository; + private final CollectorRepository collectorRepository; - public PayloadApi(CollectorRepository collectorRepository) { - this.collectorRepository = collectorRepository; - } + public PayloadApi(CollectorRepository collectorRepository) { + this.collectorRepository = collectorRepository; + } - @Autowired - public void setPayloadRepository(PayloadRepository payloadRepository) { - this.payloadRepository = payloadRepository; - } + @Autowired + public void setPayloadRepository(PayloadRepository payloadRepository) { + this.payloadRepository = payloadRepository; + } - @Autowired - public void setTagRepository(TagRepository tagRepository) { - this.tagRepository = tagRepository; - } + @Autowired + public void setTagRepository(TagRepository tagRepository) { + this.tagRepository = tagRepository; + } - @Autowired - public void setPayloadService(PayloadService payloadService) { - this.payloadService = payloadService; - } + @Autowired + public void setPayloadService(PayloadService payloadService) { + this.payloadService = payloadService; + } - @Autowired - public void setAttackPatternRepository(AttackPatternRepository attackPatternRepository) { - this.attackPatternRepository = attackPatternRepository; - } + @Autowired + public void setAttackPatternRepository(AttackPatternRepository attackPatternRepository) { + this.attackPatternRepository = attackPatternRepository; + } - @Autowired - public void setDocumentRepository(DocumentRepository documentRepository) { - this.documentRepository = documentRepository; - } + @Autowired + public void setDocumentRepository(DocumentRepository documentRepository) { + this.documentRepository = documentRepository; + } - @PostMapping("/api/payloads/search") - public Page payloads(@RequestBody @Valid final SearchPaginationInput searchPaginationInput) { - return buildPaginationJPA( - (Specification specification, Pageable pageable) -> this.payloadRepository.findAll( - specification, pageable), - searchPaginationInput, - Payload.class - ); - } + @PostMapping("/api/payloads/search") + public Page payloads( + @RequestBody @Valid final SearchPaginationInput searchPaginationInput) { + return buildPaginationJPA( + (Specification specification, Pageable pageable) -> + this.payloadRepository.findAll(specification, pageable), + searchPaginationInput, + Payload.class); + } - @GetMapping("/api/payloads/{payloadId}") - public Payload payload(@PathVariable String payloadId) { - return payloadRepository.findById(payloadId).orElseThrow(ElementNotFoundException::new); - } + @GetMapping("/api/payloads/{payloadId}") + public Payload payload(@PathVariable String payloadId) { + return payloadRepository.findById(payloadId).orElseThrow(ElementNotFoundException::new); + } - @PostMapping("/api/payloads") - @PreAuthorize("isPlanner()") - @Transactional(rollbackOn = Exception.class) - public Payload createPayload(@Valid @RequestBody PayloadCreateInput input) { - switch (PayloadType.fromString(input.getType())) { - case PayloadType.COMMAND: - Command commandPayload = new Command(); - commandPayload.setUpdateAttributes(input); - commandPayload.setAttackPatterns(fromIterable(attackPatternRepository.findAllById(input.getAttackPatternsIds()))); - commandPayload.setTags(iterableToSet(tagRepository.findAllById(input.getTagIds()))); - commandPayload = payloadRepository.save(commandPayload); - this.payloadService.updateInjectorContractsForPayload(commandPayload); - return commandPayload; - case PayloadType.EXECUTABLE: - Executable executablePayload = new Executable(); - PayloadCreateInput validatedInput = validateExecutableCreateInput(input); - executablePayload.setUpdateAttributes(validatedInput); - executablePayload.setAttackPatterns(fromIterable(attackPatternRepository.findAllById(validatedInput.getAttackPatternsIds()))); - executablePayload.setTags(iterableToSet(tagRepository.findAllById(validatedInput.getTagIds()))); - executablePayload.setExecutableFile(documentRepository.findById(validatedInput.getExecutableFile()).orElseThrow()); - executablePayload = payloadRepository.save(executablePayload); - this.payloadService.updateInjectorContractsForPayload(executablePayload); - return executablePayload; - case PayloadType.FILE_DROP: - FileDrop fileDropPayload = new FileDrop(); - fileDropPayload.setUpdateAttributes(input); - fileDropPayload.setAttackPatterns(fromIterable(attackPatternRepository.findAllById(input.getAttackPatternsIds()))); - fileDropPayload.setTags(iterableToSet(tagRepository.findAllById(input.getTagIds()))); - fileDropPayload.setFileDropFile(documentRepository.findById(input.getFileDropFile()).orElseThrow()); - fileDropPayload = payloadRepository.save(fileDropPayload); - this.payloadService.updateInjectorContractsForPayload(fileDropPayload); - return fileDropPayload; - case PayloadType.DNS_RESOLUTION: - DnsResolution dnsResolutionPayload = new DnsResolution(); - dnsResolutionPayload.setUpdateAttributes(input); - dnsResolutionPayload.setAttackPatterns(fromIterable(attackPatternRepository.findAllById(input.getAttackPatternsIds()))); - dnsResolutionPayload.setTags(iterableToSet(tagRepository.findAllById(input.getTagIds()))); - dnsResolutionPayload = payloadRepository.save(dnsResolutionPayload); - this.payloadService.updateInjectorContractsForPayload(dnsResolutionPayload); - return dnsResolutionPayload; - case PayloadType.NETWORK_TRAFFIC: - NetworkTraffic networkTrafficPayload = new NetworkTraffic(); - networkTrafficPayload.setUpdateAttributes(input); - networkTrafficPayload.setAttackPatterns(fromIterable(attackPatternRepository.findAllById(input.getAttackPatternsIds()))); - networkTrafficPayload.setTags(iterableToSet(tagRepository.findAllById(input.getTagIds()))); - networkTrafficPayload = payloadRepository.save(networkTrafficPayload); - this.payloadService.updateInjectorContractsForPayload(networkTrafficPayload); - return networkTrafficPayload; - default: - throw new UnsupportedOperationException("Payload type " + input.getType() + " is not supported"); - } + @PostMapping("/api/payloads") + @PreAuthorize("isPlanner()") + @Transactional(rollbackOn = Exception.class) + public Payload createPayload(@Valid @RequestBody PayloadCreateInput input) { + switch (PayloadType.fromString(input.getType())) { + case PayloadType.COMMAND: + Command commandPayload = new Command(); + commandPayload.setUpdateAttributes(input); + commandPayload.setAttackPatterns( + fromIterable(attackPatternRepository.findAllById(input.getAttackPatternsIds()))); + commandPayload.setTags(iterableToSet(tagRepository.findAllById(input.getTagIds()))); + commandPayload = payloadRepository.save(commandPayload); + this.payloadService.updateInjectorContractsForPayload(commandPayload); + return commandPayload; + case PayloadType.EXECUTABLE: + Executable executablePayload = new Executable(); + PayloadCreateInput validatedInput = validateExecutableCreateInput(input); + executablePayload.setUpdateAttributes(validatedInput); + executablePayload.setAttackPatterns( + fromIterable( + attackPatternRepository.findAllById(validatedInput.getAttackPatternsIds()))); + executablePayload.setTags( + iterableToSet(tagRepository.findAllById(validatedInput.getTagIds()))); + executablePayload.setExecutableFile( + documentRepository.findById(validatedInput.getExecutableFile()).orElseThrow()); + executablePayload = payloadRepository.save(executablePayload); + this.payloadService.updateInjectorContractsForPayload(executablePayload); + return executablePayload; + case PayloadType.FILE_DROP: + FileDrop fileDropPayload = new FileDrop(); + fileDropPayload.setUpdateAttributes(input); + fileDropPayload.setAttackPatterns( + fromIterable(attackPatternRepository.findAllById(input.getAttackPatternsIds()))); + fileDropPayload.setTags(iterableToSet(tagRepository.findAllById(input.getTagIds()))); + fileDropPayload.setFileDropFile( + documentRepository.findById(input.getFileDropFile()).orElseThrow()); + fileDropPayload = payloadRepository.save(fileDropPayload); + this.payloadService.updateInjectorContractsForPayload(fileDropPayload); + return fileDropPayload; + case PayloadType.DNS_RESOLUTION: + DnsResolution dnsResolutionPayload = new DnsResolution(); + dnsResolutionPayload.setUpdateAttributes(input); + dnsResolutionPayload.setAttackPatterns( + fromIterable(attackPatternRepository.findAllById(input.getAttackPatternsIds()))); + dnsResolutionPayload.setTags(iterableToSet(tagRepository.findAllById(input.getTagIds()))); + dnsResolutionPayload = payloadRepository.save(dnsResolutionPayload); + this.payloadService.updateInjectorContractsForPayload(dnsResolutionPayload); + return dnsResolutionPayload; + case PayloadType.NETWORK_TRAFFIC: + NetworkTraffic networkTrafficPayload = new NetworkTraffic(); + networkTrafficPayload.setUpdateAttributes(input); + networkTrafficPayload.setAttackPatterns( + fromIterable(attackPatternRepository.findAllById(input.getAttackPatternsIds()))); + networkTrafficPayload.setTags(iterableToSet(tagRepository.findAllById(input.getTagIds()))); + networkTrafficPayload = payloadRepository.save(networkTrafficPayload); + this.payloadService.updateInjectorContractsForPayload(networkTrafficPayload); + return networkTrafficPayload; + default: + throw new UnsupportedOperationException( + "Payload type " + input.getType() + " is not supported"); } + } - private static PayloadCreateInput validateExecutableCreateInput(PayloadCreateInput input) { - Optional maybeArch = Optional.ofNullable(input.getExecutableArch()); - if (maybeArch.isPresent()) { - return input; - } else { - throw new BadRequestException("Executable arch is missing"); - } + private static PayloadCreateInput validateExecutableCreateInput(PayloadCreateInput input) { + Optional maybeArch = Optional.ofNullable(input.getExecutableArch()); + if (maybeArch.isPresent()) { + return input; + } else { + throw new BadRequestException("Executable arch is missing"); } + } - private static PayloadUpdateInput validateExecutableUpdateInput(PayloadUpdateInput input) { - Optional maybeArch = Optional.ofNullable(input.getExecutableArch()); - if (maybeArch.isPresent()) { - return input; - } else { - throw new BadRequestException("Executable arch is missing"); - } + private static PayloadUpdateInput validateExecutableUpdateInput(PayloadUpdateInput input) { + Optional maybeArch = Optional.ofNullable(input.getExecutableArch()); + if (maybeArch.isPresent()) { + return input; + } else { + throw new BadRequestException("Executable arch is missing"); } + } - @PutMapping("/api/payloads/{payloadId}") - @PreAuthorize("isPlanner()") - @Transactional(rollbackOn = Exception.class) - public Payload updatePayload( - @NotBlank @PathVariable final String payloadId, - @Valid @RequestBody PayloadUpdateInput input) { - Payload payload = this.payloadRepository.findById(payloadId).orElseThrow(ElementNotFoundException::new); - payload.setAttackPatterns(fromIterable(attackPatternRepository.findAllById(input.getAttackPatternsIds()))); - payload.setTags(iterableToSet(tagRepository.findAllById(input.getTagIds()))); - payload.setUpdatedAt(Instant.now()); - switch (PayloadType.fromString(payload.getType())) { - case PayloadType.COMMAND: - Command payloadCommand = (Command) Hibernate.unproxy(payload); - payloadCommand.setUpdateAttributes(input); - payloadCommand = payloadRepository.save(payloadCommand); - this.payloadService.updateInjectorContractsForPayload(payloadCommand); - return payloadCommand; - case PayloadType.EXECUTABLE: - PayloadUpdateInput validatedInput = validateExecutableUpdateInput(input); - Executable payloadExecutable = (Executable) Hibernate.unproxy(payload); - payloadExecutable.setUpdateAttributes(validatedInput); - payloadExecutable.setExecutableFile(documentRepository.findById(validatedInput.getExecutableFile()).orElseThrow()); - payloadExecutable = payloadRepository.save(payloadExecutable); - this.payloadService.updateInjectorContractsForPayload(payloadExecutable); - return payloadExecutable; - case PayloadType.FILE_DROP: - FileDrop payloadFileDrop = (FileDrop) Hibernate.unproxy(payload); - payloadFileDrop.setUpdateAttributes(input); - payloadFileDrop.setFileDropFile(documentRepository.findById(input.getFileDropFile()).orElseThrow()); - payloadFileDrop = payloadRepository.save(payloadFileDrop); - this.payloadService.updateInjectorContractsForPayload(payloadFileDrop); - return payloadFileDrop; - case PayloadType.DNS_RESOLUTION: - DnsResolution payloadDnsResolution = (DnsResolution) Hibernate.unproxy(payload); - payloadDnsResolution.setUpdateAttributes(input); - payloadDnsResolution = payloadRepository.save(payloadDnsResolution); - this.payloadService.updateInjectorContractsForPayload(payloadDnsResolution); - return payloadDnsResolution; - case PayloadType.NETWORK_TRAFFIC: - NetworkTraffic payloadNetworkTraffic = (NetworkTraffic) Hibernate.unproxy(payload); - payloadNetworkTraffic.setUpdateAttributes(input); - payloadNetworkTraffic = payloadRepository.save(payloadNetworkTraffic); - this.payloadService.updateInjectorContractsForPayload(payloadNetworkTraffic); - return payloadNetworkTraffic; - default: - throw new UnsupportedOperationException("Payload type " + payload.getType() + " is not supported"); - } + @PutMapping("/api/payloads/{payloadId}") + @PreAuthorize("isPlanner()") + @Transactional(rollbackOn = Exception.class) + public Payload updatePayload( + @NotBlank @PathVariable final String payloadId, + @Valid @RequestBody PayloadUpdateInput input) { + Payload payload = + this.payloadRepository.findById(payloadId).orElseThrow(ElementNotFoundException::new); + payload.setAttackPatterns( + fromIterable(attackPatternRepository.findAllById(input.getAttackPatternsIds()))); + payload.setTags(iterableToSet(tagRepository.findAllById(input.getTagIds()))); + payload.setUpdatedAt(Instant.now()); + switch (PayloadType.fromString(payload.getType())) { + case PayloadType.COMMAND: + Command payloadCommand = (Command) Hibernate.unproxy(payload); + payloadCommand.setUpdateAttributes(input); + payloadCommand = payloadRepository.save(payloadCommand); + this.payloadService.updateInjectorContractsForPayload(payloadCommand); + return payloadCommand; + case PayloadType.EXECUTABLE: + PayloadUpdateInput validatedInput = validateExecutableUpdateInput(input); + Executable payloadExecutable = (Executable) Hibernate.unproxy(payload); + payloadExecutable.setUpdateAttributes(validatedInput); + payloadExecutable.setExecutableFile( + documentRepository.findById(validatedInput.getExecutableFile()).orElseThrow()); + payloadExecutable = payloadRepository.save(payloadExecutable); + this.payloadService.updateInjectorContractsForPayload(payloadExecutable); + return payloadExecutable; + case PayloadType.FILE_DROP: + FileDrop payloadFileDrop = (FileDrop) Hibernate.unproxy(payload); + payloadFileDrop.setUpdateAttributes(input); + payloadFileDrop.setFileDropFile( + documentRepository.findById(input.getFileDropFile()).orElseThrow()); + payloadFileDrop = payloadRepository.save(payloadFileDrop); + this.payloadService.updateInjectorContractsForPayload(payloadFileDrop); + return payloadFileDrop; + case PayloadType.DNS_RESOLUTION: + DnsResolution payloadDnsResolution = (DnsResolution) Hibernate.unproxy(payload); + payloadDnsResolution.setUpdateAttributes(input); + payloadDnsResolution = payloadRepository.save(payloadDnsResolution); + this.payloadService.updateInjectorContractsForPayload(payloadDnsResolution); + return payloadDnsResolution; + case PayloadType.NETWORK_TRAFFIC: + NetworkTraffic payloadNetworkTraffic = (NetworkTraffic) Hibernate.unproxy(payload); + payloadNetworkTraffic.setUpdateAttributes(input); + payloadNetworkTraffic = payloadRepository.save(payloadNetworkTraffic); + this.payloadService.updateInjectorContractsForPayload(payloadNetworkTraffic); + return payloadNetworkTraffic; + default: + throw new UnsupportedOperationException( + "Payload type " + payload.getType() + " is not supported"); } + } - @PostMapping(PAYLOAD_URI + "/{payloadId}/duplicate") - @PreAuthorize("isPlanner()") - @Transactional(rollbackOn = Exception.class) - public Payload duplicatePayload(@NotBlank @PathVariable final String payloadId) { - return this.payloadService.duplicate(payloadId); - } + @PostMapping(PAYLOAD_URI + "/{payloadId}/duplicate") + @PreAuthorize("isPlanner()") + @Transactional(rollbackOn = Exception.class) + public Payload duplicatePayload(@NotBlank @PathVariable final String payloadId) { + return this.payloadService.duplicate(payloadId); + } - @PostMapping("/api/payloads/upsert") - @PreAuthorize("isPlanner()") - @org.springframework.transaction.annotation.Transactional(rollbackFor = Exception.class) - public Payload upsertPayload(@Valid @RequestBody PayloadUpsertInput input) { - Optional payload = payloadRepository.findByExternalId(input.getExternalId()); - if (payload.isPresent()) { - Payload existingPayload = payload.get(); - if( input.getCollector() != null ) { - existingPayload.setCollector(collectorRepository.findById(input.getCollector()).orElseThrow()); - } - existingPayload.setAttackPatterns(fromIterable(attackPatternRepository.findAllByExternalIdInIgnoreCase(input.getAttackPatternsExternalIds()))); - existingPayload.setTags(iterableToSet(tagRepository.findAllById(input.getTagIds()))); - existingPayload.setUpdatedAt(Instant.now()); - switch (PayloadType.fromString(existingPayload.getType())) { - case PayloadType.COMMAND: - Command payloadCommand = (Command) Hibernate.unproxy(existingPayload); - payloadCommand.setUpdateAttributes(input); - payloadCommand = payloadRepository.save(payloadCommand); - this.payloadService.updateInjectorContractsForPayload(payloadCommand); - return payloadCommand; - case PayloadType.EXECUTABLE: - Executable payloadExecutable = (Executable) Hibernate.unproxy(existingPayload); - payloadExecutable.setUpdateAttributes(input); - payloadExecutable.setExecutableFile(documentRepository.findById(input.getExecutableFile()).orElseThrow()); - payloadExecutable = payloadRepository.save(payloadExecutable); - this.payloadService.updateInjectorContractsForPayload(payloadExecutable); - return payloadExecutable; - case PayloadType.FILE_DROP: - FileDrop payloadFileDrop = (FileDrop) Hibernate.unproxy(existingPayload); - payloadFileDrop.setUpdateAttributes(input); - payloadFileDrop.setFileDropFile(documentRepository.findById(input.getFileDropFile()).orElseThrow()); - payloadFileDrop = payloadRepository.save(payloadFileDrop); - this.payloadService.updateInjectorContractsForPayload(payloadFileDrop); - return payloadFileDrop; - case PayloadType.DNS_RESOLUTION: - DnsResolution payloadDnsResolution = (DnsResolution) Hibernate.unproxy(existingPayload); - payloadDnsResolution.setUpdateAttributes(input); - payloadDnsResolution = payloadRepository.save(payloadDnsResolution); - this.payloadService.updateInjectorContractsForPayload(payloadDnsResolution); - return payloadDnsResolution; - case PayloadType.NETWORK_TRAFFIC: - NetworkTraffic payloadNetworkTraffic = (NetworkTraffic) Hibernate.unproxy(existingPayload); - payloadNetworkTraffic.setUpdateAttributes(input); - payloadNetworkTraffic = payloadRepository.save(payloadNetworkTraffic); - this.payloadService.updateInjectorContractsForPayload(payloadNetworkTraffic); - return payloadNetworkTraffic; - default: - throw new UnsupportedOperationException("Payload type " + existingPayload.getType() + " is not supported"); - } - } else { - switch (PayloadType.fromString(input.getType())) { - case PayloadType.COMMAND: - Command commandPayload = new Command(); - commandPayload.setUpdateAttributes(input); - if( input.getCollector() != null ) { - commandPayload.setCollector(collectorRepository.findById(input.getCollector()).orElseThrow()); - } - commandPayload.setAttackPatterns(fromIterable(attackPatternRepository.findAllByExternalIdInIgnoreCase(input.getAttackPatternsExternalIds()))); - commandPayload.setTags(iterableToSet(tagRepository.findAllById(input.getTagIds()))); - commandPayload = payloadRepository.save(commandPayload); - this.payloadService.updateInjectorContractsForPayload(commandPayload); - return commandPayload; - case PayloadType.EXECUTABLE: - Executable executablePayload = new Executable(); - executablePayload.setUpdateAttributes(input); - if( input.getCollector() != null ) { - executablePayload.setCollector(collectorRepository.findById(input.getCollector()).orElseThrow()); - } - executablePayload.setAttackPatterns(fromIterable(attackPatternRepository.findAllByExternalIdInIgnoreCase(input.getAttackPatternsExternalIds()))); - executablePayload.setTags(iterableToSet(tagRepository.findAllById(input.getTagIds()))); - executablePayload.setExecutableFile(documentRepository.findById(input.getExecutableFile()).orElseThrow()); - executablePayload = payloadRepository.save(executablePayload); - this.payloadService.updateInjectorContractsForPayload(executablePayload); - return executablePayload; - case PayloadType.FILE_DROP: - FileDrop fileDropPayload = new FileDrop(); - fileDropPayload.setUpdateAttributes(input); - if( input.getCollector() != null ) { - fileDropPayload.setCollector(collectorRepository.findById(input.getCollector()).orElseThrow()); - } - fileDropPayload.setAttackPatterns(fromIterable(attackPatternRepository.findAllByExternalIdInIgnoreCase(input.getAttackPatternsExternalIds()))); - fileDropPayload.setTags(iterableToSet(tagRepository.findAllById(input.getTagIds()))); - fileDropPayload.setFileDropFile(documentRepository.findById(input.getFileDropFile()).orElseThrow()); - fileDropPayload = payloadRepository.save(fileDropPayload); - this.payloadService.updateInjectorContractsForPayload(fileDropPayload); - return fileDropPayload; - case PayloadType.DNS_RESOLUTION: - DnsResolution dnsResolutionPayload = new DnsResolution(); - dnsResolutionPayload.setUpdateAttributes(input); - if( input.getCollector() != null ) { - dnsResolutionPayload.setCollector(collectorRepository.findById(input.getCollector()).orElseThrow()); - } - dnsResolutionPayload.setAttackPatterns(fromIterable(attackPatternRepository.findAllByExternalIdInIgnoreCase(input.getAttackPatternsExternalIds()))); - dnsResolutionPayload.setTags(iterableToSet(tagRepository.findAllById(input.getTagIds()))); - dnsResolutionPayload = payloadRepository.save(dnsResolutionPayload); - this.payloadService.updateInjectorContractsForPayload(dnsResolutionPayload); - return dnsResolutionPayload; - case PayloadType.NETWORK_TRAFFIC: - NetworkTraffic networkTrafficPayload = new NetworkTraffic(); - networkTrafficPayload.setUpdateAttributes(input); - if( input.getCollector() != null ) { - networkTrafficPayload.setCollector(collectorRepository.findById(input.getCollector()).orElseThrow()); - } - networkTrafficPayload.setAttackPatterns(fromIterable(attackPatternRepository.findAllByExternalIdInIgnoreCase(input.getAttackPatternsExternalIds()))); - networkTrafficPayload.setTags(iterableToSet(tagRepository.findAllById(input.getTagIds()))); - networkTrafficPayload = payloadRepository.save(networkTrafficPayload); - this.payloadService.updateInjectorContractsForPayload(networkTrafficPayload); - return networkTrafficPayload; - default: - throw new UnsupportedOperationException("Payload type " + input.getType() + " is not supported"); - } - } + @PostMapping("/api/payloads/upsert") + @PreAuthorize("isPlanner()") + @org.springframework.transaction.annotation.Transactional(rollbackFor = Exception.class) + public Payload upsertPayload(@Valid @RequestBody PayloadUpsertInput input) { + Optional payload = payloadRepository.findByExternalId(input.getExternalId()); + if (payload.isPresent()) { + Payload existingPayload = payload.get(); + if (input.getCollector() != null) { + existingPayload.setCollector( + collectorRepository.findById(input.getCollector()).orElseThrow()); + } + existingPayload.setAttackPatterns( + fromIterable( + attackPatternRepository.findAllByExternalIdInIgnoreCase( + input.getAttackPatternsExternalIds()))); + existingPayload.setTags(iterableToSet(tagRepository.findAllById(input.getTagIds()))); + existingPayload.setUpdatedAt(Instant.now()); + switch (PayloadType.fromString(existingPayload.getType())) { + case PayloadType.COMMAND: + Command payloadCommand = (Command) Hibernate.unproxy(existingPayload); + payloadCommand.setUpdateAttributes(input); + payloadCommand = payloadRepository.save(payloadCommand); + this.payloadService.updateInjectorContractsForPayload(payloadCommand); + return payloadCommand; + case PayloadType.EXECUTABLE: + Executable payloadExecutable = (Executable) Hibernate.unproxy(existingPayload); + payloadExecutable.setUpdateAttributes(input); + payloadExecutable.setExecutableFile( + documentRepository.findById(input.getExecutableFile()).orElseThrow()); + payloadExecutable = payloadRepository.save(payloadExecutable); + this.payloadService.updateInjectorContractsForPayload(payloadExecutable); + return payloadExecutable; + case PayloadType.FILE_DROP: + FileDrop payloadFileDrop = (FileDrop) Hibernate.unproxy(existingPayload); + payloadFileDrop.setUpdateAttributes(input); + payloadFileDrop.setFileDropFile( + documentRepository.findById(input.getFileDropFile()).orElseThrow()); + payloadFileDrop = payloadRepository.save(payloadFileDrop); + this.payloadService.updateInjectorContractsForPayload(payloadFileDrop); + return payloadFileDrop; + case PayloadType.DNS_RESOLUTION: + DnsResolution payloadDnsResolution = (DnsResolution) Hibernate.unproxy(existingPayload); + payloadDnsResolution.setUpdateAttributes(input); + payloadDnsResolution = payloadRepository.save(payloadDnsResolution); + this.payloadService.updateInjectorContractsForPayload(payloadDnsResolution); + return payloadDnsResolution; + case PayloadType.NETWORK_TRAFFIC: + NetworkTraffic payloadNetworkTraffic = + (NetworkTraffic) Hibernate.unproxy(existingPayload); + payloadNetworkTraffic.setUpdateAttributes(input); + payloadNetworkTraffic = payloadRepository.save(payloadNetworkTraffic); + this.payloadService.updateInjectorContractsForPayload(payloadNetworkTraffic); + return payloadNetworkTraffic; + default: + throw new UnsupportedOperationException( + "Payload type " + existingPayload.getType() + " is not supported"); + } + } else { + switch (PayloadType.fromString(input.getType())) { + case PayloadType.COMMAND: + Command commandPayload = new Command(); + commandPayload.setUpdateAttributes(input); + if (input.getCollector() != null) { + commandPayload.setCollector( + collectorRepository.findById(input.getCollector()).orElseThrow()); + } + commandPayload.setAttackPatterns( + fromIterable( + attackPatternRepository.findAllByExternalIdInIgnoreCase( + input.getAttackPatternsExternalIds()))); + commandPayload.setTags(iterableToSet(tagRepository.findAllById(input.getTagIds()))); + commandPayload = payloadRepository.save(commandPayload); + this.payloadService.updateInjectorContractsForPayload(commandPayload); + return commandPayload; + case PayloadType.EXECUTABLE: + Executable executablePayload = new Executable(); + executablePayload.setUpdateAttributes(input); + if (input.getCollector() != null) { + executablePayload.setCollector( + collectorRepository.findById(input.getCollector()).orElseThrow()); + } + executablePayload.setAttackPatterns( + fromIterable( + attackPatternRepository.findAllByExternalIdInIgnoreCase( + input.getAttackPatternsExternalIds()))); + executablePayload.setTags(iterableToSet(tagRepository.findAllById(input.getTagIds()))); + executablePayload.setExecutableFile( + documentRepository.findById(input.getExecutableFile()).orElseThrow()); + executablePayload = payloadRepository.save(executablePayload); + this.payloadService.updateInjectorContractsForPayload(executablePayload); + return executablePayload; + case PayloadType.FILE_DROP: + FileDrop fileDropPayload = new FileDrop(); + fileDropPayload.setUpdateAttributes(input); + if (input.getCollector() != null) { + fileDropPayload.setCollector( + collectorRepository.findById(input.getCollector()).orElseThrow()); + } + fileDropPayload.setAttackPatterns( + fromIterable( + attackPatternRepository.findAllByExternalIdInIgnoreCase( + input.getAttackPatternsExternalIds()))); + fileDropPayload.setTags(iterableToSet(tagRepository.findAllById(input.getTagIds()))); + fileDropPayload.setFileDropFile( + documentRepository.findById(input.getFileDropFile()).orElseThrow()); + fileDropPayload = payloadRepository.save(fileDropPayload); + this.payloadService.updateInjectorContractsForPayload(fileDropPayload); + return fileDropPayload; + case PayloadType.DNS_RESOLUTION: + DnsResolution dnsResolutionPayload = new DnsResolution(); + dnsResolutionPayload.setUpdateAttributes(input); + if (input.getCollector() != null) { + dnsResolutionPayload.setCollector( + collectorRepository.findById(input.getCollector()).orElseThrow()); + } + dnsResolutionPayload.setAttackPatterns( + fromIterable( + attackPatternRepository.findAllByExternalIdInIgnoreCase( + input.getAttackPatternsExternalIds()))); + dnsResolutionPayload.setTags(iterableToSet(tagRepository.findAllById(input.getTagIds()))); + dnsResolutionPayload = payloadRepository.save(dnsResolutionPayload); + this.payloadService.updateInjectorContractsForPayload(dnsResolutionPayload); + return dnsResolutionPayload; + case PayloadType.NETWORK_TRAFFIC: + NetworkTraffic networkTrafficPayload = new NetworkTraffic(); + networkTrafficPayload.setUpdateAttributes(input); + if (input.getCollector() != null) { + networkTrafficPayload.setCollector( + collectorRepository.findById(input.getCollector()).orElseThrow()); + } + networkTrafficPayload.setAttackPatterns( + fromIterable( + attackPatternRepository.findAllByExternalIdInIgnoreCase( + input.getAttackPatternsExternalIds()))); + networkTrafficPayload.setTags( + iterableToSet(tagRepository.findAllById(input.getTagIds()))); + networkTrafficPayload = payloadRepository.save(networkTrafficPayload); + this.payloadService.updateInjectorContractsForPayload(networkTrafficPayload); + return networkTrafficPayload; + default: + throw new UnsupportedOperationException( + "Payload type " + input.getType() + " is not supported"); + } } + } - @Secured(ROLE_ADMIN) - @DeleteMapping("/api/payloads/{payloadId}") - public void deletePayload(@PathVariable String payloadId) { - payloadRepository.deleteById(payloadId); - } + @Secured(ROLE_ADMIN) + @DeleteMapping("/api/payloads/{payloadId}") + public void deletePayload(@PathVariable String payloadId) { + payloadRepository.deleteById(payloadId); + } } diff --git a/openbas-api/src/main/java/io/openbas/rest/payload/form/PayloadCreateInput.java b/openbas-api/src/main/java/io/openbas/rest/payload/form/PayloadCreateInput.java index 292db6f3b7..c9ca845b54 100644 --- a/openbas-api/src/main/java/io/openbas/rest/payload/form/PayloadCreateInput.java +++ b/openbas-api/src/main/java/io/openbas/rest/payload/form/PayloadCreateInput.java @@ -1,5 +1,7 @@ package io.openbas.rest.payload.form; +import static io.openbas.config.AppConfig.MANDATORY_MESSAGE; + import com.fasterxml.jackson.annotation.JsonProperty; import io.openbas.database.model.Endpoint; import io.openbas.database.model.Endpoint.PLATFORM_TYPE; @@ -10,13 +12,10 @@ import jakarta.validation.constraints.NotBlank; import jakarta.validation.constraints.NotEmpty; import jakarta.validation.constraints.NotNull; -import lombok.Getter; -import lombok.Setter; - import java.util.ArrayList; import java.util.List; - -import static io.openbas.config.AppConfig.MANDATORY_MESSAGE; +import lombok.Getter; +import lombok.Setter; @Getter @Setter @@ -81,5 +80,3 @@ public class PayloadCreateInput { @JsonProperty("payload_attack_patterns") private List attackPatternsIds = new ArrayList<>(); } - - diff --git a/openbas-api/src/main/java/io/openbas/rest/payload/form/PayloadUpdateInput.java b/openbas-api/src/main/java/io/openbas/rest/payload/form/PayloadUpdateInput.java index ac64a1efae..5eadc776fb 100644 --- a/openbas-api/src/main/java/io/openbas/rest/payload/form/PayloadUpdateInput.java +++ b/openbas-api/src/main/java/io/openbas/rest/payload/form/PayloadUpdateInput.java @@ -1,67 +1,64 @@ package io.openbas.rest.payload.form; +import static io.openbas.config.AppConfig.MANDATORY_MESSAGE; + import com.fasterxml.jackson.annotation.JsonProperty; import io.openbas.database.model.Endpoint; import io.openbas.database.model.Endpoint.PLATFORM_TYPE; import io.openbas.database.model.PayloadArgument; import io.openbas.database.model.PayloadPrerequisite; import jakarta.validation.constraints.NotBlank; -import lombok.Getter; -import lombok.Setter; - import java.util.ArrayList; import java.util.List; - -import static io.openbas.config.AppConfig.MANDATORY_MESSAGE; +import lombok.Getter; +import lombok.Setter; @Getter @Setter public class PayloadUpdateInput { - @NotBlank(message = MANDATORY_MESSAGE) - @JsonProperty("payload_name") - private String name; + @NotBlank(message = MANDATORY_MESSAGE) + @JsonProperty("payload_name") + private String name; - @JsonProperty("payload_platforms") - private PLATFORM_TYPE[] platforms; + @JsonProperty("payload_platforms") + private PLATFORM_TYPE[] platforms; - @JsonProperty("payload_description") - private String description; + @JsonProperty("payload_description") + private String description; - @JsonProperty("command_executor") - private String executor; + @JsonProperty("command_executor") + private String executor; - @JsonProperty("command_content") - private String content; + @JsonProperty("command_content") + private String content; - @JsonProperty("executable_arch") - private Endpoint.PLATFORM_ARCH executableArch; + @JsonProperty("executable_arch") + private Endpoint.PLATFORM_ARCH executableArch; - @JsonProperty("executable_file") - private String executableFile; + @JsonProperty("executable_file") + private String executableFile; - @JsonProperty("file_drop_file") - private String fileDropFile; + @JsonProperty("file_drop_file") + private String fileDropFile; - @JsonProperty("dns_resolution_hostname") - private String hostname; + @JsonProperty("dns_resolution_hostname") + private String hostname; - @JsonProperty("payload_arguments") - private List arguments; + @JsonProperty("payload_arguments") + private List arguments; - @JsonProperty("payload_prerequisites") - private List prerequisites; + @JsonProperty("payload_prerequisites") + private List prerequisites; - @JsonProperty("payload_cleanup_executor") - private String cleanupExecutor; + @JsonProperty("payload_cleanup_executor") + private String cleanupExecutor; - @JsonProperty("payload_cleanup_command") - private String cleanupCommand; + @JsonProperty("payload_cleanup_command") + private String cleanupCommand; - @JsonProperty("payload_tags") - private List tagIds = new ArrayList<>(); + @JsonProperty("payload_tags") + private List tagIds = new ArrayList<>(); - @JsonProperty("payload_attack_patterns") - private List attackPatternsIds = new ArrayList<>(); + @JsonProperty("payload_attack_patterns") + private List attackPatternsIds = new ArrayList<>(); } - - diff --git a/openbas-api/src/main/java/io/openbas/rest/payload/form/PayloadUpsertInput.java b/openbas-api/src/main/java/io/openbas/rest/payload/form/PayloadUpsertInput.java index f59d5326b3..36617a6d17 100644 --- a/openbas-api/src/main/java/io/openbas/rest/payload/form/PayloadUpsertInput.java +++ b/openbas-api/src/main/java/io/openbas/rest/payload/form/PayloadUpsertInput.java @@ -1,84 +1,81 @@ package io.openbas.rest.payload.form; +import static io.openbas.config.AppConfig.MANDATORY_MESSAGE; + import com.fasterxml.jackson.annotation.JsonProperty; import io.openbas.database.model.PayloadArgument; import io.openbas.database.model.PayloadPrerequisite; import jakarta.validation.constraints.NotBlank; -import lombok.Getter; -import lombok.Setter; - import java.util.ArrayList; import java.util.List; - -import static io.openbas.config.AppConfig.MANDATORY_MESSAGE; +import lombok.Getter; +import lombok.Setter; @Getter @Setter public class PayloadUpsertInput { - @NotBlank(message = MANDATORY_MESSAGE) - @JsonProperty("payload_type") - private String type; + @NotBlank(message = MANDATORY_MESSAGE) + @JsonProperty("payload_type") + private String type; - @NotBlank(message = MANDATORY_MESSAGE) - @JsonProperty("payload_name") - private String name; + @NotBlank(message = MANDATORY_MESSAGE) + @JsonProperty("payload_name") + private String name; - @NotBlank(message = MANDATORY_MESSAGE) - @JsonProperty("payload_source") - private String source; + @NotBlank(message = MANDATORY_MESSAGE) + @JsonProperty("payload_source") + private String source; - @NotBlank(message = MANDATORY_MESSAGE) - @JsonProperty("payload_status") - private String status; + @NotBlank(message = MANDATORY_MESSAGE) + @JsonProperty("payload_status") + private String status; - @NotBlank(message = MANDATORY_MESSAGE) - @JsonProperty("payload_external_id") - private String externalId; + @NotBlank(message = MANDATORY_MESSAGE) + @JsonProperty("payload_external_id") + private String externalId; - @JsonProperty("payload_collector") - private String collector; + @JsonProperty("payload_collector") + private String collector; - @JsonProperty("payload_platforms") - private String[] platforms; + @JsonProperty("payload_platforms") + private String[] platforms; - @JsonProperty("payload_description") - private String description; + @JsonProperty("payload_description") + private String description; - @JsonProperty("command_executor") - private String executor; + @JsonProperty("command_executor") + private String executor; - @JsonProperty("command_content") - private String content; + @JsonProperty("command_content") + private String content; - @JsonProperty("executable_file") - private String executableFile; + @JsonProperty("executable_file") + private String executableFile; - @JsonProperty("file_drop_file") - private String fileDropFile; + @JsonProperty("file_drop_file") + private String fileDropFile; - @JsonProperty("dns_resolution_hostname") - private String hostname; + @JsonProperty("dns_resolution_hostname") + private String hostname; - @JsonProperty("payload_arguments") - private List arguments; + @JsonProperty("payload_arguments") + private List arguments; - @JsonProperty("payload_prerequisites") - private List prerequisites; + @JsonProperty("payload_prerequisites") + private List prerequisites; - @JsonProperty("payload_cleanup_executor") - private String cleanupExecutor; + @JsonProperty("payload_cleanup_executor") + private String cleanupExecutor; - @JsonProperty("payload_cleanup_command") - private String cleanupCommand; + @JsonProperty("payload_cleanup_command") + private String cleanupCommand; - @JsonProperty("payload_tags") - private List tagIds = new ArrayList<>(); + @JsonProperty("payload_tags") + private List tagIds = new ArrayList<>(); - @JsonProperty("payload_attack_patterns") - private List attackPatternsExternalIds = new ArrayList<>(); + @JsonProperty("payload_attack_patterns") + private List attackPatternsExternalIds = new ArrayList<>(); - @JsonProperty("payload_elevation_required") - private boolean elevationRequired; + @JsonProperty("payload_elevation_required") + private boolean elevationRequired; } - - diff --git a/openbas-api/src/main/java/io/openbas/rest/report/ReportApi.java b/openbas-api/src/main/java/io/openbas/rest/report/ReportApi.java index 9108650e77..565beed396 100644 --- a/openbas-api/src/main/java/io/openbas/rest/report/ReportApi.java +++ b/openbas-api/src/main/java/io/openbas/rest/report/ReportApi.java @@ -1,5 +1,7 @@ package io.openbas.rest.report; +import static io.openbas.database.model.User.ROLE_USER; + import io.openbas.database.model.*; import io.openbas.rest.exercise.ExerciseService; import io.openbas.rest.helper.RestBehavior; @@ -9,72 +11,76 @@ import io.openbas.service.ReportService; import jakarta.transaction.Transactional; import jakarta.validation.Valid; +import java.util.UUID; import lombok.RequiredArgsConstructor; import org.springframework.security.access.annotation.Secured; import org.springframework.security.access.prepost.PreAuthorize; import org.springframework.web.bind.annotation.*; -import java.util.UUID; - -import static io.openbas.database.model.User.ROLE_USER; - @RequiredArgsConstructor @RestController @Secured(ROLE_USER) public class ReportApi extends RestBehavior { - private final ExerciseService exerciseService; - private final ReportService reportService; - private final InjectService injectService; + private final ExerciseService exerciseService; + private final ReportService reportService; + private final InjectService injectService; - @GetMapping("/api/reports/{reportId}") - @PreAuthorize("isObserver()") - public Report report(@PathVariable String reportId) { - return this.reportService.report(UUID.fromString(reportId)); - } + @GetMapping("/api/reports/{reportId}") + @PreAuthorize("isObserver()") + public Report report(@PathVariable String reportId) { + return this.reportService.report(UUID.fromString(reportId)); + } - @GetMapping("/api/exercises/{exerciseId}/reports") - @PreAuthorize("isExerciseObserver(#exerciseId)") - public Iterable exerciseReports(@PathVariable String exerciseId) { - return this.reportService.reportsFromExercise(exerciseId); - } + @GetMapping("/api/exercises/{exerciseId}/reports") + @PreAuthorize("isExerciseObserver(#exerciseId)") + public Iterable exerciseReports(@PathVariable String exerciseId) { + return this.reportService.reportsFromExercise(exerciseId); + } - @PostMapping("/api/exercises/{exerciseId}/reports") - @PreAuthorize("isExercisePlanner(#exerciseId)") - @Transactional(rollbackOn = Exception.class) - public Report createExerciseReport(@PathVariable String exerciseId, @Valid @RequestBody ReportInput input) { - Exercise exercise = this.exerciseService.exercise(exerciseId); - Report report = new Report(); - report.setExercise(exercise); - return this.reportService.updateReport(report, input); - } + @PostMapping("/api/exercises/{exerciseId}/reports") + @PreAuthorize("isExercisePlanner(#exerciseId)") + @Transactional(rollbackOn = Exception.class) + public Report createExerciseReport( + @PathVariable String exerciseId, @Valid @RequestBody ReportInput input) { + Exercise exercise = this.exerciseService.exercise(exerciseId); + Report report = new Report(); + report.setExercise(exercise); + return this.reportService.updateReport(report, input); + } - @PutMapping("/api/exercises/{exerciseId}/reports/{reportId}/inject-comments") - @PreAuthorize("isExercisePlanner(#exerciseId)") - @Transactional(rollbackOn = Exception.class) - public Iterable updateReportInjectComment(@PathVariable String exerciseId, @PathVariable String reportId, @Valid @RequestBody ReportInjectCommentInput input) { - Report report = this.reportService.report(UUID.fromString(reportId)); - assert exerciseId.equals(report.getExercise().getId()); - Inject inject = this.injectService.inject(input.getInjectId()); - assert exerciseId.equals(inject.getExercise().getId()); - return this.reportService.updateReportInjectComment(report, inject, input); - } + @PutMapping("/api/exercises/{exerciseId}/reports/{reportId}/inject-comments") + @PreAuthorize("isExercisePlanner(#exerciseId)") + @Transactional(rollbackOn = Exception.class) + public Iterable updateReportInjectComment( + @PathVariable String exerciseId, + @PathVariable String reportId, + @Valid @RequestBody ReportInjectCommentInput input) { + Report report = this.reportService.report(UUID.fromString(reportId)); + assert exerciseId.equals(report.getExercise().getId()); + Inject inject = this.injectService.inject(input.getInjectId()); + assert exerciseId.equals(inject.getExercise().getId()); + return this.reportService.updateReportInjectComment(report, inject, input); + } - @PutMapping("/api/exercises/{exerciseId}/reports/{reportId}") - @PreAuthorize("isExercisePlanner(#exerciseId)") - @Transactional(rollbackOn = Exception.class) - public Report updateExerciseReport(@PathVariable String exerciseId,@PathVariable String reportId, @Valid @RequestBody ReportInput input) { - Report report = this.reportService.report(UUID.fromString(reportId)); - assert exerciseId.equals(report.getExercise().getId()); - return this.reportService.updateReport(report, input); - } + @PutMapping("/api/exercises/{exerciseId}/reports/{reportId}") + @PreAuthorize("isExercisePlanner(#exerciseId)") + @Transactional(rollbackOn = Exception.class) + public Report updateExerciseReport( + @PathVariable String exerciseId, + @PathVariable String reportId, + @Valid @RequestBody ReportInput input) { + Report report = this.reportService.report(UUID.fromString(reportId)); + assert exerciseId.equals(report.getExercise().getId()); + return this.reportService.updateReport(report, input); + } - @DeleteMapping("/api/exercises/{exerciseId}/reports/{reportId}") - @PreAuthorize("isExercisePlanner(#exerciseId)") - @Transactional(rollbackOn = Exception.class) - public void deleteExerciseReport(@PathVariable String exerciseId, @PathVariable String reportId) { - Report report = this.reportService.report(UUID.fromString(reportId)); - assert exerciseId.equals(report.getExercise().getId()); - this.reportService.deleteReport(UUID.fromString(reportId)); - } + @DeleteMapping("/api/exercises/{exerciseId}/reports/{reportId}") + @PreAuthorize("isExercisePlanner(#exerciseId)") + @Transactional(rollbackOn = Exception.class) + public void deleteExerciseReport(@PathVariable String exerciseId, @PathVariable String reportId) { + Report report = this.reportService.report(UUID.fromString(reportId)); + assert exerciseId.equals(report.getExercise().getId()); + this.reportService.deleteReport(UUID.fromString(reportId)); + } } diff --git a/openbas-api/src/main/java/io/openbas/rest/report/form/ReportInformationInput.java b/openbas-api/src/main/java/io/openbas/rest/report/form/ReportInformationInput.java index 27bdf5ed9b..ca8ecc3a40 100644 --- a/openbas-api/src/main/java/io/openbas/rest/report/form/ReportInformationInput.java +++ b/openbas-api/src/main/java/io/openbas/rest/report/form/ReportInformationInput.java @@ -8,11 +8,11 @@ @Data public class ReportInformationInput { - @JsonProperty("report_informations_type") - @NotBlank - private ReportInformationsType reportInformationsType; + @JsonProperty("report_informations_type") + @NotBlank + private ReportInformationsType reportInformationsType; - @JsonProperty("report_informations_display") - @NotNull - private Boolean reportInformationsDisplay; + @JsonProperty("report_informations_display") + @NotNull + private Boolean reportInformationsDisplay; } diff --git a/openbas-api/src/main/java/io/openbas/rest/report/form/ReportInjectCommentInput.java b/openbas-api/src/main/java/io/openbas/rest/report/form/ReportInjectCommentInput.java index 96776533c7..0a97143bfe 100644 --- a/openbas-api/src/main/java/io/openbas/rest/report/form/ReportInjectCommentInput.java +++ b/openbas-api/src/main/java/io/openbas/rest/report/form/ReportInjectCommentInput.java @@ -1,17 +1,17 @@ package io.openbas.rest.report.form; +import static io.openbas.config.AppConfig.MANDATORY_MESSAGE; + import com.fasterxml.jackson.annotation.JsonProperty; import jakarta.validation.constraints.NotBlank; import lombok.Data; -import static io.openbas.config.AppConfig.MANDATORY_MESSAGE; - @Data public class ReportInjectCommentInput { - @NotBlank(message = MANDATORY_MESSAGE) - @JsonProperty("inject_id") - private String injectId; + @NotBlank(message = MANDATORY_MESSAGE) + @JsonProperty("inject_id") + private String injectId; - @JsonProperty("report_inject_comment") - private String comment; + @JsonProperty("report_inject_comment") + private String comment; } diff --git a/openbas-api/src/main/java/io/openbas/rest/report/form/ReportInput.java b/openbas-api/src/main/java/io/openbas/rest/report/form/ReportInput.java index ff329fdb56..70a76c108c 100644 --- a/openbas-api/src/main/java/io/openbas/rest/report/form/ReportInput.java +++ b/openbas-api/src/main/java/io/openbas/rest/report/form/ReportInput.java @@ -1,23 +1,21 @@ package io.openbas.rest.report.form; -import com.fasterxml.jackson.annotation.JsonProperty; +import static io.openbas.config.AppConfig.MANDATORY_MESSAGE; +import com.fasterxml.jackson.annotation.JsonProperty; import jakarta.validation.constraints.NotBlank; -import lombok.Data; - import java.util.List; - -import static io.openbas.config.AppConfig.MANDATORY_MESSAGE; +import lombok.Data; @Data public class ReportInput { - @NotBlank(message = MANDATORY_MESSAGE) - @JsonProperty("report_name") - private String name; + @NotBlank(message = MANDATORY_MESSAGE) + @JsonProperty("report_name") + private String name; - @JsonProperty("report_informations") - private List reportInformations; + @JsonProperty("report_informations") + private List reportInformations; - @JsonProperty("report_global_observation") - private String globalObservation; + @JsonProperty("report_global_observation") + private String globalObservation; } diff --git a/openbas-api/src/main/java/io/openbas/rest/scenario/ScenarioApi.java b/openbas-api/src/main/java/io/openbas/rest/scenario/ScenarioApi.java index c8f7a79641..7ad60e1509 100644 --- a/openbas-api/src/main/java/io/openbas/rest/scenario/ScenarioApi.java +++ b/openbas-api/src/main/java/io/openbas/rest/scenario/ScenarioApi.java @@ -1,5 +1,13 @@ package io.openbas.rest.scenario; +import static io.openbas.database.model.User.ROLE_ADMIN; +import static io.openbas.database.model.User.ROLE_USER; +import static io.openbas.database.specification.ScenarioSpecification.byName; +import static io.openbas.helper.StreamHelper.fromIterable; +import static io.openbas.helper.StreamHelper.iterableToSet; +import static java.time.Instant.now; +import static java.time.temporal.ChronoUnit.MINUTES; + import io.openbas.aop.LogExecutionTime; import io.openbas.database.model.*; import io.openbas.database.raw.RawPaginationScenario; @@ -20,6 +28,8 @@ import jakarta.validation.Valid; import jakarta.validation.constraints.NotBlank; import jakarta.validation.constraints.NotNull; +import java.io.IOException; +import java.util.List; import lombok.RequiredArgsConstructor; import org.springframework.data.domain.Page; import org.springframework.data.domain.PageRequest; @@ -31,17 +41,6 @@ import org.springframework.web.multipart.MultipartFile; import org.springframework.web.server.ResponseStatusException; -import java.io.IOException; -import java.util.List; - -import static io.openbas.database.model.User.ROLE_ADMIN; -import static io.openbas.database.model.User.ROLE_USER; -import static io.openbas.database.specification.ScenarioSpecification.byName; -import static io.openbas.helper.StreamHelper.fromIterable; -import static io.openbas.helper.StreamHelper.iterableToSet; -import static java.time.Instant.now; -import static java.time.temporal.ChronoUnit.MINUTES; - @RestController @Secured(ROLE_USER) @RequiredArgsConstructor @@ -61,7 +60,6 @@ public class ScenarioApi extends RestBehavior { private final ScenarioRepository scenarioRepository; private final ScenarioToExerciseService scenarioToExerciseService; - @PostMapping(SCENARIO_URI) public Scenario createScenario(@Valid @RequestBody final ScenarioInput input) { if (input == null) { @@ -85,7 +83,8 @@ public List scenarios() { @LogExecutionTime @PostMapping(SCENARIO_URI + "/search") - public Page scenarios(@RequestBody @Valid final SearchPaginationInput searchPaginationInput) { + public Page scenarios( + @RequestBody @Valid final SearchPaginationInput searchPaginationInput) { return this.scenarioService.scenarios(searchPaginationInput); } @@ -145,7 +144,8 @@ public void exportScenario( @RequestParam(required = false) final boolean isWithVariableValues, HttpServletResponse response) throws IOException { - this.scenarioService.exportScenario(scenarioId, isWithTeams, isWithPlayers, isWithVariableValues, response); + this.scenarioService.exportScenario( + scenarioId, isWithTeams, isWithPlayers, isWithVariableValues, response); } // -- IMPORT -- @@ -161,8 +161,12 @@ public void importScenario(@RequestPart("file") @NotNull MultipartFile file) thr @GetMapping(SCENARIO_URI + "/{scenarioId}/teams") @PreAuthorize("isScenarioObserver(#scenarioId)") public Iterable scenarioTeams(@PathVariable @NotBlank final String scenarioId) { - return TeamHelper.rawTeamToSimplerTeam(teamRepository.rawTeamByScenarioId(scenarioId), - injectExpectationRepository, injectRepository, communicationRepository, exerciseTeamUserRepository, + return TeamHelper.rawTeamToSimplerTeam( + teamRepository.rawTeamByScenarioId(scenarioId), + injectExpectationRepository, + injectRepository, + communicationRepository, + exerciseTeamUserRepository, scenarioRepository); } @@ -256,8 +260,11 @@ public Scenario updateScenarioRecurrence( // -- OPTION -- @GetMapping(SCENARIO_URI + "/options") - public List optionsByName(@RequestParam(required = false) final String searchText) { - return fromIterable(this.scenarioRepository.findAll(byName(searchText), Sort.by(Sort.Direction.ASC, "name"))) + public List optionsByName( + @RequestParam(required = false) final String searchText) { + return fromIterable( + this.scenarioRepository.findAll( + byName(searchText), Sort.by(Sort.Direction.ASC, "name"))) .stream() .map(i -> new FilterUtilsJpa.Option(i.getId(), i.getName())) .toList(); @@ -265,15 +272,16 @@ public List optionsByName(@RequestParam(required = false) @PostMapping(SCENARIO_URI + "/options") public List optionsById(@RequestBody final List ids) { - return fromIterable(this.scenarioRepository.findAllById(ids)) - .stream() + return fromIterable(this.scenarioRepository.findAllById(ids)).stream() .map(i -> new FilterUtilsJpa.Option(i.getId(), i.getName())) .toList(); } @GetMapping(SCENARIO_URI + "/category/options") - public List categoryOptionsByName(@RequestParam(required = false) final String searchText) { - return this.scenarioRepository.findDistinctCategoriesBySearchTerm(searchText, PageRequest.of(0, 10)) + public List categoryOptionsByName( + @RequestParam(required = false) final String searchText) { + return this.scenarioRepository + .findDistinctCategoriesBySearchTerm(searchText, PageRequest.of(0, 10)) .stream() .map(i -> new FilterUtilsJpa.Option(i, i)) .toList(); @@ -283,8 +291,8 @@ public List categoryOptionsByName(@RequestParam(required @PutMapping(SCENARIO_URI + "/{scenarioId}/lessons") @PreAuthorize("isScenarioPlanner(#scenarioId)") @Transactional(rollbackOn = Exception.class) - public Scenario updateScenarioLessons(@PathVariable String scenarioId, - @Valid @RequestBody LessonsInput input) { + public Scenario updateScenarioLessons( + @PathVariable String scenarioId, @Valid @RequestBody LessonsInput input) { Scenario scenario = this.scenarioService.scenario(scenarioId); scenario.setLessonsAnonymized(input.isLessonsAnonymized()); return scenarioRepository.save(scenario); @@ -293,9 +301,10 @@ public Scenario updateScenarioLessons(@PathVariable String scenarioId, // EXERCISE @PostMapping(SCENARIO_URI + "/{scenarioId}/exercise/running") @PreAuthorize("isScenarioPlanner(#scenarioId)") - public Exercise createRunningExerciseFromScenario(@PathVariable @NotBlank final String scenarioId) { + public Exercise createRunningExerciseFromScenario( + @PathVariable @NotBlank final String scenarioId) { Scenario scenario = this.scenarioService.scenario(scenarioId); - return scenarioToExerciseService.toExercise(scenario, now().truncatedTo(MINUTES).plus(1, MINUTES), true); + return scenarioToExerciseService.toExercise( + scenario, now().truncatedTo(MINUTES).plus(1, MINUTES), true); } - } diff --git a/openbas-api/src/main/java/io/openbas/rest/scenario/ScenarioExerciseApi.java b/openbas-api/src/main/java/io/openbas/rest/scenario/ScenarioExerciseApi.java index ac1efe5fdc..d189b32087 100644 --- a/openbas-api/src/main/java/io/openbas/rest/scenario/ScenarioExerciseApi.java +++ b/openbas-api/src/main/java/io/openbas/rest/scenario/ScenarioExerciseApi.java @@ -1,5 +1,10 @@ package io.openbas.rest.scenario; +import static io.openbas.database.model.User.ROLE_USER; +import static io.openbas.database.specification.ExerciseSpecification.fromScenario; +import static io.openbas.rest.scenario.ScenarioApi.SCENARIO_URI; +import static io.openbas.utils.pagination.PaginationUtils.buildPaginationCriteriaBuilder; + import io.openbas.aop.LogExecutionTime; import io.openbas.database.model.Exercise; import io.openbas.rest.exercise.ExerciseService; @@ -14,11 +19,6 @@ import org.springframework.security.access.prepost.PreAuthorize; import org.springframework.web.bind.annotation.*; -import static io.openbas.database.model.User.ROLE_USER; -import static io.openbas.database.specification.ExerciseSpecification.fromScenario; -import static io.openbas.rest.scenario.ScenarioApi.SCENARIO_URI; -import static io.openbas.utils.pagination.PaginationUtils.buildPaginationCriteriaBuilder; - @RestController @Secured(ROLE_USER) @RequiredArgsConstructor @@ -29,7 +29,8 @@ public class ScenarioExerciseApi { @LogExecutionTime @GetMapping(SCENARIO_URI + "/{scenarioId}/exercises") @PreAuthorize("isScenarioObserver(#scenarioId)") - public Iterable scenarioExercises(@PathVariable @NotBlank final String scenarioId) { + public Iterable scenarioExercises( + @PathVariable @NotBlank final String scenarioId) { return exerciseService.scenarioExercises(scenarioId); } @@ -40,14 +41,14 @@ public Iterable scenarioExercises( @PathVariable @NotBlank final String scenarioId, @RequestBody @Valid final SearchPaginationInput searchPaginationInput) { return buildPaginationCriteriaBuilder( - (Specification specification, Specification specificationCount, Pageable pageable) -> this.exerciseService.exercises( - fromScenario(scenarioId).and(specification), - fromScenario(scenarioId).and(specificationCount), - pageable - ), + (Specification specification, + Specification specificationCount, + Pageable pageable) -> + this.exerciseService.exercises( + fromScenario(scenarioId).and(specification), + fromScenario(scenarioId).and(specificationCount), + pageable), searchPaginationInput, - Exercise.class - ); + Exercise.class); } - } diff --git a/openbas-api/src/main/java/io/openbas/rest/scenario/ScenarioImportApi.java b/openbas-api/src/main/java/io/openbas/rest/scenario/ScenarioImportApi.java index 3afeea9e20..712beed769 100644 --- a/openbas-api/src/main/java/io/openbas/rest/scenario/ScenarioImportApi.java +++ b/openbas-api/src/main/java/io/openbas/rest/scenario/ScenarioImportApi.java @@ -1,5 +1,8 @@ package io.openbas.rest.scenario; +import static io.openbas.database.model.User.ROLE_USER; +import static io.openbas.rest.scenario.ScenarioApi.SCENARIO_URI; + import io.openbas.database.model.ImportMapper; import io.openbas.database.model.Scenario; import io.openbas.database.repository.ImportMapperRepository; @@ -13,6 +16,7 @@ import jakarta.transaction.Transactional; import jakarta.validation.Valid; import jakarta.validation.constraints.NotBlank; +import java.util.UUID; import lombok.RequiredArgsConstructor; import lombok.extern.java.Log; import org.springframework.security.access.annotation.Secured; @@ -21,58 +25,67 @@ import org.springframework.web.bind.annotation.RequestBody; import org.springframework.web.bind.annotation.RestController; -import java.util.UUID; - -import static io.openbas.database.model.User.ROLE_USER; -import static io.openbas.rest.scenario.ScenarioApi.SCENARIO_URI; - @RestController @RequiredArgsConstructor @Log public class ScenarioImportApi extends RestBehavior { - private final InjectService injectService; - private final ImportMapperRepository importMapperRepository; - private final ScenarioService scenarioService; + private final InjectService injectService; + private final ImportMapperRepository importMapperRepository; + private final ScenarioService scenarioService; - @PostMapping(SCENARIO_URI + "/{scenarioId}/xls/{importId}/dry") - @Transactional(rollbackOn = Exception.class) - @Operation(summary = "Test the import of injects from an xls file") - @Secured(ROLE_USER) - public ImportTestSummary dryRunImportXLSFile(@PathVariable @NotBlank final String scenarioId, - @PathVariable @NotBlank final String importId, - @Valid @RequestBody final InjectsImportInput input) { - Scenario scenario = scenarioService.scenario(scenarioId); + @PostMapping(SCENARIO_URI + "/{scenarioId}/xls/{importId}/dry") + @Transactional(rollbackOn = Exception.class) + @Operation(summary = "Test the import of injects from an xls file") + @Secured(ROLE_USER) + public ImportTestSummary dryRunImportXLSFile( + @PathVariable @NotBlank final String scenarioId, + @PathVariable @NotBlank final String importId, + @Valid @RequestBody final InjectsImportInput input) { + Scenario scenario = scenarioService.scenario(scenarioId); - // Getting the mapper to use - ImportMapper importMapper = importMapperRepository - .findById(UUID.fromString(input.getImportMapperId())) - .orElseThrow(() -> new ElementNotFoundException(String.format("The import mapper %s was not found", input.getImportMapperId()))); + // Getting the mapper to use + ImportMapper importMapper = + importMapperRepository + .findById(UUID.fromString(input.getImportMapperId())) + .orElseThrow( + () -> + new ElementNotFoundException( + String.format( + "The import mapper %s was not found", input.getImportMapperId()))); - return injectService.importInjectIntoScenarioFromXLS(scenario, importMapper, importId, input.getName(), input.getTimezoneOffset(), false); - } + return injectService.importInjectIntoScenarioFromXLS( + scenario, importMapper, importId, input.getName(), input.getTimezoneOffset(), false); + } - @PostMapping(SCENARIO_URI + "/{scenarioId}/xls/{importId}/import") - @Transactional(rollbackOn = Exception.class) - @Operation(summary = "Validate and import injects from an xls file") - @Secured(ROLE_USER) - public ImportTestSummary validateImportXLSFile(@PathVariable @NotBlank final String scenarioId, - @PathVariable @NotBlank final String importId, - @Valid @RequestBody final InjectsImportInput input) { - Scenario scenario = scenarioService.scenario(scenarioId); + @PostMapping(SCENARIO_URI + "/{scenarioId}/xls/{importId}/import") + @Transactional(rollbackOn = Exception.class) + @Operation(summary = "Validate and import injects from an xls file") + @Secured(ROLE_USER) + public ImportTestSummary validateImportXLSFile( + @PathVariable @NotBlank final String scenarioId, + @PathVariable @NotBlank final String importId, + @Valid @RequestBody final InjectsImportInput input) { + Scenario scenario = scenarioService.scenario(scenarioId); - if(input.getLaunchDate() != null) { - scenario.setRecurrenceStart(input.getLaunchDate().toInstant()); - } + if (input.getLaunchDate() != null) { + scenario.setRecurrenceStart(input.getLaunchDate().toInstant()); + } - // Getting the mapper to use - ImportMapper importMapper = importMapperRepository - .findById(UUID.fromString(input.getImportMapperId())) - .orElseThrow(() -> new ElementNotFoundException(String.format("The import mapper %s was not found", input.getImportMapperId()))); + // Getting the mapper to use + ImportMapper importMapper = + importMapperRepository + .findById(UUID.fromString(input.getImportMapperId())) + .orElseThrow( + () -> + new ElementNotFoundException( + String.format( + "The import mapper %s was not found", input.getImportMapperId()))); - ImportTestSummary importTestSummary = injectService.importInjectIntoScenarioFromXLS(scenario, importMapper, importId, - input.getName(), input.getTimezoneOffset(), true); - scenarioService.updateScenario(scenario); - return importTestSummary; - } + ImportTestSummary importTestSummary = + injectService.importInjectIntoScenarioFromXLS( + scenario, importMapper, importId, input.getName(), input.getTimezoneOffset(), true); + scenarioService.updateScenario(scenario); + return importTestSummary; + } } diff --git a/openbas-api/src/main/java/io/openbas/rest/scenario/ScenarioStatisticApi.java b/openbas-api/src/main/java/io/openbas/rest/scenario/ScenarioStatisticApi.java index ecd675ba06..681176caea 100644 --- a/openbas-api/src/main/java/io/openbas/rest/scenario/ScenarioStatisticApi.java +++ b/openbas-api/src/main/java/io/openbas/rest/scenario/ScenarioStatisticApi.java @@ -1,20 +1,19 @@ package io.openbas.rest.scenario; +import static io.openbas.rest.scenario.ScenarioApi.SCENARIO_URI; +import static org.springframework.util.StringUtils.hasText; + import io.openbas.database.repository.ScenarioRepository; import io.openbas.rest.helper.RestBehavior; import io.openbas.rest.scenario.response.ScenarioStatistic; import io.swagger.v3.oas.annotations.Operation; import jakarta.transaction.Transactional; -import lombok.RequiredArgsConstructor; -import org.springframework.web.bind.annotation.GetMapping; -import org.springframework.web.bind.annotation.RestController; - import java.util.LinkedHashMap; import java.util.List; import java.util.Map; - -import static io.openbas.rest.scenario.ScenarioApi.SCENARIO_URI; -import static org.springframework.util.StringUtils.hasText; +import lombok.RequiredArgsConstructor; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.RestController; @RestController @RequiredArgsConstructor @@ -44,5 +43,4 @@ private Map findTopCategories() { } return categoryCount; } - } diff --git a/openbas-api/src/main/java/io/openbas/rest/scenario/export/ScenarioExportMixins.java b/openbas-api/src/main/java/io/openbas/rest/scenario/export/ScenarioExportMixins.java index 9bfabae7b1..2fba1fc11e 100644 --- a/openbas-api/src/main/java/io/openbas/rest/scenario/export/ScenarioExportMixins.java +++ b/openbas-api/src/main/java/io/openbas/rest/scenario/export/ScenarioExportMixins.java @@ -5,25 +5,23 @@ public class ScenarioExportMixins { - @JsonIncludeProperties(value = { - "scenario_id", - "scenario_name", - "scenario_description", - "scenario_subtitle", - "scenario_category", - "scenario_main_focus", - "scenario_severity", - "scenario_message_header", - "scenario_message_footer", - "scenario_mail_from", - "scenario_tags", - "scenario_documents", - }) - public static class Scenario { - } + @JsonIncludeProperties( + value = { + "scenario_id", + "scenario_name", + "scenario_description", + "scenario_subtitle", + "scenario_category", + "scenario_main_focus", + "scenario_severity", + "scenario_message_header", + "scenario_message_footer", + "scenario_mail_from", + "scenario_tags", + "scenario_documents", + }) + public static class Scenario {} @JsonIgnoreProperties(value = {"scenario_users", "scenario_organizations"}) - public static class ScenarioWithoutPlayers { - } - + public static class ScenarioWithoutPlayers {} } diff --git a/openbas-api/src/main/java/io/openbas/rest/scenario/export/ScenarioFileExport.java b/openbas-api/src/main/java/io/openbas/rest/scenario/export/ScenarioFileExport.java index f3bb4c964b..a061679322 100644 --- a/openbas-api/src/main/java/io/openbas/rest/scenario/export/ScenarioFileExport.java +++ b/openbas-api/src/main/java/io/openbas/rest/scenario/export/ScenarioFileExport.java @@ -1,15 +1,14 @@ package io.openbas.rest.scenario.export; +import static com.fasterxml.jackson.annotation.JsonInclude.Include.NON_NULL; + import com.fasterxml.jackson.annotation.JsonIgnore; import com.fasterxml.jackson.annotation.JsonInclude; import com.fasterxml.jackson.annotation.JsonProperty; import io.openbas.database.model.*; -import lombok.Data; - import java.util.ArrayList; import java.util.List; - -import static com.fasterxml.jackson.annotation.JsonInclude.Include.NON_NULL; +import lombok.Data; @Data @JsonInclude(NON_NULL) @@ -57,9 +56,8 @@ public class ScenarioFileExport { @JsonProperty("scenario_lessons_questions") private List lessonsQuestions = new ArrayList<>(); - @JsonIgnore - public static final String SCENARIO_VARIABLES = "scenario_variables"; + @JsonIgnore public static final String SCENARIO_VARIABLES = "scenario_variables"; + @JsonProperty(SCENARIO_VARIABLES) private List variables; - } diff --git a/openbas-api/src/main/java/io/openbas/rest/scenario/form/InjectsImportInput.java b/openbas-api/src/main/java/io/openbas/rest/scenario/form/InjectsImportInput.java index 9376a10be1..4bec76ad56 100644 --- a/openbas-api/src/main/java/io/openbas/rest/scenario/form/InjectsImportInput.java +++ b/openbas-api/src/main/java/io/openbas/rest/scenario/form/InjectsImportInput.java @@ -1,13 +1,12 @@ package io.openbas.rest.scenario.form; +import static io.openbas.config.AppConfig.MANDATORY_MESSAGE; + import com.fasterxml.jackson.annotation.JsonProperty; import jakarta.validation.constraints.NotBlank; import jakarta.validation.constraints.NotNull; -import lombok.Data; - import java.util.Date; - -import static io.openbas.config.AppConfig.MANDATORY_MESSAGE; +import lombok.Data; @Data public class InjectsImportInput { diff --git a/openbas-api/src/main/java/io/openbas/rest/scenario/form/InjectsImportTestInput.java b/openbas-api/src/main/java/io/openbas/rest/scenario/form/InjectsImportTestInput.java index 77d825a0fc..05f05c4437 100644 --- a/openbas-api/src/main/java/io/openbas/rest/scenario/form/InjectsImportTestInput.java +++ b/openbas-api/src/main/java/io/openbas/rest/scenario/form/InjectsImportTestInput.java @@ -1,13 +1,13 @@ package io.openbas.rest.scenario.form; +import static io.openbas.config.AppConfig.MANDATORY_MESSAGE; + import com.fasterxml.jackson.annotation.JsonProperty; import io.openbas.rest.mapper.form.ImportMapperAddInput; import jakarta.validation.constraints.NotBlank; import jakarta.validation.constraints.NotNull; import lombok.Data; -import static io.openbas.config.AppConfig.MANDATORY_MESSAGE; - @Data public class InjectsImportTestInput { diff --git a/openbas-api/src/main/java/io/openbas/rest/scenario/form/ScenarioInformationInput.java b/openbas-api/src/main/java/io/openbas/rest/scenario/form/ScenarioInformationInput.java index b6221e2069..75d13fdcd7 100644 --- a/openbas-api/src/main/java/io/openbas/rest/scenario/form/ScenarioInformationInput.java +++ b/openbas-api/src/main/java/io/openbas/rest/scenario/form/ScenarioInformationInput.java @@ -1,13 +1,12 @@ package io.openbas.rest.scenario.form; +import static io.openbas.config.AppConfig.EMAIL_FORMAT; + import com.fasterxml.jackson.annotation.JsonProperty; import jakarta.validation.constraints.Email; import jakarta.validation.constraints.NotBlank; -import lombok.Data; - import java.util.List; - -import static io.openbas.config.AppConfig.EMAIL_FORMAT; +import lombok.Data; @Data public class ScenarioInformationInput { @@ -25,5 +24,4 @@ public class ScenarioInformationInput { @JsonProperty("scenario_message_footer") private String footer; - } diff --git a/openbas-api/src/main/java/io/openbas/rest/scenario/form/ScenarioInput.java b/openbas-api/src/main/java/io/openbas/rest/scenario/form/ScenarioInput.java index 386bedbda4..7c98c9ff2a 100644 --- a/openbas-api/src/main/java/io/openbas/rest/scenario/form/ScenarioInput.java +++ b/openbas-api/src/main/java/io/openbas/rest/scenario/form/ScenarioInput.java @@ -1,15 +1,14 @@ package io.openbas.rest.scenario.form; +import static io.openbas.config.AppConfig.MANDATORY_MESSAGE; + import com.fasterxml.jackson.annotation.JsonProperty; import io.openbas.database.model.Scenario.SEVERITY; import jakarta.annotation.Nullable; import jakarta.validation.constraints.NotBlank; -import lombok.Data; - import java.util.ArrayList; import java.util.List; - -import static io.openbas.config.AppConfig.MANDATORY_MESSAGE; +import lombok.Data; @Data public class ScenarioInput { @@ -46,5 +45,4 @@ public class ScenarioInput { @JsonProperty("scenario_tags") private List tagIds = new ArrayList<>(); - } diff --git a/openbas-api/src/main/java/io/openbas/rest/scenario/form/ScenarioRecurrenceInput.java b/openbas-api/src/main/java/io/openbas/rest/scenario/form/ScenarioRecurrenceInput.java index 8e6b1faf90..fde5ad7b2c 100644 --- a/openbas-api/src/main/java/io/openbas/rest/scenario/form/ScenarioRecurrenceInput.java +++ b/openbas-api/src/main/java/io/openbas/rest/scenario/form/ScenarioRecurrenceInput.java @@ -1,9 +1,8 @@ package io.openbas.rest.scenario.form; import com.fasterxml.jackson.annotation.JsonProperty; -import lombok.Data; - import java.time.Instant; +import lombok.Data; @Data public class ScenarioRecurrenceInput { diff --git a/openbas-api/src/main/java/io/openbas/rest/scenario/form/ScenarioSimple.java b/openbas-api/src/main/java/io/openbas/rest/scenario/form/ScenarioSimple.java index 11a00f68a6..904eac6218 100644 --- a/openbas-api/src/main/java/io/openbas/rest/scenario/form/ScenarioSimple.java +++ b/openbas-api/src/main/java/io/openbas/rest/scenario/form/ScenarioSimple.java @@ -7,12 +7,11 @@ import io.openbas.database.raw.RawScenario; import io.openbas.helper.MultiIdSetDeserializer; import jakarta.validation.constraints.NotNull; -import lombok.Data; -import org.springframework.beans.BeanUtils; - import java.util.HashSet; import java.util.Set; import java.util.stream.Collectors; +import lombok.Data; +import org.springframework.beans.BeanUtils; @Data public class ScenarioSimple { @@ -42,16 +41,18 @@ public static ScenarioSimple fromRawScenario(@NotNull final RawScenario scenario simple.setName(scenario.getScenario_name()); simple.setSubtitle(scenario.getScenario_subtitle()); if (scenario.getScenario_tags() != null) { - simple.setTags(scenario.getScenario_tags().stream().map((tagId) -> { - Tag tag = new Tag(); - tag.setId(tagId); - return tag; - } - ).collect(Collectors.toSet())); + simple.setTags( + scenario.getScenario_tags().stream() + .map( + (tagId) -> { + Tag tag = new Tag(); + tag.setId(tagId); + return tag; + }) + .collect(Collectors.toSet())); } else { simple.setTags(new HashSet<>()); } return simple; } - } diff --git a/openbas-api/src/main/java/io/openbas/rest/scenario/form/ScenarioUpdateTagsInput.java b/openbas-api/src/main/java/io/openbas/rest/scenario/form/ScenarioUpdateTagsInput.java index 6551a7da59..c1cec13872 100644 --- a/openbas-api/src/main/java/io/openbas/rest/scenario/form/ScenarioUpdateTagsInput.java +++ b/openbas-api/src/main/java/io/openbas/rest/scenario/form/ScenarioUpdateTagsInput.java @@ -1,11 +1,10 @@ package io.openbas.rest.scenario.form; import com.fasterxml.jackson.annotation.JsonProperty; -import lombok.Getter; -import lombok.Setter; - import java.util.ArrayList; import java.util.List; +import lombok.Getter; +import lombok.Setter; @Setter @Getter @@ -13,5 +12,4 @@ public class ScenarioUpdateTagsInput { @JsonProperty("scenario_tags") private List tagIds = new ArrayList<>(); - } diff --git a/openbas-api/src/main/java/io/openbas/rest/scenario/form/ScenarioUpdateTeamsInput.java b/openbas-api/src/main/java/io/openbas/rest/scenario/form/ScenarioUpdateTeamsInput.java index e457107d8e..0e353efd24 100644 --- a/openbas-api/src/main/java/io/openbas/rest/scenario/form/ScenarioUpdateTeamsInput.java +++ b/openbas-api/src/main/java/io/openbas/rest/scenario/form/ScenarioUpdateTeamsInput.java @@ -1,15 +1,13 @@ package io.openbas.rest.scenario.form; import com.fasterxml.jackson.annotation.JsonProperty; -import lombok.Data; - import java.util.ArrayList; import java.util.List; +import lombok.Data; @Data public class ScenarioUpdateTeamsInput { @JsonProperty("scenario_teams") private List teamIds = new ArrayList<>(); - } diff --git a/openbas-api/src/main/java/io/openbas/rest/scenario/response/ImportMessage.java b/openbas-api/src/main/java/io/openbas/rest/scenario/response/ImportMessage.java index fabeb30316..a440bade7b 100644 --- a/openbas-api/src/main/java/io/openbas/rest/scenario/response/ImportMessage.java +++ b/openbas-api/src/main/java/io/openbas/rest/scenario/response/ImportMessage.java @@ -1,11 +1,10 @@ package io.openbas.rest.scenario.response; import com.fasterxml.jackson.annotation.JsonProperty; +import java.util.Map; import lombok.Data; import lombok.NoArgsConstructor; -import java.util.Map; - @Data @NoArgsConstructor public class ImportMessage { @@ -15,12 +14,13 @@ public enum MessageLevel { WARN, INFO } + public enum ErrorCode { NO_POTENTIAL_MATCH_FOUND("no_potential_match_found"), - SEVERAL_MATCHES ("several_matches"), - ABSOLUTE_TIME_WITHOUT_START_DATE ("absolute_time_without_start_date"), - DATE_SET_IN_PAST ("date_set_in_past"), - DATE_SET_IN_FUTURE ("date_set_in_future"), + SEVERAL_MATCHES("several_matches"), + ABSOLUTE_TIME_WITHOUT_START_DATE("absolute_time_without_start_date"), + DATE_SET_IN_PAST("date_set_in_past"), + DATE_SET_IN_FUTURE("date_set_in_future"), NO_TEAM_FOUND("no_team_found"), EXPECTATION_SCORE_UNDEFINED("expectation_score_undefined"); @@ -50,5 +50,4 @@ public ImportMessage(MessageLevel level, ErrorCode errorCode) { this.messageLevel = level; this.errorCode = errorCode; } - } diff --git a/openbas-api/src/main/java/io/openbas/rest/scenario/response/ImportPostSummary.java b/openbas-api/src/main/java/io/openbas/rest/scenario/response/ImportPostSummary.java index 6a60a25afc..d7929cf853 100644 --- a/openbas-api/src/main/java/io/openbas/rest/scenario/response/ImportPostSummary.java +++ b/openbas-api/src/main/java/io/openbas/rest/scenario/response/ImportPostSummary.java @@ -3,9 +3,8 @@ import com.fasterxml.jackson.annotation.JsonProperty; import jakarta.validation.constraints.NotBlank; import jakarta.validation.constraints.NotNull; -import lombok.Data; - import java.util.List; +import lombok.Data; @Data public class ImportPostSummary { @@ -17,5 +16,4 @@ public class ImportPostSummary { @JsonProperty("available_sheets") @NotNull private List availableSheets; - } diff --git a/openbas-api/src/main/java/io/openbas/rest/scenario/response/ImportTestSummary.java b/openbas-api/src/main/java/io/openbas/rest/scenario/response/ImportTestSummary.java index ae7b94698f..7af85fb103 100644 --- a/openbas-api/src/main/java/io/openbas/rest/scenario/response/ImportTestSummary.java +++ b/openbas-api/src/main/java/io/openbas/rest/scenario/response/ImportTestSummary.java @@ -5,10 +5,9 @@ import io.openbas.database.model.Inject; import io.openbas.rest.atomic_testing.form.InjectResultDTO; import io.openbas.utils.AtomicTestingMapper; -import lombok.Data; - import java.util.ArrayList; import java.util.List; +import lombok.Data; @Data public class ImportTestSummary { @@ -19,12 +18,10 @@ public class ImportTestSummary { @JsonProperty("total_injects") public int totalNumberOfInjects; - @JsonIgnore - private List injects = new ArrayList<>(); + @JsonIgnore private List injects = new ArrayList<>(); @JsonProperty("injects") public List getInjectResults() { return injects.stream().map(AtomicTestingMapper::toDtoWithTargetResults).toList(); } - } diff --git a/openbas-api/src/main/java/io/openbas/rest/scenario/response/ScenarioStatistic.java b/openbas-api/src/main/java/io/openbas/rest/scenario/response/ScenarioStatistic.java index 06dea12d16..95bf266932 100644 --- a/openbas-api/src/main/java/io/openbas/rest/scenario/response/ScenarioStatistic.java +++ b/openbas-api/src/main/java/io/openbas/rest/scenario/response/ScenarioStatistic.java @@ -1,9 +1,8 @@ package io.openbas.rest.scenario.response; import com.fasterxml.jackson.annotation.JsonProperty; -import lombok.Data; - import java.util.Map; +import lombok.Data; @Data public class ScenarioStatistic { @@ -13,5 +12,4 @@ public class ScenarioStatistic { @JsonProperty("scenarios_attack_scenario_count") private Map scenariosCategoriesCount; - } diff --git a/openbas-api/src/main/java/io/openbas/rest/scenario/utils/ScenarioUtils.java b/openbas-api/src/main/java/io/openbas/rest/scenario/utils/ScenarioUtils.java index e038cfef3f..bf1eeb072d 100644 --- a/openbas-api/src/main/java/io/openbas/rest/scenario/utils/ScenarioUtils.java +++ b/openbas-api/src/main/java/io/openbas/rest/scenario/utils/ScenarioUtils.java @@ -1,34 +1,30 @@ package io.openbas.rest.scenario.utils; +import static io.openbas.utils.CustomFilterUtils.computeMode; +import static java.util.Optional.ofNullable; + import io.openbas.database.model.Filters; import io.openbas.database.model.Scenario; import io.openbas.database.specification.ScenarioSpecification; import io.openbas.utils.pagination.SearchPaginationInput; -import org.jetbrains.annotations.NotNull; -import org.springframework.data.jpa.domain.Specification; - import java.util.Optional; import java.util.function.UnaryOperator; - -import static io.openbas.utils.CustomFilterUtils.computeMode; -import static java.util.Optional.ofNullable; +import org.jetbrains.annotations.NotNull; +import org.springframework.data.jpa.domain.Specification; public class ScenarioUtils { - private ScenarioUtils() { - - } + private ScenarioUtils() {} private static final String SCENARIO_RECURRENCE_FILTER = "scenario_recurrence"; - /** - * Manage filters that are not directly managed by the generic mechanics - */ + /** Manage filters that are not directly managed by the generic mechanics */ public static UnaryOperator> handleCustomFilter( @NotNull final SearchPaginationInput searchPaginationInput) { // Existence of the filter - Optional scenarioRecurrenceFilterOpt = ofNullable(searchPaginationInput.getFilterGroup()) - .flatMap(f -> f.findByKey(SCENARIO_RECURRENCE_FILTER)); + Optional scenarioRecurrenceFilterOpt = + ofNullable(searchPaginationInput.getFilterGroup()) + .flatMap(f -> f.findByKey(SCENARIO_RECURRENCE_FILTER)); if (scenarioRecurrenceFilterOpt.isPresent()) { // Purge filter @@ -47,5 +43,4 @@ public static UnaryOperator> handleCustomFilter( return (Specification specification) -> specification; } } - } diff --git a/openbas-api/src/main/java/io/openbas/rest/security/MethodSecurityConfig.java b/openbas-api/src/main/java/io/openbas/rest/security/MethodSecurityConfig.java index 80dd41b67b..7f7c9f186a 100644 --- a/openbas-api/src/main/java/io/openbas/rest/security/MethodSecurityConfig.java +++ b/openbas-api/src/main/java/io/openbas/rest/security/MethodSecurityConfig.java @@ -20,6 +20,7 @@ public class MethodSecurityConfig { @Bean MethodSecurityExpressionHandler methodSecurityExpressionHandler() { - return new SecurityExpressionHandler(this.userRepository, this.exerciseRepository, this.scenarioService); + return new SecurityExpressionHandler( + this.userRepository, this.exerciseRepository, this.scenarioService); } } diff --git a/openbas-api/src/main/java/io/openbas/rest/security/SecurityExpression.java b/openbas-api/src/main/java/io/openbas/rest/security/SecurityExpression.java index 75bbaad28f..380dcc0b80 100644 --- a/openbas-api/src/main/java/io/openbas/rest/security/SecurityExpression.java +++ b/openbas-api/src/main/java/io/openbas/rest/security/SecurityExpression.java @@ -1,5 +1,7 @@ package io.openbas.rest.security; +import static io.openbas.database.model.User.ROLE_ADMIN; + import io.openbas.config.OpenBASPrincipal; import io.openbas.database.model.Exercise; import io.openbas.database.model.Scenario; @@ -8,17 +10,15 @@ import io.openbas.database.repository.UserRepository; import io.openbas.service.ScenarioService; import jakarta.validation.constraints.NotBlank; +import java.util.List; +import java.util.Optional; import org.springframework.security.access.expression.SecurityExpressionRoot; import org.springframework.security.access.expression.method.MethodSecurityExpressionOperations; import org.springframework.security.core.Authentication; import org.springframework.security.core.GrantedAuthority; -import java.util.List; -import java.util.Optional; - -import static io.openbas.database.model.User.ROLE_ADMIN; - -public class SecurityExpression extends SecurityExpressionRoot implements MethodSecurityExpressionOperations { +public class SecurityExpression extends SecurityExpressionRoot + implements MethodSecurityExpressionOperations { private final UserRepository userRepository; private final ExerciseRepository exerciseRepository; @@ -42,15 +42,18 @@ public SecurityExpression( private OpenBASPrincipal getUser() { return (OpenBASPrincipal) this.getPrincipal(); } + public boolean isAdmin() { return isUserHasBypass(); } private boolean isUserHasBypass() { OpenBASPrincipal principal = getUser(); - return principal.getAuthorities().stream().map(GrantedAuthority::getAuthority) + return principal.getAuthorities().stream() + .map(GrantedAuthority::getAuthority) .anyMatch(s -> s.equals(ROLE_ADMIN)); } + // endregion // region exercise annotations @@ -61,8 +64,8 @@ public boolean isExercisePlanner(String exerciseId) { } Exercise exercise = exerciseRepository.findById(exerciseId).orElseThrow(); List planners = exercise.getPlanners(); - Optional planner = planners.stream() - .filter(user -> user.getId().equals(getUser().getId())).findAny(); + Optional planner = + planners.stream().filter(user -> user.getId().equals(getUser().getId())).findAny(); return planner.isPresent(); } @@ -73,8 +76,8 @@ public boolean isExerciseObserver(String exerciseId) { } Exercise exercise = exerciseRepository.findById(exerciseId).orElseThrow(); List observers = exercise.getObservers(); - Optional observer = observers.stream() - .filter(user -> user.getId().equals(getUser().getId())).findAny(); + Optional observer = + observers.stream().filter(user -> user.getId().equals(getUser().getId())).findAny(); return observer.isPresent(); } @@ -84,8 +87,8 @@ public boolean isExercisePlayer(String exerciseId) { } Exercise exercise = exerciseRepository.findById(exerciseId).orElseThrow(); List players = exercise.getUsers(); - Optional player = players.stream() - .filter(user -> user.getId().equals(getUser().getId())).findAny(); + Optional player = + players.stream().filter(user -> user.getId().equals(getUser().getId())).findAny(); return player.isPresent(); } @@ -93,6 +96,7 @@ public boolean isExercisePlayer(String exerciseId) { public boolean isExerciseObserverOrPlayer(String exerciseId) { return isExerciseObserver(exerciseId) || isExercisePlayer(exerciseId); } + // endregion // region scenario annotations @@ -103,8 +107,8 @@ public boolean isScenarioPlanner(@NotBlank final String scenarioId) { } Scenario scenario = this.scenarioService.scenario(scenarioId); List planners = scenario.getPlanners(); - Optional planner = planners.stream() - .filter(user -> user.getId().equals(getUser().getId())).findAny(); + Optional planner = + planners.stream().filter(user -> user.getId().equals(getUser().getId())).findAny(); return planner.isPresent(); } @@ -115,10 +119,11 @@ public boolean isScenarioObserver(@NotBlank final String scenarioId) { } Scenario scenario = this.scenarioService.scenario(scenarioId); List observers = scenario.getObservers(); - Optional observer = observers.stream() - .filter(user -> user.getId().equals(getUser().getId())).findAny(); + Optional observer = + observers.stream().filter(user -> user.getId().equals(getUser().getId())).findAny(); return observer.isPresent(); } + // endregion // region user annotations @@ -144,6 +149,7 @@ public boolean isPlayer() { User user = userRepository.findById(getUser().getId()).orElseThrow(); return user.isPlayer(); } + // endregion // region setters diff --git a/openbas-api/src/main/java/io/openbas/rest/security/SecurityExpressionHandler.java b/openbas-api/src/main/java/io/openbas/rest/security/SecurityExpressionHandler.java index a6f300f2d0..169b001a15 100644 --- a/openbas-api/src/main/java/io/openbas/rest/security/SecurityExpressionHandler.java +++ b/openbas-api/src/main/java/io/openbas/rest/security/SecurityExpressionHandler.java @@ -3,6 +3,7 @@ import io.openbas.database.repository.ExerciseRepository; import io.openbas.database.repository.UserRepository; import io.openbas.service.ScenarioService; +import java.util.function.Supplier; import org.aopalliance.intercept.MethodInvocation; import org.springframework.expression.EvaluationContext; import org.springframework.expression.spel.support.StandardEvaluationContext; @@ -12,8 +13,6 @@ import org.springframework.security.authentication.AuthenticationTrustResolverImpl; import org.springframework.security.core.Authentication; -import java.util.function.Supplier; - public class SecurityExpressionHandler extends DefaultMethodSecurityExpressionHandler { private final AuthenticationTrustResolver trustResolver = new AuthenticationTrustResolverImpl(); @@ -31,14 +30,19 @@ public SecurityExpressionHandler( } @Override - public EvaluationContext createEvaluationContext(Supplier authentication, - MethodInvocation invocation) { - StandardEvaluationContext context = (StandardEvaluationContext) super.createEvaluationContext(authentication, - invocation); - MethodSecurityExpressionOperations delegate = (MethodSecurityExpressionOperations) context.getRootObject() - .getValue(); + public EvaluationContext createEvaluationContext( + Supplier authentication, MethodInvocation invocation) { + StandardEvaluationContext context = + (StandardEvaluationContext) super.createEvaluationContext(authentication, invocation); + MethodSecurityExpressionOperations delegate = + (MethodSecurityExpressionOperations) context.getRootObject().getValue(); assert delegate != null; - SecurityExpression root = new SecurityExpression(delegate.getAuthentication(), this.userRepository, this.exerciseRepository, this.scenarioService); + SecurityExpression root = + new SecurityExpression( + delegate.getAuthentication(), + this.userRepository, + this.exerciseRepository, + this.scenarioService); root.setPermissionEvaluator(getPermissionEvaluator()); root.setTrustResolver(this.trustResolver); root.setRoleHierarchy(getRoleHierarchy()); diff --git a/openbas-api/src/main/java/io/openbas/rest/settings/PlatformSettingsApi.java b/openbas-api/src/main/java/io/openbas/rest/settings/PlatformSettingsApi.java index 9e87a095f0..6ba4900eaf 100644 --- a/openbas-api/src/main/java/io/openbas/rest/settings/PlatformSettingsApi.java +++ b/openbas-api/src/main/java/io/openbas/rest/settings/PlatformSettingsApi.java @@ -37,19 +37,22 @@ public PlatformSettings settings() { @Secured(ROLE_ADMIN) @PutMapping() - public PlatformSettings updateBasicConfigurationSettings(@Valid @RequestBody SettingsUpdateInput input) { + public PlatformSettings updateBasicConfigurationSettings( + @Valid @RequestBody SettingsUpdateInput input) { return platformSettingsService.updateBasicConfigurationSettings(input); } @Secured(ROLE_ADMIN) @PutMapping("/enterprise_edition") - public PlatformSettings updateSettingsEnterpriseEdition(@Valid @RequestBody SettingsEnterpriseEditionUpdateInput input) { + public PlatformSettings updateSettingsEnterpriseEdition( + @Valid @RequestBody SettingsEnterpriseEditionUpdateInput input) { return platformSettingsService.updateSettingsEnterpriseEdition(input); } @Secured(ROLE_ADMIN) @PutMapping("/platform_whitemark") - public PlatformSettings updateSettingsPlatformWhitemark(@Valid @RequestBody SettingsPlatformWhitemarkUpdateInput input) { + public PlatformSettings updateSettingsPlatformWhitemark( + @Valid @RequestBody SettingsPlatformWhitemarkUpdateInput input) { return platformSettingsService.updateSettingsPlatformWhitemark(input); } diff --git a/openbas-api/src/main/java/io/openbas/rest/settings/form/PolicyInput.java b/openbas-api/src/main/java/io/openbas/rest/settings/form/PolicyInput.java index f3e0a8685f..3eaad08bbb 100644 --- a/openbas-api/src/main/java/io/openbas/rest/settings/form/PolicyInput.java +++ b/openbas-api/src/main/java/io/openbas/rest/settings/form/PolicyInput.java @@ -8,13 +8,12 @@ @Getter public class PolicyInput { - @JsonProperty("platform_login_message") - private String loginMessage; + @JsonProperty("platform_login_message") + private String loginMessage; - @JsonProperty("platform_consent_message") - private String consentMessage; - - @JsonProperty("platform_consent_confirm_text") - private String consentConfirmText; + @JsonProperty("platform_consent_message") + private String consentMessage; + @JsonProperty("platform_consent_confirm_text") + private String consentConfirmText; } diff --git a/openbas-api/src/main/java/io/openbas/rest/settings/form/SettingsEnterpriseEditionUpdateInput.java b/openbas-api/src/main/java/io/openbas/rest/settings/form/SettingsEnterpriseEditionUpdateInput.java index bc9f2373ae..223f09297f 100644 --- a/openbas-api/src/main/java/io/openbas/rest/settings/form/SettingsEnterpriseEditionUpdateInput.java +++ b/openbas-api/src/main/java/io/openbas/rest/settings/form/SettingsEnterpriseEditionUpdateInput.java @@ -1,16 +1,16 @@ package io.openbas.rest.settings.form; +import static io.openbas.config.AppConfig.MANDATORY_MESSAGE; + import com.fasterxml.jackson.annotation.JsonProperty; import jakarta.validation.constraints.NotBlank; import lombok.Getter; import lombok.Setter; -import static io.openbas.config.AppConfig.MANDATORY_MESSAGE; - @Setter @Getter public class SettingsEnterpriseEditionUpdateInput { - @NotBlank(message = MANDATORY_MESSAGE) - @JsonProperty("platform_enterprise_edition") - private String enterpriseEdition; + @NotBlank(message = MANDATORY_MESSAGE) + @JsonProperty("platform_enterprise_edition") + private String enterpriseEdition; } diff --git a/openbas-api/src/main/java/io/openbas/rest/settings/form/SettingsPlatformWhitemarkUpdateInput.java b/openbas-api/src/main/java/io/openbas/rest/settings/form/SettingsPlatformWhitemarkUpdateInput.java index ac5313aeae..317eff612d 100644 --- a/openbas-api/src/main/java/io/openbas/rest/settings/form/SettingsPlatformWhitemarkUpdateInput.java +++ b/openbas-api/src/main/java/io/openbas/rest/settings/form/SettingsPlatformWhitemarkUpdateInput.java @@ -1,16 +1,16 @@ package io.openbas.rest.settings.form; +import static io.openbas.config.AppConfig.MANDATORY_MESSAGE; + import com.fasterxml.jackson.annotation.JsonProperty; import jakarta.validation.constraints.NotBlank; import lombok.Getter; import lombok.Setter; -import static io.openbas.config.AppConfig.MANDATORY_MESSAGE; - @Setter @Getter public class SettingsPlatformWhitemarkUpdateInput { - @NotBlank(message = MANDATORY_MESSAGE) - @JsonProperty("platform_whitemark") - private String platformWhitemark; + @NotBlank(message = MANDATORY_MESSAGE) + @JsonProperty("platform_whitemark") + private String platformWhitemark; } diff --git a/openbas-api/src/main/java/io/openbas/rest/settings/form/SettingsUpdateInput.java b/openbas-api/src/main/java/io/openbas/rest/settings/form/SettingsUpdateInput.java index 947a31135b..be37f5a01d 100644 --- a/openbas-api/src/main/java/io/openbas/rest/settings/form/SettingsUpdateInput.java +++ b/openbas-api/src/main/java/io/openbas/rest/settings/form/SettingsUpdateInput.java @@ -1,26 +1,25 @@ package io.openbas.rest.settings.form; -import com.fasterxml.jackson.annotation.JsonProperty; +import static io.openbas.config.AppConfig.MANDATORY_MESSAGE; +import com.fasterxml.jackson.annotation.JsonProperty; import jakarta.validation.constraints.NotBlank; import lombok.Getter; import lombok.Setter; -import static io.openbas.config.AppConfig.MANDATORY_MESSAGE; - @Setter @Getter public class SettingsUpdateInput { - @NotBlank(message = MANDATORY_MESSAGE) - @JsonProperty("platform_name") - private String name; + @NotBlank(message = MANDATORY_MESSAGE) + @JsonProperty("platform_name") + private String name; - @NotBlank(message = MANDATORY_MESSAGE) - @JsonProperty("platform_theme") - private String theme; + @NotBlank(message = MANDATORY_MESSAGE) + @JsonProperty("platform_theme") + private String theme; - @NotBlank(message = MANDATORY_MESSAGE) - @JsonProperty("platform_lang") - private String lang; + @NotBlank(message = MANDATORY_MESSAGE) + @JsonProperty("platform_lang") + private String lang; } diff --git a/openbas-api/src/main/java/io/openbas/rest/settings/form/ThemeInput.java b/openbas-api/src/main/java/io/openbas/rest/settings/form/ThemeInput.java index 0ce56a7fa0..ea5eefc97a 100644 --- a/openbas-api/src/main/java/io/openbas/rest/settings/form/ThemeInput.java +++ b/openbas-api/src/main/java/io/openbas/rest/settings/form/ThemeInput.java @@ -35,5 +35,4 @@ public class ThemeInput { @JsonProperty("logo_login_url") private String logoLoginUrl; - } diff --git a/openbas-api/src/main/java/io/openbas/rest/settings/response/OAuthProvider.java b/openbas-api/src/main/java/io/openbas/rest/settings/response/OAuthProvider.java index 95413ee526..aaee826c41 100644 --- a/openbas-api/src/main/java/io/openbas/rest/settings/response/OAuthProvider.java +++ b/openbas-api/src/main/java/io/openbas/rest/settings/response/OAuthProvider.java @@ -4,42 +4,42 @@ public class OAuthProvider { - @JsonProperty("provider_name") - private String name; + @JsonProperty("provider_name") + private String name; - @JsonProperty("provider_uri") - private String uri; + @JsonProperty("provider_uri") + private String uri; - @JsonProperty("provider_login") - private String login; + @JsonProperty("provider_login") + private String login; - public OAuthProvider(String name, String uri, String login) { - this.name = name; - this.uri = uri; - this.login = login; - } + public OAuthProvider(String name, String uri, String login) { + this.name = name; + this.uri = uri; + this.login = login; + } - public String getName() { - return name; - } + public String getName() { + return name; + } - public void setName(String name) { - this.name = name; - } + public void setName(String name) { + this.name = name; + } - public String getLogin() { - return login; - } + public String getLogin() { + return login; + } - public void setLogin(String login) { - this.login = login; - } + public void setLogin(String login) { + this.login = login; + } - public String getUri() { - return uri; - } + public String getUri() { + return uri; + } - public void setUri(String uri) { - this.uri = uri; - } + public void setUri(String uri) { + this.uri = uri; + } } diff --git a/openbas-api/src/main/java/io/openbas/rest/settings/response/PlatformSettings.java b/openbas-api/src/main/java/io/openbas/rest/settings/response/PlatformSettings.java index 49a230c46d..f65cf2f15d 100644 --- a/openbas-api/src/main/java/io/openbas/rest/settings/response/PlatformSettings.java +++ b/openbas-api/src/main/java/io/openbas/rest/settings/response/PlatformSettings.java @@ -1,20 +1,19 @@ package io.openbas.rest.settings.response; +import static lombok.AccessLevel.NONE; + import com.fasterxml.jackson.annotation.JsonProperty; import io.openbas.rest.settings.form.PolicyInput; import io.openbas.rest.settings.form.ThemeInput; import jakarta.validation.constraints.NotNull; -import lombok.AllArgsConstructor; -import lombok.Getter; -import lombok.NoArgsConstructor; -import lombok.Setter; - import java.util.ArrayList; import java.util.HashMap; import java.util.List; import java.util.Map; - -import static lombok.AccessLevel.NONE; +import lombok.AllArgsConstructor; +import lombok.Getter; +import lombok.NoArgsConstructor; +import lombok.Setter; @Setter @Getter @@ -127,8 +126,9 @@ public class PlatformSettings { public Map> getPlatformBannerByLevel() { Map> platformBannerByLevelLowerCase = new HashMap<>(); - if(this.platformBannerByLevel != null) { - this.platformBannerByLevel.forEach((key, value) -> platformBannerByLevelLowerCase.put(key.toLowerCase(), value)); + if (this.platformBannerByLevel != null) { + this.platformBannerByLevel.forEach( + (key, value) -> platformBannerByLevelLowerCase.put(key.toLowerCase(), value)); return platformBannerByLevelLowerCase; } return null; @@ -158,5 +158,4 @@ public Map> getPlatformBannerByLevel() { @NotNull @JsonProperty("expectation_manual_default_score_value") private int expectationDefaultScoreValue; - } diff --git a/openbas-api/src/main/java/io/openbas/rest/statistic/StatisticApi.java b/openbas-api/src/main/java/io/openbas/rest/statistic/StatisticApi.java index 4cf9bb4665..cded56a02e 100644 --- a/openbas-api/src/main/java/io/openbas/rest/statistic/StatisticApi.java +++ b/openbas-api/src/main/java/io/openbas/rest/statistic/StatisticApi.java @@ -1,5 +1,8 @@ package io.openbas.rest.statistic; +import static io.openbas.config.SessionHelper.currentUser; +import static io.openbas.helper.StreamHelper.fromIterable; + import io.openbas.config.OpenBASPrincipal; import io.openbas.database.model.AttackPattern; import io.openbas.database.raw.RawGlobalInjectExpectation; @@ -18,19 +21,15 @@ import io.swagger.v3.oas.annotations.responses.ApiResponse; import jakarta.transaction.Transactional; import jakarta.validation.constraints.NotNull; -import lombok.RequiredArgsConstructor; -import org.springframework.web.bind.annotation.GetMapping; -import org.springframework.web.bind.annotation.RestController; - import java.time.Instant; import java.time.temporal.ChronoUnit; import java.util.ArrayList; import java.util.List; import java.util.stream.Collectors; import java.util.stream.Stream; - -import static io.openbas.config.SessionHelper.currentUser; -import static io.openbas.helper.StreamHelper.fromIterable; +import lombok.RequiredArgsConstructor; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.RestController; @RestController @RequiredArgsConstructor @@ -47,9 +46,14 @@ public class StatisticApi extends RestBehavior { @GetMapping("/api/statistics") @Transactional(rollbackOn = Exception.class) @Operation(summary = "Retrieve platform statistics") - @ApiResponse(responseCode = "200", description = "Successful operation", content = { - @Content(mediaType = "application/json", schema = @Schema(implementation = PlatformStatistic.class)) - }) + @ApiResponse( + responseCode = "200", + description = "Successful operation", + content = { + @Content( + mediaType = "application/json", + schema = @Schema(implementation = PlatformStatistic.class)) + }) public PlatformStatistic platformStatistic() { Instant now = Instant.now(); PlatformStatistic statistic = new PlatformStatistic(); @@ -94,67 +98,89 @@ private StatisticElement computeUserStat(Instant from, StatisticRepository repos return new StatisticElement(global, progression); } - private List computeGlobalExpectationResults(@NotNull final Instant from) { - List rawInjectExpectations = fromIterable(this.exerciseRepository.allInjectExpectationsFromDate(from)); + private List computeGlobalExpectationResults( + @NotNull final Instant from) { + List rawInjectExpectations = + fromIterable(this.exerciseRepository.allInjectExpectationsFromDate(from)); return AtomicTestingUtils.getExpectationResultByTypesFromRaw(rawInjectExpectations); } - private List computeUserExpectationResults(@NotNull final Instant from) { + private List computeUserExpectationResults( + @NotNull final Instant from) { OpenBASPrincipal user = currentUser(); - List rawInjectExpectations = fromIterable(this.exerciseRepository.allGrantedInjectExpectationsFromDate(from, user.getId())); + List rawInjectExpectations = + fromIterable( + this.exerciseRepository.allGrantedInjectExpectationsFromDate(from, user.getId())); return AtomicTestingUtils.getExpectationResultByTypesFromRaw(rawInjectExpectations); } private List computeGlobalInjectExpectationResults( @NotNull final Instant from) { - List rawGlobalInjectExpectations = fromIterable(this.exerciseRepository.rawGlobalInjectExpectationResultsFromDate(from)); - return injectExpectationResultsByAttackPatternFromRawGlobalInjectExpectation(rawGlobalInjectExpectations); + List rawGlobalInjectExpectations = + fromIterable(this.exerciseRepository.rawGlobalInjectExpectationResultsFromDate(from)); + return injectExpectationResultsByAttackPatternFromRawGlobalInjectExpectation( + rawGlobalInjectExpectations); } private List computeUserInjectExpectationResults( @NotNull final Instant from) { OpenBASPrincipal user = currentUser(); - List rawGlobalInjectExpectations = fromIterable(this.exerciseRepository.rawGrantedInjectExpectationResultsFromDate(from, user.getId())); - return injectExpectationResultsByAttackPatternFromRawGlobalInjectExpectation(rawGlobalInjectExpectations); + List rawGlobalInjectExpectations = + fromIterable( + this.exerciseRepository.rawGrantedInjectExpectationResultsFromDate(from, user.getId())); + return injectExpectationResultsByAttackPatternFromRawGlobalInjectExpectation( + rawGlobalInjectExpectations); } - private List injectExpectationResultsByAttackPatternFromRawGlobalInjectExpectation(List rawGlobalInjectExpectations ) { + private List + injectExpectationResultsByAttackPatternFromRawGlobalInjectExpectation( + List rawGlobalInjectExpectations) { return rawGlobalInjectExpectations.stream() - .map(RawGlobalInjectExpectation::getAttack_pattern_id) - .distinct() - .map( - attackPatternId -> - { - InjectExpectationResultsByAttackPattern resultExpectation = new InjectExpectationResultsByAttackPattern(); - resultExpectation.setAttackPattern(new AttackPattern()); - resultExpectation.getAttackPattern().setId(attackPatternId); - resultExpectation.setResults(rawGlobalInjectExpectations.stream() - .filter((expectation) -> expectation.getAttack_pattern_id().equals(attackPatternId)) - .map((expectation) -> { - InjectExpectationResultsByAttackPattern.InjectExpectationResultsByType resultInjectExpectationResultsByAttackPattern = new InjectExpectationResultsByAttackPattern.InjectExpectationResultsByType(); - resultInjectExpectationResultsByAttackPattern.setInjectTitle(expectation.getInject_title()); - if(expectation.getInject_expectation_type() != null) { - SimpleRawInjectExpectation rawInjectExpectation = new SimpleRawInjectExpectation(); - rawInjectExpectation.setInject_expectation_score(expectation.getInject_expectation_score()); - rawInjectExpectation.setInject_expectation_expected_score(expectation.getInject_expectation_expected_score()); - rawInjectExpectation.setInject_expectation_type(expectation.getInject_expectation_type()); - resultInjectExpectationResultsByAttackPattern - .setResults(AtomicTestingUtils.getExpectationResultByTypesFromRaw(Stream.of(rawInjectExpectation) - .collect(Collectors.toList()))); - } else { - resultInjectExpectationResultsByAttackPattern - .setResults(AtomicTestingUtils.getExpectationResultByTypesFromRaw(new ArrayList<>())); - } - return resultInjectExpectationResultsByAttackPattern; - }) - .collect(Collectors.toList()) - ); - - return resultExpectation; - } - ) - .collect(Collectors.toList()) - ; + .map(RawGlobalInjectExpectation::getAttack_pattern_id) + .distinct() + .map( + attackPatternId -> { + InjectExpectationResultsByAttackPattern resultExpectation = + new InjectExpectationResultsByAttackPattern(); + resultExpectation.setAttackPattern(new AttackPattern()); + resultExpectation.getAttackPattern().setId(attackPatternId); + resultExpectation.setResults( + rawGlobalInjectExpectations.stream() + .filter( + (expectation) -> + expectation.getAttack_pattern_id().equals(attackPatternId)) + .map( + (expectation) -> { + InjectExpectationResultsByAttackPattern.InjectExpectationResultsByType + resultInjectExpectationResultsByAttackPattern = + new InjectExpectationResultsByAttackPattern + .InjectExpectationResultsByType(); + resultInjectExpectationResultsByAttackPattern.setInjectTitle( + expectation.getInject_title()); + if (expectation.getInject_expectation_type() != null) { + SimpleRawInjectExpectation rawInjectExpectation = + new SimpleRawInjectExpectation(); + rawInjectExpectation.setInject_expectation_score( + expectation.getInject_expectation_score()); + rawInjectExpectation.setInject_expectation_expected_score( + expectation.getInject_expectation_expected_score()); + rawInjectExpectation.setInject_expectation_type( + expectation.getInject_expectation_type()); + resultInjectExpectationResultsByAttackPattern.setResults( + AtomicTestingUtils.getExpectationResultByTypesFromRaw( + Stream.of(rawInjectExpectation) + .collect(Collectors.toList()))); + } else { + resultInjectExpectationResultsByAttackPattern.setResults( + AtomicTestingUtils.getExpectationResultByTypesFromRaw( + new ArrayList<>())); + } + return resultInjectExpectationResultsByAttackPattern; + }) + .collect(Collectors.toList())); + + return resultExpectation; + }) + .collect(Collectors.toList()); } - } diff --git a/openbas-api/src/main/java/io/openbas/rest/statistic/response/PlatformStatistic.java b/openbas-api/src/main/java/io/openbas/rest/statistic/response/PlatformStatistic.java index 8076a97c2f..3fae03bf59 100644 --- a/openbas-api/src/main/java/io/openbas/rest/statistic/response/PlatformStatistic.java +++ b/openbas-api/src/main/java/io/openbas/rest/statistic/response/PlatformStatistic.java @@ -1,49 +1,47 @@ package io.openbas.rest.statistic.response; import com.fasterxml.jackson.annotation.JsonProperty; -import io.openbas.utils.AtomicTestingMapper.ExpectationResultsByType; import io.openbas.rest.inject.form.InjectExpectationResultsByAttackPattern; +import io.openbas.utils.AtomicTestingMapper.ExpectationResultsByType; +import java.util.List; import lombok.Getter; import lombok.Setter; -import java.util.List; - @Setter @Getter public class PlatformStatistic { - @JsonProperty("platform_id") - private String platformId = "openbas"; - - @JsonProperty("scenarios_count") - private StatisticElement scenariosCount; + @JsonProperty("platform_id") + private String platformId = "openbas"; - @JsonProperty("exercises_count") - private StatisticElement exercisesCount; + @JsonProperty("scenarios_count") + private StatisticElement scenariosCount; - @JsonProperty("users_count") - private StatisticElement usersCount; + @JsonProperty("exercises_count") + private StatisticElement exercisesCount; - @JsonProperty("teams_count") - private StatisticElement teamsCount; + @JsonProperty("users_count") + private StatisticElement usersCount; - @JsonProperty("assets_count") - private StatisticElement assetsCount; + @JsonProperty("teams_count") + private StatisticElement teamsCount; - @JsonProperty("asset_groups_count") - private StatisticElement assetGroupsCount; + @JsonProperty("assets_count") + private StatisticElement assetsCount; - @JsonProperty("injects_count") - private StatisticElement injectsCount; + @JsonProperty("asset_groups_count") + private StatisticElement assetGroupsCount; - @JsonProperty("expectation_results") - private List results; + @JsonProperty("injects_count") + private StatisticElement injectsCount; - @JsonProperty("inject_expectation_results") - private List injectResults; + @JsonProperty("expectation_results") + private List results; - public PlatformStatistic() { - // Default constructor - } + @JsonProperty("inject_expectation_results") + private List injectResults; + public PlatformStatistic() { + // Default constructor + } } diff --git a/openbas-api/src/main/java/io/openbas/rest/statistic/response/StatisticElement.java b/openbas-api/src/main/java/io/openbas/rest/statistic/response/StatisticElement.java index ff19bc2efe..05bfe8deea 100644 --- a/openbas-api/src/main/java/io/openbas/rest/statistic/response/StatisticElement.java +++ b/openbas-api/src/main/java/io/openbas/rest/statistic/response/StatisticElement.java @@ -7,15 +7,14 @@ @Setter @Getter public class StatisticElement { - @JsonProperty("global_count") - private long global; + @JsonProperty("global_count") + private long global; - @JsonProperty("progression_count") - private long progression; - - public StatisticElement(long global, long progression) { - this.global = global; - this.progression = progression; - } + @JsonProperty("progression_count") + private long progression; + public StatisticElement(long global, long progression) { + this.global = global; + this.progression = progression; + } } diff --git a/openbas-api/src/main/java/io/openbas/rest/stream/StreamApi.java b/openbas-api/src/main/java/io/openbas/rest/stream/StreamApi.java index f0baf476ac..0b9c95eb30 100644 --- a/openbas-api/src/main/java/io/openbas/rest/stream/StreamApi.java +++ b/openbas-api/src/main/java/io/openbas/rest/stream/StreamApi.java @@ -1,11 +1,20 @@ package io.openbas.rest.stream; +import static io.openbas.config.SessionHelper.currentUser; +import static io.openbas.database.audit.ModelBaseListener.DATA_DELETE; +import static java.time.Instant.now; + import com.fasterxml.jackson.annotation.JsonProperty; import com.fasterxml.jackson.databind.JsonNode; import com.fasterxml.jackson.databind.node.ObjectNode; import io.openbas.config.OpenBASPrincipal; import io.openbas.database.audit.BaseEvent; import io.openbas.rest.helper.RestBehavior; +import java.time.Duration; +import java.util.HashMap; +import java.util.Map; +import java.util.logging.Level; +import java.util.logging.Logger; import org.springframework.context.event.EventListener; import org.springframework.http.HttpHeaders; import org.springframework.http.MediaType; @@ -19,78 +28,81 @@ import reactor.util.function.Tuple2; import reactor.util.function.Tuples; -import java.time.Duration; -import java.util.HashMap; -import java.util.Map; -import java.util.logging.Level; -import java.util.logging.Logger; - -import static io.openbas.config.SessionHelper.currentUser; -import static io.openbas.database.audit.ModelBaseListener.DATA_DELETE; -import static java.time.Instant.now; - @RestController public class StreamApi extends RestBehavior { - public static final String EVENT_TYPE_MESSAGE = "message"; - public static final String EVENT_TYPE_PING = "ping"; - public static final String X_ACCEL_BUFFERING = "X-Accel-Buffering"; - private static final Logger LOGGER = Logger.getLogger(StreamApi.class.getName()); - private final Map>> consumers = new HashMap<>(); + public static final String EVENT_TYPE_MESSAGE = "message"; + public static final String EVENT_TYPE_PING = "ping"; + public static final String X_ACCEL_BUFFERING = "X-Accel-Buffering"; + private static final Logger LOGGER = Logger.getLogger(StreamApi.class.getName()); + private final Map>> consumers = new HashMap<>(); - private void sendStreamEvent(FluxSink flux, BaseEvent event) { - // Serialize the instance now for lazy session decoupling - event.setInstanceData(mapper.valueToTree(event.getInstance())); - ServerSentEvent message = ServerSentEvent.builder(event) - .event(EVENT_TYPE_MESSAGE).build(); - flux.next(message); - } + private void sendStreamEvent(FluxSink flux, BaseEvent event) { + // Serialize the instance now for lazy session decoupling + event.setInstanceData(mapper.valueToTree(event.getInstance())); + ServerSentEvent message = + ServerSentEvent.builder(event).event(EVENT_TYPE_MESSAGE).build(); + flux.next(message); + } - @EventListener - public void listenDatabaseUpdate(BaseEvent event) { - consumers.entrySet().stream() - .parallel().forEach(entry -> { - Tuple2> tupleFlux = entry.getValue(); - OpenBASPrincipal listener = tupleFlux.getT1(); - FluxSink fluxSink = tupleFlux.getT2(); - boolean isCurrentObserver = event.isUserObserver(listener.isAdmin()); - if (!isCurrentObserver) { - // If user as no visibility, we can send a "delete" userEvent with only the internal id - try { - String propertyId = event.getInstance().getClass().getDeclaredField("id") - .getAnnotation(JsonProperty.class).value(); - ObjectNode deleteNode = mapper.createObjectNode(); - deleteNode.set(propertyId, mapper.convertValue(event.getInstance().getId(), JsonNode.class)); - BaseEvent userEvent = event.clone(); - userEvent.setInstanceData(deleteNode); - userEvent.setType(DATA_DELETE); - sendStreamEvent(fluxSink, userEvent); - } catch (Exception e) { - String simpleName = event.getInstance().getClass().getSimpleName(); - LOGGER.log(Level.WARNING, "Class " + simpleName + " cant be streamed", e); - } - } else { - sendStreamEvent(fluxSink, event); - } - }); - } + @EventListener + public void listenDatabaseUpdate(BaseEvent event) { + consumers.entrySet().stream() + .parallel() + .forEach( + entry -> { + Tuple2> tupleFlux = entry.getValue(); + OpenBASPrincipal listener = tupleFlux.getT1(); + FluxSink fluxSink = tupleFlux.getT2(); + boolean isCurrentObserver = event.isUserObserver(listener.isAdmin()); + if (!isCurrentObserver) { + // If user as no visibility, we can send a "delete" userEvent with only the internal + // id + try { + String propertyId = + event + .getInstance() + .getClass() + .getDeclaredField("id") + .getAnnotation(JsonProperty.class) + .value(); + ObjectNode deleteNode = mapper.createObjectNode(); + deleteNode.set( + propertyId, mapper.convertValue(event.getInstance().getId(), JsonNode.class)); + BaseEvent userEvent = event.clone(); + userEvent.setInstanceData(deleteNode); + userEvent.setType(DATA_DELETE); + sendStreamEvent(fluxSink, userEvent); + } catch (Exception e) { + String simpleName = event.getInstance().getClass().getSimpleName(); + LOGGER.log(Level.WARNING, "Class " + simpleName + " cant be streamed", e); + } + } else { + sendStreamEvent(fluxSink, event); + } + }); + } - /** - * Create a flux for current user & session - */ - @GetMapping(path = "/api/stream", produces = MediaType.TEXT_EVENT_STREAM_VALUE) - public ResponseEntity> streamFlux() { - String sessionId = RequestContextHolder.currentRequestAttributes().getSessionId(); - // Build the database event flux. - Flux dataFlux = Flux.create(fluxSinkConsumer -> consumers.put(sessionId, Tuples.of(currentUser(), fluxSinkConsumer))) - .doAfterTerminate(() -> consumers.remove(sessionId)); - // Build the health check flux. - Flux ping = Flux.interval(Duration.ofSeconds(1)) - .map(l -> ServerSentEvent.builder(now().getEpochSecond()).event(EVENT_TYPE_PING).build()); - // Merge the 2 flux to create the final one. - return ResponseEntity.ok() - .header(HttpHeaders.CACHE_CONTROL, "no-cache") - .header(X_ACCEL_BUFFERING, "no") - .body(Flux.merge(dataFlux, ping)); - } + /** Create a flux for current user & session */ + @GetMapping(path = "/api/stream", produces = MediaType.TEXT_EVENT_STREAM_VALUE) + public ResponseEntity> streamFlux() { + String sessionId = RequestContextHolder.currentRequestAttributes().getSessionId(); + // Build the database event flux. + Flux dataFlux = + Flux.create( + fluxSinkConsumer -> + consumers.put(sessionId, Tuples.of(currentUser(), fluxSinkConsumer))) + .doAfterTerminate(() -> consumers.remove(sessionId)); + // Build the health check flux. + Flux ping = + Flux.interval(Duration.ofSeconds(1)) + .map( + l -> + ServerSentEvent.builder(now().getEpochSecond()).event(EVENT_TYPE_PING).build()); + // Merge the 2 flux to create the final one. + return ResponseEntity.ok() + .header(HttpHeaders.CACHE_CONTROL, "no-cache") + .header(X_ACCEL_BUFFERING, "no") + .body(Flux.merge(dataFlux, ping)); + } } diff --git a/openbas-api/src/main/java/io/openbas/rest/stream/ai/AiApi.java b/openbas-api/src/main/java/io/openbas/rest/stream/ai/AiApi.java index f1836d4b1f..cc3288065c 100644 --- a/openbas-api/src/main/java/io/openbas/rest/stream/ai/AiApi.java +++ b/openbas-api/src/main/java/io/openbas/rest/stream/ai/AiApi.java @@ -1,10 +1,20 @@ package io.openbas.rest.stream.ai; +import static io.openbas.rest.stream.ai.AiPrompt.generatePrompt; + import com.fasterxml.jackson.core.JsonProcessingException; import com.fasterxml.jackson.databind.node.ObjectNode; import io.openbas.config.OpenBASPrincipal; import io.openbas.rest.helper.RestBehavior; import jakarta.validation.Valid; +import java.net.URI; +import java.net.http.HttpClient; +import java.net.http.HttpRequest; +import java.net.http.HttpResponse; +import java.util.HashMap; +import java.util.Map; +import java.util.concurrent.CompletableFuture; +import java.util.logging.Logger; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.http.HttpHeaders; import org.springframework.http.MediaType; @@ -16,259 +26,331 @@ import reactor.core.publisher.FluxSink; import reactor.util.function.Tuple2; -import java.net.URI; -import java.net.http.HttpClient; -import java.net.http.HttpRequest; -import java.net.http.HttpResponse; -import java.util.HashMap; -import java.util.Map; -import java.util.concurrent.CompletableFuture; -import java.util.logging.Logger; - -import static io.openbas.rest.stream.ai.AiPrompt.generatePrompt; - @RestController public class AiApi extends RestBehavior { - public static final String X_ACCEL_BUFFERING = "X-Accel-Buffering"; - private static final Logger LOGGER = Logger.getLogger(AiApi.class.getName()); - private final Map>> consumers = new HashMap<>(); - private AiConfig aiConfig; + public static final String X_ACCEL_BUFFERING = "X-Accel-Buffering"; + private static final Logger LOGGER = Logger.getLogger(AiApi.class.getName()); + private final Map>> consumers = new HashMap<>(); + private AiConfig aiConfig; - @Autowired - public void setAiConfig(AiConfig aiConfig) { - this.aiConfig = aiConfig; - } + @Autowired + public void setAiConfig(AiConfig aiConfig) { + this.aiConfig = aiConfig; + } - public ResponseEntity> queryAi(String body) { - if (!aiConfig.isEnabled()) { - throw new UnsupportedOperationException("AI mode is disabled"); - } - @SuppressWarnings("resource") HttpClient client = HttpClient.newHttpClient(); - String uri = switch (aiConfig.getType()) { - case "mistralai", "openai" -> aiConfig.getEndpoint() + "/v1/chat/completions"; - default -> throw new UnsupportedOperationException("Invalid ai type"); + public ResponseEntity> queryAi(String body) { + if (!aiConfig.isEnabled()) { + throw new UnsupportedOperationException("AI mode is disabled"); + } + @SuppressWarnings("resource") + HttpClient client = HttpClient.newHttpClient(); + String uri = + switch (aiConfig.getType()) { + case "mistralai", "openai" -> aiConfig.getEndpoint() + "/v1/chat/completions"; + default -> throw new UnsupportedOperationException("Invalid ai type"); }; - var request = HttpRequest.newBuilder(URI.create(uri)) - .POST(HttpRequest.BodyPublishers.ofString(body)) - .header("Authorization", "Bearer " + aiConfig.getToken()) - .header("Accept", "text/event-stream") - .build(); - Flux dataFlux = Flux.create(objectFluxSink -> { - try { - CompletableFuture> completableFuture = client.sendAsync(request, responseInfo -> { - if (responseInfo.statusCode() == 200) { - return new AiSubscriber(s -> { - try { - ObjectNode resultNode = mapper.readValue(s, ObjectNode.class); - String id = resultNode.get("id").textValue(); - String content = resultNode.get("choices").get(0).get("delta").get("content").textValue(); - objectFluxSink.next(new AiResult(id, content)); - } catch (Exception e) { - // Nothing to do - } + var request = + HttpRequest.newBuilder(URI.create(uri)) + .POST(HttpRequest.BodyPublishers.ofString(body)) + .header("Authorization", "Bearer " + aiConfig.getToken()) + .header("Accept", "text/event-stream") + .build(); + Flux dataFlux = + Flux.create( + objectFluxSink -> { + try { + CompletableFuture> completableFuture = + client.sendAsync( + request, + responseInfo -> { + if (responseInfo.statusCode() == 200) { + return new AiSubscriber( + s -> { + try { + ObjectNode resultNode = mapper.readValue(s, ObjectNode.class); + String id = resultNode.get("id").textValue(); + String content = + resultNode + .get("choices") + .get(0) + .get("delta") + .get("content") + .textValue(); + objectFluxSink.next(new AiResult(id, content)); + } catch (Exception e) { + // Nothing to do + } + }); + } else { + throw new RuntimeException("Request failed"); + } }); - } else { - throw new RuntimeException("Request failed"); - } - }); - completableFuture.thenApply(voidHttpResponse -> { - objectFluxSink.complete(); - return "done"; - }); - } catch (Exception e) { + completableFuture.thenApply( + voidHttpResponse -> { + objectFluxSink.complete(); + return "done"; + }); + } catch (Exception e) { objectFluxSink.complete(); - } - }); - return ResponseEntity.ok() - .header(HttpHeaders.CACHE_CONTROL, "no-cache") - .header(X_ACCEL_BUFFERING, "no") - .body(dataFlux); - } + } + }); + return ResponseEntity.ok() + .header(HttpHeaders.CACHE_CONTROL, "no-cache") + .header(X_ACCEL_BUFFERING, "no") + .body(dataFlux); + } - @PostMapping(path = "/api/ai/fix_spelling", produces = MediaType.TEXT_EVENT_STREAM_VALUE) - public ResponseEntity> aiFixSpelling(@Valid @RequestBody final AiGenericTextInput aiGenericTextInput) throws JsonProcessingException { - if (!aiConfig.isEnabled()) { - throw new UnsupportedOperationException("AI is disabled in this platform, please ask your administrator."); - } - String prompt = "\n" + - "# Instructions\n" + - "- Examine the provided text for any spelling mistakes and correct them accordingly in the original language of the text.\n" + - "- Ensure that all words are accurately spelled and that the grammar is correct.\n" + - "- If no mistake is detected, just return the original text without anything else.\n" + - "- Do NOT change the length of the text.\n" + - "- Your response should match the provided content format which is " + aiGenericTextInput.getFormat() + ". Be sure to respect this format and to NOT output anything else than the format and the intended content.\n" + - "\n" + - " # Content\n" + - aiGenericTextInput.getContent(); - AiQueryModel body = generatePrompt(prompt, aiConfig); - return queryAi(mapper.writeValueAsString(body)); + @PostMapping(path = "/api/ai/fix_spelling", produces = MediaType.TEXT_EVENT_STREAM_VALUE) + public ResponseEntity> aiFixSpelling( + @Valid @RequestBody final AiGenericTextInput aiGenericTextInput) + throws JsonProcessingException { + if (!aiConfig.isEnabled()) { + throw new UnsupportedOperationException( + "AI is disabled in this platform, please ask your administrator."); } + String prompt = + "\n" + + "# Instructions\n" + + "- Examine the provided text for any spelling mistakes and correct them accordingly in the original language of the text.\n" + + "- Ensure that all words are accurately spelled and that the grammar is correct.\n" + + "- If no mistake is detected, just return the original text without anything else.\n" + + "- Do NOT change the length of the text.\n" + + "- Your response should match the provided content format which is " + + aiGenericTextInput.getFormat() + + ". Be sure to respect this format and to NOT output anything else than the format and the intended content.\n" + + "\n" + + " # Content\n" + + aiGenericTextInput.getContent(); + AiQueryModel body = generatePrompt(prompt, aiConfig); + return queryAi(mapper.writeValueAsString(body)); + } - @PostMapping(path = "/api/ai/make_shorter", produces = MediaType.TEXT_EVENT_STREAM_VALUE) - public ResponseEntity> aiMakeShorter(@Valid @RequestBody final AiGenericTextInput aiGenericTextInput) throws JsonProcessingException { - if (!aiConfig.isEnabled()) { - throw new UnsupportedOperationException("AI is disabled in this platform, please ask your administrator."); - } - String prompt = "\n" + - "# Instructions\n" + - "- Examine the provided text related to cybersecurity and cyber threat intelligence and make it shorter by dividing by 2 the size / length of the text or the number of paragraphs.\n" + - "- Make it shorter by dividing by 2 the number of lines but you should keep the main ideas and concepts as well as original language of the text.\n" + - "- Do NOT summarize nor enumerate points.\n" + - "- Ensure that all words are accurately spelled and that the grammar is correct.\n" + - "- Your response should match the provided content format which is " + aiGenericTextInput.getFormat() + ". Be sure to respect this format and to NOT output anything else than the format.\n" + - "\n" + - "# Content" + - aiGenericTextInput.getContent(); - AiQueryModel body = generatePrompt(prompt, aiConfig); - return queryAi(mapper.writeValueAsString(body)); + @PostMapping(path = "/api/ai/make_shorter", produces = MediaType.TEXT_EVENT_STREAM_VALUE) + public ResponseEntity> aiMakeShorter( + @Valid @RequestBody final AiGenericTextInput aiGenericTextInput) + throws JsonProcessingException { + if (!aiConfig.isEnabled()) { + throw new UnsupportedOperationException( + "AI is disabled in this platform, please ask your administrator."); } + String prompt = + "\n" + + "# Instructions\n" + + "- Examine the provided text related to cybersecurity and cyber threat intelligence and make it shorter by dividing by 2 the size / length of the text or the number of paragraphs.\n" + + "- Make it shorter by dividing by 2 the number of lines but you should keep the main ideas and concepts as well as original language of the text.\n" + + "- Do NOT summarize nor enumerate points.\n" + + "- Ensure that all words are accurately spelled and that the grammar is correct.\n" + + "- Your response should match the provided content format which is " + + aiGenericTextInput.getFormat() + + ". Be sure to respect this format and to NOT output anything else than the format.\n" + + "\n" + + "# Content" + + aiGenericTextInput.getContent(); + AiQueryModel body = generatePrompt(prompt, aiConfig); + return queryAi(mapper.writeValueAsString(body)); + } - @PostMapping(path = "/api/ai/make_longer", produces = MediaType.TEXT_EVENT_STREAM_VALUE) - public ResponseEntity> aiMakeLonger(@Valid @RequestBody final AiGenericTextInput aiGenericTextInput) throws JsonProcessingException { - if (!aiConfig.isEnabled()) { - throw new UnsupportedOperationException("AI is disabled in this platform, please ask your administrator."); - } - String prompt = "\n" + - "# Instructions\n" + - "- Examine the provided text related to cybersecurity and cyber threat intelligence and make it longer by doubling the size / length of the text or the number of paragraphs.\n" + - "- Make it longer by doubling the number of lines by explaining concepts and developing the ideas but NOT too long, the final size should be twice the initial one.\n" + - "- Respect the original language of the text.\n" + - "- Do NOT summarize nor enumerate points.\n" + - "- Ensure that all words are accurately spelled and that the grammar is correct.\n" + - "- Your response should match the provided content format which is " + aiGenericTextInput.getFormat() + ". Be sure to respect this format and to NOT output anything else than the format.\n" + - "\n" + - "# Content" + - aiGenericTextInput.getContent(); - AiQueryModel body = generatePrompt(prompt, aiConfig); - return queryAi(mapper.writeValueAsString(body)); + @PostMapping(path = "/api/ai/make_longer", produces = MediaType.TEXT_EVENT_STREAM_VALUE) + public ResponseEntity> aiMakeLonger( + @Valid @RequestBody final AiGenericTextInput aiGenericTextInput) + throws JsonProcessingException { + if (!aiConfig.isEnabled()) { + throw new UnsupportedOperationException( + "AI is disabled in this platform, please ask your administrator."); } + String prompt = + "\n" + + "# Instructions\n" + + "- Examine the provided text related to cybersecurity and cyber threat intelligence and make it longer by doubling the size / length of the text or the number of paragraphs.\n" + + "- Make it longer by doubling the number of lines by explaining concepts and developing the ideas but NOT too long, the final size should be twice the initial one.\n" + + "- Respect the original language of the text.\n" + + "- Do NOT summarize nor enumerate points.\n" + + "- Ensure that all words are accurately spelled and that the grammar is correct.\n" + + "- Your response should match the provided content format which is " + + aiGenericTextInput.getFormat() + + ". Be sure to respect this format and to NOT output anything else than the format.\n" + + "\n" + + "# Content" + + aiGenericTextInput.getContent(); + AiQueryModel body = generatePrompt(prompt, aiConfig); + return queryAi(mapper.writeValueAsString(body)); + } - @PostMapping(path = "/api/ai/change_tone", produces = MediaType.TEXT_EVENT_STREAM_VALUE) - public ResponseEntity> aiChangeTone(@Valid @RequestBody final AiGenericTextInput aiGenericTextInput) throws JsonProcessingException { - if (!aiConfig.isEnabled()) { - throw new UnsupportedOperationException("AI is disabled in this platform, please ask your administrator."); - } - String prompt = "\n" + - "# Instructions\n" + - "- Examine the provided text related to cybersecurity and cyber threat intelligence and change its tone to be more " + aiGenericTextInput.getTone() + ".\n" + - "- Do NOT change the length of the text, the size of the output should be the same as the input.\n" + - "- Do NOT summarize nor enumerate points.\n" + - "- Ensure that all words are accurately spelled and that the grammar is correct.\n" + - "- Your response should match the provided content in the same format which is " + aiGenericTextInput.getFormat() + ". Be sure to respect this format and to NOT output anything else than the format.\n" + - "\n" + - "# Content" + - aiGenericTextInput.getContent(); - AiQueryModel body = generatePrompt(prompt, aiConfig); - return queryAi(mapper.writeValueAsString(body)); + @PostMapping(path = "/api/ai/change_tone", produces = MediaType.TEXT_EVENT_STREAM_VALUE) + public ResponseEntity> aiChangeTone( + @Valid @RequestBody final AiGenericTextInput aiGenericTextInput) + throws JsonProcessingException { + if (!aiConfig.isEnabled()) { + throw new UnsupportedOperationException( + "AI is disabled in this platform, please ask your administrator."); } + String prompt = + "\n" + + "# Instructions\n" + + "- Examine the provided text related to cybersecurity and cyber threat intelligence and change its tone to be more " + + aiGenericTextInput.getTone() + + ".\n" + + "- Do NOT change the length of the text, the size of the output should be the same as the input.\n" + + "- Do NOT summarize nor enumerate points.\n" + + "- Ensure that all words are accurately spelled and that the grammar is correct.\n" + + "- Your response should match the provided content in the same format which is " + + aiGenericTextInput.getFormat() + + ". Be sure to respect this format and to NOT output anything else than the format.\n" + + "\n" + + "# Content" + + aiGenericTextInput.getContent(); + AiQueryModel body = generatePrompt(prompt, aiConfig); + return queryAi(mapper.writeValueAsString(body)); + } - @PostMapping(path = "/api/ai/summarize", produces = MediaType.TEXT_EVENT_STREAM_VALUE) - public ResponseEntity> aiSummarize(@Valid @RequestBody final AiGenericTextInput aiGenericTextInput) throws JsonProcessingException { - if (!aiConfig.isEnabled()) { - throw new UnsupportedOperationException("AI is disabled in this platform, please ask your administrator."); - } - String prompt = "\n" + - "# Instructions\n" + - "- Examine the provided text related to cybersecurity and cyber threat intelligence and summarize it with main ideas and concepts.\n" + - "- Make it shorter and summarize key points highlighting the deep meaning of the text.\n" + - "- Ensure that all words are accurately spelled and that the grammar is correct.\n" + - "- Your response should match the provided content format which is " + aiGenericTextInput.getFormat() + ". Be sure to respect this format and to NOT output anything else than the format.\n" + - "\n" + - " # Content" + - aiGenericTextInput.getContent(); - AiQueryModel body = generatePrompt(prompt, aiConfig); - return queryAi(mapper.writeValueAsString(body)); + @PostMapping(path = "/api/ai/summarize", produces = MediaType.TEXT_EVENT_STREAM_VALUE) + public ResponseEntity> aiSummarize( + @Valid @RequestBody final AiGenericTextInput aiGenericTextInput) + throws JsonProcessingException { + if (!aiConfig.isEnabled()) { + throw new UnsupportedOperationException( + "AI is disabled in this platform, please ask your administrator."); } + String prompt = + "\n" + + "# Instructions\n" + + "- Examine the provided text related to cybersecurity and cyber threat intelligence and summarize it with main ideas and concepts.\n" + + "- Make it shorter and summarize key points highlighting the deep meaning of the text.\n" + + "- Ensure that all words are accurately spelled and that the grammar is correct.\n" + + "- Your response should match the provided content format which is " + + aiGenericTextInput.getFormat() + + ". Be sure to respect this format and to NOT output anything else than the format.\n" + + "\n" + + " # Content" + + aiGenericTextInput.getContent(); + AiQueryModel body = generatePrompt(prompt, aiConfig); + return queryAi(mapper.writeValueAsString(body)); + } - @PostMapping(path = "/api/ai/explain", produces = MediaType.TEXT_EVENT_STREAM_VALUE) - public ResponseEntity> aiExplain(@Valid @RequestBody final AiGenericTextInput aiGenericTextInput) throws JsonProcessingException { - if (!aiConfig.isEnabled()) { - throw new UnsupportedOperationException("AI is disabled in this platform, please ask your administrator."); - } - String prompt = "\n" + - "# Instructions\n" + - "- Examine the provided text related to cybersecurity and cyber threat intelligence and explain it.\n" + - "- Popularize the text to enlighten non-specialist by explaining key concepts and overall meaning.\n" + - "- Ensure that all words are accurately spelled and that the grammar is correct. \n" + - "- Your response should be done in plain text regardless of the original format.\n" + - "\n" + - " # Content" + - aiGenericTextInput.getContent(); - AiQueryModel body = generatePrompt(prompt, aiConfig); - return queryAi(mapper.writeValueAsString(body)); + @PostMapping(path = "/api/ai/explain", produces = MediaType.TEXT_EVENT_STREAM_VALUE) + public ResponseEntity> aiExplain( + @Valid @RequestBody final AiGenericTextInput aiGenericTextInput) + throws JsonProcessingException { + if (!aiConfig.isEnabled()) { + throw new UnsupportedOperationException( + "AI is disabled in this platform, please ask your administrator."); } + String prompt = + "\n" + + "# Instructions\n" + + "- Examine the provided text related to cybersecurity and cyber threat intelligence and explain it.\n" + + "- Popularize the text to enlighten non-specialist by explaining key concepts and overall meaning.\n" + + "- Ensure that all words are accurately spelled and that the grammar is correct. \n" + + "- Your response should be done in plain text regardless of the original format.\n" + + "\n" + + " # Content" + + aiGenericTextInput.getContent(); + AiQueryModel body = generatePrompt(prompt, aiConfig); + return queryAi(mapper.writeValueAsString(body)); + } - @PostMapping(path = "/api/ai/generate_message", produces = MediaType.TEXT_EVENT_STREAM_VALUE) - public ResponseEntity> aiGenerateMessage(@Valid @RequestBody final AiMessageInput aiMessageInput) throws JsonProcessingException { - if (!aiConfig.isEnabled()) { - throw new UnsupportedOperationException("AI is disabled in this platform, please ask your administrator."); - } - String prompt = "\n" + - "# Instructions\n" + - "- We are in the context of a cybersecurity breach and attack simulation or a cybersecurity crisis exercise.\n" + - "- Examine the provided context related to a cybersecurity breach and attack simulation.\n" + - "- You should generate a message from " + aiMessageInput.getSender() + " to " + aiMessageInput.getRecipient() + " given the provided input.\n" + - "- The message should have a tone of " + aiMessageInput.getTone() + ".\n" + - "- You should fake it and not writing about the simulation but like if it is a true cybersecurity threat and / or incident.\n" + - "- The summary should have " + aiMessageInput.getParagraphs().toString() + " of approximately 5 lines each.\n" + - "- Ensure that all words are accurately spelled and that the grammar is correct.\n" + - "- Your response should match the provided content format which is " + aiMessageInput.getFormat() + ". Be sure to respect this format and to NOT output anything else than the format.\n" + - "\n" + - " # Context" + - aiMessageInput.getContext() + - "\n" + - " # Input" + - aiMessageInput.getInput(); - AiQueryModel body = generatePrompt(prompt, aiConfig); - return queryAi(mapper.writeValueAsString(body)); + @PostMapping(path = "/api/ai/generate_message", produces = MediaType.TEXT_EVENT_STREAM_VALUE) + public ResponseEntity> aiGenerateMessage( + @Valid @RequestBody final AiMessageInput aiMessageInput) throws JsonProcessingException { + if (!aiConfig.isEnabled()) { + throw new UnsupportedOperationException( + "AI is disabled in this platform, please ask your administrator."); } + String prompt = + "\n" + + "# Instructions\n" + + "- We are in the context of a cybersecurity breach and attack simulation or a cybersecurity crisis exercise.\n" + + "- Examine the provided context related to a cybersecurity breach and attack simulation.\n" + + "- You should generate a message from " + + aiMessageInput.getSender() + + " to " + + aiMessageInput.getRecipient() + + " given the provided input.\n" + + "- The message should have a tone of " + + aiMessageInput.getTone() + + ".\n" + + "- You should fake it and not writing about the simulation but like if it is a true cybersecurity threat and / or incident.\n" + + "- The summary should have " + + aiMessageInput.getParagraphs().toString() + + " of approximately 5 lines each.\n" + + "- Ensure that all words are accurately spelled and that the grammar is correct.\n" + + "- Your response should match the provided content format which is " + + aiMessageInput.getFormat() + + ". Be sure to respect this format and to NOT output anything else than the format.\n" + + "\n" + + " # Context" + + aiMessageInput.getContext() + + "\n" + + " # Input" + + aiMessageInput.getInput(); + AiQueryModel body = generatePrompt(prompt, aiConfig); + return queryAi(mapper.writeValueAsString(body)); + } - @PostMapping(path = "/api/ai/generate_subject", produces = MediaType.TEXT_EVENT_STREAM_VALUE) - public ResponseEntity> aiGenerateSubject(@Valid @RequestBody final AiMessageInput aiMessageInput) throws JsonProcessingException { - if (!aiConfig.isEnabled()) { - throw new UnsupportedOperationException("AI is disabled in this platform, please ask your administrator."); - } - String prompt = "\n" + - "# Instructions\n" + - "- We are in the context of a cybersecurity breach and attack simulation or a cybersecurity crisis exercise.\n" + - "- Examine the provided context related to a cybersecurity breach and attack simulation.\n" + - "- You should generate the subject of the email from " + aiMessageInput.getSender() + " to " + aiMessageInput.getRecipient() + " given the provided input.\n" + - "- The subject should have a tone of " + aiMessageInput.getTone() + ".\n" + - "- Ensure that all words are accurately spelled and that the grammar is correct.\n" + - "- You should fake it and not writing about the simulation but like if it is a true cybersecurity threat and / or incident.\n" + - "- Your response should match the provided content format which is " + aiMessageInput.getFormat() + ". Be sure to respect this format and to NOT output anything else than the format.\n" + - "\n" + - " # Context" + - aiMessageInput.getContext() + - "\n" + - " # Input" + - aiMessageInput.getInput(); - AiQueryModel body = generatePrompt(prompt, aiConfig); - return queryAi(mapper.writeValueAsString(body)); + @PostMapping(path = "/api/ai/generate_subject", produces = MediaType.TEXT_EVENT_STREAM_VALUE) + public ResponseEntity> aiGenerateSubject( + @Valid @RequestBody final AiMessageInput aiMessageInput) throws JsonProcessingException { + if (!aiConfig.isEnabled()) { + throw new UnsupportedOperationException( + "AI is disabled in this platform, please ask your administrator."); } + String prompt = + "\n" + + "# Instructions\n" + + "- We are in the context of a cybersecurity breach and attack simulation or a cybersecurity crisis exercise.\n" + + "- Examine the provided context related to a cybersecurity breach and attack simulation.\n" + + "- You should generate the subject of the email from " + + aiMessageInput.getSender() + + " to " + + aiMessageInput.getRecipient() + + " given the provided input.\n" + + "- The subject should have a tone of " + + aiMessageInput.getTone() + + ".\n" + + "- Ensure that all words are accurately spelled and that the grammar is correct.\n" + + "- You should fake it and not writing about the simulation but like if it is a true cybersecurity threat and / or incident.\n" + + "- Your response should match the provided content format which is " + + aiMessageInput.getFormat() + + ". Be sure to respect this format and to NOT output anything else than the format.\n" + + "\n" + + " # Context" + + aiMessageInput.getContext() + + "\n" + + " # Input" + + aiMessageInput.getInput(); + AiQueryModel body = generatePrompt(prompt, aiConfig); + return queryAi(mapper.writeValueAsString(body)); + } - @PostMapping(path = "/api/ai/generate_media", produces = MediaType.TEXT_EVENT_STREAM_VALUE) - public ResponseEntity> aiGenerateMedia(@Valid @RequestBody final AiMediaInput aiMediaInput) throws JsonProcessingException { - if (!aiConfig.isEnabled()) { - throw new UnsupportedOperationException("AI is disabled in this platform, please ask your administrator."); - } - String prompt = "\n" + - "# Instructions\n" + - "- We are in the context of a cybersecurity breach and attack simulation or a cybersecurity crisis exercise.\n" + - "- Examine the provided context related to a cybersecurity breach and attack simulation.\n" + - "- You should generate an article as a journalist to put media pressure on the company given the provided input.\n" + - "- The article should have a tone of " + aiMediaInput.getTone() + ".\n" + - "- Ensure that all words are accurately spelled and that the grammar is correct.\n" + - "- You should fake it and not writing about the simulation but like if it is a true cybersecurity threat and / or incident.\n" + - "- The article should look like a true cybersecurity article in a newspaper.\n" + - "- Your response should match the provided content format which is " + aiMediaInput.getFormat() + ". Be sure to respect this format and to NOT output anything else than the format.\n" + - "\n" + - " # Context" + - aiMediaInput.getContext() + - "\n" + - " # Input" + - aiMediaInput.getInput(); - AiQueryModel body = generatePrompt(prompt, aiConfig); - return queryAi(mapper.writeValueAsString(body)); + @PostMapping(path = "/api/ai/generate_media", produces = MediaType.TEXT_EVENT_STREAM_VALUE) + public ResponseEntity> aiGenerateMedia( + @Valid @RequestBody final AiMediaInput aiMediaInput) throws JsonProcessingException { + if (!aiConfig.isEnabled()) { + throw new UnsupportedOperationException( + "AI is disabled in this platform, please ask your administrator."); } + String prompt = + "\n" + + "# Instructions\n" + + "- We are in the context of a cybersecurity breach and attack simulation or a cybersecurity crisis exercise.\n" + + "- Examine the provided context related to a cybersecurity breach and attack simulation.\n" + + "- You should generate an article as a journalist to put media pressure on the company given the provided input.\n" + + "- The article should have a tone of " + + aiMediaInput.getTone() + + ".\n" + + "- Ensure that all words are accurately spelled and that the grammar is correct.\n" + + "- You should fake it and not writing about the simulation but like if it is a true cybersecurity threat and / or incident.\n" + + "- The article should look like a true cybersecurity article in a newspaper.\n" + + "- Your response should match the provided content format which is " + + aiMediaInput.getFormat() + + ". Be sure to respect this format and to NOT output anything else than the format.\n" + + "\n" + + " # Context" + + aiMediaInput.getContext() + + "\n" + + " # Input" + + aiMediaInput.getInput(); + AiQueryModel body = generatePrompt(prompt, aiConfig); + return queryAi(mapper.writeValueAsString(body)); + } } diff --git a/openbas-api/src/main/java/io/openbas/rest/stream/ai/AiGenericTextInput.java b/openbas-api/src/main/java/io/openbas/rest/stream/ai/AiGenericTextInput.java index 48347effad..e60a582970 100644 --- a/openbas-api/src/main/java/io/openbas/rest/stream/ai/AiGenericTextInput.java +++ b/openbas-api/src/main/java/io/openbas/rest/stream/ai/AiGenericTextInput.java @@ -1,23 +1,23 @@ package io.openbas.rest.stream.ai; +import static io.openbas.config.AppConfig.MANDATORY_MESSAGE; + import com.fasterxml.jackson.annotation.JsonProperty; import jakarta.validation.constraints.NotBlank; import lombok.Getter; import lombok.Setter; -import static io.openbas.config.AppConfig.MANDATORY_MESSAGE; - @Getter @Setter public class AiGenericTextInput { - @NotBlank(message = MANDATORY_MESSAGE) - @JsonProperty("ai_content") - private String content; + @NotBlank(message = MANDATORY_MESSAGE) + @JsonProperty("ai_content") + private String content; - @JsonProperty("ai_format") - private String format; + @JsonProperty("ai_format") + private String format; - @JsonProperty("ai_tone") - private String tone; + @JsonProperty("ai_tone") + private String tone; } diff --git a/openbas-api/src/main/java/io/openbas/rest/stream/ai/AiMediaInput.java b/openbas-api/src/main/java/io/openbas/rest/stream/ai/AiMediaInput.java index 0aec4ade11..4334dddac7 100644 --- a/openbas-api/src/main/java/io/openbas/rest/stream/ai/AiMediaInput.java +++ b/openbas-api/src/main/java/io/openbas/rest/stream/ai/AiMediaInput.java @@ -1,38 +1,38 @@ package io.openbas.rest.stream.ai; +import static io.openbas.config.AppConfig.MANDATORY_MESSAGE; + import com.fasterxml.jackson.annotation.JsonProperty; import jakarta.annotation.Nullable; import jakarta.validation.constraints.NotBlank; import lombok.Getter; import lombok.Setter; -import static io.openbas.config.AppConfig.MANDATORY_MESSAGE; - @Getter @Setter public class AiMediaInput { - @NotBlank(message = MANDATORY_MESSAGE) - @JsonProperty("ai_input") - private String input; - - @Nullable - @JsonProperty("ai_paragraphs") - private Integer paragraphs = 5; - - @Nullable - @JsonProperty("ai_context") - private String context = "No context"; - - @Nullable - @JsonProperty("ai_tone") - private String tone = "natural"; - - @Nullable - @JsonProperty("ai_author") - private String author; - - @Nullable - @NotBlank(message = MANDATORY_MESSAGE) - @JsonProperty("ai_format") - private String format; + @NotBlank(message = MANDATORY_MESSAGE) + @JsonProperty("ai_input") + private String input; + + @Nullable + @JsonProperty("ai_paragraphs") + private Integer paragraphs = 5; + + @Nullable + @JsonProperty("ai_context") + private String context = "No context"; + + @Nullable + @JsonProperty("ai_tone") + private String tone = "natural"; + + @Nullable + @JsonProperty("ai_author") + private String author; + + @Nullable + @NotBlank(message = MANDATORY_MESSAGE) + @JsonProperty("ai_format") + private String format; } diff --git a/openbas-api/src/main/java/io/openbas/rest/stream/ai/AiMessageInput.java b/openbas-api/src/main/java/io/openbas/rest/stream/ai/AiMessageInput.java index 3a941d92c1..6408c50721 100644 --- a/openbas-api/src/main/java/io/openbas/rest/stream/ai/AiMessageInput.java +++ b/openbas-api/src/main/java/io/openbas/rest/stream/ai/AiMessageInput.java @@ -1,41 +1,41 @@ package io.openbas.rest.stream.ai; +import static io.openbas.config.AppConfig.MANDATORY_MESSAGE; + import com.fasterxml.jackson.annotation.JsonProperty; import jakarta.annotation.Nullable; import jakarta.validation.constraints.NotBlank; import lombok.Getter; import lombok.Setter; -import static io.openbas.config.AppConfig.MANDATORY_MESSAGE; - @Getter @Setter public class AiMessageInput { - @NotBlank(message = MANDATORY_MESSAGE) - @JsonProperty("ai_input") - private String input; + @NotBlank(message = MANDATORY_MESSAGE) + @JsonProperty("ai_input") + private String input; - @Nullable - @JsonProperty("ai_paragraphs") - private Integer paragraphs = 5; + @Nullable + @JsonProperty("ai_paragraphs") + private Integer paragraphs = 5; - @Nullable - @JsonProperty("ai_context") - private String context = "No context"; + @Nullable + @JsonProperty("ai_context") + private String context = "No context"; - @Nullable - @JsonProperty("ai_tone") - private String tone = "natural"; + @Nullable + @JsonProperty("ai_tone") + private String tone = "natural"; - @Nullable - @JsonProperty("ai_sender") - private String sender; + @Nullable + @JsonProperty("ai_sender") + private String sender; - @Nullable - @JsonProperty("ai_recipient") - private String recipient; + @Nullable + @JsonProperty("ai_recipient") + private String recipient; - @NotBlank(message = MANDATORY_MESSAGE) - @JsonProperty("ai_format") - private String format; + @NotBlank(message = MANDATORY_MESSAGE) + @JsonProperty("ai_format") + private String format; } diff --git a/openbas-api/src/main/java/io/openbas/rest/stream/ai/AiPrompt.java b/openbas-api/src/main/java/io/openbas/rest/stream/ai/AiPrompt.java index 812470f456..036c33cd8e 100644 --- a/openbas-api/src/main/java/io/openbas/rest/stream/ai/AiPrompt.java +++ b/openbas-api/src/main/java/io/openbas/rest/stream/ai/AiPrompt.java @@ -3,14 +3,14 @@ import java.util.List; public class AiPrompt { - public static AiQueryModel generatePrompt(String prompt, AiConfig aiConfig) { - AiQueryModel aiQueryModel = new AiQueryModel(); - aiQueryModel.setModel(aiConfig.getModel()); - aiQueryModel.setStream(true); - AiQueryMessageModel aiQueryMessageModel = new AiQueryMessageModel(); - aiQueryMessageModel.setRole("user"); - aiQueryMessageModel.setContent(prompt); - aiQueryModel.setMessages(List.of(aiQueryMessageModel)); - return aiQueryModel; - } + public static AiQueryModel generatePrompt(String prompt, AiConfig aiConfig) { + AiQueryModel aiQueryModel = new AiQueryModel(); + aiQueryModel.setModel(aiConfig.getModel()); + aiQueryModel.setStream(true); + AiQueryMessageModel aiQueryMessageModel = new AiQueryMessageModel(); + aiQueryMessageModel.setRole("user"); + aiQueryMessageModel.setContent(prompt); + aiQueryModel.setMessages(List.of(aiQueryMessageModel)); + return aiQueryModel; + } } diff --git a/openbas-api/src/main/java/io/openbas/rest/stream/ai/AiQueryMessageModel.java b/openbas-api/src/main/java/io/openbas/rest/stream/ai/AiQueryMessageModel.java index d626b82b82..9b32126484 100644 --- a/openbas-api/src/main/java/io/openbas/rest/stream/ai/AiQueryMessageModel.java +++ b/openbas-api/src/main/java/io/openbas/rest/stream/ai/AiQueryMessageModel.java @@ -6,25 +6,25 @@ @Getter public class AiQueryMessageModel { - @JsonProperty("role") - private String role; + @JsonProperty("role") + private String role; - @JsonProperty("content") - private String content; + @JsonProperty("content") + private String content; - public String getRole() { - return role; - } + public String getRole() { + return role; + } - public void setRole(String role) { - this.role = role; - } + public void setRole(String role) { + this.role = role; + } - public String getContent() { - return content; - } + public String getContent() { + return content; + } - public void setContent(String content) { - this.content = content; - } + public void setContent(String content) { + this.content = content; + } } diff --git a/openbas-api/src/main/java/io/openbas/rest/stream/ai/AiQueryModel.java b/openbas-api/src/main/java/io/openbas/rest/stream/ai/AiQueryModel.java index f8fbee2c06..176b7a6303 100644 --- a/openbas-api/src/main/java/io/openbas/rest/stream/ai/AiQueryModel.java +++ b/openbas-api/src/main/java/io/openbas/rest/stream/ai/AiQueryModel.java @@ -1,43 +1,42 @@ package io.openbas.rest.stream.ai; import com.fasterxml.jackson.annotation.JsonProperty; -import lombok.Getter; - import java.util.List; +import lombok.Getter; @Getter public class AiQueryModel { - @JsonProperty("model") - private String model; + @JsonProperty("model") + private String model; - @JsonProperty("stream") - private Boolean stream; + @JsonProperty("stream") + private Boolean stream; - @JsonProperty("messages") - private List messages; + @JsonProperty("messages") + private List messages; - public String getModel() { - return model; - } + public String getModel() { + return model; + } - public void setModel(String model) { - this.model = model; - } + public void setModel(String model) { + this.model = model; + } - public Boolean getStream() { - return stream; - } + public Boolean getStream() { + return stream; + } - public void setStream(Boolean stream) { - this.stream = stream; - } + public void setStream(Boolean stream) { + this.stream = stream; + } - public List getMessages() { - return messages; - } + public List getMessages() { + return messages; + } - public void setMessages(List messages) { - this.messages = messages; - } + public void setMessages(List messages) { + this.messages = messages; + } } diff --git a/openbas-api/src/main/java/io/openbas/rest/stream/ai/AiResult.java b/openbas-api/src/main/java/io/openbas/rest/stream/ai/AiResult.java index 89423d9829..3d8a913043 100644 --- a/openbas-api/src/main/java/io/openbas/rest/stream/ai/AiResult.java +++ b/openbas-api/src/main/java/io/openbas/rest/stream/ai/AiResult.java @@ -6,15 +6,14 @@ @Getter public class AiResult { - @JsonProperty("chunk_id") - private String id; + @JsonProperty("chunk_id") + private String id; - @JsonProperty("chunk_content") - private String content; - - public AiResult(String id, String content) { - this.id = id; - this.content = content; - } + @JsonProperty("chunk_content") + private String content; + public AiResult(String id, String content) { + this.id = id; + this.content = content; + } } diff --git a/openbas-api/src/main/java/io/openbas/rest/stream/ai/AiSubscriber.java b/openbas-api/src/main/java/io/openbas/rest/stream/ai/AiSubscriber.java index 56c0b95650..1887109787 100644 --- a/openbas-api/src/main/java/io/openbas/rest/stream/ai/AiSubscriber.java +++ b/openbas-api/src/main/java/io/openbas/rest/stream/ai/AiSubscriber.java @@ -1,5 +1,7 @@ package io.openbas.rest.stream.ai; +import static java.nio.charset.StandardCharsets.UTF_8; + import java.net.http.HttpResponse; import java.nio.ByteBuffer; import java.util.List; @@ -9,100 +11,98 @@ import java.util.function.Consumer; import java.util.regex.Pattern; -import static java.nio.charset.StandardCharsets.UTF_8; - public class AiSubscriber implements HttpResponse.BodySubscriber { - protected static final Pattern dataLinePattern = Pattern.compile("^data: ?(.*)$"); - - protected static String extractMessageData(String[] messageLines) { - var s = new StringBuilder(); - for (var line : messageLines) { - var m = dataLinePattern.matcher(line); - if (m.matches()) { - s.append(m.group(1)); - } - } - return s.toString(); + protected static final Pattern dataLinePattern = Pattern.compile("^data: ?(.*)$"); + + protected static String extractMessageData(String[] messageLines) { + var s = new StringBuilder(); + for (var line : messageLines) { + var m = dataLinePattern.matcher(line); + if (m.matches()) { + s.append(m.group(1)); + } } - - protected final Consumer messageDataConsumer; - protected final CompletableFuture future; - protected volatile Flow.Subscription subscription; - protected volatile String deferredText; - - public AiSubscriber(Consumer messageDataConsumer) { - this.messageDataConsumer = messageDataConsumer; - this.future = new CompletableFuture<>(); - this.subscription = null; - this.deferredText = null; + return s.toString(); + } + + protected final Consumer messageDataConsumer; + protected final CompletableFuture future; + protected volatile Flow.Subscription subscription; + protected volatile String deferredText; + + public AiSubscriber(Consumer messageDataConsumer) { + this.messageDataConsumer = messageDataConsumer; + this.future = new CompletableFuture<>(); + this.subscription = null; + this.deferredText = null; + } + + @Override + public void onSubscribe(Flow.Subscription subscription) { + this.subscription = subscription; + try { + this.deferredText = ""; + this.subscription.request(1); + } catch (Exception e) { + this.future.completeExceptionally(e); + this.subscription.cancel(); } - - @Override - public void onSubscribe(Flow.Subscription subscription) { - this.subscription = subscription; - try { - this.deferredText = ""; - this.subscription.request(1); - } catch (Exception e) { - this.future.completeExceptionally(e); - this.subscription.cancel(); + } + + @Override + public void onNext(List buffers) { + try { + // Volatile read + var deferredText = this.deferredText; + + for (var buffer : buffers) { + // TODO: Safe to assume multi-byte chars don't get split across buffers? + var s = deferredText + UTF_8.decode(buffer); + + // -1 means don't discard trailing empty tokens ... so the final token will + // be whatever is left after the last \n\n (possibly the empty string, but + // not necessarily), which is the part we need to defer until the next loop + // iteration + var tokens = s.split("\n\n", -1); + + // Final token gets deferred, not processed here + for (var i = 0; i < tokens.length - 1; i++) { + var message = tokens[i]; + var lines = message.split("\n"); + var data = extractMessageData(lines); + this.messageDataConsumer.accept(data); } - } - @Override - public void onNext(List buffers) { - try { - // Volatile read - var deferredText = this.deferredText; - - for (var buffer : buffers) { - // TODO: Safe to assume multi-byte chars don't get split across buffers? - var s = deferredText + UTF_8.decode(buffer); - - // -1 means don't discard trailing empty tokens ... so the final token will - // be whatever is left after the last \n\n (possibly the empty string, but - // not necessarily), which is the part we need to defer until the next loop - // iteration - var tokens = s.split("\n\n", -1); - - // Final token gets deferred, not processed here - for (var i = 0; i < tokens.length - 1; i++) { - var message = tokens[i]; - var lines = message.split("\n"); - var data = extractMessageData(lines); - this.messageDataConsumer.accept(data); - } - - // Defer the final token - deferredText = tokens[tokens.length - 1]; - } - - // Volatile write - this.deferredText = deferredText; - - this.subscription.request(1); - } catch (Exception e) { - this.future.completeExceptionally(e); - this.subscription.cancel(); - } - } + // Defer the final token + deferredText = tokens[tokens.length - 1]; + } - @Override - public void onError(Throwable e) { - this.future.completeExceptionally(e); - } + // Volatile write + this.deferredText = deferredText; - @Override - public void onComplete() { - try { - this.future.complete(null); - } catch (Exception e) { - this.future.completeExceptionally(e); - } + this.subscription.request(1); + } catch (Exception e) { + this.future.completeExceptionally(e); + this.subscription.cancel(); } - - @Override - public CompletionStage getBody() { - return this.future; + } + + @Override + public void onError(Throwable e) { + this.future.completeExceptionally(e); + } + + @Override + public void onComplete() { + try { + this.future.complete(null); + } catch (Exception e) { + this.future.completeExceptionally(e); } + } + + @Override + public CompletionStage getBody() { + return this.future; + } } diff --git a/openbas-api/src/main/java/io/openbas/rest/tag/TagApi.java b/openbas-api/src/main/java/io/openbas/rest/tag/TagApi.java index 49bfa7a3da..d27e501118 100644 --- a/openbas-api/src/main/java/io/openbas/rest/tag/TagApi.java +++ b/openbas-api/src/main/java/io/openbas/rest/tag/TagApi.java @@ -1,5 +1,10 @@ package io.openbas.rest.tag; +import static io.openbas.database.model.User.ROLE_ADMIN; +import static io.openbas.database.specification.TagSpecification.byName; +import static io.openbas.helper.StreamHelper.fromIterable; +import static io.openbas.utils.pagination.PaginationUtils.buildPaginationJPA; + import io.openbas.database.model.Tag; import io.openbas.database.repository.TagRepository; import io.openbas.rest.exception.ElementNotFoundException; @@ -10,6 +15,8 @@ import io.openbas.utils.pagination.SearchPaginationInput; import jakarta.transaction.Transactional; import jakarta.validation.Valid; +import java.util.List; +import java.util.Optional; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.data.domain.Page; import org.springframework.data.domain.Pageable; @@ -18,95 +25,86 @@ import org.springframework.security.access.annotation.Secured; import org.springframework.web.bind.annotation.*; -import java.util.List; -import java.util.Optional; - -import static io.openbas.database.model.User.ROLE_ADMIN; -import static io.openbas.database.specification.TagSpecification.byName; -import static io.openbas.helper.StreamHelper.fromIterable; -import static io.openbas.utils.pagination.PaginationUtils.buildPaginationJPA; - @RestController public class TagApi extends RestBehavior { - public static final String TAG_URI = "/api/tags"; - - private TagRepository tagRepository; - - @Autowired - public void setTagRepository(TagRepository tagRepository) { - this.tagRepository = tagRepository; - } - - @GetMapping("/api/tags") - public Iterable tags() { - return tagRepository.findAll(); - } - - @PostMapping("/api/tags/search") - public Page tags(@RequestBody @Valid SearchPaginationInput searchPaginationInput) { - return buildPaginationJPA( - (Specification specification, Pageable pageable) -> this.tagRepository.findAll( - specification, pageable), - searchPaginationInput, - Tag.class - ); - } - - @Secured(ROLE_ADMIN) - @PutMapping("/api/tags/{tagId}") - @Transactional(rollbackOn = Exception.class) - public Tag updateTag(@PathVariable String tagId, - @Valid @RequestBody TagUpdateInput input) { - Tag tag = tagRepository.findById(tagId).orElseThrow(ElementNotFoundException::new); - tag.setUpdateAttributes(input); - return tagRepository.save(tag); - } - - @Secured(ROLE_ADMIN) - @PostMapping("/api/tags") - @Transactional(rollbackOn = Exception.class) - public Tag createTag(@Valid @RequestBody TagCreateInput input) { - Tag tag = new Tag(); - tag.setUpdateAttributes(input); - return tagRepository.save(tag); - } - - @Secured(ROLE_ADMIN) - @PostMapping("/api/tags/upsert") - @Transactional(rollbackOn = Exception.class) - public Tag upsertTag(@Valid @RequestBody TagCreateInput input) { - Optional tag = tagRepository.findByName(input.getName()); - if( tag.isPresent() ) { - return tag.get(); - } else { - Tag newTag = new Tag(); - newTag.setUpdateAttributes(input); - return tagRepository.save(newTag); - } - } - - @Secured(ROLE_ADMIN) - @DeleteMapping("/api/tags/{tagId}") - public void deleteTag(@PathVariable String tagId) { - tagRepository.deleteById(tagId); - } - - // -- OPTION -- - - @GetMapping(TAG_URI + "/options") - public List optionsByName(@RequestParam(required = false) final String searchText) { - return fromIterable(this.tagRepository.findAll(byName(searchText), Sort.by(Sort.Direction.ASC, "name"))) - .stream() - .map(i -> new FilterUtilsJpa.Option(i.getId(), i.getName())) - .toList(); - } - - @PostMapping(TAG_URI + "/options") - public List optionsById(@RequestBody final List ids) { - return fromIterable(this.tagRepository.findAllById(ids)) - .stream() - .map(i -> new FilterUtilsJpa.Option(i.getId(), i.getName())) - .toList(); + public static final String TAG_URI = "/api/tags"; + + private TagRepository tagRepository; + + @Autowired + public void setTagRepository(TagRepository tagRepository) { + this.tagRepository = tagRepository; + } + + @GetMapping("/api/tags") + public Iterable tags() { + return tagRepository.findAll(); + } + + @PostMapping("/api/tags/search") + public Page tags(@RequestBody @Valid SearchPaginationInput searchPaginationInput) { + return buildPaginationJPA( + (Specification specification, Pageable pageable) -> + this.tagRepository.findAll(specification, pageable), + searchPaginationInput, + Tag.class); + } + + @Secured(ROLE_ADMIN) + @PutMapping("/api/tags/{tagId}") + @Transactional(rollbackOn = Exception.class) + public Tag updateTag(@PathVariable String tagId, @Valid @RequestBody TagUpdateInput input) { + Tag tag = tagRepository.findById(tagId).orElseThrow(ElementNotFoundException::new); + tag.setUpdateAttributes(input); + return tagRepository.save(tag); + } + + @Secured(ROLE_ADMIN) + @PostMapping("/api/tags") + @Transactional(rollbackOn = Exception.class) + public Tag createTag(@Valid @RequestBody TagCreateInput input) { + Tag tag = new Tag(); + tag.setUpdateAttributes(input); + return tagRepository.save(tag); + } + + @Secured(ROLE_ADMIN) + @PostMapping("/api/tags/upsert") + @Transactional(rollbackOn = Exception.class) + public Tag upsertTag(@Valid @RequestBody TagCreateInput input) { + Optional tag = tagRepository.findByName(input.getName()); + if (tag.isPresent()) { + return tag.get(); + } else { + Tag newTag = new Tag(); + newTag.setUpdateAttributes(input); + return tagRepository.save(newTag); } + } + + @Secured(ROLE_ADMIN) + @DeleteMapping("/api/tags/{tagId}") + public void deleteTag(@PathVariable String tagId) { + tagRepository.deleteById(tagId); + } + + // -- OPTION -- + + @GetMapping(TAG_URI + "/options") + public List optionsByName( + @RequestParam(required = false) final String searchText) { + return fromIterable( + this.tagRepository.findAll(byName(searchText), Sort.by(Sort.Direction.ASC, "name"))) + .stream() + .map(i -> new FilterUtilsJpa.Option(i.getId(), i.getName())) + .toList(); + } + + @PostMapping(TAG_URI + "/options") + public List optionsById(@RequestBody final List ids) { + return fromIterable(this.tagRepository.findAllById(ids)).stream() + .map(i -> new FilterUtilsJpa.Option(i.getId(), i.getName())) + .toList(); + } } diff --git a/openbas-api/src/main/java/io/openbas/rest/tag/form/TagCreateInput.java b/openbas-api/src/main/java/io/openbas/rest/tag/form/TagCreateInput.java index f18f6161a6..b49de8c5ec 100644 --- a/openbas-api/src/main/java/io/openbas/rest/tag/form/TagCreateInput.java +++ b/openbas-api/src/main/java/io/openbas/rest/tag/form/TagCreateInput.java @@ -1,23 +1,21 @@ package io.openbas.rest.tag.form; -import com.fasterxml.jackson.annotation.JsonProperty; +import static io.openbas.config.AppConfig.MANDATORY_MESSAGE; +import com.fasterxml.jackson.annotation.JsonProperty; import jakarta.validation.constraints.NotBlank; import lombok.Getter; import lombok.Setter; -import static io.openbas.config.AppConfig.MANDATORY_MESSAGE; - @Setter @Getter public class TagCreateInput { - @NotBlank(message = MANDATORY_MESSAGE) - @JsonProperty("tag_name") - private String name; - - @NotBlank(message = MANDATORY_MESSAGE) - @JsonProperty("tag_color") - private String color; + @NotBlank(message = MANDATORY_MESSAGE) + @JsonProperty("tag_name") + private String name; + @NotBlank(message = MANDATORY_MESSAGE) + @JsonProperty("tag_color") + private String color; } diff --git a/openbas-api/src/main/java/io/openbas/rest/tag/form/TagUpdateInput.java b/openbas-api/src/main/java/io/openbas/rest/tag/form/TagUpdateInput.java index bcfe53c94b..daf7adc7ea 100644 --- a/openbas-api/src/main/java/io/openbas/rest/tag/form/TagUpdateInput.java +++ b/openbas-api/src/main/java/io/openbas/rest/tag/form/TagUpdateInput.java @@ -1,34 +1,33 @@ package io.openbas.rest.tag.form; -import com.fasterxml.jackson.annotation.JsonProperty; +import static io.openbas.config.AppConfig.MANDATORY_MESSAGE; +import com.fasterxml.jackson.annotation.JsonProperty; import jakarta.validation.constraints.NotBlank; -import static io.openbas.config.AppConfig.MANDATORY_MESSAGE; - public class TagUpdateInput { - @NotBlank(message = MANDATORY_MESSAGE) - @JsonProperty("tag_name") - private String name; + @NotBlank(message = MANDATORY_MESSAGE) + @JsonProperty("tag_name") + private String name; - @NotBlank(message = MANDATORY_MESSAGE) - @JsonProperty("tag_color") - private String color; + @NotBlank(message = MANDATORY_MESSAGE) + @JsonProperty("tag_color") + private String color; - public String getName() { - return name; - } + public String getName() { + return name; + } - public void setName(String name) { - this.name = name; - } + public void setName(String name) { + this.name = name; + } - public String getColor() { - return color; - } + public String getColor() { + return color; + } - public void setColor(String color) { - this.color = color; - } + public void setColor(String color) { + this.color = color; + } } diff --git a/openbas-api/src/main/java/io/openbas/rest/team/ExerciseTeamApi.java b/openbas-api/src/main/java/io/openbas/rest/team/ExerciseTeamApi.java index 87d6d3ba4f..f1ceada754 100644 --- a/openbas-api/src/main/java/io/openbas/rest/team/ExerciseTeamApi.java +++ b/openbas-api/src/main/java/io/openbas/rest/team/ExerciseTeamApi.java @@ -1,5 +1,10 @@ package io.openbas.rest.team; +import static io.openbas.database.model.User.ROLE_USER; +import static io.openbas.database.specification.TeamSpecification.contextual; +import static io.openbas.database.specification.TeamSpecification.fromExercise; +import static io.openbas.rest.exercise.ExerciseApi.EXERCISE_URI; + import io.openbas.database.model.Team; import io.openbas.rest.helper.RestBehavior; import io.openbas.rest.team.output.TeamOutput; @@ -19,11 +24,6 @@ import org.springframework.web.bind.annotation.RequestBody; import org.springframework.web.bind.annotation.RestController; -import static io.openbas.database.model.User.ROLE_USER; -import static io.openbas.database.specification.TeamSpecification.contextual; -import static io.openbas.database.specification.TeamSpecification.fromExercise; -import static io.openbas.rest.exercise.ExerciseApi.EXERCISE_URI; - @RequiredArgsConstructor @RestController @Secured(ROLE_USER) @@ -38,8 +38,8 @@ public class ExerciseTeamApi extends RestBehavior { public Page searchTeams( @PathVariable @NotBlank final String exerciseId, @RequestBody @Valid SearchPaginationInput searchPaginationInput) { - final Specification teamSpecification = contextual(false).or(fromExercise(exerciseId).and(contextual(true))); + final Specification teamSpecification = + contextual(false).or(fromExercise(exerciseId).and(contextual(true))); return this.teamService.teamPagination(searchPaginationInput, teamSpecification); } - } diff --git a/openbas-api/src/main/java/io/openbas/rest/team/ScenarioTeamApi.java b/openbas-api/src/main/java/io/openbas/rest/team/ScenarioTeamApi.java index 6a3a06c478..c2e041a426 100644 --- a/openbas-api/src/main/java/io/openbas/rest/team/ScenarioTeamApi.java +++ b/openbas-api/src/main/java/io/openbas/rest/team/ScenarioTeamApi.java @@ -1,5 +1,10 @@ package io.openbas.rest.team; +import static io.openbas.database.model.User.ROLE_USER; +import static io.openbas.database.specification.TeamSpecification.contextual; +import static io.openbas.database.specification.TeamSpecification.fromScenario; +import static io.openbas.rest.scenario.ScenarioApi.SCENARIO_URI; + import io.openbas.database.model.Team; import io.openbas.rest.helper.RestBehavior; import io.openbas.rest.team.output.TeamOutput; @@ -19,11 +24,6 @@ import org.springframework.web.bind.annotation.RequestBody; import org.springframework.web.bind.annotation.RestController; -import static io.openbas.database.model.User.ROLE_USER; -import static io.openbas.database.specification.TeamSpecification.contextual; -import static io.openbas.database.specification.TeamSpecification.fromScenario; -import static io.openbas.rest.scenario.ScenarioApi.SCENARIO_URI; - @RequiredArgsConstructor @RestController @Secured(ROLE_USER) @@ -38,8 +38,8 @@ public class ScenarioTeamApi extends RestBehavior { public Page teams( @PathVariable @NotBlank final String scenarioId, @RequestBody @Valid SearchPaginationInput searchPaginationInput) { - final Specification teamSpecification = contextual(false).or(fromScenario(scenarioId).and(contextual(true))); + final Specification teamSpecification = + contextual(false).or(fromScenario(scenarioId).and(contextual(true))); return this.teamService.teamPagination(searchPaginationInput, teamSpecification); } - } diff --git a/openbas-api/src/main/java/io/openbas/rest/team/TeamApi.java b/openbas-api/src/main/java/io/openbas/rest/team/TeamApi.java index 211fb8c72e..84a41da6c1 100644 --- a/openbas-api/src/main/java/io/openbas/rest/team/TeamApi.java +++ b/openbas-api/src/main/java/io/openbas/rest/team/TeamApi.java @@ -1,5 +1,16 @@ package io.openbas.rest.team; +import static io.openbas.config.SessionHelper.currentUser; +import static io.openbas.database.model.User.ROLE_USER; +import static io.openbas.database.specification.TeamSpecification.*; +import static io.openbas.helper.DatabaseHelper.updateRelation; +import static io.openbas.helper.StreamHelper.fromIterable; +import static io.openbas.helper.StreamHelper.iterableToSet; +import static java.lang.Boolean.FALSE; +import static java.lang.Boolean.TRUE; +import static java.time.Instant.now; +import static org.springframework.util.StringUtils.hasText; + import io.openbas.config.OpenBASPrincipal; import io.openbas.database.model.Organization; import io.openbas.database.model.Team; @@ -20,6 +31,8 @@ import io.openbas.utils.pagination.SearchPaginationInput; import jakarta.validation.Valid; import jakarta.validation.constraints.NotNull; +import java.util.List; +import java.util.Optional; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.data.domain.Page; import org.springframework.data.jpa.domain.Specification; @@ -28,229 +41,246 @@ import org.springframework.transaction.annotation.Transactional; import org.springframework.web.bind.annotation.*; -import java.util.List; -import java.util.Optional; - -import static io.openbas.config.SessionHelper.currentUser; -import static io.openbas.database.model.User.ROLE_USER; -import static io.openbas.database.specification.TeamSpecification.*; -import static io.openbas.helper.DatabaseHelper.updateRelation; -import static io.openbas.helper.StreamHelper.fromIterable; -import static io.openbas.helper.StreamHelper.iterableToSet; -import static java.lang.Boolean.FALSE; -import static java.lang.Boolean.TRUE; -import static java.time.Instant.now; -import static org.springframework.util.StringUtils.hasText; - @RestController @Secured(ROLE_USER) public class TeamApi extends RestBehavior { - private ExerciseRepository exerciseRepository; - private ScenarioRepository scenarioRepository; - private TeamRepository teamRepository; - private CommunicationRepository communicationRepository; - private InjectExpectationRepository injectExpectationRepository; - private InjectRepository injectRepository; - private UserRepository userRepository; - private OrganizationRepository organizationRepository; - private TagRepository tagRepository; - private ExerciseTeamUserRepository exerciseTeamUserRepository; - - private TeamService teamService; - - @Autowired - public void setExerciseRepository(ExerciseRepository exerciseRepository) { - this.exerciseRepository = exerciseRepository; + private ExerciseRepository exerciseRepository; + private ScenarioRepository scenarioRepository; + private TeamRepository teamRepository; + private CommunicationRepository communicationRepository; + private InjectExpectationRepository injectExpectationRepository; + private InjectRepository injectRepository; + private UserRepository userRepository; + private OrganizationRepository organizationRepository; + private TagRepository tagRepository; + private ExerciseTeamUserRepository exerciseTeamUserRepository; + + private TeamService teamService; + + @Autowired + public void setExerciseRepository(ExerciseRepository exerciseRepository) { + this.exerciseRepository = exerciseRepository; + } + + @Autowired + public void setScenarioRepository(ScenarioRepository scenarioRepository) { + this.scenarioRepository = scenarioRepository; + } + + @Autowired + public void setTeamRepository(TeamRepository teamRepository) { + this.teamRepository = teamRepository; + } + + @Autowired + public void setUserRepository(UserRepository userRepository) { + this.userRepository = userRepository; + } + + @Autowired + public void setOrganizationRepository(OrganizationRepository organizationRepository) { + this.organizationRepository = organizationRepository; + } + + @Autowired + public void setInjectExpectationRepository( + InjectExpectationRepository injectExpectationRepository) { + this.injectExpectationRepository = injectExpectationRepository; + } + + @Autowired + public void setInjectRepository(InjectRepository injectRepository) { + this.injectRepository = injectRepository; + } + + @Autowired + public void setCommunicationRepository(CommunicationRepository communicationRepository) { + this.communicationRepository = communicationRepository; + } + + @Autowired + public void setExerciseTeamUserRepository(ExerciseTeamUserRepository exerciseTeamUserRepository) { + this.exerciseTeamUserRepository = exerciseTeamUserRepository; + } + + @Autowired + public void setTagRepository(TagRepository tagRepository) { + this.tagRepository = tagRepository; + } + + @Autowired + public void setTeamService(TeamService teamService) { + this.teamService = teamService; + } + + @GetMapping("/api/teams") + @PreAuthorize("isObserver()") + public Iterable getTeams() { + List teams; + OpenBASPrincipal currentUser = currentUser(); + if (currentUser.isAdmin()) { + // We get all the teams as raw + teams = fromIterable(teamRepository.rawTeams()); + } else { + // We get the teams that are linked to the organizations we are part of + User local = + userRepository.findById(currentUser.getId()).orElseThrow(ElementNotFoundException::new); + List organizationIds = + local.getGroups().stream() + .flatMap(group -> group.getOrganizations().stream()) + .map(Organization::getId) + .toList(); + teams = teamRepository.rawTeamsAccessibleFromOrganization(organizationIds); } - @Autowired - public void setScenarioRepository(ScenarioRepository scenarioRepository) { - this.scenarioRepository = scenarioRepository; + return TeamHelper.rawTeamToSimplerTeam( + teams, + injectExpectationRepository, + injectRepository, + communicationRepository, + exerciseTeamUserRepository, + scenarioRepository); + } + + @PostMapping("/api/teams/search") + @PreAuthorize("isObserver()") + @Transactional(readOnly = true) + @Tracing(name = "Paginate teams", layer = "api", operation = "POST") + public Page searchTeams( + @RequestBody @Valid SearchPaginationInput searchPaginationInput) { + final Specification teamSpecification = contextual(false); + return this.teamService.teamPagination(searchPaginationInput, teamSpecification); + } + + @PostMapping("/api/teams/find") + @PreAuthorize("isObserver()") + @Transactional(readOnly = true) + @Tracing(name = "Find teams", layer = "api", operation = "POST") + public List findTeams(@RequestBody @Valid @NotNull final List teamIds) { + return this.teamService.find(fromIds(teamIds)); + } + + @GetMapping("/api/teams/{teamId}") + @PreAuthorize("isObserver()") + public Team getTeam(@PathVariable String teamId) { + return teamRepository.findById(teamId).orElseThrow(ElementNotFoundException::new); + } + + @GetMapping("/api/teams/{teamId}/players") + @PreAuthorize("isObserver()") + public Iterable getTeamPlayers(@PathVariable String teamId) { + return teamRepository.findById(teamId).orElseThrow(ElementNotFoundException::new).getUsers(); + } + + @PostMapping("/api/teams") + @PreAuthorize("isPlanner()") + @Transactional(rollbackFor = Exception.class) + public Team createTeam(@Valid @RequestBody TeamCreateInput input) { + isTeamAlreadyExists(input); + Team team = new Team(); + team.setUpdateAttributes(input); + team.setOrganization( + updateRelation(input.getOrganizationId(), team.getOrganization(), organizationRepository)); + team.setTags(iterableToSet(tagRepository.findAllById(input.getTagIds()))); + team.setExercises(fromIterable(exerciseRepository.findAllById(input.getExerciseIds()))); + team.setScenarios(fromIterable(scenarioRepository.findAllById(input.getScenarioIds()))); + return teamRepository.save(team); + } + + @PostMapping("/api/teams/upsert") + @PreAuthorize("isPlanner()") + @Transactional(rollbackFor = Exception.class) + public Team upsertTeam(@Valid @RequestBody TeamCreateInput input) { + if (input.getContextual() && input.getExerciseIds().toArray().length > 1) { + throw new UnsupportedOperationException( + "Contextual team can only be associated to one exercise"); } - - @Autowired - public void setTeamRepository(TeamRepository teamRepository) { - this.teamRepository = teamRepository; + Optional team = teamRepository.findByName(input.getName()); + if (team.isPresent()) { + Team existingTeam = team.get(); + existingTeam.setUpdateAttributes(input); + existingTeam.setUpdatedAt(now()); + existingTeam.setTags(iterableToSet(tagRepository.findAllById(input.getTagIds()))); + existingTeam.setOrganization( + updateRelation( + input.getOrganizationId(), existingTeam.getOrganization(), organizationRepository)); + return teamRepository.save(existingTeam); + } else { + Team newTeam = new Team(); + newTeam.setUpdateAttributes(input); + newTeam.setOrganization( + updateRelation( + input.getOrganizationId(), newTeam.getOrganization(), organizationRepository)); + newTeam.setTags(iterableToSet(tagRepository.findAllById(input.getTagIds()))); + newTeam.setExercises(fromIterable(exerciseRepository.findAllById(input.getExerciseIds()))); + newTeam.setScenarios(fromIterable(scenarioRepository.findAllById(input.getScenarioIds()))); + return teamRepository.save(newTeam); } - - @Autowired - public void setUserRepository(UserRepository userRepository) { - this.userRepository = userRepository; + } + + @DeleteMapping("/api/teams/{teamId}") + @PreAuthorize("isPlanner()") + public void deleteTeam(@PathVariable String teamId) { + teamRepository.deleteById(teamId); + } + + @PutMapping("/api/teams/{teamId}") + @PreAuthorize("isPlanner()") + public Team updateTeam(@PathVariable String teamId, @Valid @RequestBody TeamUpdateInput input) { + Team team = teamRepository.findById(teamId).orElseThrow(ElementNotFoundException::new); + team.setUpdateAttributes(input); + team.setUpdatedAt(now()); + team.setTags(iterableToSet(tagRepository.findAllById(input.getTagIds()))); + team.setOrganization( + updateRelation(input.getOrganizationId(), team.getOrganization(), organizationRepository)); + return teamRepository.save(team); + } + + @PutMapping("/api/teams/{teamId}/players") + @PreAuthorize("isPlanner()") + public Team updateTeamUsers( + @PathVariable String teamId, @Valid @RequestBody UpdateUsersTeamInput input) { + Team team = teamRepository.findById(teamId).orElseThrow(ElementNotFoundException::new); + Iterable teamUsers = userRepository.findAllById(input.getUserIds()); + team.setUsers(fromIterable(teamUsers)); + return teamRepository.save(team); + } + + // -- PRIVATE -- + + private void isTeamAlreadyExists(@NotNull final TeamCreateInput input) { + List teams = this.teamRepository.findAllByNameIgnoreCase(input.getName()); + if (teams.isEmpty()) return; + + if (FALSE.equals(input.getContextual()) + && teams.stream().anyMatch(t -> FALSE.equals(t.getContextual()))) { + throw new AlreadyExistingException( + "Global teams (non contextual) cannot have the same name (already exists)"); } - - @Autowired - public void setOrganizationRepository(OrganizationRepository organizationRepository) { - this.organizationRepository = organizationRepository; - } - - @Autowired - public void setInjectExpectationRepository(InjectExpectationRepository injectExpectationRepository) { - this.injectExpectationRepository = injectExpectationRepository; - } - - @Autowired - public void setInjectRepository(InjectRepository injectRepository) { - this.injectRepository = injectRepository; - } - - @Autowired - public void setCommunicationRepository(CommunicationRepository communicationRepository) { - this.communicationRepository = communicationRepository; - } - - @Autowired - public void setExerciseTeamUserRepository(ExerciseTeamUserRepository exerciseTeamUserRepository) { - this.exerciseTeamUserRepository = exerciseTeamUserRepository; - } - - @Autowired - public void setTagRepository(TagRepository tagRepository) { - this.tagRepository = tagRepository; - } - - - @Autowired - public void setTeamService(TeamService teamService) { - this.teamService = teamService; - } - - @GetMapping("/api/teams") - @PreAuthorize("isObserver()") - public Iterable getTeams() { - List teams; - OpenBASPrincipal currentUser = currentUser(); - if (currentUser.isAdmin()) { - //We get all the teams as raw - teams = fromIterable(teamRepository.rawTeams()); - } else { - //We get the teams that are linked to the organizations we are part of - User local = userRepository.findById(currentUser.getId()).orElseThrow(ElementNotFoundException::new); - List organizationIds = local.getGroups().stream() - .flatMap(group -> group.getOrganizations().stream()) - .map(Organization::getId) - .toList(); - teams = teamRepository.rawTeamsAccessibleFromOrganization(organizationIds); - } - - return TeamHelper.rawTeamToSimplerTeam(teams, injectExpectationRepository, injectRepository, communicationRepository, - exerciseTeamUserRepository, scenarioRepository); - } - - @PostMapping("/api/teams/search") - @PreAuthorize("isObserver()") - @Transactional(readOnly = true) - @Tracing(name = "Paginate teams", layer = "api", operation = "POST") - public Page searchTeams(@RequestBody @Valid SearchPaginationInput searchPaginationInput) { - final Specification teamSpecification = contextual(false); - return this.teamService.teamPagination(searchPaginationInput, teamSpecification); - } - - @PostMapping("/api/teams/find") - @PreAuthorize("isObserver()") - @Transactional(readOnly = true) - @Tracing(name = "Find teams", layer = "api", operation = "POST") - public List findTeams(@RequestBody @Valid @NotNull final List teamIds) { - return this.teamService.find(fromIds(teamIds)); - } - - @GetMapping("/api/teams/{teamId}") - @PreAuthorize("isObserver()") - public Team getTeam(@PathVariable String teamId) { - return teamRepository.findById(teamId).orElseThrow(ElementNotFoundException::new); - } - - @GetMapping("/api/teams/{teamId}/players") - @PreAuthorize("isObserver()") - public Iterable getTeamPlayers(@PathVariable String teamId) { - return teamRepository.findById(teamId).orElseThrow(ElementNotFoundException::new).getUsers(); - } - - @PostMapping("/api/teams") - @PreAuthorize("isPlanner()") - @Transactional(rollbackFor = Exception.class) - public Team createTeam(@Valid @RequestBody TeamCreateInput input) { - isTeamAlreadyExists(input); - Team team = new Team(); - team.setUpdateAttributes(input); - team.setOrganization(updateRelation(input.getOrganizationId(), team.getOrganization(), organizationRepository)); - team.setTags(iterableToSet(tagRepository.findAllById(input.getTagIds()))); - team.setExercises(fromIterable(exerciseRepository.findAllById(input.getExerciseIds()))); - team.setScenarios(fromIterable(scenarioRepository.findAllById(input.getScenarioIds()))); - return teamRepository.save(team); - } - - @PostMapping("/api/teams/upsert") - @PreAuthorize("isPlanner()") - @Transactional(rollbackFor = Exception.class) - public Team upsertTeam(@Valid @RequestBody TeamCreateInput input) { - if (input.getContextual() && input.getExerciseIds().toArray().length > 1) { - throw new UnsupportedOperationException("Contextual team can only be associated to one exercise"); - } - Optional team = teamRepository.findByName(input.getName()); - if (team.isPresent()) { - Team existingTeam = team.get(); - existingTeam.setUpdateAttributes(input); - existingTeam.setUpdatedAt(now()); - existingTeam.setTags(iterableToSet(tagRepository.findAllById(input.getTagIds()))); - existingTeam.setOrganization(updateRelation(input.getOrganizationId(), existingTeam.getOrganization(), organizationRepository)); - return teamRepository.save(existingTeam); - } else { - Team newTeam = new Team(); - newTeam.setUpdateAttributes(input); - newTeam.setOrganization(updateRelation(input.getOrganizationId(), newTeam.getOrganization(), organizationRepository)); - newTeam.setTags(iterableToSet(tagRepository.findAllById(input.getTagIds()))); - newTeam.setExercises(fromIterable(exerciseRepository.findAllById(input.getExerciseIds()))); - newTeam.setScenarios(fromIterable(scenarioRepository.findAllById(input.getScenarioIds()))); - return teamRepository.save(newTeam); - } - } - - @DeleteMapping("/api/teams/{teamId}") - @PreAuthorize("isPlanner()") - public void deleteTeam(@PathVariable String teamId) { - teamRepository.deleteById(teamId); - } - - @PutMapping("/api/teams/{teamId}") - @PreAuthorize("isPlanner()") - public Team updateTeam(@PathVariable String teamId, @Valid @RequestBody TeamUpdateInput input) { - Team team = teamRepository.findById(teamId).orElseThrow(ElementNotFoundException::new); - team.setUpdateAttributes(input); - team.setUpdatedAt(now()); - team.setTags(iterableToSet(tagRepository.findAllById(input.getTagIds()))); - team.setOrganization(updateRelation(input.getOrganizationId(), team.getOrganization(), organizationRepository)); - return teamRepository.save(team); - } - - @PutMapping("/api/teams/{teamId}/players") - @PreAuthorize("isPlanner()") - public Team updateTeamUsers(@PathVariable String teamId, @Valid @RequestBody UpdateUsersTeamInput input) { - Team team = teamRepository.findById(teamId).orElseThrow(ElementNotFoundException::new); - Iterable teamUsers = userRepository.findAllById(input.getUserIds()); - team.setUsers(fromIterable(teamUsers)); - return teamRepository.save(team); - } - - // -- PRIVATE -- - - private void isTeamAlreadyExists(@NotNull final TeamCreateInput input) { - List teams = this.teamRepository.findAllByNameIgnoreCase(input.getName()); - if (teams.isEmpty()) return; - - if (FALSE.equals(input.getContextual()) && teams.stream().anyMatch(t -> FALSE.equals(t.getContextual()))) { - throw new AlreadyExistingException("Global teams (non contextual) cannot have the same name (already exists)"); - } - if (TRUE.equals(input.getContextual())) { - String exerciseId = input.getExerciseIds().stream().findFirst().orElse(null); - if (hasText(exerciseId) && teams.stream().anyMatch(t -> TRUE.equals(t.getContextual()) && t.getExercises().stream().anyMatch((e) -> exerciseId.equals(e.getId())))) { - throw new AlreadyExistingException("A contextual team with the same name already exists on this simulation"); - } - String scenarioId = input.getScenarioIds().stream().findFirst().orElse(null); - if (hasText(scenarioId) && teams.stream().anyMatch(t -> TRUE.equals(t.getContextual()) && t.getScenarios().stream().anyMatch((e) -> scenarioId.equals(e.getId())))) { - throw new AlreadyExistingException("A contextual team with the same name already exists on this scenario"); - } - } - + if (TRUE.equals(input.getContextual())) { + String exerciseId = input.getExerciseIds().stream().findFirst().orElse(null); + if (hasText(exerciseId) + && teams.stream() + .anyMatch( + t -> + TRUE.equals(t.getContextual()) + && t.getExercises().stream() + .anyMatch((e) -> exerciseId.equals(e.getId())))) { + throw new AlreadyExistingException( + "A contextual team with the same name already exists on this simulation"); + } + String scenarioId = input.getScenarioIds().stream().findFirst().orElse(null); + if (hasText(scenarioId) + && teams.stream() + .anyMatch( + t -> + TRUE.equals(t.getContextual()) + && t.getScenarios().stream() + .anyMatch((e) -> scenarioId.equals(e.getId())))) { + throw new AlreadyExistingException( + "A contextual team with the same name already exists on this scenario"); + } } + } } diff --git a/openbas-api/src/main/java/io/openbas/rest/team/TeamQueryHelper.java b/openbas-api/src/main/java/io/openbas/rest/team/TeamQueryHelper.java index 4c2e762d7b..9259f05eb1 100644 --- a/openbas-api/src/main/java/io/openbas/rest/team/TeamQueryHelper.java +++ b/openbas-api/src/main/java/io/openbas/rest/team/TeamQueryHelper.java @@ -1,5 +1,7 @@ package io.openbas.rest.team; +import static io.openbas.utils.JpaUtils.createJoinArrayAggOnId; + import io.openbas.database.model.Team; import io.openbas.rest.team.output.TeamOutput; import jakarta.persistence.Tuple; @@ -8,20 +10,15 @@ import jakarta.persistence.criteria.CriteriaQuery; import jakarta.persistence.criteria.Expression; import jakarta.persistence.criteria.Root; - import java.time.Instant; import java.util.Arrays; import java.util.Collections; import java.util.List; import java.util.stream.Collectors; -import static io.openbas.utils.JpaUtils.createJoinArrayAggOnId; - public class TeamQueryHelper { - private TeamQueryHelper() { - - } + private TeamQueryHelper() {} // -- SELECT -- @@ -32,36 +29,38 @@ public static void select(CriteriaBuilder cb, CriteriaQuery cq, Root execution(TypedQuery query) { - return query.getResultList() - .stream() - .map(tuple -> TeamOutput.builder() - .id(tuple.get("team_id", String.class)) - .name(tuple.get("team_name", String.class)) - .description(tuple.get("team_description", String.class)) - .contextual(tuple.get("team_contextual", Boolean.class)) - .updatedAt(tuple.get("team_updated_at", Instant.class)) - .tags(Arrays.stream(tuple.get("team_tags", String[].class)).collect(Collectors.toSet())) - .users(Arrays.stream(tuple.get("team_users", String[].class)).collect(Collectors.toSet())) - .build()) + return query.getResultList().stream() + .map( + tuple -> + TeamOutput.builder() + .id(tuple.get("team_id", String.class)) + .name(tuple.get("team_name", String.class)) + .description(tuple.get("team_description", String.class)) + .contextual(tuple.get("team_contextual", Boolean.class)) + .updatedAt(tuple.get("team_updated_at", Instant.class)) + .tags( + Arrays.stream(tuple.get("team_tags", String[].class)) + .collect(Collectors.toSet())) + .users( + Arrays.stream(tuple.get("team_users", String[].class)) + .collect(Collectors.toSet())) + .build()) .toList(); } - } diff --git a/openbas-api/src/main/java/io/openbas/rest/team/form/TeamCreateInput.java b/openbas-api/src/main/java/io/openbas/rest/team/form/TeamCreateInput.java index 9825600631..fc60836cfd 100644 --- a/openbas-api/src/main/java/io/openbas/rest/team/form/TeamCreateInput.java +++ b/openbas-api/src/main/java/io/openbas/rest/team/form/TeamCreateInput.java @@ -1,14 +1,12 @@ package io.openbas.rest.team.form; -import com.fasterxml.jackson.annotation.JsonProperty; +import static io.openbas.config.AppConfig.MANDATORY_MESSAGE; +import com.fasterxml.jackson.annotation.JsonProperty; import jakarta.validation.constraints.NotBlank; -import lombok.Data; - import java.util.ArrayList; import java.util.List; - -import static io.openbas.config.AppConfig.MANDATORY_MESSAGE; +import lombok.Data; @Data public class TeamCreateInput { diff --git a/openbas-api/src/main/java/io/openbas/rest/team/form/TeamUpdateInput.java b/openbas-api/src/main/java/io/openbas/rest/team/form/TeamUpdateInput.java index 5c6459ad47..c07cd6bdc7 100644 --- a/openbas-api/src/main/java/io/openbas/rest/team/form/TeamUpdateInput.java +++ b/openbas-api/src/main/java/io/openbas/rest/team/form/TeamUpdateInput.java @@ -1,57 +1,56 @@ package io.openbas.rest.team.form; -import com.fasterxml.jackson.annotation.JsonProperty; +import static io.openbas.config.AppConfig.MANDATORY_MESSAGE; +import com.fasterxml.jackson.annotation.JsonProperty; import jakarta.validation.constraints.NotBlank; import java.util.ArrayList; import java.util.List; -import static io.openbas.config.AppConfig.MANDATORY_MESSAGE; - public class TeamUpdateInput { - @NotBlank(message = MANDATORY_MESSAGE) - @JsonProperty("team_name") - private String name; + @NotBlank(message = MANDATORY_MESSAGE) + @JsonProperty("team_name") + private String name; - @JsonProperty("team_description") - private String description; + @JsonProperty("team_description") + private String description; - @JsonProperty("team_organization") - private String organizationId; + @JsonProperty("team_organization") + private String organizationId; - @JsonProperty("team_tags") - private List tagIds = new ArrayList<>(); + @JsonProperty("team_tags") + private List tagIds = new ArrayList<>(); - public String getName() { - return name; - } + public String getName() { + return name; + } - public void setName(String name) { - this.name = name; - } + public void setName(String name) { + this.name = name; + } - public String getDescription() { - return description; - } + public String getDescription() { + return description; + } - public void setDescription(String description) { - this.description = description; - } + public void setDescription(String description) { + this.description = description; + } - public String getOrganizationId() { - return organizationId; - } + public String getOrganizationId() { + return organizationId; + } - public void setOrganizationId(String organizationId) { - this.organizationId = organizationId; - } + public void setOrganizationId(String organizationId) { + this.organizationId = organizationId; + } - public List getTagIds() { - return tagIds; - } + public List getTagIds() { + return tagIds; + } - public void setTagIds(List tagIds) { - this.tagIds = tagIds; - } + public void setTagIds(List tagIds) { + this.tagIds = tagIds; + } } diff --git a/openbas-api/src/main/java/io/openbas/rest/team/form/UpdateUsersTeamInput.java b/openbas-api/src/main/java/io/openbas/rest/team/form/UpdateUsersTeamInput.java index a76f312cae..04c2bcd05d 100644 --- a/openbas-api/src/main/java/io/openbas/rest/team/form/UpdateUsersTeamInput.java +++ b/openbas-api/src/main/java/io/openbas/rest/team/form/UpdateUsersTeamInput.java @@ -1,19 +1,18 @@ package io.openbas.rest.team.form; import com.fasterxml.jackson.annotation.JsonProperty; - import java.util.List; public class UpdateUsersTeamInput { - @JsonProperty("team_users") - private List userIds; + @JsonProperty("team_users") + private List userIds; - public List getUserIds() { - return userIds; - } + public List getUserIds() { + return userIds; + } - public void setUserIds(List userIds) { - this.userIds = userIds; - } + public void setUserIds(List userIds) { + this.userIds = userIds; + } } diff --git a/openbas-api/src/main/java/io/openbas/rest/team/output/TeamOutput.java b/openbas-api/src/main/java/io/openbas/rest/team/output/TeamOutput.java index c532706d45..da78f44461 100644 --- a/openbas-api/src/main/java/io/openbas/rest/team/output/TeamOutput.java +++ b/openbas-api/src/main/java/io/openbas/rest/team/output/TeamOutput.java @@ -3,11 +3,10 @@ import com.fasterxml.jackson.annotation.JsonProperty; import jakarta.validation.constraints.NotBlank; import jakarta.validation.constraints.NotNull; -import lombok.Builder; -import lombok.Data; - import java.time.Instant; import java.util.Set; +import lombok.Builder; +import lombok.Data; @Builder @Data @@ -41,5 +40,4 @@ public class TeamOutput { public long getUsersNumber() { return getUsers().size(); } - } diff --git a/openbas-api/src/main/java/io/openbas/rest/user/MeApi.java b/openbas-api/src/main/java/io/openbas/rest/user/MeApi.java index 860427240d..dc74e747e5 100644 --- a/openbas-api/src/main/java/io/openbas/rest/user/MeApi.java +++ b/openbas-api/src/main/java/io/openbas/rest/user/MeApi.java @@ -1,5 +1,10 @@ package io.openbas.rest.user; +import static io.openbas.config.SessionHelper.currentUser; +import static io.openbas.database.model.User.ROLE_USER; +import static io.openbas.database.specification.TokenSpecification.fromUser; +import static io.openbas.helper.DatabaseHelper.updateRelation; + import io.openbas.config.SessionManager; import io.openbas.database.model.Token; import io.openbas.database.model.User; @@ -17,25 +22,18 @@ import jakarta.annotation.Resource; import jakarta.transaction.Transactional; import jakarta.validation.Valid; +import java.util.List; +import java.util.UUID; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.http.ResponseEntity; import org.springframework.security.access.AccessDeniedException; import org.springframework.security.access.annotation.Secured; import org.springframework.web.bind.annotation.*; -import java.util.List; -import java.util.UUID; - -import static io.openbas.config.SessionHelper.currentUser; -import static io.openbas.database.model.User.ROLE_USER; -import static io.openbas.database.specification.TokenSpecification.fromUser; -import static io.openbas.helper.DatabaseHelper.updateRelation; - @RestController public class MeApi extends RestBehavior { - @Resource - private SessionManager sessionManager; + @Resource private SessionManager sessionManager; private OrganizationRepository organizationRepository; private TokenRepository tokenRepository; @@ -71,15 +69,19 @@ public ResponseEntity logout() { @Secured(ROLE_USER) @GetMapping("/api/me") public User me() { - return userRepository.findById(currentUser().getId()).orElseThrow(ElementNotFoundException::new); + return userRepository + .findById(currentUser().getId()) + .orElseThrow(ElementNotFoundException::new); } @Secured(ROLE_USER) @PutMapping("/api/me/profile") public User updateProfile(@Valid @RequestBody UpdateProfileInput input) { - User user = userRepository.findById(currentUser().getId()).orElseThrow(ElementNotFoundException::new); + User user = + userRepository.findById(currentUser().getId()).orElseThrow(ElementNotFoundException::new); user.setUpdateAttributes(input); - user.setOrganization(updateRelation(input.getOrganizationId(), user.getOrganization(), organizationRepository)); + user.setOrganization( + updateRelation(input.getOrganizationId(), user.getOrganization(), organizationRepository)); User savedUser = userRepository.save(user); sessionManager.refreshUserSessions(savedUser); return savedUser; @@ -88,7 +90,8 @@ public User updateProfile(@Valid @RequestBody UpdateProfileInput input) { @Secured(ROLE_USER) @PutMapping("/api/me/information") public User updateInformation(@Valid @RequestBody UpdateUserInfoInput input) { - User user = userRepository.findById(currentUser().getId()).orElseThrow(ElementNotFoundException::new); + User user = + userRepository.findById(currentUser().getId()).orElseThrow(ElementNotFoundException::new); user.setUpdateAttributes(input); User savedUser = userRepository.save(user); sessionManager.refreshUserSessions(savedUser); @@ -97,8 +100,10 @@ public User updateInformation(@Valid @RequestBody UpdateUserInfoInput input) { @Secured(ROLE_USER) @PutMapping("/api/me/password") - public User updatePassword(@Valid @RequestBody UpdateMePasswordInput input) throws InputValidationException { - User user = userRepository.findById(currentUser().getId()).orElseThrow(ElementNotFoundException::new); + public User updatePassword(@Valid @RequestBody UpdateMePasswordInput input) + throws InputValidationException { + User user = + userRepository.findById(currentUser().getId()).orElseThrow(ElementNotFoundException::new); if (userService.isUserPasswordValid(user, input.getCurrentPassword())) { user.setPassword(userService.encodeUserPassword(input.getPassword())); return userRepository.save(user); @@ -110,9 +115,12 @@ public User updatePassword(@Valid @RequestBody UpdateMePasswordInput input) thro @Secured(ROLE_USER) @PostMapping("/api/me/token/refresh") @Transactional(rollbackOn = Exception.class) - public Token renewToken(@Valid @RequestBody RenewTokenInput input) throws InputValidationException { - User user = userRepository.findById(currentUser().getId()).orElseThrow(ElementNotFoundException::new); - Token token = tokenRepository.findById(input.getTokenId()).orElseThrow(ElementNotFoundException::new); + public Token renewToken(@Valid @RequestBody RenewTokenInput input) + throws InputValidationException { + User user = + userRepository.findById(currentUser().getId()).orElseThrow(ElementNotFoundException::new); + Token token = + tokenRepository.findById(input.getTokenId()).orElseThrow(ElementNotFoundException::new); if (!user.equals(token.getUser())) { throw new AccessDeniedException("You are not allowed to renew this token"); } diff --git a/openbas-api/src/main/java/io/openbas/rest/user/PlayerApi.java b/openbas-api/src/main/java/io/openbas/rest/user/PlayerApi.java index af62960bcc..d79855a23d 100644 --- a/openbas-api/src/main/java/io/openbas/rest/user/PlayerApi.java +++ b/openbas-api/src/main/java/io/openbas/rest/user/PlayerApi.java @@ -1,5 +1,11 @@ package io.openbas.rest.user; +import static io.openbas.config.SessionHelper.currentUser; +import static io.openbas.helper.DatabaseHelper.updateRelation; +import static io.openbas.helper.StreamHelper.fromIterable; +import static io.openbas.helper.StreamHelper.iterableToSet; +import static java.time.Instant.now; + import io.openbas.aop.LogExecutionTime; import io.openbas.config.SessionManager; import io.openbas.database.model.Communication; @@ -16,29 +22,21 @@ import jakarta.annotation.Resource; import jakarta.transaction.Transactional; import jakarta.validation.Valid; +import java.util.Optional; +import java.util.stream.Stream; import lombok.RequiredArgsConstructor; import org.springframework.data.domain.Page; import org.springframework.security.access.prepost.PreAuthorize; import org.springframework.util.StringUtils; import org.springframework.web.bind.annotation.*; -import java.util.Optional; -import java.util.stream.Stream; - -import static io.openbas.config.SessionHelper.currentUser; -import static io.openbas.helper.DatabaseHelper.updateRelation; -import static io.openbas.helper.StreamHelper.fromIterable; -import static io.openbas.helper.StreamHelper.iterableToSet; -import static java.time.Instant.now; - @RestController @RequiredArgsConstructor public class PlayerApi extends RestBehavior { public static final String PLAYER_URI = "/api/players"; - @Resource - private SessionManager sessionManager; + @Resource private SessionManager sessionManager; private final CommunicationRepository communicationRepository; private final OrganizationRepository organizationRepository; @@ -50,7 +48,8 @@ public class PlayerApi extends RestBehavior { @LogExecutionTime @PostMapping(PLAYER_URI + "/search") - public Page players(@RequestBody @Valid SearchPaginationInput searchPaginationInput) { + public Page players( + @RequestBody @Valid SearchPaginationInput searchPaginationInput) { return this.playerService.playerPagination(searchPaginationInput); } @@ -69,7 +68,8 @@ public User createPlayer(@Valid @RequestBody PlayerInput input) { User user = new User(); user.setUpdateAttributes(input); user.setTags(iterableToSet(tagRepository.findAllById(input.getTagIds()))); - user.setOrganization(updateRelation(input.getOrganizationId(), user.getOrganization(), organizationRepository)); + user.setOrganization( + updateRelation(input.getOrganizationId(), user.getOrganization(), organizationRepository)); User savedUser = userRepository.save(user); userService.createUserToken(savedUser); return savedUser; @@ -85,15 +85,24 @@ public User upsertPlayer(@Valid @RequestBody PlayerInput input) { User existingUser = user.get(); existingUser.setUpdateAttributes(input); existingUser.setUpdatedAt(now()); - Iterable tags = Stream.concat(existingUser.getTags().stream().map(Tag::getId).toList().stream(), - input.getTagIds().stream()).distinct().toList(); + Iterable tags = + Stream.concat( + existingUser.getTags().stream().map(Tag::getId).toList().stream(), + input.getTagIds().stream()) + .distinct() + .toList(); existingUser.setTags(iterableToSet(tagRepository.findAllById(tags))); - Iterable teams = Stream.concat(existingUser.getTeams().stream().map(Team::getId).toList().stream(), - input.getTeamIds().stream()).distinct().toList(); + Iterable teams = + Stream.concat( + existingUser.getTeams().stream().map(Team::getId).toList().stream(), + input.getTeamIds().stream()) + .distinct() + .toList(); existingUser.setTeams(fromIterable(teamRepository.findAllById(teams))); if (StringUtils.hasText(input.getOrganizationId())) { existingUser.setOrganization( - updateRelation(input.getOrganizationId(), existingUser.getOrganization(), organizationRepository)); + updateRelation( + input.getOrganizationId(), existingUser.getOrganization(), organizationRepository)); } return userRepository.save(existingUser); } else { @@ -101,7 +110,8 @@ public User upsertPlayer(@Valid @RequestBody PlayerInput input) { newUser.setUpdateAttributes(input); newUser.setTags(iterableToSet(tagRepository.findAllById(input.getTagIds()))); newUser.setOrganization( - updateRelation(input.getOrganizationId(), newUser.getOrganization(), organizationRepository)); + updateRelation( + input.getOrganizationId(), newUser.getOrganization(), organizationRepository)); newUser.setTeams(fromIterable(teamRepository.findAllById(input.getTeamIds()))); User savedUser = userRepository.save(newUser); userService.createUserToken(savedUser); @@ -119,7 +129,8 @@ public User updatePlayer(@PathVariable String userId, @Valid @RequestBody Player } user.setUpdateAttributes(input); user.setTags(iterableToSet(tagRepository.findAllById(input.getTagIds()))); - user.setOrganization(updateRelation(input.getOrganizationId(), user.getOrganization(), organizationRepository)); + user.setOrganization( + updateRelation(input.getOrganizationId(), user.getOrganization(), organizationRepository)); return userRepository.save(user); } diff --git a/openbas-api/src/main/java/io/openbas/rest/user/PlayerQueryHelper.java b/openbas-api/src/main/java/io/openbas/rest/user/PlayerQueryHelper.java index 53b720d95c..ec65a6d842 100644 --- a/openbas-api/src/main/java/io/openbas/rest/user/PlayerQueryHelper.java +++ b/openbas-api/src/main/java/io/openbas/rest/user/PlayerQueryHelper.java @@ -1,5 +1,8 @@ package io.openbas.rest.user; +import static io.openbas.utils.JpaUtils.createJoinArrayAggOnId; +import static io.openbas.utils.JpaUtils.createLeftJoin; + import io.openbas.database.model.User; import io.openbas.rest.user.form.player.PlayerOutput; import jakarta.persistence.Tuple; @@ -8,66 +11,61 @@ import jakarta.persistence.criteria.CriteriaQuery; import jakarta.persistence.criteria.Expression; import jakarta.persistence.criteria.Root; - import java.util.Arrays; import java.util.Collections; import java.util.List; import java.util.stream.Collectors; -import static io.openbas.utils.JpaUtils.createJoinArrayAggOnId; -import static io.openbas.utils.JpaUtils.createLeftJoin; - public class PlayerQueryHelper { - private PlayerQueryHelper() { - - } + private PlayerQueryHelper() {} // -- SELECT -- public static void select(CriteriaBuilder cb, CriteriaQuery cq, Root userRoot) { // Array aggregations Expression tagIdsExpression = createJoinArrayAggOnId(cb, userRoot, "tags"); - Expression organizationIdExpression = createLeftJoin(userRoot, "organization").get("id"); + Expression organizationIdExpression = + createLeftJoin(userRoot, "organization").get("id"); // Multiselect cq.multiselect( - userRoot.get("id").alias("user_id"), - userRoot.get("email").alias("user_email"), - userRoot.get("firstname").alias("user_firstname"), - userRoot.get("lastname").alias("user_lastname"), - userRoot.get("country").alias("user_country"), - userRoot.get("phone").alias("user_phone"), - userRoot.get("phone2").alias("user_phone2"), - userRoot.get("pgpKey").alias("user_pgp_key"), - organizationIdExpression.alias("user_organization"), - tagIdsExpression.alias("user_tags") - ).distinct(true); + userRoot.get("id").alias("user_id"), + userRoot.get("email").alias("user_email"), + userRoot.get("firstname").alias("user_firstname"), + userRoot.get("lastname").alias("user_lastname"), + userRoot.get("country").alias("user_country"), + userRoot.get("phone").alias("user_phone"), + userRoot.get("phone2").alias("user_phone2"), + userRoot.get("pgpKey").alias("user_pgp_key"), + organizationIdExpression.alias("user_organization"), + tagIdsExpression.alias("user_tags")) + .distinct(true); // Group by - cq.groupBy(Collections.singletonList( - userRoot.get("id") - )); + cq.groupBy(Collections.singletonList(userRoot.get("id"))); } // -- EXECUTION -- public static List execution(TypedQuery query) { - return query.getResultList() - .stream() - .map(tuple -> PlayerOutput.builder() - .id(tuple.get("user_id", String.class)) - .email(tuple.get("user_email", String.class)) - .firstname(tuple.get("user_firstname", String.class)) - .lastname(tuple.get("user_lastname", String.class)) - .country(tuple.get("user_country", String.class)) - .phone(tuple.get("user_phone", String.class)) - .phone2(tuple.get("user_phone2", String.class)) - .pgpKey(tuple.get("user_pgp_key", String.class)) - .organization(tuple.get("user_organization", String.class)) - .tags(Arrays.stream(tuple.get("user_tags", String[].class)).collect(Collectors.toSet())) - .build()) + return query.getResultList().stream() + .map( + tuple -> + PlayerOutput.builder() + .id(tuple.get("user_id", String.class)) + .email(tuple.get("user_email", String.class)) + .firstname(tuple.get("user_firstname", String.class)) + .lastname(tuple.get("user_lastname", String.class)) + .country(tuple.get("user_country", String.class)) + .phone(tuple.get("user_phone", String.class)) + .phone2(tuple.get("user_phone2", String.class)) + .pgpKey(tuple.get("user_pgp_key", String.class)) + .organization(tuple.get("user_organization", String.class)) + .tags( + Arrays.stream(tuple.get("user_tags", String[].class)) + .collect(Collectors.toSet())) + .build()) .toList(); } - } diff --git a/openbas-api/src/main/java/io/openbas/rest/user/PlayerService.java b/openbas-api/src/main/java/io/openbas/rest/user/PlayerService.java index aee52d2abd..0c1f6bb200 100644 --- a/openbas-api/src/main/java/io/openbas/rest/user/PlayerService.java +++ b/openbas-api/src/main/java/io/openbas/rest/user/PlayerService.java @@ -1,5 +1,13 @@ package io.openbas.rest.user; +import static io.openbas.config.SessionHelper.currentUser; +import static io.openbas.database.criteria.GenericCriteria.countQuery; +import static io.openbas.database.specification.UserSpecification.accessibleFromOrganizations; +import static io.openbas.rest.user.PlayerQueryHelper.execution; +import static io.openbas.rest.user.PlayerQueryHelper.select; +import static io.openbas.utils.pagination.PaginationUtils.buildPaginationCriteriaBuilder; +import static io.openbas.utils.pagination.SortUtilsCriteriaBuilder.toSortCriteriaBuilder; + import io.openbas.config.OpenBASPrincipal; import io.openbas.database.model.Organization; import io.openbas.database.model.User; @@ -12,6 +20,7 @@ import jakarta.persistence.Tuple; import jakarta.persistence.TypedQuery; import jakarta.persistence.criteria.*; +import java.util.List; import lombok.RequiredArgsConstructor; import org.apache.commons.lang3.function.TriFunction; import org.jetbrains.annotations.NotNull; @@ -21,48 +30,36 @@ import org.springframework.data.jpa.domain.Specification; import org.springframework.stereotype.Service; -import java.util.List; - -import static io.openbas.config.SessionHelper.currentUser; -import static io.openbas.database.criteria.GenericCriteria.countQuery; -import static io.openbas.database.specification.UserSpecification.accessibleFromOrganizations; -import static io.openbas.rest.user.PlayerQueryHelper.execution; -import static io.openbas.rest.user.PlayerQueryHelper.select; -import static io.openbas.utils.pagination.PaginationUtils.buildPaginationCriteriaBuilder; -import static io.openbas.utils.pagination.SortUtilsCriteriaBuilder.toSortCriteriaBuilder; - @Service @RequiredArgsConstructor public class PlayerService { - @PersistenceContext - private EntityManager entityManager; + @PersistenceContext private EntityManager entityManager; private final UserRepository userRepository; - public Page playerPagination( - @NotNull SearchPaginationInput searchPaginationInput) { - TriFunction, Specification, Pageable, Page> playersFunction; + public Page playerPagination(@NotNull SearchPaginationInput searchPaginationInput) { + TriFunction, Specification, Pageable, Page> + playersFunction; OpenBASPrincipal currentUser = currentUser(); if (currentUser.isAdmin()) { playersFunction = this::paginate; } else { - User local = userRepository.findById(currentUser.getId()).orElseThrow(ElementNotFoundException::new); - List organizationIds = local.getGroups().stream() - .flatMap(group -> group.getOrganizations().stream()) - .map(Organization::getId) - .toList(); - playersFunction = (specification, specificationCount, pageable) -> this.paginate( - accessibleFromOrganizations(organizationIds).and(specification), - accessibleFromOrganizations(organizationIds).and(specificationCount), - pageable - ); + User local = + userRepository.findById(currentUser.getId()).orElseThrow(ElementNotFoundException::new); + List organizationIds = + local.getGroups().stream() + .flatMap(group -> group.getOrganizations().stream()) + .map(Organization::getId) + .toList(); + playersFunction = + (specification, specificationCount, pageable) -> + this.paginate( + accessibleFromOrganizations(organizationIds).and(specification), + accessibleFromOrganizations(organizationIds).and(specificationCount), + pageable); } - return buildPaginationCriteriaBuilder( - playersFunction, - searchPaginationInput, - User.class - ); + return buildPaginationCriteriaBuilder(playersFunction, searchPaginationInput, User.class); } // -- PRIVATE -- @@ -104,5 +101,4 @@ private Page paginate( return new PageImpl<>(players, pageable, total); } - } diff --git a/openbas-api/src/main/java/io/openbas/rest/user/UserApi.java b/openbas-api/src/main/java/io/openbas/rest/user/UserApi.java index 87d40f27a6..ffa1ea35be 100644 --- a/openbas-api/src/main/java/io/openbas/rest/user/UserApi.java +++ b/openbas-api/src/main/java/io/openbas/rest/user/UserApi.java @@ -1,5 +1,10 @@ package io.openbas.rest.user; +import static io.openbas.database.model.User.ROLE_ADMIN; +import static io.openbas.helper.DatabaseHelper.updateRelation; +import static io.openbas.helper.StreamHelper.iterableToSet; +import static io.openbas.utils.pagination.PaginationUtils.buildPaginationJPA; + import io.openbas.config.SessionManager; import io.openbas.database.model.User; import io.openbas.database.raw.RawUser; @@ -20,6 +25,8 @@ import jakarta.annotation.Resource; import jakarta.transaction.Transactional; import jakarta.validation.Valid; +import java.util.List; +import java.util.Optional; import org.apache.commons.collections4.map.PassiveExpiringMap; import org.apache.commons.lang3.RandomStringUtils; import org.springframework.beans.factory.annotation.Autowired; @@ -30,163 +37,164 @@ import org.springframework.security.access.annotation.Secured; import org.springframework.web.bind.annotation.*; -import java.util.List; -import java.util.Optional; - -import static io.openbas.database.model.User.ROLE_ADMIN; -import static io.openbas.helper.DatabaseHelper.updateRelation; -import static io.openbas.helper.StreamHelper.iterableToSet; -import static io.openbas.utils.pagination.PaginationUtils.buildPaginationJPA; - @RestController public class UserApi extends RestBehavior { - PassiveExpiringMap resetTokenMap = new PassiveExpiringMap<>(1000 * 60 * 10); - @Resource - private SessionManager sessionManager; - private OrganizationRepository organizationRepository; - private UserRepository userRepository; - private TagRepository tagRepository; - private UserService userService; - private MailingService mailingService; - - @Autowired - public void setMailingService(MailingService mailingService) { - this.mailingService = mailingService; - } - - @Autowired - public void setTagRepository(TagRepository tagRepository) { - this.tagRepository = tagRepository; + PassiveExpiringMap resetTokenMap = new PassiveExpiringMap<>(1000 * 60 * 10); + @Resource private SessionManager sessionManager; + private OrganizationRepository organizationRepository; + private UserRepository userRepository; + private TagRepository tagRepository; + private UserService userService; + private MailingService mailingService; + + @Autowired + public void setMailingService(MailingService mailingService) { + this.mailingService = mailingService; + } + + @Autowired + public void setTagRepository(TagRepository tagRepository) { + this.tagRepository = tagRepository; + } + + @Autowired + public void setOrganizationRepository(OrganizationRepository organizationRepository) { + this.organizationRepository = organizationRepository; + } + + @Autowired + public void setUserService(UserService userService) { + this.userService = userService; + } + + @Autowired + public void setUserRepository(UserRepository userRepository) { + this.userRepository = userRepository; + } + + @PostMapping("/api/login") + public User login(@Valid @RequestBody LoginUserInput input) { + Optional optionalUser = userRepository.findByEmailIgnoreCase(input.getLogin()); + if (optionalUser.isPresent()) { + User user = optionalUser.get(); + if (userService.isUserPasswordValid(user, input.getPassword())) { + userService.createUserSession(user); + return user; + } } - - @Autowired - public void setOrganizationRepository(OrganizationRepository organizationRepository) { - this.organizationRepository = organizationRepository; + throw new AccessDeniedException("Invalid credentials"); + } + + @PostMapping("/api/reset") + public void passwordReset(@Valid @RequestBody ResetUserInput input) { + Optional optionalUser = userRepository.findByEmailIgnoreCase(input.getLogin()); + if (optionalUser.isPresent()) { + User user = optionalUser.get(); + String resetToken = RandomStringUtils.randomNumeric(8); + String username = user.getName() != null ? user.getName() : user.getEmail(); + if ("fr".equals(input.getLang())) { + String subject = resetToken + " est votre code de récupération de compte OpenBAS"; + String body = + "Bonjour " + + username + + ",
" + + "Nous avons reçu une demande de réinitialisation de votre mot de passe OpenBAS.
" + + "Entrez le code de réinitialisation du mot de passe suivant : " + + resetToken; + mailingService.sendEmail(subject, body, List.of(user)); + } else { + String subject = resetToken + " is your recovery code of your OpenBAS account"; + String body = + "Hi " + + username + + ",
" + + "A request has been made to reset your OpenBAS password.
" + + "Enter the following password recovery code: " + + resetToken; + mailingService.sendEmail(subject, body, List.of(user)); + } + // Store in memory reset token + resetTokenMap.put(resetToken, user.getId()); } - - @Autowired - public void setUserService(UserService userService) { - this.userService = userService; - } - - @Autowired - public void setUserRepository(UserRepository userRepository) { - this.userRepository = userRepository; - } - - @PostMapping("/api/login") - public User login(@Valid @RequestBody LoginUserInput input) { - Optional optionalUser = userRepository.findByEmailIgnoreCase(input.getLogin()); - if (optionalUser.isPresent()) { - User user = optionalUser.get(); - if (userService.isUserPasswordValid(user, input.getPassword())) { - userService.createUserSession(user); - return user; - } - } - throw new AccessDeniedException("Invalid credentials"); - } - - @PostMapping("/api/reset") - public void passwordReset(@Valid @RequestBody ResetUserInput input) { - Optional optionalUser = userRepository.findByEmailIgnoreCase(input.getLogin()); - if (optionalUser.isPresent()) { - User user = optionalUser.get(); - String resetToken = RandomStringUtils.randomNumeric(8); - String username = user.getName() != null ? user.getName() : user.getEmail(); - if ("fr".equals(input.getLang())) { - String subject = resetToken + " est votre code de récupération de compte OpenBAS"; - String body = "Bonjour " + username + ",
" + - "Nous avons reçu une demande de réinitialisation de votre mot de passe OpenBAS.
" + - "Entrez le code de réinitialisation du mot de passe suivant : " + resetToken; - mailingService.sendEmail(subject, body, List.of(user)); - } else { - String subject = resetToken + " is your recovery code of your OpenBAS account"; - String body = "Hi " + username + ",
" + - "A request has been made to reset your OpenBAS password.
" + - "Enter the following password recovery code: " + resetToken; - mailingService.sendEmail(subject, body, List.of(user)); - } - // Store in memory reset token - resetTokenMap.put(resetToken, user.getId()); - } - } - - @PostMapping("/api/reset/{token}") - public User changePasswordReset(@PathVariable String token, @Valid @RequestBody ChangePasswordInput input) throws InputValidationException { - String userId = resetTokenMap.get(token); - if (userId != null) { - String password = input.getPassword(); - String passwordValidation = input.getPasswordValidation(); - if (!passwordValidation.equals(password)) { - throw new InputValidationException("password_validation", "Bad password validation"); - } - User changeUser = userRepository.findById(userId).orElseThrow(ElementNotFoundException::new); - changeUser.setPassword(userService.encodeUserPassword(password)); - User savedUser = userRepository.save(changeUser); - resetTokenMap.remove(token); - return savedUser; - } - // Bad token or expired token - throw new AccessDeniedException("Invalid credentials"); - } - - @GetMapping("/api/reset/{token}") - public boolean validatePasswordResetToken(@PathVariable String token) { - return resetTokenMap.get(token) != null; - } - - @Secured(ROLE_ADMIN) - @GetMapping("/api/users") - public List users() { - return userRepository.rawAll(); - } - - @PostMapping("/api/users/search") - public Page users(@RequestBody @Valid final SearchPaginationInput searchPaginationInput) { - return buildPaginationJPA( - (Specification specification, Pageable pageable) -> this.userRepository.findAll( - specification, pageable), - searchPaginationInput, - User.class - ); - } - - @Secured(ROLE_ADMIN) - @PutMapping("/api/users/{userId}/password") - @Transactional(rollbackOn = Exception.class) - public User changePassword(@PathVariable String userId, - @Valid @RequestBody ChangePasswordInput input) { - User user = userRepository.findById(userId).orElseThrow(ElementNotFoundException::new); - user.setPassword(userService.encodeUserPassword(input.getPassword())); - return userRepository.save(user); - } - - @Secured(ROLE_ADMIN) - @PostMapping("/api/users") - @Transactional(rollbackOn = Exception.class) - public User createUser(@Valid @RequestBody CreateUserInput input) { - return userService.createUser(input, 1); - } - - @Secured(ROLE_ADMIN) - @PutMapping("/api/users/{userId}") - @Transactional(rollbackOn = Exception.class) - public User updateUser(@PathVariable String userId, @Valid @RequestBody UpdateUserInput input) { - User user = userRepository.findById(userId).orElseThrow(ElementNotFoundException::new); - user.setUpdateAttributes(input); - user.setTags(iterableToSet(tagRepository.findAllById(input.getTagIds()))); - user.setOrganization(updateRelation(input.getOrganizationId(), user.getOrganization(), organizationRepository)); - User savedUser = userRepository.save(user); - sessionManager.refreshUserSessions(savedUser); - return savedUser; - } - - @Secured(ROLE_ADMIN) - @DeleteMapping("/api/users/{userId}") - @Transactional(rollbackOn = Exception.class) - public void deleteUser(@PathVariable String userId) { - sessionManager.invalidateUserSession(userId); - userRepository.deleteById(userId); + } + + @PostMapping("/api/reset/{token}") + public User changePasswordReset( + @PathVariable String token, @Valid @RequestBody ChangePasswordInput input) + throws InputValidationException { + String userId = resetTokenMap.get(token); + if (userId != null) { + String password = input.getPassword(); + String passwordValidation = input.getPasswordValidation(); + if (!passwordValidation.equals(password)) { + throw new InputValidationException("password_validation", "Bad password validation"); + } + User changeUser = userRepository.findById(userId).orElseThrow(ElementNotFoundException::new); + changeUser.setPassword(userService.encodeUserPassword(password)); + User savedUser = userRepository.save(changeUser); + resetTokenMap.remove(token); + return savedUser; } + // Bad token or expired token + throw new AccessDeniedException("Invalid credentials"); + } + + @GetMapping("/api/reset/{token}") + public boolean validatePasswordResetToken(@PathVariable String token) { + return resetTokenMap.get(token) != null; + } + + @Secured(ROLE_ADMIN) + @GetMapping("/api/users") + public List users() { + return userRepository.rawAll(); + } + + @PostMapping("/api/users/search") + public Page users(@RequestBody @Valid final SearchPaginationInput searchPaginationInput) { + return buildPaginationJPA( + (Specification specification, Pageable pageable) -> + this.userRepository.findAll(specification, pageable), + searchPaginationInput, + User.class); + } + + @Secured(ROLE_ADMIN) + @PutMapping("/api/users/{userId}/password") + @Transactional(rollbackOn = Exception.class) + public User changePassword( + @PathVariable String userId, @Valid @RequestBody ChangePasswordInput input) { + User user = userRepository.findById(userId).orElseThrow(ElementNotFoundException::new); + user.setPassword(userService.encodeUserPassword(input.getPassword())); + return userRepository.save(user); + } + + @Secured(ROLE_ADMIN) + @PostMapping("/api/users") + @Transactional(rollbackOn = Exception.class) + public User createUser(@Valid @RequestBody CreateUserInput input) { + return userService.createUser(input, 1); + } + + @Secured(ROLE_ADMIN) + @PutMapping("/api/users/{userId}") + @Transactional(rollbackOn = Exception.class) + public User updateUser(@PathVariable String userId, @Valid @RequestBody UpdateUserInput input) { + User user = userRepository.findById(userId).orElseThrow(ElementNotFoundException::new); + user.setUpdateAttributes(input); + user.setTags(iterableToSet(tagRepository.findAllById(input.getTagIds()))); + user.setOrganization( + updateRelation(input.getOrganizationId(), user.getOrganization(), organizationRepository)); + User savedUser = userRepository.save(user); + sessionManager.refreshUserSessions(savedUser); + return savedUser; + } + + @Secured(ROLE_ADMIN) + @DeleteMapping("/api/users/{userId}") + @Transactional(rollbackOn = Exception.class) + public void deleteUser(@PathVariable String userId) { + sessionManager.invalidateUserSession(userId); + userRepository.deleteById(userId); + } } diff --git a/openbas-api/src/main/java/io/openbas/rest/user/form/login/LoginUserInput.java b/openbas-api/src/main/java/io/openbas/rest/user/form/login/LoginUserInput.java index b5f4430c08..a2c61a49cd 100644 --- a/openbas-api/src/main/java/io/openbas/rest/user/form/login/LoginUserInput.java +++ b/openbas-api/src/main/java/io/openbas/rest/user/form/login/LoginUserInput.java @@ -1,11 +1,11 @@ package io.openbas.rest.user.form.login; +import static io.openbas.config.AppConfig.MANDATORY_MESSAGE; + import com.fasterxml.jackson.annotation.JsonProperty; import jakarta.validation.constraints.NotBlank; import lombok.*; -import static io.openbas.config.AppConfig.MANDATORY_MESSAGE; - @Builder @Getter @Setter @@ -13,11 +13,10 @@ @AllArgsConstructor public class LoginUserInput { - @NotBlank(message = MANDATORY_MESSAGE) - private String login; - - @NotBlank(message = MANDATORY_MESSAGE) - @JsonProperty - private String password; + @NotBlank(message = MANDATORY_MESSAGE) + private String login; + @NotBlank(message = MANDATORY_MESSAGE) + @JsonProperty + private String password; } diff --git a/openbas-api/src/main/java/io/openbas/rest/user/form/login/ResetUserInput.java b/openbas-api/src/main/java/io/openbas/rest/user/form/login/ResetUserInput.java index 5520d67d96..a199713fbb 100644 --- a/openbas-api/src/main/java/io/openbas/rest/user/form/login/ResetUserInput.java +++ b/openbas-api/src/main/java/io/openbas/rest/user/form/login/ResetUserInput.java @@ -1,29 +1,29 @@ package io.openbas.rest.user.form.login; -import jakarta.validation.constraints.NotBlank; - import static io.openbas.config.AppConfig.MANDATORY_MESSAGE; +import jakarta.validation.constraints.NotBlank; + public class ResetUserInput { - @NotBlank(message = MANDATORY_MESSAGE) - private String login; + @NotBlank(message = MANDATORY_MESSAGE) + private String login; - private String lang; + private String lang; - public String getLogin() { - return login; - } + public String getLogin() { + return login; + } - public void setLogin(String login) { - this.login = login; - } + public void setLogin(String login) { + this.login = login; + } - public String getLang() { - return lang; - } + public String getLang() { + return lang; + } - public void setLang(String lang) { - this.lang = lang; - } + public void setLang(String lang) { + this.lang = lang; + } } diff --git a/openbas-api/src/main/java/io/openbas/rest/user/form/me/UpdateMePasswordInput.java b/openbas-api/src/main/java/io/openbas/rest/user/form/me/UpdateMePasswordInput.java index e8f93e6d80..5aad6813a8 100644 --- a/openbas-api/src/main/java/io/openbas/rest/user/form/me/UpdateMePasswordInput.java +++ b/openbas-api/src/main/java/io/openbas/rest/user/form/me/UpdateMePasswordInput.java @@ -1,34 +1,33 @@ package io.openbas.rest.user.form.me; -import com.fasterxml.jackson.annotation.JsonProperty; +import static io.openbas.config.AppConfig.MANDATORY_MESSAGE; +import com.fasterxml.jackson.annotation.JsonProperty; import jakarta.validation.constraints.NotBlank; -import static io.openbas.config.AppConfig.MANDATORY_MESSAGE; - public class UpdateMePasswordInput { - @NotBlank(message = MANDATORY_MESSAGE) - @JsonProperty("user_current_password") - private String currentPassword; + @NotBlank(message = MANDATORY_MESSAGE) + @JsonProperty("user_current_password") + private String currentPassword; - @NotBlank(message = MANDATORY_MESSAGE) - @JsonProperty("user_plain_password") - private String password; + @NotBlank(message = MANDATORY_MESSAGE) + @JsonProperty("user_plain_password") + private String password; - public String getCurrentPassword() { - return currentPassword; - } + public String getCurrentPassword() { + return currentPassword; + } - public void setCurrentPassword(String currentPassword) { - this.currentPassword = currentPassword; - } + public void setCurrentPassword(String currentPassword) { + this.currentPassword = currentPassword; + } - public String getPassword() { - return password; - } + public String getPassword() { + return password; + } - public void setPassword(String password) { - this.password = password; - } + public void setPassword(String password) { + this.password = password; + } } diff --git a/openbas-api/src/main/java/io/openbas/rest/user/form/me/UpdateProfileInput.java b/openbas-api/src/main/java/io/openbas/rest/user/form/me/UpdateProfileInput.java index 8d8a1fe4c4..eaee296832 100644 --- a/openbas-api/src/main/java/io/openbas/rest/user/form/me/UpdateProfileInput.java +++ b/openbas-api/src/main/java/io/openbas/rest/user/form/me/UpdateProfileInput.java @@ -1,41 +1,39 @@ package io.openbas.rest.user.form.me; -import com.fasterxml.jackson.annotation.JsonProperty; -import lombok.Getter; -import lombok.Setter; +import static io.openbas.config.AppConfig.EMAIL_FORMAT; +import static io.openbas.config.AppConfig.MANDATORY_MESSAGE; +import com.fasterxml.jackson.annotation.JsonProperty; import jakarta.validation.constraints.Email; import jakarta.validation.constraints.NotBlank; - -import static io.openbas.config.AppConfig.EMAIL_FORMAT; -import static io.openbas.config.AppConfig.MANDATORY_MESSAGE; +import lombok.Getter; +import lombok.Setter; @Getter @Setter public class UpdateProfileInput { - @Email(message = EMAIL_FORMAT) - @JsonProperty("user_email") - private String email; - - @NotBlank(message = MANDATORY_MESSAGE) - @JsonProperty("user_firstname") - private String firstname; + @Email(message = EMAIL_FORMAT) + @JsonProperty("user_email") + private String email; - @NotBlank(message = MANDATORY_MESSAGE) - @JsonProperty("user_lastname") - private String lastname; + @NotBlank(message = MANDATORY_MESSAGE) + @JsonProperty("user_firstname") + private String firstname; - @JsonProperty("user_organization") - private String organizationId; + @NotBlank(message = MANDATORY_MESSAGE) + @JsonProperty("user_lastname") + private String lastname; - @JsonProperty("user_lang") - private String lang; + @JsonProperty("user_organization") + private String organizationId; - @JsonProperty("user_theme") - private String theme; + @JsonProperty("user_lang") + private String lang; - @JsonProperty("user_country") - private String country; + @JsonProperty("user_theme") + private String theme; + @JsonProperty("user_country") + private String country; } diff --git a/openbas-api/src/main/java/io/openbas/rest/user/form/player/PlayerInput.java b/openbas-api/src/main/java/io/openbas/rest/user/form/player/PlayerInput.java index 25cf5c78b1..87a7ff520d 100644 --- a/openbas-api/src/main/java/io/openbas/rest/user/form/player/PlayerInput.java +++ b/openbas-api/src/main/java/io/openbas/rest/user/form/player/PlayerInput.java @@ -1,18 +1,16 @@ package io.openbas.rest.user.form.player; -import com.fasterxml.jackson.annotation.JsonProperty; -import jakarta.validation.constraints.Pattern; -import lombok.Getter; -import lombok.Setter; +import static io.openbas.config.AppConfig.EMAIL_FORMAT; +import static io.openbas.config.AppConfig.PHONE_FORMAT; +import com.fasterxml.jackson.annotation.JsonProperty; import jakarta.validation.constraints.Email; import jakarta.validation.constraints.NotBlank; - +import jakarta.validation.constraints.Pattern; import java.util.ArrayList; import java.util.List; - -import static io.openbas.config.AppConfig.EMAIL_FORMAT; -import static io.openbas.config.AppConfig.PHONE_FORMAT; +import lombok.Getter; +import lombok.Setter; @Getter @Setter diff --git a/openbas-api/src/main/java/io/openbas/rest/user/form/player/PlayerOutput.java b/openbas-api/src/main/java/io/openbas/rest/user/form/player/PlayerOutput.java index 1366288f5d..27c8e4b4ef 100644 --- a/openbas-api/src/main/java/io/openbas/rest/user/form/player/PlayerOutput.java +++ b/openbas-api/src/main/java/io/openbas/rest/user/form/player/PlayerOutput.java @@ -2,11 +2,10 @@ import com.fasterxml.jackson.annotation.JsonProperty; import jakarta.validation.constraints.NotBlank; +import java.util.Set; import lombok.Builder; import lombok.Data; -import java.util.Set; - @Builder @Data public class PlayerOutput { @@ -42,5 +41,4 @@ public class PlayerOutput { @JsonProperty("user_tags") private Set tags; - } diff --git a/openbas-api/src/main/java/io/openbas/rest/user/form/user/ChangePasswordInput.java b/openbas-api/src/main/java/io/openbas/rest/user/form/user/ChangePasswordInput.java index 0bc83106e1..3f5c12ef36 100644 --- a/openbas-api/src/main/java/io/openbas/rest/user/form/user/ChangePasswordInput.java +++ b/openbas-api/src/main/java/io/openbas/rest/user/form/user/ChangePasswordInput.java @@ -1,34 +1,33 @@ package io.openbas.rest.user.form.user; -import com.fasterxml.jackson.annotation.JsonProperty; +import static io.openbas.config.AppConfig.MANDATORY_MESSAGE; +import com.fasterxml.jackson.annotation.JsonProperty; import jakarta.validation.constraints.NotBlank; -import static io.openbas.config.AppConfig.MANDATORY_MESSAGE; - public class ChangePasswordInput { - @NotBlank(message = MANDATORY_MESSAGE) - @JsonProperty("password") - private String password; + @NotBlank(message = MANDATORY_MESSAGE) + @JsonProperty("password") + private String password; - @NotBlank(message = MANDATORY_MESSAGE) - @JsonProperty("password_validation") - private String passwordValidation; + @NotBlank(message = MANDATORY_MESSAGE) + @JsonProperty("password_validation") + private String passwordValidation; - public String getPassword() { - return password; - } + public String getPassword() { + return password; + } - public void setPassword(String password) { - this.password = password; - } + public void setPassword(String password) { + this.password = password; + } - public String getPasswordValidation() { - return passwordValidation; - } + public String getPasswordValidation() { + return passwordValidation; + } - public void setPasswordValidation(String passwordValidation) { - this.passwordValidation = passwordValidation; - } + public void setPasswordValidation(String passwordValidation) { + this.passwordValidation = passwordValidation; + } } diff --git a/openbas-api/src/main/java/io/openbas/rest/user/form/user/CreateUserInput.java b/openbas-api/src/main/java/io/openbas/rest/user/form/user/CreateUserInput.java index f7f116e106..6a87e73b48 100644 --- a/openbas-api/src/main/java/io/openbas/rest/user/form/user/CreateUserInput.java +++ b/openbas-api/src/main/java/io/openbas/rest/user/form/user/CreateUserInput.java @@ -1,15 +1,14 @@ package io.openbas.rest.user.form.user; -import com.fasterxml.jackson.annotation.JsonProperty; -import lombok.Getter; -import lombok.Setter; +import static io.openbas.config.AppConfig.EMAIL_FORMAT; +import com.fasterxml.jackson.annotation.JsonProperty; import jakarta.validation.constraints.Email; import jakarta.validation.constraints.NotBlank; import java.util.ArrayList; import java.util.List; - -import static io.openbas.config.AppConfig.EMAIL_FORMAT; +import lombok.Getter; +import lombok.Setter; @Getter @Setter @@ -37,5 +36,4 @@ public class CreateUserInput { @JsonProperty("user_tags") private List tagIds = new ArrayList<>(); - } diff --git a/openbas-api/src/main/java/io/openbas/rest/user/form/user/RenewTokenInput.java b/openbas-api/src/main/java/io/openbas/rest/user/form/user/RenewTokenInput.java index c82efdf0b6..aac23d9716 100644 --- a/openbas-api/src/main/java/io/openbas/rest/user/form/user/RenewTokenInput.java +++ b/openbas-api/src/main/java/io/openbas/rest/user/form/user/RenewTokenInput.java @@ -1,22 +1,21 @@ package io.openbas.rest.user.form.user; -import com.fasterxml.jackson.annotation.JsonProperty; +import static io.openbas.config.AppConfig.MANDATORY_MESSAGE; +import com.fasterxml.jackson.annotation.JsonProperty; import jakarta.validation.constraints.NotBlank; -import static io.openbas.config.AppConfig.MANDATORY_MESSAGE; - public class RenewTokenInput { - @NotBlank(message = MANDATORY_MESSAGE) - @JsonProperty("token_id") - private String tokenId; + @NotBlank(message = MANDATORY_MESSAGE) + @JsonProperty("token_id") + private String tokenId; - public String getTokenId() { - return tokenId; - } + public String getTokenId() { + return tokenId; + } - public void setTokenId(String tokenId) { - this.tokenId = tokenId; - } + public void setTokenId(String tokenId) { + this.tokenId = tokenId; + } } diff --git a/openbas-api/src/main/java/io/openbas/rest/user/form/user/UpdatePasswordInput.java b/openbas-api/src/main/java/io/openbas/rest/user/form/user/UpdatePasswordInput.java index 10d28ec612..177698f5eb 100644 --- a/openbas-api/src/main/java/io/openbas/rest/user/form/user/UpdatePasswordInput.java +++ b/openbas-api/src/main/java/io/openbas/rest/user/form/user/UpdatePasswordInput.java @@ -1,22 +1,21 @@ package io.openbas.rest.user.form.user; -import com.fasterxml.jackson.annotation.JsonProperty; +import static io.openbas.config.AppConfig.MANDATORY_MESSAGE; +import com.fasterxml.jackson.annotation.JsonProperty; import jakarta.validation.constraints.NotBlank; -import static io.openbas.config.AppConfig.MANDATORY_MESSAGE; - public class UpdatePasswordInput { - @NotBlank(message = MANDATORY_MESSAGE) - @JsonProperty("user_plain_password") - private String password; + @NotBlank(message = MANDATORY_MESSAGE) + @JsonProperty("user_plain_password") + private String password; - public String getPassword() { - return password; - } + public String getPassword() { + return password; + } - public void setPassword(String password) { - this.password = password; - } + public void setPassword(String password) { + this.password = password; + } } diff --git a/openbas-api/src/main/java/io/openbas/rest/user/form/user/UpdateUserInfoInput.java b/openbas-api/src/main/java/io/openbas/rest/user/form/user/UpdateUserInfoInput.java index 3ff18e6f2b..2b4ecd3128 100644 --- a/openbas-api/src/main/java/io/openbas/rest/user/form/user/UpdateUserInfoInput.java +++ b/openbas-api/src/main/java/io/openbas/rest/user/form/user/UpdateUserInfoInput.java @@ -8,13 +8,12 @@ @Setter public class UpdateUserInfoInput { - @JsonProperty("user_pgp_key") - private String pgpKey; + @JsonProperty("user_pgp_key") + private String pgpKey; - @JsonProperty("user_phone") - private String phone; - - @JsonProperty("user_phone2") - private String phone2; + @JsonProperty("user_phone") + private String phone; + @JsonProperty("user_phone2") + private String phone2; } diff --git a/openbas-api/src/main/java/io/openbas/rest/user/form/user/UpdateUserInput.java b/openbas-api/src/main/java/io/openbas/rest/user/form/user/UpdateUserInput.java index 6a1164e44d..bfd76e6e0a 100644 --- a/openbas-api/src/main/java/io/openbas/rest/user/form/user/UpdateUserInput.java +++ b/openbas-api/src/main/java/io/openbas/rest/user/form/user/UpdateUserInput.java @@ -1,17 +1,15 @@ package io.openbas.rest.user.form.user; -import com.fasterxml.jackson.annotation.JsonProperty; -import jakarta.validation.constraints.Pattern; -import lombok.Getter; -import lombok.Setter; +import static io.openbas.config.AppConfig.EMAIL_FORMAT; +import static io.openbas.config.AppConfig.PHONE_FORMAT; +import com.fasterxml.jackson.annotation.JsonProperty; import jakarta.validation.constraints.Email; - +import jakarta.validation.constraints.Pattern; import java.util.ArrayList; import java.util.List; - -import static io.openbas.config.AppConfig.EMAIL_FORMAT; -import static io.openbas.config.AppConfig.PHONE_FORMAT; +import lombok.Getter; +import lombok.Setter; @Getter @Setter @@ -46,5 +44,4 @@ public class UpdateUserInput { @JsonProperty("user_tags") private List tagIds = new ArrayList<>(); - } diff --git a/openbas-api/src/main/java/io/openbas/rest/variable/VariableApi.java b/openbas-api/src/main/java/io/openbas/rest/variable/VariableApi.java index a3a55957ab..fdd1605ae3 100644 --- a/openbas-api/src/main/java/io/openbas/rest/variable/VariableApi.java +++ b/openbas-api/src/main/java/io/openbas/rest/variable/VariableApi.java @@ -1,5 +1,9 @@ package io.openbas.rest.variable; +import static io.openbas.database.model.User.ROLE_USER; +import static io.openbas.rest.exercise.ExerciseApi.EXERCISE_URI; +import static io.openbas.rest.scenario.ScenarioApi.SCENARIO_URI; + import io.openbas.database.model.Exercise; import io.openbas.database.model.Scenario; import io.openbas.database.model.Variable; @@ -16,10 +20,6 @@ import org.springframework.security.access.prepost.PreAuthorize; import org.springframework.web.bind.annotation.*; -import static io.openbas.database.model.User.ROLE_USER; -import static io.openbas.rest.exercise.ExerciseApi.EXERCISE_URI; -import static io.openbas.rest.scenario.ScenarioApi.SCENARIO_URI; - @RequiredArgsConstructor @RestController @Secured(ROLE_USER) @@ -40,7 +40,8 @@ public Variable createVariableForExercise( @Valid @RequestBody final VariableInput input) { Variable variable = new Variable(); variable.setUpdateAttributes(input); - Exercise exercise = this.exerciseRepository.findById(exerciseId).orElseThrow(ElementNotFoundException::new); + Exercise exercise = + this.exerciseRepository.findById(exerciseId).orElseThrow(ElementNotFoundException::new); variable.setExercise(exercise); return this.variableService.createVariable(variable); } @@ -114,5 +115,4 @@ public void deleteVariableForScenario( assert scenarioId.equals(variable.getScenario().getId()); this.variableService.deleteVariable(variableId); } - } diff --git a/openbas-api/src/main/java/io/openbas/rest/variable/form/VariableInput.java b/openbas-api/src/main/java/io/openbas/rest/variable/form/VariableInput.java index 9379b917e2..8b696e8b8c 100644 --- a/openbas-api/src/main/java/io/openbas/rest/variable/form/VariableInput.java +++ b/openbas-api/src/main/java/io/openbas/rest/variable/form/VariableInput.java @@ -1,19 +1,18 @@ package io.openbas.rest.variable.form; -import com.fasterxml.jackson.annotation.JsonProperty; -import lombok.Data; +import static io.openbas.config.AppConfig.MANDATORY_MESSAGE; +import com.fasterxml.jackson.annotation.JsonProperty; import jakarta.validation.constraints.NotBlank; import jakarta.validation.constraints.Pattern; - -import static io.openbas.config.AppConfig.MANDATORY_MESSAGE; +import lombok.Data; @Data public class VariableInput { @JsonProperty("variable_key") @NotBlank(message = MANDATORY_MESSAGE) - @Pattern(regexp="^[a-z_]+$") + @Pattern(regexp = "^[a-z_]+$") private String key; @JsonProperty("variable_value") @@ -21,5 +20,4 @@ public class VariableInput { @JsonProperty("variable_description") private String description; - } diff --git a/openbas-api/src/main/java/io/openbas/runner/InitAdminCommandLineRunner.java b/openbas-api/src/main/java/io/openbas/runner/InitAdminCommandLineRunner.java index 2e2fcc22eb..2dfd44b5da 100644 --- a/openbas-api/src/main/java/io/openbas/runner/InitAdminCommandLineRunner.java +++ b/openbas-api/src/main/java/io/openbas/runner/InitAdminCommandLineRunner.java @@ -1,9 +1,16 @@ package io.openbas.runner; +import static io.openbas.database.model.Token.ADMIN_TOKEN_UUID; +import static io.openbas.database.model.User.*; +import static org.springframework.util.StringUtils.hasText; + import io.openbas.database.model.Token; import io.openbas.database.model.User; import io.openbas.database.repository.TokenRepository; import io.openbas.database.repository.UserRepository; +import java.time.Instant; +import java.util.Optional; +import java.util.UUID; import org.apache.commons.validator.routines.EmailValidator; import org.jetbrains.annotations.NotNull; import org.springframework.beans.factory.annotation.Value; @@ -12,14 +19,6 @@ import org.springframework.stereotype.Component; import org.springframework.transaction.annotation.Transactional; -import java.time.Instant; -import java.util.Optional; -import java.util.UUID; - -import static io.openbas.database.model.Token.ADMIN_TOKEN_UUID; -import static io.openbas.database.model.User.*; -import static org.springframework.util.StringUtils.hasText; - @Component public class InitAdminCommandLineRunner implements CommandLineRunner { @@ -66,20 +65,24 @@ private User createUser() { if (!hasText(this.adminEmail)) { throw new IllegalArgumentException("Config properties 'openbas.admin.email' cannot be null"); } else if (!EmailValidator.getInstance().isValid(this.adminEmail)) { - throw new IllegalArgumentException("Config properties 'openbas.admin.email' should be a valid email address"); + throw new IllegalArgumentException( + "Config properties 'openbas.admin.email' should be a valid email address"); } if (!hasText(this.adminPassword)) { - throw new IllegalArgumentException("Config properties 'openbas.admin.password' cannot be null"); + throw new IllegalArgumentException( + "Config properties 'openbas.admin.password' cannot be null"); } - this.userRepository.createAdmin(ADMIN_UUID, ADMIN_FIRSTNAME, ADMIN_LASTNAME, this.adminEmail, encodedPassword()); + this.userRepository.createAdmin( + ADMIN_UUID, ADMIN_FIRSTNAME, ADMIN_LASTNAME, this.adminEmail, encodedPassword()); return this.userRepository.findById(ADMIN_UUID).orElseThrow(); } private User updateUser(@NotNull final User user) { if (hasText(this.adminEmail)) { if (!EmailValidator.getInstance().isValid(this.adminEmail)) { - throw new IllegalArgumentException("Config property 'openbas.admin.email' must be a valid email address with a valid domain."); + throw new IllegalArgumentException( + "Config property 'openbas.admin.email' must be a valid email address with a valid domain."); } user.setEmail(this.adminEmail); } @@ -99,10 +102,12 @@ private void createToken(@NotNull final User user) { try { UUID.fromString(this.adminToken); } catch (IllegalArgumentException e) { - throw new IllegalArgumentException("Config properties 'openbas.admin.token' should be a valid UUID"); + throw new IllegalArgumentException( + "Config properties 'openbas.admin.token' should be a valid UUID"); } - this.tokenRepository.createToken(ADMIN_TOKEN_UUID, user.getId(), this.adminToken, Instant.now()); + this.tokenRepository.createToken( + ADMIN_TOKEN_UUID, user.getId(), this.adminToken, Instant.now()); } private void updateToken(@NotNull final Token token) { @@ -110,7 +115,8 @@ private void updateToken(@NotNull final Token token) { try { UUID.fromString(this.adminToken); } catch (IllegalArgumentException e) { - throw new IllegalArgumentException("Config properties 'openbas.admin.token' should be a valid UUID"); + throw new IllegalArgumentException( + "Config properties 'openbas.admin.token' should be a valid UUID"); } token.setValue(this.adminToken); } diff --git a/openbas-api/src/main/java/io/openbas/scheduler/PlatformJobDefinitions.java b/openbas-api/src/main/java/io/openbas/scheduler/PlatformJobDefinitions.java index b6dcdfa8e3..90c0f03745 100644 --- a/openbas-api/src/main/java/io/openbas/scheduler/PlatformJobDefinitions.java +++ b/openbas-api/src/main/java/io/openbas/scheduler/PlatformJobDefinitions.java @@ -1,5 +1,7 @@ package io.openbas.scheduler; +import static org.quartz.JobKey.jobKey; + import io.openbas.scheduler.jobs.ComchecksExecutionJob; import io.openbas.scheduler.jobs.InjectsExecutionJob; import io.openbas.scheduler.jobs.ScenarioExecutionJob; @@ -8,26 +10,30 @@ import org.springframework.context.annotation.Bean; import org.springframework.stereotype.Component; -import static org.quartz.JobKey.jobKey; - @Component public class PlatformJobDefinitions { - @Bean - public JobDetail getInjectsExecution() { - return JobBuilder.newJob(InjectsExecutionJob.class) - .storeDurably().withIdentity(jobKey("InjectsExecutionJob")).build(); - } + @Bean + public JobDetail getInjectsExecution() { + return JobBuilder.newJob(InjectsExecutionJob.class) + .storeDurably() + .withIdentity(jobKey("InjectsExecutionJob")) + .build(); + } - @Bean - public JobDetail getComchecksExecution() { - return JobBuilder.newJob(ComchecksExecutionJob.class) - .storeDurably().withIdentity(jobKey("ComchecksExecutionJob")).build(); - } + @Bean + public JobDetail getComchecksExecution() { + return JobBuilder.newJob(ComchecksExecutionJob.class) + .storeDurably() + .withIdentity(jobKey("ComchecksExecutionJob")) + .build(); + } - @Bean - public JobDetail getScenarioExecution() { - return JobBuilder.newJob(ScenarioExecutionJob.class) - .storeDurably().withIdentity(jobKey("ScenarioExecutionJob")).build(); - } + @Bean + public JobDetail getScenarioExecution() { + return JobBuilder.newJob(ScenarioExecutionJob.class) + .storeDurably() + .withIdentity(jobKey("ScenarioExecutionJob")) + .build(); + } } diff --git a/openbas-api/src/main/java/io/openbas/scheduler/PlatformTriggers.java b/openbas-api/src/main/java/io/openbas/scheduler/PlatformTriggers.java index b5bbbf76cd..f5f8c9cf3a 100644 --- a/openbas-api/src/main/java/io/openbas/scheduler/PlatformTriggers.java +++ b/openbas-api/src/main/java/io/openbas/scheduler/PlatformTriggers.java @@ -1,48 +1,48 @@ package io.openbas.scheduler; +import static org.quartz.CronScheduleBuilder.cronSchedule; +import static org.quartz.SimpleScheduleBuilder.repeatMinutelyForever; +import static org.quartz.TriggerBuilder.newTrigger; + import org.quartz.Trigger; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.context.annotation.Bean; import org.springframework.stereotype.Component; -import static org.quartz.CronScheduleBuilder.cronSchedule; -import static org.quartz.SimpleScheduleBuilder.repeatMinutelyForever; -import static org.quartz.TriggerBuilder.newTrigger; - @Component public class PlatformTriggers { - private PlatformJobDefinitions platformJobs; - - @Autowired - public void setPlatformJobs(PlatformJobDefinitions platformJobs) { - this.platformJobs = platformJobs; - } - - @Bean - public Trigger injectsExecutionTrigger() { - return newTrigger() - .forJob(platformJobs.getInjectsExecution()) - .withIdentity("InjectsExecutionTrigger") - .withSchedule(cronSchedule("0 0/1 * * * ?")) // Every minute align on clock - .build(); - } - - @Bean - public Trigger comchecksExecutionTrigger() { - return newTrigger() - .forJob(platformJobs.getComchecksExecution()) - .withIdentity("ComchecksExecutionTrigger") - .withSchedule(repeatMinutelyForever()) - .build(); - } - - @Bean - public Trigger scenarioExecutionTrigger() { - return newTrigger() - .forJob(this.platformJobs.getScenarioExecution()) - .withIdentity("ScenarioExecutionTrigger") - .withSchedule(repeatMinutelyForever()) - .build(); - } + private PlatformJobDefinitions platformJobs; + + @Autowired + public void setPlatformJobs(PlatformJobDefinitions platformJobs) { + this.platformJobs = platformJobs; + } + + @Bean + public Trigger injectsExecutionTrigger() { + return newTrigger() + .forJob(platformJobs.getInjectsExecution()) + .withIdentity("InjectsExecutionTrigger") + .withSchedule(cronSchedule("0 0/1 * * * ?")) // Every minute align on clock + .build(); + } + + @Bean + public Trigger comchecksExecutionTrigger() { + return newTrigger() + .forJob(platformJobs.getComchecksExecution()) + .withIdentity("ComchecksExecutionTrigger") + .withSchedule(repeatMinutelyForever()) + .build(); + } + + @Bean + public Trigger scenarioExecutionTrigger() { + return newTrigger() + .forJob(this.platformJobs.getScenarioExecution()) + .withIdentity("ScenarioExecutionTrigger") + .withSchedule(repeatMinutelyForever()) + .build(); + } } diff --git a/openbas-api/src/main/java/io/openbas/scheduler/jobs/ComcheckContext.java b/openbas-api/src/main/java/io/openbas/scheduler/jobs/ComcheckContext.java index e6c3d671ec..fe05513d82 100644 --- a/openbas-api/src/main/java/io/openbas/scheduler/jobs/ComcheckContext.java +++ b/openbas-api/src/main/java/io/openbas/scheduler/jobs/ComcheckContext.java @@ -7,10 +7,10 @@ @Getter public class ComcheckContext { - private String url; + private String url; - @Override - public String toString() { - return url; - } + @Override + public String toString() { + return url; + } } diff --git a/openbas-api/src/main/java/io/openbas/scheduler/jobs/ComchecksExecutionJob.java b/openbas-api/src/main/java/io/openbas/scheduler/jobs/ComchecksExecutionJob.java index f53c9b2166..31f8d64bd3 100644 --- a/openbas-api/src/main/java/io/openbas/scheduler/jobs/ComchecksExecutionJob.java +++ b/openbas-api/src/main/java/io/openbas/scheduler/jobs/ComchecksExecutionJob.java @@ -1,5 +1,11 @@ package io.openbas.scheduler.jobs; +import static io.openbas.database.model.Comcheck.COMCHECK_STATUS.EXPIRED; +import static io.openbas.database.specification.ComcheckStatusSpecification.thatNeedExecution; +import static io.openbas.injector_contract.variables.VariableHelper.COMCHECK; +import static java.time.Instant.now; +import static java.util.stream.Collectors.groupingBy; + import com.fasterxml.jackson.databind.JsonNode; import com.fasterxml.jackson.databind.ObjectMapper; import com.fasterxml.jackson.databind.node.ObjectNode; @@ -16,6 +22,11 @@ import jakarta.annotation.Resource; import jakarta.transaction.Transactional; import jakarta.validation.constraints.NotNull; +import java.time.Instant; +import java.util.List; +import java.util.Map; +import java.util.logging.Level; +import java.util.logging.Logger; import org.quartz.DisallowConcurrentExecution; import org.quartz.Job; import org.quartz.JobExecutionContext; @@ -24,126 +35,138 @@ import org.springframework.context.ApplicationContext; import org.springframework.stereotype.Component; -import java.time.Instant; -import java.util.List; -import java.util.Map; -import java.util.logging.Level; -import java.util.logging.Logger; - -import static io.openbas.injector_contract.variables.VariableHelper.COMCHECK; -import static io.openbas.database.model.Comcheck.COMCHECK_STATUS.EXPIRED; -import static io.openbas.database.specification.ComcheckStatusSpecification.thatNeedExecution; -import static java.time.Instant.now; -import static java.util.stream.Collectors.groupingBy; - @Component @DisallowConcurrentExecution public class ComchecksExecutionJob implements Job { - private static final Logger LOGGER = Logger.getLogger(ComchecksExecutionJob.class.getName()); - @Resource - private OpenBASConfig openBASConfig; - private ApplicationContext context; - private ComcheckRepository comcheckRepository; - private ComcheckStatusRepository comcheckStatusRepository; - - private InjectorContractRepository injectorContractRepository; - private ExecutionContextService executionContextService; - - @Resource - private ObjectMapper mapper; - - @Autowired - public void setComcheckRepository(ComcheckRepository comcheckRepository) { - this.comcheckRepository = comcheckRepository; - } - - @Autowired - public void setOpenBASConfig(OpenBASConfig OpenBASConfig) { - this.openBASConfig = OpenBASConfig; - } - - @Autowired - public void setContext(ApplicationContext context) { - this.context = context; - } - - @Autowired - public void setComcheckStatusRepository(ComcheckStatusRepository comcheckStatusRepository) { - this.comcheckStatusRepository = comcheckStatusRepository; - } - - @Autowired - public void setInjectorContractRepository(InjectorContractRepository injectorContractRepository) { - this.injectorContractRepository = injectorContractRepository; - } - - @Autowired - public void setExecutionContextService(@NotNull final ExecutionContextService executionContextService) { - this.executionContextService = executionContextService; - } - - private Inject buildComcheckEmail(Comcheck comCheck) { - Inject emailInject = new Inject(); - emailInject.setInjectorContract(injectorContractRepository.findById(EmailContract.EMAIL_DEFAULT).orElseThrow()); - emailInject.setExercise(comCheck.getExercise()); - ObjectNode content = mapper.createObjectNode(); - content.set("subject", mapper.convertValue(comCheck.getSubject(), JsonNode.class)); - content.set("body", mapper.convertValue(comCheck.getMessage(), JsonNode.class)); - content.set("expectationType", mapper.convertValue("none", JsonNode.class)); - emailInject.setContent(content); - return emailInject; - } - - private ComcheckContext buildComcheckLink(ComcheckStatus status) { - ComcheckContext comcheckContext = new ComcheckContext(); - String comCheckLink = openBASConfig.getBaseUrl() + "/comcheck/" + status.getId(); - comcheckContext.setUrl("" + comCheckLink + ""); - return comcheckContext; - } - - @Override - @Transactional - public void execute(JobExecutionContext jobExecutionContext) throws JobExecutionException { - Instant now = now(); - try { - // 01. Manage expired comchecks. - List toExpired = comcheckRepository.thatMustBeExpired(now); - comcheckRepository.saveAll(toExpired.stream() - .peek(comcheck -> comcheck.setState(EXPIRED)).toList()); - // 02. Send all required statuses - List allStatuses = comcheckStatusRepository.findAll(thatNeedExecution()); - Map> byComchecks = allStatuses.stream().collect(groupingBy(ComcheckStatus::getComcheck)); - byComchecks.entrySet().stream().parallel().forEach(entry -> { + private static final Logger LOGGER = Logger.getLogger(ComchecksExecutionJob.class.getName()); + @Resource private OpenBASConfig openBASConfig; + private ApplicationContext context; + private ComcheckRepository comcheckRepository; + private ComcheckStatusRepository comcheckStatusRepository; + + private InjectorContractRepository injectorContractRepository; + private ExecutionContextService executionContextService; + + @Resource private ObjectMapper mapper; + + @Autowired + public void setComcheckRepository(ComcheckRepository comcheckRepository) { + this.comcheckRepository = comcheckRepository; + } + + @Autowired + public void setOpenBASConfig(OpenBASConfig OpenBASConfig) { + this.openBASConfig = OpenBASConfig; + } + + @Autowired + public void setContext(ApplicationContext context) { + this.context = context; + } + + @Autowired + public void setComcheckStatusRepository(ComcheckStatusRepository comcheckStatusRepository) { + this.comcheckStatusRepository = comcheckStatusRepository; + } + + @Autowired + public void setInjectorContractRepository(InjectorContractRepository injectorContractRepository) { + this.injectorContractRepository = injectorContractRepository; + } + + @Autowired + public void setExecutionContextService( + @NotNull final ExecutionContextService executionContextService) { + this.executionContextService = executionContextService; + } + + private Inject buildComcheckEmail(Comcheck comCheck) { + Inject emailInject = new Inject(); + emailInject.setInjectorContract( + injectorContractRepository.findById(EmailContract.EMAIL_DEFAULT).orElseThrow()); + emailInject.setExercise(comCheck.getExercise()); + ObjectNode content = mapper.createObjectNode(); + content.set("subject", mapper.convertValue(comCheck.getSubject(), JsonNode.class)); + content.set("body", mapper.convertValue(comCheck.getMessage(), JsonNode.class)); + content.set("expectationType", mapper.convertValue("none", JsonNode.class)); + emailInject.setContent(content); + return emailInject; + } + + private ComcheckContext buildComcheckLink(ComcheckStatus status) { + ComcheckContext comcheckContext = new ComcheckContext(); + String comCheckLink = openBASConfig.getBaseUrl() + "/comcheck/" + status.getId(); + comcheckContext.setUrl("" + comCheckLink + ""); + return comcheckContext; + } + + @Override + @Transactional + public void execute(JobExecutionContext jobExecutionContext) throws JobExecutionException { + Instant now = now(); + try { + // 01. Manage expired comchecks. + List toExpired = comcheckRepository.thatMustBeExpired(now); + comcheckRepository.saveAll( + toExpired.stream().peek(comcheck -> comcheck.setState(EXPIRED)).toList()); + // 02. Send all required statuses + List allStatuses = comcheckStatusRepository.findAll(thatNeedExecution()); + Map> byComchecks = + allStatuses.stream().collect(groupingBy(ComcheckStatus::getComcheck)); + byComchecks.entrySet().stream() + .parallel() + .forEach( + entry -> { Comcheck comCheck = entry.getKey(); // Send the email to users Exercise exercise = comCheck.getExercise(); List comcheckStatuses = entry.getValue(); - List userInjectContexts = comcheckStatuses.stream().map(comcheckStatus -> { - ExecutionContext injectContext = this.executionContextService.executionContext(comcheckStatus.getUser(), exercise, "Comcheck"); - injectContext.put(COMCHECK, buildComcheckLink(comcheckStatus)); // Add specific inject variable for comcheck link - return injectContext; - }).toList(); + List userInjectContexts = + comcheckStatuses.stream() + .map( + comcheckStatus -> { + ExecutionContext injectContext = + this.executionContextService.executionContext( + comcheckStatus.getUser(), exercise, "Comcheck"); + injectContext.put( + COMCHECK, + buildComcheckLink( + comcheckStatus)); // Add specific inject variable for comcheck + // link + return injectContext; + }) + .toList(); Inject emailInject = buildComcheckEmail(comCheck); - ExecutableInject injection = new ExecutableInject(false, true, emailInject, userInjectContexts); + ExecutableInject injection = + new ExecutableInject(false, true, emailInject, userInjectContexts); EmailExecutor emailExecutor = context.getBean(EmailExecutor.class); Execution execution = emailExecutor.executeInjection(injection); // Save the status sent date - List usersSuccessfullyNotified = execution.getTraces().stream() - .filter(executionTrace -> executionTrace.getStatus().equals(ExecutionStatus.SUCCESS)) - .flatMap(t -> t.getIdentifiers().stream()).toList(); - List statusToUpdate = comcheckStatuses.stream() - .filter(comcheckStatus -> usersSuccessfullyNotified.contains(comcheckStatus.getUser().getId())) + List usersSuccessfullyNotified = + execution.getTraces().stream() + .filter( + executionTrace -> + executionTrace.getStatus().equals(ExecutionStatus.SUCCESS)) + .flatMap(t -> t.getIdentifiers().stream()) + .toList(); + List statusToUpdate = + comcheckStatuses.stream() + .filter( + comcheckStatus -> + usersSuccessfullyNotified.contains( + comcheckStatus.getUser().getId())) .toList(); if (!statusToUpdate.isEmpty()) { - comcheckStatusRepository.saveAll(statusToUpdate.stream() - .peek(comcheckStatus -> comcheckStatus.setLastSent(now)) - .toList()); + comcheckStatusRepository.saveAll( + statusToUpdate.stream() + .peek(comcheckStatus -> comcheckStatus.setLastSent(now)) + .toList()); } - }); - } catch (Exception e) { - LOGGER.log(Level.SEVERE, e.getMessage(), e); - throw new JobExecutionException(e); - } + }); + } catch (Exception e) { + LOGGER.log(Level.SEVERE, e.getMessage(), e); + throw new JobExecutionException(e); } + } } diff --git a/openbas-api/src/main/java/io/openbas/scheduler/jobs/InjectsExecutionJob.java b/openbas-api/src/main/java/io/openbas/scheduler/jobs/InjectsExecutionJob.java index 784c17e599..2d2e945417 100644 --- a/openbas-api/src/main/java/io/openbas/scheduler/jobs/InjectsExecutionJob.java +++ b/openbas-api/src/main/java/io/openbas/scheduler/jobs/InjectsExecutionJob.java @@ -1,5 +1,8 @@ package io.openbas.scheduler.jobs; +import static java.time.Instant.now; +import static java.util.stream.Collectors.groupingBy; + import com.fasterxml.jackson.databind.ObjectMapper; import io.openbas.asset.QueueService; import io.openbas.database.model.*; @@ -11,6 +14,11 @@ import jakarta.annotation.Resource; import jakarta.persistence.EntityManager; import jakarta.persistence.PersistenceContext; +import java.time.Instant; +import java.util.List; +import java.util.Map; +import java.util.logging.Level; +import java.util.logging.Logger; import lombok.RequiredArgsConstructor; import org.quartz.DisallowConcurrentExecution; import org.quartz.Job; @@ -20,239 +28,283 @@ import org.springframework.context.ApplicationContext; import org.springframework.stereotype.Component; -import java.time.Instant; -import java.util.List; -import java.util.Map; -import java.util.logging.Level; -import java.util.logging.Logger; - -import static java.time.Instant.now; -import static java.util.stream.Collectors.groupingBy; - @Component @DisallowConcurrentExecution @RequiredArgsConstructor public class InjectsExecutionJob implements Job { - private static final Logger LOGGER = Logger.getLogger(InjectsExecutionJob.class.getName()); + private static final Logger LOGGER = Logger.getLogger(InjectsExecutionJob.class.getName()); - private final ApplicationContext context; - private final InjectHelper injectHelper; - private final DryInjectRepository dryInjectRepository; - private final InjectRepository injectRepository; - private final InjectorRepository injectorRepository; - private final InjectStatusRepository injectStatusRepository; - private final DryInjectStatusRepository dryInjectStatusRepository; - private final ExerciseRepository exerciseRepository; - private final QueueService queueService; - private final ExecutionExecutorService executionExecutorService; - private final AtomicTestingService atomicTestingService; + private final ApplicationContext context; + private final InjectHelper injectHelper; + private final DryInjectRepository dryInjectRepository; + private final InjectRepository injectRepository; + private final InjectorRepository injectorRepository; + private final InjectStatusRepository injectStatusRepository; + private final DryInjectStatusRepository dryInjectStatusRepository; + private final ExerciseRepository exerciseRepository; + private final QueueService queueService; + private final ExecutionExecutorService executionExecutorService; + private final AtomicTestingService atomicTestingService; - private final List executionStatusesNotReady = - List.of(ExecutionStatus.QUEUING, ExecutionStatus.DRAFT, ExecutionStatus.EXECUTING, ExecutionStatus.PENDING); + private final List executionStatusesNotReady = + List.of( + ExecutionStatus.QUEUING, + ExecutionStatus.DRAFT, + ExecutionStatus.EXECUTING, + ExecutionStatus.PENDING); - @Resource - protected ObjectMapper mapper; + @Resource protected ObjectMapper mapper; - @PersistenceContext - private EntityManager entityManager; + @PersistenceContext private EntityManager entityManager; - @Autowired - public void setEntityManager(EntityManager entityManager) { - this.entityManager = entityManager; - } + @Autowired + public void setEntityManager(EntityManager entityManager) { + this.entityManager = entityManager; + } - public void handleAutoStartExercises() { - List exercises = exerciseRepository.findAllShouldBeInRunningState(now()); - exerciseRepository.saveAll(exercises.stream() - .peek(exercise -> { - exercise.setStatus(ExerciseStatus.RUNNING); - exercise.setUpdatedAt(now()); - }).toList()); - } + public void handleAutoStartExercises() { + List exercises = exerciseRepository.findAllShouldBeInRunningState(now()); + exerciseRepository.saveAll( + exercises.stream() + .peek( + exercise -> { + exercise.setStatus(ExerciseStatus.RUNNING); + exercise.setUpdatedAt(now()); + }) + .toList()); + } - public void handleAutoClosingExercises() { - // Change status of finished exercises. - List mustBeFinishedExercises = exerciseRepository.thatMustBeFinished(); - exerciseRepository.saveAll(mustBeFinishedExercises.stream() - .peek(exercise -> { - exercise.setStatus(ExerciseStatus.FINISHED); - exercise.setEnd(now()); - exercise.setUpdatedAt(now()); - }).toList()); - } + public void handleAutoClosingExercises() { + // Change status of finished exercises. + List mustBeFinishedExercises = exerciseRepository.thatMustBeFinished(); + exerciseRepository.saveAll( + mustBeFinishedExercises.stream() + .peek( + exercise -> { + exercise.setStatus(ExerciseStatus.FINISHED); + exercise.setEnd(now()); + exercise.setUpdatedAt(now()); + }) + .toList()); + } - private void executeExternal(ExecutableInject executableInject) { - Inject inject = executableInject.getInjection().getInject(); - inject.getInjectorContract().ifPresent(injectorContract -> { - Injection source = executableInject.getInjection(); - Inject executingInject = null; - InjectStatus injectRunningStatus = null; - DryInjectStatus dryInjectRunningStatus = null; - if (source instanceof Inject) { + private void executeExternal(ExecutableInject executableInject) { + Inject inject = executableInject.getInjection().getInject(); + inject + .getInjectorContract() + .ifPresent( + injectorContract -> { + Injection source = executableInject.getInjection(); + Inject executingInject = null; + InjectStatus injectRunningStatus = null; + DryInjectStatus dryInjectRunningStatus = null; + if (source instanceof Inject) { executingInject = injectRepository.findById(source.getId()).orElseThrow(); injectRunningStatus = executingInject.getStatus().orElseThrow(); - } - if (source instanceof DryInject) { - DryInject executingInjectDry = dryInjectRepository.findById(source.getId()).orElseThrow(); + } + if (source instanceof DryInject) { + DryInject executingInjectDry = + dryInjectRepository.findById(source.getId()).orElseThrow(); dryInjectRunningStatus = executingInjectDry.getStatus().orElseThrow(); - } - try { + } + try { String jsonInject = mapper.writeValueAsString(executableInject); queueService.publish(injectorContract.getInjector().getType(), jsonInject); - } catch (Exception e) { + } catch (Exception e) { if (source instanceof Inject) { - injectRunningStatus.getTraces().add(InjectStatusExecution.traceError(e.getMessage())); - injectStatusRepository.save(injectRunningStatus); - executingInject.setUpdatedAt(now()); - injectRepository.save(executingInject); + injectRunningStatus + .getTraces() + .add(InjectStatusExecution.traceError(e.getMessage())); + injectStatusRepository.save(injectRunningStatus); + executingInject.setUpdatedAt(now()); + injectRepository.save(executingInject); } if (source instanceof DryInject) { - dryInjectRunningStatus.getTraces().add(InjectStatusExecution.traceError(e.getMessage())); - dryInjectStatusRepository.save(dryInjectRunningStatus); + dryInjectRunningStatus + .getTraces() + .add(InjectStatusExecution.traceError(e.getMessage())); + dryInjectStatusRepository.save(dryInjectRunningStatus); } - } - }); - } + } + }); + } - private void executeInternal(ExecutableInject executableInject) { - Injection source = executableInject.getInjection(); - // Execute - source.getInject().getInjectorContract().ifPresent(injectorContract -> { - io.openbas.execution.Injector executor = context.getBean(injectorContract.getInjector().getType(), io.openbas.execution.Injector.class); - Execution execution = executor.executeInjection(executableInject); - // After execution, expectations are already created - // Injection status is filled after complete execution - // Report inject execution - if (source instanceof Inject) { + private void executeInternal(ExecutableInject executableInject) { + Injection source = executableInject.getInjection(); + // Execute + source + .getInject() + .getInjectorContract() + .ifPresent( + injectorContract -> { + io.openbas.execution.Injector executor = + context.getBean( + injectorContract.getInjector().getType(), + io.openbas.execution.Injector.class); + Execution execution = executor.executeInjection(executableInject); + // After execution, expectations are already created + // Injection status is filled after complete execution + // Report inject execution + if (source instanceof Inject) { Inject executedInject = injectRepository.findById(source.getId()).orElseThrow(); InjectStatus completeStatus = InjectStatus.fromExecution(execution, executedInject); injectStatusRepository.save(completeStatus); executedInject.setUpdatedAt(now()); executedInject.setStatus(completeStatus); injectRepository.save(executedInject); - } - // Report dry inject execution - if (source instanceof DryInject) { + } + // Report dry inject execution + if (source instanceof DryInject) { DryInject executedDry = dryInjectRepository.findById(source.getId()).orElseThrow(); - DryInjectStatus completeStatus = DryInjectStatus.fromExecution(execution, executedDry); + DryInjectStatus completeStatus = + DryInjectStatus.fromExecution(execution, executedDry); dryInjectStatusRepository.save(completeStatus); executedDry.setStatus(completeStatus); dryInjectRepository.save(executedDry); - } - }); - } - - private void executeInject(ExecutableInject executableInject) { - // Depending on injector type (internal or external) execution must be done differently - Inject inject = executableInject.getInjection().getInject(); + } + }); + } - // We are now checking if we depend on another inject and if it did not failed - if (inject.getDependsOn() != null - && inject.getDependsOn().getStatus().isPresent() - && ( inject.getDependsOn().getStatus().get().getName().equals(ExecutionStatus.ERROR) - || executionStatusesNotReady.contains(inject.getDependsOn().getStatus().get().getName()))) { - InjectStatus status = new InjectStatus(); - if (inject.getStatus().isEmpty()) { - status.setInject(inject); - } else { - status = inject.getStatus().get(); - } - String errorMsg = inject.getDependsOn().getStatus().get().getName().equals(ExecutionStatus.ERROR) ? - "The inject is depending on another inject that failed" - : "The inject is depending on another inject that is not executed yet"; - status.getTraces().add(InjectStatusExecution.traceError(errorMsg)); - status.setName(ExecutionStatus.ERROR); - status.setTrackingSentDate(Instant.now()); - status.setCommandsLines(atomicTestingService.getCommandsLinesFromInject(inject)); - injectStatusRepository.save(status); - } else { - inject.getInjectorContract().ifPresent(injectorContract -> { + private void executeInject(ExecutableInject executableInject) { + // Depending on injector type (internal or external) execution must be done differently + Inject inject = executableInject.getInjection().getInject(); + // We are now checking if we depend on another inject and if it did not failed + if (inject.getDependsOn() != null + && inject.getDependsOn().getStatus().isPresent() + && (inject.getDependsOn().getStatus().get().getName().equals(ExecutionStatus.ERROR) + || executionStatusesNotReady.contains( + inject.getDependsOn().getStatus().get().getName()))) { + InjectStatus status = new InjectStatus(); + if (inject.getStatus().isEmpty()) { + status.setInject(inject); + } else { + status = inject.getStatus().get(); + } + String errorMsg = + inject.getDependsOn().getStatus().get().getName().equals(ExecutionStatus.ERROR) + ? "The inject is depending on another inject that failed" + : "The inject is depending on another inject that is not executed yet"; + status.getTraces().add(InjectStatusExecution.traceError(errorMsg)); + status.setName(ExecutionStatus.ERROR); + status.setTrackingSentDate(Instant.now()); + status.setCommandsLines(atomicTestingService.getCommandsLinesFromInject(inject)); + injectStatusRepository.save(status); + } else { + inject + .getInjectorContract() + .ifPresent( + injectorContract -> { if (!inject.isReady()) { - // Status - if (inject.getStatus().isEmpty()) { - InjectStatus status = new InjectStatus(); - status.getTraces().add(InjectStatusExecution.traceError("The inject is not ready to be executed (missing mandatory fields)")); - status.setName(ExecutionStatus.ERROR); - status.setTrackingSentDate(Instant.now()); - status.setInject(inject); - status.setCommandsLines(atomicTestingService.getCommandsLinesFromInject(inject)); - injectStatusRepository.save(status); - } else { - InjectStatus status = inject.getStatus().get(); - status.getTraces().add(InjectStatusExecution.traceError("The inject is not ready to be executed (missing mandatory fields)")); - status.setName(ExecutionStatus.ERROR); - status.setTrackingSentDate(Instant.now()); - status.setCommandsLines(atomicTestingService.getCommandsLinesFromInject(inject)); - injectStatusRepository.save(status); - } - return; + // Status + if (inject.getStatus().isEmpty()) { + InjectStatus status = new InjectStatus(); + status + .getTraces() + .add( + InjectStatusExecution.traceError( + "The inject is not ready to be executed (missing mandatory fields)")); + status.setName(ExecutionStatus.ERROR); + status.setTrackingSentDate(Instant.now()); + status.setInject(inject); + status.setCommandsLines( + atomicTestingService.getCommandsLinesFromInject(inject)); + injectStatusRepository.save(status); + } else { + InjectStatus status = inject.getStatus().get(); + status + .getTraces() + .add( + InjectStatusExecution.traceError( + "The inject is not ready to be executed (missing mandatory fields)")); + status.setName(ExecutionStatus.ERROR); + status.setTrackingSentDate(Instant.now()); + status.setCommandsLines( + atomicTestingService.getCommandsLinesFromInject(inject)); + injectStatusRepository.save(status); + } + return; } - Injector externalInjector = injectorRepository.findByType(injectorContract.getInjector().getType()).orElseThrow(); + Injector externalInjector = + injectorRepository + .findByType(injectorContract.getInjector().getType()) + .orElseThrow(); LOGGER.log(Level.INFO, "Executing inject " + inject.getInject().getTitle()); // Executor logics ExecutableInject newExecutableInject = executableInject; if (Boolean.TRUE.equals(injectorContract.getNeedsExecutor())) { - try { - // Status - if (inject.getStatus().isEmpty()) { - InjectStatus status = new InjectStatus(); - status.setName(ExecutionStatus.EXECUTING); - status.setTrackingSentDate(Instant.now()); - status.setInject(inject); - status.setCommandsLines(atomicTestingService.getCommandsLinesFromInject(inject)); - injectStatusRepository.save(status); - } else { - InjectStatus status = inject.getStatus().get(); - status.setName(ExecutionStatus.EXECUTING); - status.setTrackingSentDate(Instant.now()); - status.setCommandsLines(atomicTestingService.getCommandsLinesFromInject(inject)); - injectStatusRepository.save(status); - } - newExecutableInject = this.executionExecutorService.launchExecutorContext(executableInject, inject); - } catch (InterruptedException e) { - throw new RuntimeException(e); + try { + // Status + if (inject.getStatus().isEmpty()) { + InjectStatus status = new InjectStatus(); + status.setName(ExecutionStatus.EXECUTING); + status.setTrackingSentDate(Instant.now()); + status.setInject(inject); + status.setCommandsLines( + atomicTestingService.getCommandsLinesFromInject(inject)); + injectStatusRepository.save(status); + } else { + InjectStatus status = inject.getStatus().get(); + status.setName(ExecutionStatus.EXECUTING); + status.setTrackingSentDate(Instant.now()); + status.setCommandsLines( + atomicTestingService.getCommandsLinesFromInject(inject)); + injectStatusRepository.save(status); } + newExecutableInject = + this.executionExecutorService.launchExecutorContext( + executableInject, inject); + } catch (InterruptedException e) { + throw new RuntimeException(e); + } } if (externalInjector.isExternal()) { - executeExternal(newExecutableInject); + executeExternal(newExecutableInject); } else { - executeInternal(newExecutableInject); + executeInternal(newExecutableInject); } - }); - } + }); } + } - public void updateExercise(String exerciseId) { - Exercise exercise = exerciseRepository.findById(exerciseId).orElseThrow(); - exercise.setUpdatedAt(now()); - exerciseRepository.save(exercise); - } + public void updateExercise(String exerciseId) { + Exercise exercise = exerciseRepository.findById(exerciseId).orElseThrow(); + exercise.setUpdatedAt(now()); + exerciseRepository.save(exercise); + } - @Override - public void execute(JobExecutionContext jobExecutionContext) throws JobExecutionException { - try { - // Handle starting exercises if needed. - handleAutoStartExercises(); - // Get all injects to execute grouped by exercise. - List injects = injectHelper.getInjectsToRun(); - Map> byExercises = injects.stream().collect(groupingBy(ex -> ex.getInjection().getExercise() == null ? "atomic" : ex.getInjection().getExercise().getId())); - // Execute injects in parallel for each exercise. - byExercises.forEach((exercise, executableInjects) -> { - // Execute each inject for the exercise in order. - executableInjects.forEach(this::executeInject); - // Update the exercise - if (!exercise.equals("atomic")) { - updateExercise(exercise); - } - }); - // Change status of finished exercises. - handleAutoClosingExercises(); - } catch (Exception e) { - LOGGER.log(Level.SEVERE, e.getMessage(), e); - throw new JobExecutionException(e); - } + @Override + public void execute(JobExecutionContext jobExecutionContext) throws JobExecutionException { + try { + // Handle starting exercises if needed. + handleAutoStartExercises(); + // Get all injects to execute grouped by exercise. + List injects = injectHelper.getInjectsToRun(); + Map> byExercises = + injects.stream() + .collect( + groupingBy( + ex -> + ex.getInjection().getExercise() == null + ? "atomic" + : ex.getInjection().getExercise().getId())); + // Execute injects in parallel for each exercise. + byExercises.forEach( + (exercise, executableInjects) -> { + // Execute each inject for the exercise in order. + executableInjects.forEach(this::executeInject); + // Update the exercise + if (!exercise.equals("atomic")) { + updateExercise(exercise); + } + }); + // Change status of finished exercises. + handleAutoClosingExercises(); + } catch (Exception e) { + LOGGER.log(Level.SEVERE, e.getMessage(), e); + throw new JobExecutionException(e); } + } } diff --git a/openbas-api/src/main/java/io/openbas/scheduler/jobs/ScenarioExecutionJob.java b/openbas-api/src/main/java/io/openbas/scheduler/jobs/ScenarioExecutionJob.java index 77086b2533..8f867115fa 100644 --- a/openbas-api/src/main/java/io/openbas/scheduler/jobs/ScenarioExecutionJob.java +++ b/openbas-api/src/main/java/io/openbas/scheduler/jobs/ScenarioExecutionJob.java @@ -1,5 +1,7 @@ package io.openbas.scheduler.jobs; +import static io.openbas.database.specification.ExerciseSpecification.recurringInstanceNotStarted; + import com.cronutils.model.Cron; import com.cronutils.model.CronType; import com.cronutils.model.definition.CronDefinition; @@ -12,6 +14,12 @@ import io.openbas.service.ScenarioService; import io.openbas.service.ScenarioToExerciseService; import jakarta.validation.constraints.NotBlank; +import java.time.Duration; +import java.time.Instant; +import java.time.ZoneId; +import java.time.ZonedDateTime; +import java.time.temporal.ChronoUnit; +import java.util.List; import lombok.RequiredArgsConstructor; import org.jetbrains.annotations.NotNull; import org.quartz.Job; @@ -20,15 +28,6 @@ import org.springframework.stereotype.Component; import org.springframework.transaction.annotation.Transactional; -import java.time.Duration; -import java.time.Instant; -import java.time.ZoneId; -import java.time.ZonedDateTime; -import java.time.temporal.ChronoUnit; -import java.util.List; - -import static io.openbas.database.specification.ExerciseSpecification.recurringInstanceNotStarted; - @Component @RequiredArgsConstructor public class ScenarioExecutionJob implements Job { @@ -48,44 +47,51 @@ private void createExercisesFromScenarios() { // Find each scenario with cron where now is between start and end date List scenarios = this.scenarioService.recurringScenarios(Instant.now()); // Filter on valid cron scenario -> Start date on cron is in 1 minute - List validScenarios = scenarios.stream() - .filter(scenario -> { - Instant startDate = cronToDate(scenario.getRecurrence()).minus(1, ChronoUnit.MINUTES); - Instant now = Instant.now(); - - ZonedDateTime startDateMinute = startDate.atZone(ZoneId.of("UTC")).truncatedTo(ChronoUnit.MINUTES); - ZonedDateTime nowMinute = now.atZone(ZoneId.of("UTC")).truncatedTo(ChronoUnit.MINUTES); - return startDateMinute.equals(nowMinute); - }) - .toList(); + List validScenarios = + scenarios.stream() + .filter( + scenario -> { + Instant startDate = + cronToDate(scenario.getRecurrence()).minus(1, ChronoUnit.MINUTES); + Instant now = Instant.now(); + + ZonedDateTime startDateMinute = + startDate.atZone(ZoneId.of("UTC")).truncatedTo(ChronoUnit.MINUTES); + ZonedDateTime nowMinute = + now.atZone(ZoneId.of("UTC")).truncatedTo(ChronoUnit.MINUTES); + return startDateMinute.equals(nowMinute); + }) + .toList(); // Check if a simulation link to this scenario already exists // Retrieve simulations not started, link to a scenario - List alreadyExistIds = this.exerciseRepository.findAll(recurringInstanceNotStarted()) - .stream() - .map(Exercise::getScenario) - .map(Scenario::getId) - .toList(); + List alreadyExistIds = + this.exerciseRepository.findAll(recurringInstanceNotStarted()).stream() + .map(Exercise::getScenario) + .map(Scenario::getId) + .toList(); // Filter scenarios with this results validScenarios.stream() .filter(scenario -> !alreadyExistIds.contains(scenario.getId())) // Create simulation with start date provided by cron - .forEach(scenario -> this.scenarioToExerciseService.toExercise(scenario, cronToDate(scenario.getRecurrence()), - false)); + .forEach( + scenario -> + this.scenarioToExerciseService.toExercise( + scenario, cronToDate(scenario.getRecurrence()), false)); } private void cleanOutdatedRecurringScenario() { // Find each scenario with cron is outdated: - List scenarios = this.scenarioService.potentialOutdatedRecurringScenario(Instant.now()); - List validScenarios = scenarios.stream() - .filter(this::isScenarioOutdated) - .toList(); + List scenarios = + this.scenarioService.potentialOutdatedRecurringScenario(Instant.now()); + List validScenarios = scenarios.stream().filter(this::isScenarioOutdated).toList(); // Remove recurring setup - validScenarios.forEach(s -> { - s.setRecurrenceStart(null); - s.setRecurrenceEnd(null); - s.setRecurrence(null); - }); + validScenarios.forEach( + s -> { + s.setRecurrenceStart(null); + s.setRecurrenceEnd(null); + s.setRecurrence(null); + }); // Save it this.scenarioService.updateScenarios(scenarios); } @@ -99,7 +105,8 @@ private boolean isScenarioOutdated(@NotNull final Scenario scenario) { return true; } - // There are no next execution -> example: end date is tomorrow at 1AM and execution cron is at 6AM and it's 6PM + // There are no next execution -> example: end date is tomorrow at 1AM and execution cron is at + // 6AM and it's 6PM Instant nextExecution = cronToDate(scenario.getRecurrence()); return nextExecution.isAfter(scenario.getRecurrenceEnd()); } @@ -112,10 +119,11 @@ private Instant cronToDate(@NotBlank final String cronExpression) { Cron cron = parser.parse(cronExpression); ExecutionTime executionTime = ExecutionTime.forCron(cron); - Duration timeToNextExecution = executionTime.timeToNextExecution(ZonedDateTime.now(ZoneId.of("UTC"))) - .orElse(Duration.ZERO); + Duration timeToNextExecution = + executionTime + .timeToNextExecution(ZonedDateTime.now(ZoneId.of("UTC"))) + .orElse(Duration.ZERO); return Instant.now().plus(timeToNextExecution); } - } diff --git a/openbas-api/src/main/java/io/openbas/schema/SchemaApi.java b/openbas-api/src/main/java/io/openbas/schema/SchemaApi.java index 3400af425a..e606386922 100644 --- a/openbas-api/src/main/java/io/openbas/schema/SchemaApi.java +++ b/openbas-api/src/main/java/io/openbas/schema/SchemaApi.java @@ -6,11 +6,10 @@ import io.openbas.utils.schema.SchemaUtils; import jakarta.validation.Valid; import jakarta.validation.constraints.NotNull; +import java.util.List; import lombok.RequiredArgsConstructor; import org.springframework.web.bind.annotation.*; -import java.util.List; - @RequiredArgsConstructor @RestController @RequestMapping @@ -20,21 +19,19 @@ public class SchemaApi extends RestBehavior { public List schemas( @PathVariable @NotNull final String className, @RequestParam final boolean filterableOnly, - @RequestBody @Valid @NotNull List filterNames) throws ClassNotFoundException { + @RequestBody @Valid @NotNull List filterNames) + throws ClassNotFoundException { String completeClassName = "io.openbas.database.model." + className; if (filterableOnly) { - return SchemaUtils.schemaWithSubtypes(Class.forName(completeClassName)) - .stream() + return SchemaUtils.schemaWithSubtypes(Class.forName(completeClassName)).stream() .filter(PropertySchema::isFilterable) .filter(p -> filterNames.isEmpty() || filterNames.contains(p.getJsonName())) .map(PropertySchemaDTO::new) .toList(); } - return SchemaUtils.schemaWithSubtypes(Class.forName(completeClassName)) - .stream() + return SchemaUtils.schemaWithSubtypes(Class.forName(completeClassName)).stream() .filter(p -> filterNames.isEmpty() || filterNames.contains(p.getJsonName())) .map(PropertySchemaDTO::new) .toList(); } - } diff --git a/openbas-api/src/main/java/io/openbas/schema/model/PropertySchemaDTO.java b/openbas-api/src/main/java/io/openbas/schema/model/PropertySchemaDTO.java index 9a95537e18..31791f57ba 100644 --- a/openbas-api/src/main/java/io/openbas/schema/model/PropertySchemaDTO.java +++ b/openbas-api/src/main/java/io/openbas/schema/model/PropertySchemaDTO.java @@ -4,11 +4,10 @@ import io.openbas.utils.schema.PropertySchema; import jakarta.validation.constraints.NotBlank; import jakarta.validation.constraints.NotNull; -import lombok.Data; -import lombok.NoArgsConstructor; - import java.util.Collection; import java.util.List; +import lombok.Data; +import lombok.NoArgsConstructor; @Data @NoArgsConstructor @@ -24,17 +23,20 @@ public class PropertySchemaDTO { @JsonProperty("schema_property_type_array") private boolean isArray; + @JsonProperty("schema_property_values") private List values; + @JsonProperty("schema_property_has_dynamic_value") private boolean dynamicValues; public PropertySchemaDTO(@NotNull final PropertySchema propertySchema) { this.setJsonName(propertySchema.getJsonName()); - this.setArray(propertySchema.getType().isArray() || Collection.class.isAssignableFrom(propertySchema.getType())); + this.setArray( + propertySchema.getType().isArray() + || Collection.class.isAssignableFrom(propertySchema.getType())); this.setValues(propertySchema.getAvailableValues()); this.setDynamicValues(propertySchema.isDynamicValues()); this.setType(propertySchema.getType().getSimpleName().toLowerCase()); } - } diff --git a/openbas-api/src/main/java/io/openbas/search/FullTextSearchApi.java b/openbas-api/src/main/java/io/openbas/search/FullTextSearchApi.java index ecfadb7e20..8872b9eef7 100644 --- a/openbas-api/src/main/java/io/openbas/search/FullTextSearchApi.java +++ b/openbas-api/src/main/java/io/openbas/search/FullTextSearchApi.java @@ -1,10 +1,13 @@ package io.openbas.search; +import static io.openbas.database.model.User.ROLE_USER; + import io.openbas.database.model.Base; import io.openbas.rest.helper.RestBehavior; import io.openbas.utils.pagination.SearchPaginationInput; import jakarta.validation.Valid; import jakarta.validation.constraints.NotBlank; +import java.util.Map; import lombok.Data; import lombok.RequiredArgsConstructor; import org.springframework.data.domain.Page; @@ -14,10 +17,6 @@ import org.springframework.web.bind.annotation.RequestBody; import org.springframework.web.bind.annotation.RestController; -import java.util.Map; - -import static io.openbas.database.model.User.ROLE_USER; - @RequiredArgsConstructor @RestController @Secured(ROLE_USER) @@ -28,14 +27,16 @@ public class FullTextSearchApi extends RestBehavior { private final FullTextSearchService fullTextSearchService; @PostMapping(GLOBAL_SEARCH_URI) - public Map, FullTextSearchService.FullTextSearchCountResult> fullTextSearch(@Valid @RequestBody final SearchTerm searchTerm) { + public Map, FullTextSearchService.FullTextSearchCountResult> + fullTextSearch(@Valid @RequestBody final SearchTerm searchTerm) { return this.fullTextSearchService.fullTextSearch(searchTerm.getSearchTerm()); } @PostMapping(GLOBAL_SEARCH_URI + "/{clazz}") public Page fullTextSearch( @PathVariable @NotBlank final String clazz, - @RequestBody @Valid SearchPaginationInput searchPaginationInput) throws ClassNotFoundException { + @RequestBody @Valid SearchPaginationInput searchPaginationInput) + throws ClassNotFoundException { return this.fullTextSearchService.fullTextSearch(clazz, searchPaginationInput); } @@ -43,5 +44,4 @@ public Page fullTextSearch( public static class SearchTerm { private String searchTerm; } - } diff --git a/openbas-api/src/main/java/io/openbas/search/FullTextSearchService.java b/openbas-api/src/main/java/io/openbas/search/FullTextSearchService.java index 92da2ba8c1..90541a3f16 100644 --- a/openbas-api/src/main/java/io/openbas/search/FullTextSearchService.java +++ b/openbas-api/src/main/java/io/openbas/search/FullTextSearchService.java @@ -1,5 +1,9 @@ package io.openbas.search; +import static io.openbas.utils.pagination.PaginationUtils.buildPaginationJPA; +import static io.openbas.utils.pagination.SortUtilsRuntime.toSortRuntime; +import static org.springframework.util.StringUtils.hasText; + import io.openbas.database.model.*; import io.openbas.database.repository.*; import io.openbas.database.specification.SpecificationUtils; @@ -7,6 +11,9 @@ import jakarta.annotation.PostConstruct; import jakarta.validation.constraints.NotBlank; import jakarta.validation.constraints.NotNull; +import java.util.*; +import java.util.stream.Collectors; +import javax.annotation.Nullable; import lombok.AllArgsConstructor; import lombok.Data; import lombok.RequiredArgsConstructor; @@ -17,14 +24,6 @@ import org.springframework.data.jpa.repository.JpaSpecificationExecutor; import org.springframework.stereotype.Component; -import javax.annotation.Nullable; -import java.util.*; -import java.util.stream.Collectors; - -import static io.openbas.utils.pagination.PaginationUtils.buildPaginationJPA; -import static io.openbas.utils.pagination.SortUtilsRuntime.toSortRuntime; -import static org.springframework.util.StringUtils.hasText; - @Component @RequiredArgsConstructor public class FullTextSearchService { @@ -39,55 +38,70 @@ public class FullTextSearchService { private Map, JpaSpecificationExecutor> repositoryMap; - private Map, List> searchListByClassMap ; + private Map, List> searchListByClassMap; @PostConstruct @SuppressWarnings("unchecked") public void init() { - this.repositoryMap = Map.of( - (Class) Asset.class, (JpaSpecificationExecutor) this.assetRepository, - (Class) AssetGroup.class, (JpaSpecificationExecutor) this.assetGroupRepository, - (Class) User.class, (JpaSpecificationExecutor) this.userRepository, - (Class) Team.class, (JpaSpecificationExecutor) this.teamRepository, - (Class) Organization.class, (JpaSpecificationExecutor) this.organizationRepository, - (Class) Scenario.class, (JpaSpecificationExecutor) this.scenarioRepository, - (Class) Exercise.class, (JpaSpecificationExecutor) this.exerciseRepository - ); - - this.searchListByClassMap = Map.of((Class) Asset.class, List.of("name", "id"), - (Class) AssetGroup.class, List.of("name", "id"), - (Class) User.class, List.of("email", "id"), - (Class) Team.class, List.of("name", "id"), - (Class) Organization.class, List.of("name", "id"), - (Class) Scenario.class, List.of("name", "id"), - (Class) Exercise.class, List.of("name", "id") - ); + this.repositoryMap = + Map.of( + (Class) Asset.class, (JpaSpecificationExecutor) this.assetRepository, + (Class) AssetGroup.class, (JpaSpecificationExecutor) this.assetGroupRepository, + (Class) User.class, (JpaSpecificationExecutor) this.userRepository, + (Class) Team.class, (JpaSpecificationExecutor) this.teamRepository, + (Class) Organization.class, + (JpaSpecificationExecutor) this.organizationRepository, + (Class) Scenario.class, (JpaSpecificationExecutor) this.scenarioRepository, + (Class) Exercise.class, (JpaSpecificationExecutor) this.exerciseRepository); + + this.searchListByClassMap = + Map.of( + (Class) Asset.class, + List.of("name", "id"), + (Class) AssetGroup.class, + List.of("name", "id"), + (Class) User.class, + List.of("email", "id"), + (Class) Team.class, + List.of("name", "id"), + (Class) Organization.class, + List.of("name", "id"), + (Class) Scenario.class, + List.of("name", "id"), + (Class) Exercise.class, + List.of("name", "id")); } public Page fullTextSearch( - @NotBlank final String clazz, - @NotNull final SearchPaginationInput searchPaginationInput) throws ClassNotFoundException { + @NotBlank final String clazz, @NotNull final SearchPaginationInput searchPaginationInput) + throws ClassNotFoundException { if (!hasText(searchPaginationInput.getTextSearch())) { - Pageable pageable = PageRequest.of(searchPaginationInput.getPage(), searchPaginationInput.getSize(), toSortRuntime(searchPaginationInput.getSorts())); + Pageable pageable = + PageRequest.of( + searchPaginationInput.getPage(), + searchPaginationInput.getSize(), + toSortRuntime(searchPaginationInput.getSorts())); return new PageImpl<>(Collections.emptyList(), pageable, 0); } Class clazzUnknown = Class.forName(clazz); - Class clazzT = this.repositoryMap.keySet().stream() - .filter((k) -> k.isAssignableFrom(clazzUnknown)) - .findFirst() - .orElseThrow(() -> new IllegalArgumentException(clazz + " is not handle by full text search")); + Class clazzT = + this.repositoryMap.keySet().stream() + .filter((k) -> k.isAssignableFrom(clazzUnknown)) + .findFirst() + .orElseThrow( + () -> new IllegalArgumentException(clazz + " is not handle by full text search")); JpaSpecificationExecutor repository = repositoryMap.get(clazzT); String finalSearchTerm = getFinalSearchTerm(searchPaginationInput.getTextSearch()); return buildPaginationJPA( - repository::findAll, - searchPaginationInput, - clazzT, - SpecificationUtils.fullTextSearch(finalSearchTerm, searchListByClassMap.get(clazzT)) - ).map(this::transform); + repository::findAll, + searchPaginationInput, + clazzT, + SpecificationUtils.fullTextSearch(finalSearchTerm, searchListByClassMap.get(clazzT))) + .map(this::transform); } private FullTextSearchResult transform(T element) { @@ -154,66 +168,65 @@ private FullTextSearchResult transform(T element) { result.setClazz(Exercise.class.getSimpleName()); return result; } - default -> { - } + default -> {} } return null; } @SuppressWarnings("unchecked") - public Map, FullTextSearchCountResult> fullTextSearch(@Nullable final String searchTerm) { + public Map, FullTextSearchCountResult> fullTextSearch( + @Nullable final String searchTerm) { if (!hasText(searchTerm)) { return Map.of( (Class) Asset.class, new FullTextSearchCountResult(Asset.class.getSimpleName(), 0L), - (Class) AssetGroup.class, new FullTextSearchCountResult(AssetGroup.class.getSimpleName(), 0L), + (Class) AssetGroup.class, + new FullTextSearchCountResult(AssetGroup.class.getSimpleName(), 0L), (Class) User.class, new FullTextSearchCountResult(User.class.getSimpleName(), 0L), (Class) Team.class, new FullTextSearchCountResult(Team.class.getSimpleName(), 0L), - (Class) Organization.class, new FullTextSearchCountResult(Organization.class.getSimpleName(), 0L), - (Class) Scenario.class, new FullTextSearchCountResult(Scenario.class.getSimpleName(), 0L), - (Class) Exercise.class, new FullTextSearchCountResult(Exercise.class.getSimpleName(), 0L) - ); + (Class) Organization.class, + new FullTextSearchCountResult(Organization.class.getSimpleName(), 0L), + (Class) Scenario.class, + new FullTextSearchCountResult(Scenario.class.getSimpleName(), 0L), + (Class) Exercise.class, + new FullTextSearchCountResult(Exercise.class.getSimpleName(), 0L)); } Map, FullTextSearchCountResult> results = new HashMap<>(); String finalSearchTerm = getFinalSearchTerm(searchTerm); - repositoryMap.forEach((className, repository) -> { - long count = repository.count(SpecificationUtils.fullTextSearch(finalSearchTerm, searchListByClassMap.get(className))); - results.put(className, new FullTextSearchCountResult(className.getSimpleName(), count)); - }); + repositoryMap.forEach( + (className, repository) -> { + long count = + repository.count( + SpecificationUtils.fullTextSearch( + finalSearchTerm, searchListByClassMap.get(className))); + results.put(className, new FullTextSearchCountResult(className.getSimpleName(), count)); + }); return results; } private static String getFinalSearchTerm(String searchTerm) { return Arrays.stream(searchTerm.split(" ")) - .map((s) -> "(" + s + ":*)") - .collect(Collectors.joining(" & ")); + .map((s) -> "(" + s + ":*)") + .collect(Collectors.joining(" & ")); } @AllArgsConstructor @Data public static class FullTextSearchCountResult { - @NotBlank - private String clazz; - @NotBlank - private long count; - + @NotBlank private String clazz; + @NotBlank private long count; } @Data public static class FullTextSearchResult { - @NotBlank - private String id; - @NotBlank - private String name; + @NotBlank private String id; + @NotBlank private String name; private String description; private Set tags; - @NotBlank - private String clazz; - + @NotBlank private String clazz; } - } diff --git a/openbas-api/src/main/java/io/openbas/security/SsoRefererAuthenticationFailureHandler.java b/openbas-api/src/main/java/io/openbas/security/SsoRefererAuthenticationFailureHandler.java index 955faa47e1..1f4d4efd51 100644 --- a/openbas-api/src/main/java/io/openbas/security/SsoRefererAuthenticationFailureHandler.java +++ b/openbas-api/src/main/java/io/openbas/security/SsoRefererAuthenticationFailureHandler.java @@ -1,18 +1,17 @@ package io.openbas.security; -import org.springframework.security.core.AuthenticationException; -import org.springframework.security.web.authentication.SimpleUrlAuthenticationFailureHandler; -import org.springframework.security.web.savedrequest.HttpSessionRequestCache; -import org.springframework.security.web.savedrequest.RequestCache; -import org.springframework.security.web.savedrequest.SavedRequest; +import static org.springframework.http.HttpHeaders.REFERER; import jakarta.servlet.ServletException; import jakarta.servlet.http.HttpServletRequest; import jakarta.servlet.http.HttpServletResponse; import java.io.IOException; import java.util.List; - -import static org.springframework.http.HttpHeaders.REFERER; +import org.springframework.security.core.AuthenticationException; +import org.springframework.security.web.authentication.SimpleUrlAuthenticationFailureHandler; +import org.springframework.security.web.savedrequest.HttpSessionRequestCache; +import org.springframework.security.web.savedrequest.RequestCache; +import org.springframework.security.web.savedrequest.SavedRequest; public class SsoRefererAuthenticationFailureHandler extends SimpleUrlAuthenticationFailureHandler { @@ -20,15 +19,16 @@ public class SsoRefererAuthenticationFailureHandler extends SimpleUrlAuthenticat @Override public void onAuthenticationFailure( - HttpServletRequest request, - HttpServletResponse response, - AuthenticationException exception) throws ServletException, IOException { + HttpServletRequest request, HttpServletResponse response, AuthenticationException exception) + throws ServletException, IOException { this.saveException(request, exception); SavedRequest savedRequest = this.requestCache.getRequest(request, response); if (savedRequest != null) { List refererValues = savedRequest.getHeaderValues(REFERER); if (refererValues.size() == 1) { - this.getRedirectStrategy().sendRedirect(request, response, refererValues.get(0)+"?error="+exception.getMessage()); + this.getRedirectStrategy() + .sendRedirect( + request, response, refererValues.get(0) + "?error=" + exception.getMessage()); return; } } diff --git a/openbas-api/src/main/java/io/openbas/security/SsoRefererAuthenticationSuccessHandler.java b/openbas-api/src/main/java/io/openbas/security/SsoRefererAuthenticationSuccessHandler.java index c9f9dbd14d..cf610d370b 100644 --- a/openbas-api/src/main/java/io/openbas/security/SsoRefererAuthenticationSuccessHandler.java +++ b/openbas-api/src/main/java/io/openbas/security/SsoRefererAuthenticationSuccessHandler.java @@ -1,18 +1,17 @@ package io.openbas.security; -import org.springframework.security.core.Authentication; -import org.springframework.security.web.authentication.SimpleUrlAuthenticationSuccessHandler; -import org.springframework.security.web.savedrequest.HttpSessionRequestCache; -import org.springframework.security.web.savedrequest.RequestCache; -import org.springframework.security.web.savedrequest.SavedRequest; +import static org.springframework.http.HttpHeaders.REFERER; import jakarta.servlet.ServletException; import jakarta.servlet.http.HttpServletRequest; import jakarta.servlet.http.HttpServletResponse; import java.io.IOException; import java.util.List; - -import static org.springframework.http.HttpHeaders.REFERER; +import org.springframework.security.core.Authentication; +import org.springframework.security.web.authentication.SimpleUrlAuthenticationSuccessHandler; +import org.springframework.security.web.savedrequest.HttpSessionRequestCache; +import org.springframework.security.web.savedrequest.RequestCache; +import org.springframework.security.web.savedrequest.SavedRequest; public class SsoRefererAuthenticationSuccessHandler extends SimpleUrlAuthenticationSuccessHandler { @@ -24,9 +23,8 @@ public SsoRefererAuthenticationSuccessHandler() { @Override public void onAuthenticationSuccess( - HttpServletRequest request, - HttpServletResponse response, - Authentication authentication) throws ServletException, IOException { + HttpServletRequest request, HttpServletResponse response, Authentication authentication) + throws ServletException, IOException { SavedRequest savedRequest = this.requestCache.getRequest(request, response); if (savedRequest != null) { List refererValues = savedRequest.getHeaderValues(REFERER); diff --git a/openbas-api/src/main/java/io/openbas/security/TokenAuthenticationFilter.java b/openbas-api/src/main/java/io/openbas/security/TokenAuthenticationFilter.java index 18661868a1..5f46ce1dde 100644 --- a/openbas-api/src/main/java/io/openbas/security/TokenAuthenticationFilter.java +++ b/openbas-api/src/main/java/io/openbas/security/TokenAuthenticationFilter.java @@ -1,5 +1,8 @@ package io.openbas.security; +import static java.util.Optional.ofNullable; +import static org.springframework.util.StringUtils.hasLength; + import io.openbas.database.model.Token; import io.openbas.database.model.User; import io.openbas.database.repository.TokenRepository; @@ -9,68 +12,66 @@ import jakarta.servlet.http.Cookie; import jakarta.servlet.http.HttpServletRequest; import jakarta.servlet.http.HttpServletResponse; +import java.io.IOException; +import java.util.Arrays; +import java.util.Optional; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.security.core.context.SecurityContext; import org.springframework.security.core.context.SecurityContextHolder; import org.springframework.web.filter.OncePerRequestFilter; -import java.io.IOException; -import java.util.Arrays; -import java.util.Optional; - -import static java.util.Optional.ofNullable; -import static org.springframework.util.StringUtils.hasLength; - public class TokenAuthenticationFilter extends OncePerRequestFilter { - private static final String COOKIE_NAME = "openbas_token"; - private static final String HEADER_NAME = "Authorization"; - private static final String BEARER_PREFIX = "bearer "; - private TokenRepository tokenRepository; - private UserService userService; + private static final String COOKIE_NAME = "openbas_token"; + private static final String HEADER_NAME = "Authorization"; + private static final String BEARER_PREFIX = "bearer "; + private TokenRepository tokenRepository; + private UserService userService; - @Autowired - public void setTokenRepository(TokenRepository tokenRepository) { - this.tokenRepository = tokenRepository; - } + @Autowired + public void setTokenRepository(TokenRepository tokenRepository) { + this.tokenRepository = tokenRepository; + } - @Autowired - public void setUserService(UserService userService) { - this.userService = userService; - } + @Autowired + public void setUserService(UserService userService) { + this.userService = userService; + } - private String parseAuthorization(String value) { - if (value.toLowerCase().startsWith(BEARER_PREFIX)) { - return value.substring(BEARER_PREFIX.length()); - } - return value; + private String parseAuthorization(String value) { + if (value.toLowerCase().startsWith(BEARER_PREFIX)) { + return value.substring(BEARER_PREFIX.length()); } + return value; + } - private String getAuthToken(HttpServletRequest request) { - String header = request.getHeader(HEADER_NAME); - Cookie[] cookies = ofNullable(request.getCookies()).orElse(new Cookie[0]); - Optional defaultCookie = Arrays.stream(cookies) - .filter(cookie -> COOKIE_NAME.equals(cookie.getName())).findFirst(); - return hasLength(header) ? parseAuthorization(header) : - defaultCookie.orElseGet(() -> new Cookie(COOKIE_NAME, null)).getValue(); - } + private String getAuthToken(HttpServletRequest request) { + String header = request.getHeader(HEADER_NAME); + Cookie[] cookies = ofNullable(request.getCookies()).orElse(new Cookie[0]); + Optional defaultCookie = + Arrays.stream(cookies).filter(cookie -> COOKIE_NAME.equals(cookie.getName())).findFirst(); + return hasLength(header) + ? parseAuthorization(header) + : defaultCookie.orElseGet(() -> new Cookie(COOKIE_NAME, null)).getValue(); + } - @Override - @SuppressWarnings("NullableProblems") - protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain) - throws ServletException, IOException { - // Extract from request - String authToken = getAuthToken(request); - if (authToken != null) { - Optional token = tokenRepository.findByValue(authToken); - SecurityContext userContext = SecurityContextHolder.getContext(); - if (token.isPresent()) { - User user = token.get().getUser(); - userService.createUserSession(user); - } else if (userContext.getAuthentication() != null) { - SecurityContextHolder.setContext(SecurityContextHolder.createEmptyContext()); - } - } - filterChain.doFilter(request, response); + @Override + @SuppressWarnings("NullableProblems") + protected void doFilterInternal( + HttpServletRequest request, HttpServletResponse response, FilterChain filterChain) + throws ServletException, IOException { + // Extract from request + String authToken = getAuthToken(request); + if (authToken != null) { + Optional token = tokenRepository.findByValue(authToken); + SecurityContext userContext = SecurityContextHolder.getContext(); + if (token.isPresent()) { + User user = token.get().getUser(); + userService.createUserSession(user); + } else if (userContext.getAuthentication() != null) { + SecurityContextHolder.setContext(SecurityContextHolder.createEmptyContext()); + } } + filterChain.doFilter(request, response); + } } diff --git a/openbas-api/src/main/java/io/openbas/service/AtomicTestingService.java b/openbas-api/src/main/java/io/openbas/service/AtomicTestingService.java index f947391e3c..bd27410e7d 100644 --- a/openbas-api/src/main/java/io/openbas/service/AtomicTestingService.java +++ b/openbas-api/src/main/java/io/openbas/service/AtomicTestingService.java @@ -1,5 +1,17 @@ package io.openbas.service; +import static io.openbas.config.SessionHelper.currentUser; +import static io.openbas.database.criteria.GenericCriteria.countQuery; +import static io.openbas.database.model.Command.COMMAND_TYPE; +import static io.openbas.helper.StreamHelper.fromIterable; +import static io.openbas.helper.StreamHelper.iterableToSet; +import static io.openbas.utils.AtomicTestingUtils.*; +import static io.openbas.utils.JpaUtils.createJoinArrayAggOnId; +import static io.openbas.utils.JpaUtils.createLeftJoin; +import static io.openbas.utils.StringUtils.duplicateString; +import static io.openbas.utils.pagination.PaginationUtils.buildPaginationCriteriaBuilder; +import static io.openbas.utils.pagination.SortUtilsCriteriaBuilder.toSortCriteriaBuilder; + import com.fasterxml.jackson.core.JsonProcessingException; import com.fasterxml.jackson.databind.JsonNode; import com.fasterxml.jackson.databind.ObjectMapper; @@ -27,6 +39,9 @@ import jakarta.persistence.criteria.*; import jakarta.transaction.Transactional; import jakarta.validation.constraints.NotBlank; +import java.time.Instant; +import java.util.*; +import java.util.stream.StreamSupport; import lombok.RequiredArgsConstructor; import lombok.extern.java.Log; import org.hibernate.Hibernate; @@ -40,417 +55,422 @@ import org.springframework.stereotype.Service; import org.springframework.validation.annotation.Validated; -import java.time.Instant; -import java.util.*; -import java.util.stream.StreamSupport; - -import static io.openbas.config.SessionHelper.currentUser; -import static io.openbas.database.criteria.GenericCriteria.countQuery; -import static io.openbas.database.model.Command.COMMAND_TYPE; -import static io.openbas.helper.StreamHelper.fromIterable; -import static io.openbas.helper.StreamHelper.iterableToSet; -import static io.openbas.utils.AtomicTestingUtils.*; -import static io.openbas.utils.JpaUtils.createJoinArrayAggOnId; -import static io.openbas.utils.JpaUtils.createLeftJoin; -import static io.openbas.utils.StringUtils.duplicateString; -import static io.openbas.utils.pagination.PaginationUtils.buildPaginationCriteriaBuilder; -import static io.openbas.utils.pagination.SortUtilsCriteriaBuilder.toSortCriteriaBuilder; - @Service @Log @RequiredArgsConstructor public class AtomicTestingService { - @Resource - protected ObjectMapper mapper; - - private final AssetGroupRepository assetGroupRepository; - private final AssetRepository assetRepository; - private final InjectRepository injectRepository; - private final InjectExpectationRepository injectExpectationRepository; - private final InjectStatusRepository injectStatusRepository; - private final InjectorContractRepository injectorContractRepository; - private final InjectDocumentRepository injectDocumentRepository; - private final UserRepository userRepository; - private final TeamRepository teamRepository; - private final TagRepository tagRepository; - private final DocumentRepository documentRepository; - private ApplicationContext context; - - private static final String PRE_DEFINE_EXPECTATIONS = "predefinedExpectations"; - private static final String EXPECTATIONS = "expectations"; - - @PersistenceContext - private EntityManager entityManager; - - @Autowired - public void setContext(ApplicationContext context) { - this.context = context; + @Resource protected ObjectMapper mapper; + + private final AssetGroupRepository assetGroupRepository; + private final AssetRepository assetRepository; + private final InjectRepository injectRepository; + private final InjectExpectationRepository injectExpectationRepository; + private final InjectStatusRepository injectStatusRepository; + private final InjectorContractRepository injectorContractRepository; + private final InjectDocumentRepository injectDocumentRepository; + private final UserRepository userRepository; + private final TeamRepository teamRepository; + private final TagRepository tagRepository; + private final DocumentRepository documentRepository; + private ApplicationContext context; + + private static final String PRE_DEFINE_EXPECTATIONS = "predefinedExpectations"; + private static final String EXPECTATIONS = "expectations"; + + @PersistenceContext private EntityManager entityManager; + + @Autowired + public void setContext(ApplicationContext context) { + this.context = context; + } + + public InjectResultDTO findById(String injectId) { + Optional inject = injectRepository.findWithStatusById(injectId); + InjectResultDTO result = + inject + .map(AtomicTestingMapper::toDtoWithTargetResults) + .orElseThrow(ElementNotFoundException::new); + result.setCommandsLines(getCommandsLinesFromInject(inject.get())); + return result; + } + + @Transactional + public InjectResultDTO createOrUpdate(AtomicTestingInput input, String injectId) { + Inject injectToSave = new Inject(); + if (injectId != null) { + injectToSave = injectRepository.findById(injectId).orElseThrow(); } - public InjectResultDTO findById(String injectId) { - Optional inject = injectRepository.findWithStatusById(injectId); - InjectResultDTO result = inject - .map(AtomicTestingMapper::toDtoWithTargetResults) - .orElseThrow(ElementNotFoundException::new); - result.setCommandsLines(getCommandsLinesFromInject(inject.get())); - return result; + InjectorContract injectorContract = + injectorContractRepository + .findById(input.getInjectorContract()) + .orElseThrow(ElementNotFoundException::new); + ObjectNode finalContent = input.getContent(); + // Set expectations + if (injectId == null) { + finalContent = setExpectations(input, injectorContract, finalContent); } - - @Transactional - public InjectResultDTO createOrUpdate(AtomicTestingInput input, String injectId) { - Inject injectToSave = new Inject(); - if (injectId != null) { - injectToSave = injectRepository.findById(injectId).orElseThrow(); - } - - InjectorContract injectorContract = - injectorContractRepository.findById(input.getInjectorContract()).orElseThrow(ElementNotFoundException::new); - ObjectNode finalContent = input.getContent(); - // Set expectations - if (injectId == null) { - finalContent = setExpectations(input, injectorContract, finalContent); - } - injectToSave.setTitle(input.getTitle()); - injectToSave.setContent(finalContent); - injectToSave.setInjectorContract(injectorContract); - injectToSave.setAllTeams(input.isAllTeams()); - injectToSave.setDescription(input.getDescription()); - injectToSave.setDependsDuration(0L); - injectToSave.setUser(userRepository.findById(currentUser().getId()).orElseThrow()); - injectToSave.setExercise(null); - - // Set dependencies - injectToSave.setDependsOn(null); - injectToSave.setTeams(fromIterable(teamRepository.findAllById(input.getTeams()))); - injectToSave.setTags(iterableToSet(tagRepository.findAllById(input.getTagIds()))); - injectToSave.setAssets(fromIterable(this.assetRepository.findAllById(input.getAssets()))); - injectToSave.setAssetGroups(fromIterable(this.assetGroupRepository.findAllById(input.getAssetGroups()))); - - List previousDocumentIds = injectToSave - .getDocuments() - .stream() - .map(InjectDocument::getDocument) - .map(Document::getId) + injectToSave.setTitle(input.getTitle()); + injectToSave.setContent(finalContent); + injectToSave.setInjectorContract(injectorContract); + injectToSave.setAllTeams(input.isAllTeams()); + injectToSave.setDescription(input.getDescription()); + injectToSave.setDependsDuration(0L); + injectToSave.setUser(userRepository.findById(currentUser().getId()).orElseThrow()); + injectToSave.setExercise(null); + + // Set dependencies + injectToSave.setDependsOn(null); + injectToSave.setTeams(fromIterable(teamRepository.findAllById(input.getTeams()))); + injectToSave.setTags(iterableToSet(tagRepository.findAllById(input.getTagIds()))); + injectToSave.setAssets(fromIterable(this.assetRepository.findAllById(input.getAssets()))); + injectToSave.setAssetGroups( + fromIterable(this.assetGroupRepository.findAllById(input.getAssetGroups()))); + + List previousDocumentIds = + injectToSave.getDocuments().stream() + .map(InjectDocument::getDocument) + .map(Document::getId) + .toList(); + + Inject finalInjectToSave = injectToSave; + List injectDocuments = + input.getDocuments().stream() + .map( + i -> { + if (!previousDocumentIds.contains(i.getDocumentId())) { + InjectDocument injectDocument = new InjectDocument(); + injectDocument.setInject(finalInjectToSave); + injectDocument.setDocument( + documentRepository.findById(i.getDocumentId()).orElseThrow()); + injectDocument.setAttached(i.isAttached()); + return injectDocument; + } + return null; + }) + .filter(Objects::nonNull) + .toList(); + injectToSave.getDocuments().addAll(injectDocuments); + Inject inject = injectRepository.save(injectToSave); + return AtomicTestingMapper.toDto( + inject, getTargets(inject.getTeams(), inject.getAssets(), inject.getAssetGroups())); + } + + private ObjectNode setExpectations( + AtomicTestingInput input, InjectorContract injectorContract, ObjectNode finalContent) { + if (input.getContent() == null + || input.getContent().get(EXPECTATIONS) == null + || input.getContent().get(EXPECTATIONS).isEmpty()) { + try { + JsonNode jsonNode = mapper.readTree(injectorContract.getContent()); + List contractElements = + StreamSupport.stream(jsonNode.get("fields").spliterator(), false) + .filter( + contractElement -> + contractElement + .get("type") + .asText() + .equals(ContractType.Expectation.name().toLowerCase())) .toList(); - - Inject finalInjectToSave = injectToSave; - List injectDocuments = input.getDocuments().stream() - .map(i -> { - if (!previousDocumentIds.contains(i.getDocumentId())) { - InjectDocument injectDocument = new InjectDocument(); - injectDocument.setInject(finalInjectToSave); - injectDocument.setDocument(documentRepository.findById(i.getDocumentId()).orElseThrow()); - injectDocument.setAttached(i.isAttached()); - return injectDocument; - } - return null; - }).filter(Objects::nonNull).toList(); - injectToSave.getDocuments().addAll(injectDocuments); - Inject inject = injectRepository.save(injectToSave); - return AtomicTestingMapper.toDto( - inject, getTargets( - inject.getTeams(), - inject.getAssets(), - inject.getAssetGroups() - ) - ); - } - - private ObjectNode setExpectations(AtomicTestingInput input, InjectorContract injectorContract, ObjectNode finalContent) { - if (input.getContent() == null || input.getContent().get(EXPECTATIONS) == null - || input.getContent().get(EXPECTATIONS).isEmpty()) { - try { - JsonNode jsonNode = mapper.readTree(injectorContract.getContent()); - List contractElements = - StreamSupport.stream(jsonNode.get("fields").spliterator(), false) - .filter(contractElement -> contractElement.get("type").asText() - .equals(ContractType.Expectation.name().toLowerCase())).toList(); - if (!contractElements.isEmpty()) { - JsonNode contractElement = contractElements.getFirst(); - if (!contractElement.get(PRE_DEFINE_EXPECTATIONS).isNull() && !contractElement.get(PRE_DEFINE_EXPECTATIONS).isEmpty()) { - finalContent = finalContent != null ? finalContent : mapper.createObjectNode(); - ArrayNode predefinedExpectations = mapper.createArrayNode(); - StreamSupport.stream(contractElement.get(PRE_DEFINE_EXPECTATIONS).spliterator(), false).forEach(predefinedExpectation -> { - ObjectNode newExpectation = predefinedExpectation.deepCopy(); - newExpectation.put("expectation_score", 100); - predefinedExpectations.add(newExpectation); - }); - // We need the remove in case there are empty expectations because put is deprecated and putifabsent doesn't replace empty expectations - if(finalContent.has(EXPECTATIONS) && finalContent.get(EXPECTATIONS).isEmpty()) { - finalContent.remove(EXPECTATIONS); - } - finalContent.putIfAbsent(EXPECTATIONS, predefinedExpectations); - } - } - } catch (JsonProcessingException e) { - log.severe("Cannot open injector contract"); + if (!contractElements.isEmpty()) { + JsonNode contractElement = contractElements.getFirst(); + if (!contractElement.get(PRE_DEFINE_EXPECTATIONS).isNull() + && !contractElement.get(PRE_DEFINE_EXPECTATIONS).isEmpty()) { + finalContent = finalContent != null ? finalContent : mapper.createObjectNode(); + ArrayNode predefinedExpectations = mapper.createArrayNode(); + StreamSupport.stream(contractElement.get(PRE_DEFINE_EXPECTATIONS).spliterator(), false) + .forEach( + predefinedExpectation -> { + ObjectNode newExpectation = predefinedExpectation.deepCopy(); + newExpectation.put("expectation_score", 100); + predefinedExpectations.add(newExpectation); + }); + // We need the remove in case there are empty expectations because put is deprecated and + // putifabsent doesn't replace empty expectations + if (finalContent.has(EXPECTATIONS) && finalContent.get(EXPECTATIONS).isEmpty()) { + finalContent.remove(EXPECTATIONS); } + finalContent.putIfAbsent(EXPECTATIONS, predefinedExpectations); + } } - return finalContent; + } catch (JsonProcessingException e) { + log.severe("Cannot open injector contract"); + } } - - @Transactional - @Validated - public InjectResultDTO getDuplicateAtomicTesting(@NotBlank String id) { - Inject injectOrigin = injectRepository.findById(id).orElseThrow(ElementNotFoundException::new); - Inject injectDuplicate = copyInject(injectOrigin, true); - injectDuplicate.setExercise(injectOrigin.getExercise()); - injectDuplicate.setScenario(injectOrigin.getScenario()); - Inject inject = injectRepository.save(injectDuplicate); - return AtomicTestingMapper.toDto( - inject, getTargets( - inject.getTeams(), - inject.getAssets(), - inject.getAssetGroups() - ) - ); + return finalContent; + } + + @Transactional + @Validated + public InjectResultDTO getDuplicateAtomicTesting(@NotBlank String id) { + Inject injectOrigin = injectRepository.findById(id).orElseThrow(ElementNotFoundException::new); + Inject injectDuplicate = copyInject(injectOrigin, true); + injectDuplicate.setExercise(injectOrigin.getExercise()); + injectDuplicate.setScenario(injectOrigin.getScenario()); + Inject inject = injectRepository.save(injectDuplicate); + return AtomicTestingMapper.toDto( + inject, getTargets(inject.getTeams(), inject.getAssets(), inject.getAssetGroups())); + } + + public Inject copyInject(@NotNull Inject injectOrigin, boolean isAtomic) { + ObjectMapper objectMapper = new ObjectMapper(); + Inject injectDuplicate = new Inject(); + injectDuplicate.setUser(injectOrigin.getUser()); + if (isAtomic) { + injectDuplicate.setTitle(duplicateString(injectOrigin.getTitle())); + } else { + injectDuplicate.setTitle(injectOrigin.getTitle()); } - - public Inject copyInject(@NotNull Inject injectOrigin, boolean isAtomic) { - ObjectMapper objectMapper = new ObjectMapper(); - Inject injectDuplicate = new Inject(); - injectDuplicate.setUser(injectOrigin.getUser()); - if (isAtomic) { - injectDuplicate.setTitle(duplicateString(injectOrigin.getTitle())); - } else { - injectDuplicate.setTitle(injectOrigin.getTitle()); - } - injectDuplicate.setDescription(injectOrigin.getDescription()); - try { - ObjectNode content = objectMapper - .readValue(objectMapper.writeValueAsString(injectOrigin.getContent()), ObjectNode.class); - injectDuplicate.setContent(content); - } catch (JsonProcessingException e) { - throw new RuntimeException(e); - } - injectDuplicate.setAllTeams(injectOrigin.isAllTeams()); - injectDuplicate.setTeams(injectOrigin.getTeams().stream().toList()); - injectDuplicate.setEnabled(injectOrigin.isEnabled()); - injectDuplicate.setDependsDuration(injectOrigin.getDependsDuration()); - injectDuplicate.setDependsOn(injectOrigin.getDependsOn()); - injectDuplicate.setCountry(injectOrigin.getCountry()); - injectDuplicate.setCity(injectOrigin.getCity()); - injectDuplicate.setInjectorContract(injectOrigin.getInjectorContract().orElse(null)); - injectDuplicate.setAssetGroups(injectOrigin.getAssetGroups().stream().toList()); - injectDuplicate.setAssets(injectOrigin.getAssets().stream().toList()); - injectDuplicate.setCommunications(injectOrigin.getCommunications().stream().toList()); - injectDuplicate.setPayloads(injectOrigin.getPayloads().stream().toList()); - injectDuplicate.setTags(new HashSet<>(injectOrigin.getTags())); - return injectDuplicate; + injectDuplicate.setDescription(injectOrigin.getDescription()); + try { + ObjectNode content = + objectMapper.readValue( + objectMapper.writeValueAsString(injectOrigin.getContent()), ObjectNode.class); + injectDuplicate.setContent(content); + } catch (JsonProcessingException e) { + throw new RuntimeException(e); } - - public InjectResultDTO updateAtomicTestingTags(String injectId, AtomicTestingUpdateTagsInput input) { - - Inject inject = injectRepository.findById(injectId).orElseThrow(); - inject.setTags(iterableToSet(this.tagRepository.findAllById(input.getTagIds()))); - - Inject saved = injectRepository.save(inject); - return AtomicTestingMapper.toDto( - saved, getTargets( - saved.getTeams(), - saved.getAssets(), - saved.getAssetGroups() - ) - ); + injectDuplicate.setAllTeams(injectOrigin.isAllTeams()); + injectDuplicate.setTeams(injectOrigin.getTeams().stream().toList()); + injectDuplicate.setEnabled(injectOrigin.isEnabled()); + injectDuplicate.setDependsDuration(injectOrigin.getDependsDuration()); + injectDuplicate.setDependsOn(injectOrigin.getDependsOn()); + injectDuplicate.setCountry(injectOrigin.getCountry()); + injectDuplicate.setCity(injectOrigin.getCity()); + injectDuplicate.setInjectorContract(injectOrigin.getInjectorContract().orElse(null)); + injectDuplicate.setAssetGroups(injectOrigin.getAssetGroups().stream().toList()); + injectDuplicate.setAssets(injectOrigin.getAssets().stream().toList()); + injectDuplicate.setCommunications(injectOrigin.getCommunications().stream().toList()); + injectDuplicate.setPayloads(injectOrigin.getPayloads().stream().toList()); + injectDuplicate.setTags(new HashSet<>(injectOrigin.getTags())); + return injectDuplicate; + } + + public InjectResultDTO updateAtomicTestingTags( + String injectId, AtomicTestingUpdateTagsInput input) { + + Inject inject = injectRepository.findById(injectId).orElseThrow(); + inject.setTags(iterableToSet(this.tagRepository.findAllById(input.getTagIds()))); + + Inject saved = injectRepository.save(inject); + return AtomicTestingMapper.toDto( + saved, getTargets(saved.getTeams(), saved.getAssets(), saved.getAssetGroups())); + } + + @Transactional + public Inject tryInject(String injectId) { + Inject inject = injectRepository.findById(injectId).orElseThrow(); + + // Reset injects outcome, communications and expectations + inject.clean(); + inject.setUpdatedAt(Instant.now()); + + // New inject status + InjectStatus injectStatus = new InjectStatus(); + injectStatus.setInject(inject); + injectStatus.setTrackingSentDate(Instant.now()); + injectStatus.setName(ExecutionStatus.QUEUING); + this.injectStatusRepository.save(injectStatus); + + // Return inject + return this.injectRepository.save(inject); + } + + @Transactional + public void deleteAtomicTesting(String injectId) { + injectDocumentRepository.deleteDocumentsFromInject(injectId); + injectRepository.deleteById(injectId); + } + + // -- PAGINATION -- + + public Page findAllAtomicTestings( + @NotNull final SearchPaginationInput searchPaginationInput) { + Specification customSpec = + Specification.where( + (root, query, cb) -> { + Predicate predicate = cb.conjunction(); + predicate = cb.and(predicate, cb.isNull(root.get("scenario"))); + predicate = cb.and(predicate, cb.isNull(root.get("exercise"))); + return predicate; + }); + return buildPaginationCriteriaBuilder( + (Specification specification, + Specification specificationCount, + Pageable pageable) -> + this.atomicTestings( + customSpec.and(specification), customSpec.and(specificationCount), pageable), + searchPaginationInput, + Inject.class); + } + + public Page atomicTestings( + Specification specification, + Specification specificationCount, + Pageable pageable) { + CriteriaBuilder cb = this.entityManager.getCriteriaBuilder(); + + CriteriaQuery cq = cb.createTupleQuery(); + Root injectRoot = cq.from(Inject.class); + selectForAtomicTesting(cb, cq, injectRoot); + + // -- Text Search and Filters -- + if (specification != null) { + Predicate predicate = specification.toPredicate(injectRoot, cq, cb); + if (predicate != null) { + cq.where(predicate); + } } - @Transactional - public Inject tryInject(String injectId) { - Inject inject = injectRepository.findById(injectId).orElseThrow(); - - // Reset injects outcome, communications and expectations - inject.clean(); - inject.setUpdatedAt(Instant.now()); - - // New inject status - InjectStatus injectStatus = new InjectStatus(); - injectStatus.setInject(inject); - injectStatus.setTrackingSentDate(Instant.now()); - injectStatus.setName(ExecutionStatus.QUEUING); - this.injectStatusRepository.save(injectStatus); - - // Return inject - return this.injectRepository.save(inject); + // -- Sorting -- + List orders = toSortCriteriaBuilder(cb, injectRoot, pageable.getSort()); + cq.orderBy(orders); + + // Type Query + TypedQuery query = entityManager.createQuery(cq); + + // -- Pagination -- + query.setFirstResult((int) pageable.getOffset()); + query.setMaxResults(pageable.getPageSize()); + + // -- EXECUTION -- + List injects = execAtomicTesting(query); + + Map> teamIds = new HashMap<>(); + Map> assetIds = new HashMap<>(); + Map> assetGroupIds = new HashMap<>(); + Map> injectExpectationIds = new HashMap<>(); + for (AtomicTestingOutput inject : injects) { + teamIds.putIfAbsent(inject.getId(), inject.getTeams()); + assetIds.putIfAbsent(inject.getId(), inject.getAssets()); + assetGroupIds.putIfAbsent(inject.getId(), inject.getAssetGroups()); + injectExpectationIds.putIfAbsent(inject.getId(), inject.getExpectations()); } - @Transactional - public void deleteAtomicTesting(String injectId) { - injectDocumentRepository.deleteDocumentsFromInject(injectId); - injectRepository.deleteById(injectId); + List teams = + this.teamRepository.rawTeamByIds( + teamIds.values().stream().flatMap(Collection::stream).distinct().toList()); + List assets = + this.assetRepository.rawByIds( + assetIds.values().stream().flatMap(Collection::stream).distinct().toList()); + List assetGroups = + this.assetGroupRepository.rawAssetGroupByIds( + assetGroupIds.values().stream().flatMap(Collection::stream).distinct().toList()); + List expectations = + this.injectExpectationRepository.rawByIds( + injectExpectationIds.values().stream().flatMap(Collection::stream).distinct().toList()); + + for (AtomicTestingOutput inject : injects) { + List currentTeamIds = teamIds.get(inject.getId()); + List currentAssetIds = assetIds.get(inject.getId()); + List currentAssetGroupIds = assetGroupIds.get(inject.getId()); + List currentInjectExpectationIds = injectExpectationIds.get(inject.getId()); + inject.setTargets( + getTargetsFromRaw( + teams.stream().filter(t -> currentTeamIds.contains(t.getTeam_id())).toList(), + assets.stream().filter(a -> currentAssetIds.contains(a.getAsset_id())).toList(), + assetGroups.stream() + .filter(ag -> currentAssetGroupIds.contains(ag.getAsset_group_id())) + .toList())); + inject.setExpectationResultByTypes( + getExpectationResultByTypesFromRaw( + expectations.stream() + .filter(e -> currentInjectExpectationIds.contains(e.getInject_expectation_id())) + .toList())); } - // -- PAGINATION -- - - public Page findAllAtomicTestings(@NotNull final SearchPaginationInput searchPaginationInput) { - Specification customSpec = Specification.where((root, query, cb) -> { - Predicate predicate = cb.conjunction(); - predicate = cb.and(predicate, cb.isNull(root.get("scenario"))); - predicate = cb.and(predicate, cb.isNull(root.get("exercise"))); - return predicate; - }); - return buildPaginationCriteriaBuilder( - (Specification specification, Specification specificationCount, Pageable pageable) -> this.atomicTestings( - customSpec.and(specification), - customSpec.and(specificationCount), - pageable - ), - searchPaginationInput, - Inject.class - ); + // -- Count Query -- + Long total = countQuery(cb, this.entityManager, Inject.class, specificationCount); + + return new PageImpl<>(injects, pageable, total); + } + + private void selectForAtomicTesting( + CriteriaBuilder cb, CriteriaQuery cq, Root injectRoot) { + // Joins + Join injectorContractJoin = + createLeftJoin(injectRoot, "injectorContract"); + Join injectorJoin = + injectorContractJoin.join("injector", JoinType.LEFT); + Join injectStatusJoin = createLeftJoin(injectRoot, "status"); + // Array aggregations + Expression injectExpectationIdsExpression = + createJoinArrayAggOnId(cb, injectRoot, EXPECTATIONS); + Expression teamIdsExpression = createJoinArrayAggOnId(cb, injectRoot, "teams"); + Expression assetIdsExpression = createJoinArrayAggOnId(cb, injectRoot, "assets"); + Expression assetGroupIdsExpression = + createJoinArrayAggOnId(cb, injectRoot, "assetGroups"); + + // SELECT + cq.multiselect( + injectRoot.get("id").alias("inject_id"), + injectRoot.get("title").alias("inject_title"), + injectRoot.get("updatedAt").alias("inject_updated_at"), + injectorJoin.get("type").alias("inject_type"), + injectorContractJoin.alias("inject_injector_contract"), + injectStatusJoin.alias("inject_status"), + injectExpectationIdsExpression.alias("inject_expectations"), + teamIdsExpression.alias("inject_teams"), + assetIdsExpression.alias("inject_assets"), + assetGroupIdsExpression.alias("inject_asset_groups")) + .distinct(true); + + // GROUP BY + cq.groupBy( + Arrays.asList( + injectRoot.get("id"), + injectorContractJoin.get("id"), + injectorJoin.get("id"), + injectStatusJoin.get("id"))); + } + + private List execAtomicTesting(TypedQuery query) { + return query.getResultList().stream() + .map( + tuple -> + new AtomicTestingOutput( + tuple.get("inject_id", String.class), + tuple.get("inject_title", String.class), + tuple.get("inject_updated_at", Instant.class), + tuple.get("inject_type", String.class), + tuple.get("inject_injector_contract", InjectorContract.class), + tuple.get("inject_status", InjectStatus.class), + tuple.get("inject_expectations", String[].class), + tuple.get("inject_teams", String[].class), + tuple.get("inject_assets", String[].class), + tuple.get("inject_asset_groups", String[].class))) + .toList(); + } + + public InjectStatusCommandLine getCommandsLinesFromInject(final Inject inject) { + if (inject.getStatus().isPresent() && inject.getStatus().get().getCommandsLines() != null) { + // Commands lines saved because inject has been executed + return inject.getStatus().get().getCommandsLines(); + } else if (inject.getInjectorContract().isPresent()) { + InjectorContract injectorContract = inject.getInjectorContract().get(); + if (injectorContract.getPayload() != null + && COMMAND_TYPE.equals(injectorContract.getPayload().getType())) { + // Inject has a command payload + Payload payload = injectorContract.getPayload(); + Command payloadCommand = (Command) Hibernate.unproxy(payload); + return new InjectStatusCommandLine( + payloadCommand.getContent() != null && !payloadCommand.getContent().isBlank() + ? List.of(payloadCommand.getContent()) + : null, + payloadCommand.getCleanupCommand() != null + && !payloadCommand.getCleanupCommand().isBlank() + ? List.of(payload.getCleanupCommand()) + : null, + payload.getExternalId()); + } else { + // Inject comes from Caldera ability and tomorrow from other(s) Executor(s) + io.openbas.execution.Injector executor = + context.getBean( + injectorContract.getInjector().getType(), io.openbas.execution.Injector.class); + return executor.getCommandsLines(injectorContract.getId()); + } } - - - public Page atomicTestings( - Specification specification, - Specification specificationCount, - Pageable pageable) { - CriteriaBuilder cb = this.entityManager.getCriteriaBuilder(); - - CriteriaQuery cq = cb.createTupleQuery(); - Root injectRoot = cq.from(Inject.class); - selectForAtomicTesting(cb, cq, injectRoot); - - // -- Text Search and Filters -- - if (specification != null) { - Predicate predicate = specification.toPredicate(injectRoot, cq, cb); - if (predicate != null) { - cq.where(predicate); - } - } - - // -- Sorting -- - List orders = toSortCriteriaBuilder(cb, injectRoot, pageable.getSort()); - cq.orderBy(orders); - - // Type Query - TypedQuery query = entityManager.createQuery(cq); - - // -- Pagination -- - query.setFirstResult((int) pageable.getOffset()); - query.setMaxResults(pageable.getPageSize()); - - // -- EXECUTION -- - List injects = execAtomicTesting(query); - - Map> teamIds = new HashMap<>(); - Map> assetIds = new HashMap<>(); - Map> assetGroupIds = new HashMap<>(); - Map> injectExpectationIds = new HashMap<>(); - for (AtomicTestingOutput inject : injects) { - teamIds.putIfAbsent(inject.getId(), inject.getTeams()); - assetIds.putIfAbsent(inject.getId(), inject.getAssets()); - assetGroupIds.putIfAbsent(inject.getId(), inject.getAssetGroups()); - injectExpectationIds.putIfAbsent(inject.getId(), inject.getExpectations()); - } - - List teams = this.teamRepository.rawTeamByIds( - teamIds.values().stream().flatMap(Collection::stream).distinct().toList() - ); - List assets = this.assetRepository.rawByIds( - assetIds.values().stream().flatMap(Collection::stream).distinct().toList() - ); - List assetGroups = this.assetGroupRepository.rawAssetGroupByIds( - assetGroupIds.values().stream().flatMap(Collection::stream).distinct().toList() - ); - List expectations = this.injectExpectationRepository.rawByIds( - injectExpectationIds.values().stream().flatMap(Collection::stream).distinct().toList()); - - for (AtomicTestingOutput inject : injects) { - List currentTeamIds = teamIds.get(inject.getId()); - List currentAssetIds = assetIds.get(inject.getId()); - List currentAssetGroupIds = assetGroupIds.get(inject.getId()); - List currentInjectExpectationIds = injectExpectationIds.get(inject.getId()); - inject.setTargets(getTargetsFromRaw( - teams.stream().filter(t -> currentTeamIds.contains(t.getTeam_id())).toList(), - assets.stream().filter(a -> currentAssetIds.contains(a.getAsset_id())).toList(), - assetGroups.stream().filter(ag -> currentAssetGroupIds.contains(ag.getAsset_group_id())).toList() - )); - inject.setExpectationResultByTypes( - getExpectationResultByTypesFromRaw( - expectations.stream().filter(e -> currentInjectExpectationIds.contains(e.getInject_expectation_id())) - .toList() - ) - ); - } - - // -- Count Query -- - Long total = countQuery(cb, this.entityManager, Inject.class, specificationCount); - - return new PageImpl<>(injects, pageable, total); - } - - private void selectForAtomicTesting(CriteriaBuilder cb, CriteriaQuery cq, Root injectRoot) { - // Joins - Join injectorContractJoin = createLeftJoin(injectRoot, "injectorContract"); - Join injectorJoin = injectorContractJoin.join("injector", JoinType.LEFT); - Join injectStatusJoin = createLeftJoin(injectRoot, "status"); - // Array aggregations - Expression injectExpectationIdsExpression = createJoinArrayAggOnId(cb, injectRoot, EXPECTATIONS); - Expression teamIdsExpression = createJoinArrayAggOnId(cb, injectRoot, "teams"); - Expression assetIdsExpression = createJoinArrayAggOnId(cb, injectRoot, "assets"); - Expression assetGroupIdsExpression = createJoinArrayAggOnId(cb, injectRoot, "assetGroups"); - - // SELECT - cq.multiselect( - injectRoot.get("id").alias("inject_id"), - injectRoot.get("title").alias("inject_title"), - injectRoot.get("updatedAt").alias("inject_updated_at"), - injectorJoin.get("type").alias("inject_type"), - injectorContractJoin.alias("inject_injector_contract"), - injectStatusJoin.alias("inject_status"), - injectExpectationIdsExpression.alias("inject_expectations"), - teamIdsExpression.alias("inject_teams"), - assetIdsExpression.alias("inject_assets"), - assetGroupIdsExpression.alias("inject_asset_groups") - ).distinct(true); - - // GROUP BY - cq.groupBy(Arrays.asList( - injectRoot.get("id"), - injectorContractJoin.get("id"), - injectorJoin.get("id"), - injectStatusJoin.get("id") - )); - } - - private List execAtomicTesting(TypedQuery query) { - return query.getResultList() - .stream() - .map(tuple -> new AtomicTestingOutput( - tuple.get("inject_id", String.class), - tuple.get("inject_title", String.class), - tuple.get("inject_updated_at", Instant.class), - tuple.get("inject_type", String.class), - tuple.get("inject_injector_contract", InjectorContract.class), - tuple.get("inject_status", InjectStatus.class), - tuple.get("inject_expectations", String[].class), - tuple.get("inject_teams", String[].class), - tuple.get("inject_assets", String[].class), - tuple.get("inject_asset_groups", String[].class) - )) - .toList(); - } - - public InjectStatusCommandLine getCommandsLinesFromInject(final Inject inject) { - if (inject.getStatus().isPresent() && inject.getStatus().get().getCommandsLines() != null) { - // Commands lines saved because inject has been executed - return inject.getStatus().get().getCommandsLines(); - } else if (inject.getInjectorContract().isPresent()) { - InjectorContract injectorContract = inject.getInjectorContract().get(); - if(injectorContract.getPayload() != null && COMMAND_TYPE.equals(injectorContract.getPayload().getType())) { - // Inject has a command payload - Payload payload = injectorContract.getPayload(); - Command payloadCommand = (Command) Hibernate.unproxy(payload); - return new InjectStatusCommandLine(payloadCommand.getContent() != null && !payloadCommand.getContent().isBlank() ? List.of(payloadCommand.getContent()) : null, - payloadCommand.getCleanupCommand() != null && !payloadCommand.getCleanupCommand().isBlank() ? List.of(payload.getCleanupCommand()) : null, payload.getExternalId()); - } else { - // Inject comes from Caldera ability and tomorrow from other(s) Executor(s) - io.openbas.execution.Injector executor = context.getBean(injectorContract.getInjector().getType(), io.openbas.execution.Injector.class); - return executor.getCommandsLines(injectorContract.getId()); - } - } - return null; - } - + return null; + } } diff --git a/openbas-api/src/main/java/io/openbas/service/ChallengeService.java b/openbas-api/src/main/java/io/openbas/service/ChallengeService.java index 659911086b..c914a71cb5 100644 --- a/openbas-api/src/main/java/io/openbas/service/ChallengeService.java +++ b/openbas-api/src/main/java/io/openbas/service/ChallengeService.java @@ -1,5 +1,8 @@ package io.openbas.service; +import static io.openbas.helper.StreamHelper.fromIterable; +import static io.openbas.injectors.challenge.ChallengeContract.CHALLENGE_PUBLISH; + import com.fasterxml.jackson.core.JsonProcessingException; import com.fasterxml.jackson.databind.ObjectMapper; import io.openbas.database.model.*; @@ -17,170 +20,197 @@ import jakarta.annotation.Resource; import jakarta.validation.constraints.NotBlank; import jakarta.validation.constraints.NotNull; -import lombok.RequiredArgsConstructor; -import org.springframework.stereotype.Service; - import java.time.Instant; import java.util.*; import java.util.regex.Pattern; import java.util.stream.Collectors; import java.util.stream.Stream; - -import static io.openbas.helper.StreamHelper.fromIterable; -import static io.openbas.injectors.challenge.ChallengeContract.CHALLENGE_PUBLISH; +import lombok.RequiredArgsConstructor; +import org.springframework.stereotype.Service; @Service @RequiredArgsConstructor public class ChallengeService { - private final ExerciseRepository exerciseRepository; - private final ChallengeRepository challengeRepository; - private final InjectRepository injectRepository; - private final InjectExpectationRepository injectExpectationRepository; - @Resource - protected ObjectMapper mapper; - - public Challenge enrichChallengeWithExercisesOrScenarios(@NotNull Challenge challenge) { - List injects = fromIterable(this.injectRepository.findAllForChallengeId("%" + challenge.getId() + "%")); - List exerciseIds = injects.stream().filter(i -> i.getExercise() != null).map(i -> i.getExercise().getId()).distinct().toList(); - challenge.setExerciseIds(exerciseIds); - List scenarioIds = injects.stream().filter(i -> i.getScenario() != null).map(i -> i.getScenario().getId()).distinct().toList(); - challenge.setScenarioIds(scenarioIds); - return challenge; + private final ExerciseRepository exerciseRepository; + private final ChallengeRepository challengeRepository; + private final InjectRepository injectRepository; + private final InjectExpectationRepository injectExpectationRepository; + @Resource protected ObjectMapper mapper; + + public Challenge enrichChallengeWithExercisesOrScenarios(@NotNull Challenge challenge) { + List injects = + fromIterable(this.injectRepository.findAllForChallengeId("%" + challenge.getId() + "%")); + List exerciseIds = + injects.stream() + .filter(i -> i.getExercise() != null) + .map(i -> i.getExercise().getId()) + .distinct() + .toList(); + challenge.setExerciseIds(exerciseIds); + List scenarioIds = + injects.stream() + .filter(i -> i.getScenario() != null) + .map(i -> i.getScenario().getId()) + .distinct() + .toList(); + challenge.setScenarioIds(scenarioIds); + return challenge; + } + + public Iterable getExerciseChallenges(@NotBlank final String exerciseId) { + Exercise exercise = exerciseRepository.findById(exerciseId).orElseThrow(); + return resolveChallenges(exercise.getInjects()) + .map(this::enrichChallengeWithExercisesOrScenarios) + .toList(); + } + + public Iterable getScenarioChallenges(@NotNull final Scenario scenario) { + return resolveChallenges(scenario.getInjects()) + .map(this::enrichChallengeWithExercisesOrScenarios) + .toList(); + } + + public ChallengeResult tryChallenge(String challengeId, ChallengeTryInput input) { + Challenge challenge = + challengeRepository.findById(challengeId).orElseThrow(ElementNotFoundException::new); + for (ChallengeFlag flag : challenge.getFlags()) { + if (checkFlag(flag, input.getValue())) { + return new ChallengeResult(true); + } } - - public Iterable getExerciseChallenges(@NotBlank final String exerciseId) { - Exercise exercise = exerciseRepository.findById(exerciseId).orElseThrow(); - return resolveChallenges(exercise.getInjects()) - .map(this::enrichChallengeWithExercisesOrScenarios) - .toList(); + return new ChallengeResult(false); + } + + public ChallengesReader playerChallenges(String exerciseId, User user) { + Exercise exercise = + exerciseRepository.findById(exerciseId).orElseThrow(ElementNotFoundException::new); + ChallengesReader reader = new ChallengesReader(exercise); + List challengeExpectations = + injectExpectationRepository.findChallengeExpectationsByExerciseAndUser( + exerciseId, user.getId()); + + // Filter expectations by unique challenge + Set seenChallenges = new HashSet<>(); + List distinctExpectations = new ArrayList<>(); + + for (InjectExpectation expectation : challengeExpectations) { + String challengeId = expectation.getChallenge().getId(); + if (!seenChallenges.contains(challengeId)) { + seenChallenges.add(challengeId); + distinctExpectations.add(expectation); + } } - public Iterable getScenarioChallenges(@NotNull final Scenario scenario) { - return resolveChallenges(scenario.getInjects()) - .map(this::enrichChallengeWithExercisesOrScenarios) - .toList(); - } - - - public ChallengeResult tryChallenge(String challengeId, ChallengeTryInput input) { - Challenge challenge = challengeRepository.findById(challengeId).orElseThrow(ElementNotFoundException::new); - for (ChallengeFlag flag : challenge.getFlags()) { - if (checkFlag(flag, input.getValue())) { - return new ChallengeResult(true); - } - } - return new ChallengeResult(false); - } - - public ChallengesReader playerChallenges(String exerciseId, User user) { - Exercise exercise = exerciseRepository.findById(exerciseId).orElseThrow(ElementNotFoundException::new); - ChallengesReader reader = new ChallengesReader(exercise); - List challengeExpectations = injectExpectationRepository.findChallengeExpectationsByExerciseAndUser(exerciseId, user.getId()); - - // Filter expectations by unique challenge - Set seenChallenges = new HashSet<>(); - List distinctExpectations = new ArrayList<>(); - - for (InjectExpectation expectation : challengeExpectations) { - String challengeId = expectation.getChallenge().getId(); - if (!seenChallenges.contains(challengeId)) { - seenChallenges.add(challengeId); - distinctExpectations.add(expectation); - } - } - - List challenges = distinctExpectations.stream() - .map(injectExpectation -> { - Challenge challenge = injectExpectation.getChallenge(); - challenge.setVirtualPublication(injectExpectation.getCreatedAt()); - return new ChallengeInformation(challenge, injectExpectation); + List challenges = + distinctExpectations.stream() + .map( + injectExpectation -> { + Challenge challenge = injectExpectation.getChallenge(); + challenge.setVirtualPublication(injectExpectation.getCreatedAt()); + return new ChallengeInformation(challenge, injectExpectation); }) - .sorted(Comparator.comparing(o -> o.getChallenge().getVirtualPublication())) - .toList(); - reader.setExerciseChallenges(challenges); - return reader; - } - - public ChallengesReader validateChallenge(String exerciseId, - String challengeId, - ChallengeTryInput input, - User user) { - ChallengeResult challengeResult = tryChallenge(challengeId, input); - if (challengeResult.getResult()) { - // Find and update the expectations linked to the user - List playerExpectations = injectExpectationRepository.findByUserAndExerciseAndChallenge(user.getId(), exerciseId, challengeId); - playerExpectations.forEach(playerExpectation -> { - playerExpectation.setScore(playerExpectation.getExpectedScore()); - InjectExpectationResult expectationResult = InjectExpectationResult.builder() - .sourceId("challenge") - .sourceType("challenge") - .sourceName("Challenge validation") - .result(Instant.now().toString()) - .date(Instant.now().toString()) - .score(playerExpectation.getExpectedScore()) - .build(); - playerExpectation.getResults().add(expectationResult); - playerExpectation.setUpdatedAt(Instant.now()); - injectExpectationRepository.save(playerExpectation); - }); - - // -- VALIDATION TYPE -- - processByValidationType(exerciseId, challengeId, user, true); - } - return playerChallenges(exerciseId, user); + .sorted(Comparator.comparing(o -> o.getChallenge().getVirtualPublication())) + .toList(); + reader.setExerciseChallenges(challenges); + return reader; + } + + public ChallengesReader validateChallenge( + String exerciseId, String challengeId, ChallengeTryInput input, User user) { + ChallengeResult challengeResult = tryChallenge(challengeId, input); + if (challengeResult.getResult()) { + // Find and update the expectations linked to the user + List playerExpectations = + injectExpectationRepository.findByUserAndExerciseAndChallenge( + user.getId(), exerciseId, challengeId); + playerExpectations.forEach( + playerExpectation -> { + playerExpectation.setScore(playerExpectation.getExpectedScore()); + InjectExpectationResult expectationResult = + InjectExpectationResult.builder() + .sourceId("challenge") + .sourceType("challenge") + .sourceName("Challenge validation") + .result(Instant.now().toString()) + .date(Instant.now().toString()) + .score(playerExpectation.getExpectedScore()) + .build(); + playerExpectation.getResults().add(expectationResult); + playerExpectation.setUpdatedAt(Instant.now()); + injectExpectationRepository.save(playerExpectation); + }); + + // -- VALIDATION TYPE -- + processByValidationType(exerciseId, challengeId, user, true); } - - private void processByValidationType(String exerciseId, String challengeId, User user, boolean isaNewExpectationResult) { - // Process expectations linked to teams where the user is a member - List teamIds = user.getTeams().stream().map(Team::getId).toList(); - // Find all expectations for this exercise, challenge and teams - List challengeExpectations = injectExpectationRepository.findChallengeExpectations(exerciseId, teamIds, challengeId); - // If user is null then expectation is from a team - List parentExpectations = challengeExpectations.stream().filter(exp -> exp.getUser() == null).toList(); - // If user is not null then expectation is from a player - Map> playerByTeam = challengeExpectations.stream().filter(exp -> exp.getUser() != null).collect(Collectors.groupingBy(InjectExpectation::getTeam)); - - // Depending on type of validation, We process the parent expectations: - List toUpdate = ExpectationUtils.processByValidationType(isaNewExpectationResult, challengeExpectations, parentExpectations, playerByTeam); - injectExpectationRepository.saveAll(toUpdate); - } - - // -- PRIVATE -- - private Stream resolveChallenges(@NotNull final List injects) { - List challenges = injects.stream() - .filter(inject -> inject.getInjectorContract() + return playerChallenges(exerciseId, user); + } + + private void processByValidationType( + String exerciseId, String challengeId, User user, boolean isaNewExpectationResult) { + // Process expectations linked to teams where the user is a member + List teamIds = user.getTeams().stream().map(Team::getId).toList(); + // Find all expectations for this exercise, challenge and teams + List challengeExpectations = + injectExpectationRepository.findChallengeExpectations(exerciseId, teamIds, challengeId); + // If user is null then expectation is from a team + List parentExpectations = + challengeExpectations.stream().filter(exp -> exp.getUser() == null).toList(); + // If user is not null then expectation is from a player + Map> playerByTeam = + challengeExpectations.stream() + .filter(exp -> exp.getUser() != null) + .collect(Collectors.groupingBy(InjectExpectation::getTeam)); + + // Depending on type of validation, We process the parent expectations: + List toUpdate = + ExpectationUtils.processByValidationType( + isaNewExpectationResult, challengeExpectations, parentExpectations, playerByTeam); + injectExpectationRepository.saveAll(toUpdate); + } + + // -- PRIVATE -- + private Stream resolveChallenges(@NotNull final List injects) { + List challenges = + injects.stream() + .filter( + inject -> + inject + .getInjectorContract() .map(contract -> contract.getId().equals(CHALLENGE_PUBLISH)) .orElse(false)) - .filter(inject -> inject.getContent() != null) - .flatMap(inject -> { - try { - ChallengeContent content = mapper.treeToValue(inject.getContent(), ChallengeContent.class); - return content.getChallenges().stream(); - } catch (JsonProcessingException e) { - return Stream.empty(); - } + .filter(inject -> inject.getContent() != null) + .flatMap( + inject -> { + try { + ChallengeContent content = + mapper.treeToValue(inject.getContent(), ChallengeContent.class); + return content.getChallenges().stream(); + } catch (JsonProcessingException e) { + return Stream.empty(); + } }) - .distinct() - .toList(); - - return fromIterable(this.challengeRepository.findAllById(challenges)).stream(); - } - - private boolean checkFlag(ChallengeFlag flag, String value) { - switch (flag.getType()) { - case VALUE -> { - return value.equalsIgnoreCase(flag.getValue()); - } - case VALUE_CASE -> { - return value.equals(flag.getValue()); - } - case REGEXP -> { - return Pattern.compile(flag.getValue()).matcher(value).matches(); - } - default -> { - return false; - } - } + .distinct() + .toList(); + + return fromIterable(this.challengeRepository.findAllById(challenges)).stream(); + } + + private boolean checkFlag(ChallengeFlag flag, String value) { + switch (flag.getType()) { + case VALUE -> { + return value.equalsIgnoreCase(flag.getValue()); + } + case VALUE_CASE -> { + return value.equals(flag.getValue()); + } + case REGEXP -> { + return Pattern.compile(flag.getValue()).matcher(value).matches(); + } + default -> { + return false; + } } + } } diff --git a/openbas-api/src/main/java/io/openbas/service/ChannelService.java b/openbas-api/src/main/java/io/openbas/service/ChannelService.java index a906ce1e65..931d231ea4 100644 --- a/openbas-api/src/main/java/io/openbas/service/ChannelService.java +++ b/openbas-api/src/main/java/io/openbas/service/ChannelService.java @@ -1,5 +1,8 @@ package io.openbas.service; +import static io.openbas.helper.StreamHelper.fromIterable; +import static io.openbas.injectors.channel.ChannelContract.CHANNEL_PUBLISH; + import com.fasterxml.jackson.core.JsonProcessingException; import com.fasterxml.jackson.databind.ObjectMapper; import io.openbas.database.model.*; @@ -13,115 +16,141 @@ import io.openbas.rest.exception.ElementNotFoundException; import io.openbas.utils.ExpectationUtils; import jakarta.annotation.Resource; -import lombok.RequiredArgsConstructor; -import org.springframework.stereotype.Service; - import java.time.Instant; import java.util.*; import java.util.stream.Collectors; - -import static io.openbas.helper.StreamHelper.fromIterable; -import static io.openbas.injectors.channel.ChannelContract.CHANNEL_PUBLISH; +import lombok.RequiredArgsConstructor; +import org.springframework.stereotype.Service; @Service @RequiredArgsConstructor public class ChannelService { - private final InjectExpectationRepository injectExpectationExecutionRepository; - private final ExerciseRepository exerciseRepository; - private final ScenarioService scenarioService; - private final ArticleRepository articleRepository; - private final ChannelRepository channelRepository; - @Resource - protected ObjectMapper mapper; + private final InjectExpectationRepository injectExpectationExecutionRepository; + private final ExerciseRepository exerciseRepository; + private final ScenarioService scenarioService; + private final ArticleRepository articleRepository; + private final ChannelRepository channelRepository; + @Resource protected ObjectMapper mapper; - public ChannelReader validateArticles(String exerciseId, String channelId, User user) { - ChannelReader channelReader; - Channel channel = channelRepository.findById(channelId).orElseThrow(ElementNotFoundException::new); - List injects; + public ChannelReader validateArticles(String exerciseId, String channelId, User user) { + ChannelReader channelReader; + Channel channel = + channelRepository.findById(channelId).orElseThrow(ElementNotFoundException::new); + List injects; - Optional exerciseOpt = exerciseRepository.findById(exerciseId); - if (exerciseOpt.isPresent()) { - Exercise exercise = exerciseOpt.get(); - channelReader = new ChannelReader(channel, exercise); - injects = exercise.getInjects(); - } else { - Scenario scenario = this.scenarioService.scenario(exerciseId); - channelReader = new ChannelReader(channel, scenario); - injects = scenario.getInjects(); - } + Optional exerciseOpt = exerciseRepository.findById(exerciseId); + if (exerciseOpt.isPresent()) { + Exercise exercise = exerciseOpt.get(); + channelReader = new ChannelReader(channel, exercise); + injects = exercise.getInjects(); + } else { + Scenario scenario = this.scenarioService.scenario(exerciseId); + channelReader = new ChannelReader(channel, scenario); + injects = scenario.getInjects(); + } - Map toPublishArticleIdsMap = injects.stream() - .filter(inject -> inject.getInjectorContract() + Map toPublishArticleIdsMap = + injects.stream() + .filter( + inject -> + inject + .getInjectorContract() .map(contract -> contract.getId().equals(CHANNEL_PUBLISH)) .orElse(false)) - .filter(inject -> inject.getStatus().isPresent()) - .sorted(Comparator.comparing(inject -> inject.getStatus().get().getTrackingSentDate())) - .flatMap(inject -> { - Instant virtualInjectDate = inject.getStatus().get().getTrackingSentDate(); - try { - ChannelContent content = mapper.treeToValue(inject.getContent(), ChannelContent.class); - if (content.getArticles() != null) { - return content.getArticles().stream().map(article -> new VirtualArticle(virtualInjectDate, article)); - } - return null; - } catch (JsonProcessingException e) { - // Invalid channel content. - return null; + .filter(inject -> inject.getStatus().isPresent()) + .sorted(Comparator.comparing(inject -> inject.getStatus().get().getTrackingSentDate())) + .flatMap( + inject -> { + Instant virtualInjectDate = inject.getStatus().get().getTrackingSentDate(); + try { + ChannelContent content = + mapper.treeToValue(inject.getContent(), ChannelContent.class); + if (content.getArticles() != null) { + return content.getArticles().stream() + .map(article -> new VirtualArticle(virtualInjectDate, article)); } + return null; + } catch (JsonProcessingException e) { + // Invalid channel content. + return null; + } }) - .filter(Objects::nonNull) - .distinct() - .collect(Collectors.toMap(VirtualArticle::id, VirtualArticle::date)); - if (!toPublishArticleIdsMap.isEmpty()) { - List
publishedArticles = fromIterable(articleRepository.findAllById(toPublishArticleIdsMap.keySet())) - .stream().filter(article -> article.getChannel().equals(channel)) - .peek(article -> article.setVirtualPublication(toPublishArticleIdsMap.get(article.getId()))) - .sorted(Comparator.comparing(Article::getVirtualPublication).reversed()) - .toList(); - channelReader.setChannelArticles(publishedArticles); - // Fulfill article expectations - List finalInjects = injects; - List expectationExecutions = publishedArticles.stream() - .flatMap(article -> finalInjects.stream() - .flatMap(inject -> inject.getUserExpectationsForArticle(user, article).stream())) - .filter(exec -> exec.getResults().isEmpty()).toList(); + .filter(Objects::nonNull) + .distinct() + .collect(Collectors.toMap(VirtualArticle::id, VirtualArticle::date)); + if (!toPublishArticleIdsMap.isEmpty()) { + List
publishedArticles = + fromIterable(articleRepository.findAllById(toPublishArticleIdsMap.keySet())).stream() + .filter(article -> article.getChannel().equals(channel)) + .peek( + article -> + article.setVirtualPublication(toPublishArticleIdsMap.get(article.getId()))) + .sorted(Comparator.comparing(Article::getVirtualPublication).reversed()) + .toList(); + channelReader.setChannelArticles(publishedArticles); + // Fulfill article expectations + List finalInjects = injects; + List expectationExecutions = + publishedArticles.stream() + .flatMap( + article -> + finalInjects.stream() + .flatMap( + inject -> + inject.getUserExpectationsForArticle(user, article).stream())) + .filter(exec -> exec.getResults().isEmpty()) + .toList(); - // Update all expectations linked to player - expectationExecutions.forEach(injectExpectationExecution -> { - injectExpectationExecution.setResults(List.of( - InjectExpectationResult.builder() - .sourceId("media-pressure") - .sourceType("media-pressure") - .sourceName("Media pressure read") - .result(Instant.now().toString()) - .date(Instant.now().toString()) - .score(injectExpectationExecution.getExpectedScore()) - .build() - )); - injectExpectationExecution.setScore(injectExpectationExecution.getExpectedScore()); - injectExpectationExecution.setUpdatedAt(Instant.now()); - injectExpectationExecutionRepository.save(injectExpectationExecution); - }); + // Update all expectations linked to player + expectationExecutions.forEach( + injectExpectationExecution -> { + injectExpectationExecution.setResults( + List.of( + InjectExpectationResult.builder() + .sourceId("media-pressure") + .sourceType("media-pressure") + .sourceName("Media pressure read") + .result(Instant.now().toString()) + .date(Instant.now().toString()) + .score(injectExpectationExecution.getExpectedScore()) + .build())); + injectExpectationExecution.setScore(injectExpectationExecution.getExpectedScore()); + injectExpectationExecution.setUpdatedAt(Instant.now()); + injectExpectationExecutionRepository.save(injectExpectationExecution); + }); - // -- VALIDATION TYPE -- - processByValidationType(user, injects, publishedArticles, expectationExecutions.size() > 0); - } - return channelReader; + // -- VALIDATION TYPE -- + processByValidationType(user, injects, publishedArticles, expectationExecutions.size() > 0); } + return channelReader; + } - private void processByValidationType(User user, List injects, List
publishedArticles, boolean isaNewExpectationResult) { - // Process expectation linked to teams where user if part of - List injectIds = injects.stream().map(Inject::getId).toList(); - List teamIds = user.getTeams().stream().map(Team::getId).toList(); - List articleIds = publishedArticles.stream().map(Article::getId).toList(); //Articles with the same channel - // Find all expectations linked to teams' user, channel and exercise - List channelExpectations = injectExpectationExecutionRepository.findChannelExpectations(injectIds, teamIds, articleIds); - List parentExpectations = channelExpectations.stream().filter(exp -> exp.getUser() == null).toList(); - Map> playerByTeam = channelExpectations.stream().filter(exp -> exp.getUser() != null).collect(Collectors.groupingBy(InjectExpectation::getTeam)); + private void processByValidationType( + User user, + List injects, + List
publishedArticles, + boolean isaNewExpectationResult) { + // Process expectation linked to teams where user if part of + List injectIds = injects.stream().map(Inject::getId).toList(); + List teamIds = user.getTeams().stream().map(Team::getId).toList(); + List articleIds = + publishedArticles.stream().map(Article::getId).toList(); // Articles with the same channel + // Find all expectations linked to teams' user, channel and exercise + List channelExpectations = + injectExpectationExecutionRepository.findChannelExpectations( + injectIds, teamIds, articleIds); + List parentExpectations = + channelExpectations.stream().filter(exp -> exp.getUser() == null).toList(); + Map> playerByTeam = + channelExpectations.stream() + .filter(exp -> exp.getUser() != null) + .collect(Collectors.groupingBy(InjectExpectation::getTeam)); - // Depending on type of validation, we process the parent expectations: - List toUpdate = ExpectationUtils.processByValidationType(isaNewExpectationResult, channelExpectations, parentExpectations, playerByTeam); - injectExpectationExecutionRepository.saveAll(toUpdate); - } + // Depending on type of validation, we process the parent expectations: + List toUpdate = + ExpectationUtils.processByValidationType( + isaNewExpectationResult, channelExpectations, parentExpectations, playerByTeam); + injectExpectationExecutionRepository.saveAll(toUpdate); + } } diff --git a/openbas-api/src/main/java/io/openbas/service/DryrunService.java b/openbas-api/src/main/java/io/openbas/service/DryrunService.java index 02415b9a9f..2da387c8c3 100644 --- a/openbas-api/src/main/java/io/openbas/service/DryrunService.java +++ b/openbas-api/src/main/java/io/openbas/service/DryrunService.java @@ -1,69 +1,66 @@ package io.openbas.service; +import static java.time.Instant.now; + import io.openbas.database.model.*; import io.openbas.database.repository.DryInjectRepository; import io.openbas.database.repository.DryRunRepository; import io.openbas.database.repository.InjectRepository; import io.openbas.database.specification.InjectSpecification; +import jakarta.transaction.Transactional; +import java.util.List; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.data.jpa.domain.Specification; import org.springframework.stereotype.Service; import org.springframework.util.Assert; -import jakarta.transaction.Transactional; -import java.util.List; - -import static java.time.Instant.now; - @Service public class DryrunService { - private static final int SPEED_DRYRUN = 100; // 100x faster. + private static final int SPEED_DRYRUN = 100; // 100x faster. - private DryRunRepository dryRunRepository; - private InjectRepository injectRepository; - private DryInjectRepository dryInjectRepository; + private DryRunRepository dryRunRepository; + private InjectRepository injectRepository; + private DryInjectRepository dryInjectRepository; - @Autowired - public void setInjectRepository(InjectRepository injectRepository) { - this.injectRepository = injectRepository; - } + @Autowired + public void setInjectRepository(InjectRepository injectRepository) { + this.injectRepository = injectRepository; + } - @Autowired - public void setDryRunRepository(DryRunRepository dryRunRepository) { - this.dryRunRepository = dryRunRepository; - } + @Autowired + public void setDryRunRepository(DryRunRepository dryRunRepository) { + this.dryRunRepository = dryRunRepository; + } - @Autowired - public void setDryInjectRepository(DryInjectRepository dryInjectRepository) { - this.dryInjectRepository = dryInjectRepository; - } + @Autowired + public void setDryInjectRepository(DryInjectRepository dryInjectRepository) { + this.dryInjectRepository = dryInjectRepository; + } - private List toDryInjects(List injects, Dryrun dryrun) { - return injects.stream() - .map(inject -> inject.toDryInject(dryrun)) - .toList(); - } + private List toDryInjects(List injects, Dryrun dryrun) { + return injects.stream().map(inject -> inject.toDryInject(dryrun)).toList(); + } - private Dryrun createDryRun(Exercise exercise, List users, String name) { - Dryrun run = new Dryrun(); - run.setName(name); - run.setSpeed(SPEED_DRYRUN); - run.setExercise(exercise); - run.setDate(now()); - run.setUsers(users); - return dryRunRepository.save(run); - } + private Dryrun createDryRun(Exercise exercise, List users, String name) { + Dryrun run = new Dryrun(); + run.setName(name); + run.setSpeed(SPEED_DRYRUN); + run.setExercise(exercise); + run.setDate(now()); + run.setUsers(users); + return dryRunRepository.save(run); + } - @Transactional(rollbackOn = Exception.class) - public Dryrun provisionDryrun(Exercise exercise, List users, String name) { - Specification injectFilters = InjectSpecification.forDryrun(exercise.getId()); - List injects = injectRepository.findAll(injectFilters); - Assert.isTrue(!injects.isEmpty(), "Cant create dryrun without injects"); - Dryrun dryrun = createDryRun(exercise, users, name); - List dryInjects = toDryInjects(injects, dryrun); - dryInjectRepository.saveAll(dryInjects); - return dryrun; - } - // endregion + @Transactional(rollbackOn = Exception.class) + public Dryrun provisionDryrun(Exercise exercise, List users, String name) { + Specification injectFilters = InjectSpecification.forDryrun(exercise.getId()); + List injects = injectRepository.findAll(injectFilters); + Assert.isTrue(!injects.isEmpty(), "Cant create dryrun without injects"); + Dryrun dryrun = createDryRun(exercise, users, name); + List dryInjects = toDryInjects(injects, dryrun); + dryInjectRepository.saveAll(dryInjects); + return dryrun; + } + // endregion } diff --git a/openbas-api/src/main/java/io/openbas/service/ExerciseExpectationService.java b/openbas-api/src/main/java/io/openbas/service/ExerciseExpectationService.java index 1e8e9613ff..8d2fd4be3a 100644 --- a/openbas-api/src/main/java/io/openbas/service/ExerciseExpectationService.java +++ b/openbas-api/src/main/java/io/openbas/service/ExerciseExpectationService.java @@ -1,5 +1,7 @@ package io.openbas.service; +import static java.time.Instant.now; + import io.openbas.database.model.Exercise; import io.openbas.database.model.InjectExpectation; import io.openbas.database.model.InjectExpectation.EXPECTATION_TYPE; @@ -10,206 +12,241 @@ import io.openbas.rest.exercise.form.ExpectationUpdateInput; import jakarta.validation.constraints.NotBlank; import jakarta.validation.constraints.NotNull; -import lombok.RequiredArgsConstructor; -import org.springframework.stereotype.Service; - import java.time.Instant; import java.util.*; - -import static java.time.Instant.now; +import lombok.RequiredArgsConstructor; +import org.springframework.stereotype.Service; @RequiredArgsConstructor @Service public class ExerciseExpectationService { - private final InjectExpectationRepository injectExpectationRepository; - private final ExerciseRepository exerciseRepository; - - public List injectExpectations(@NotBlank final String exerciseId) { - Exercise exercise = this.exerciseRepository.findById(exerciseId).orElseThrow(); - return this.injectExpectationRepository.findAllForExercise(exercise.getId()); + private final InjectExpectationRepository injectExpectationRepository; + private final ExerciseRepository exerciseRepository; + + public List injectExpectations(@NotBlank final String exerciseId) { + Exercise exercise = this.exerciseRepository.findById(exerciseId).orElseThrow(); + return this.injectExpectationRepository.findAllForExercise(exercise.getId()); + } + + public InjectExpectation updateInjectExpectation( + @NotBlank final String expectationId, @NotNull final ExpectationUpdateInput input) { + InjectExpectation injectExpectation = + this.injectExpectationRepository.findById(expectationId).orElseThrow(); + Optional exists = + injectExpectation.getResults().stream() + .filter(r -> input.getSourceId().equals(r.getSourceId())) + .findAny(); + + String result = ""; + if (injectExpectation.getType() == EXPECTATION_TYPE.MANUAL) { + result = input.getScore() >= injectExpectation.getExpectedScore() ? "Success" : "Failed"; + injectExpectation.getResults().clear(); + exists = Optional.empty(); + } else if (injectExpectation.getType() == EXPECTATION_TYPE.DETECTION) { + if (input.getScore() >= injectExpectation.getExpectedScore()) { + result = "Detected"; + } else if (input.getScore() > 0) { + result = "Partially Detected"; + } else { + result = "Not Detected"; + } + } else if (injectExpectation.getType() == EXPECTATION_TYPE.PREVENTION) { + if (input.getScore() >= injectExpectation.getExpectedScore()) { + result = "Prevented"; + } else if (input.getScore() > 0) { + result = "Partially Prevented"; + } else { + result = "Not Prevented"; + } + } + if (exists.isPresent()) { + exists.get().setResult(result); + exists.get().setScore(input.getScore()); + exists.get().setDate(now().toString()); + } else { + injectExpectation + .getResults() + .add(buildInjectExpectationResult(input.getSourceType(), result, input.getScore())); + } + if (injectExpectation.getScore() == null) { + injectExpectation.setScore(input.getScore()); + } else { + if (input.getScore() > injectExpectation.getScore() + || injectExpectation.getType() == EXPECTATION_TYPE.MANUAL) { + injectExpectation.setScore(input.getScore()); + } else { + injectExpectation.setScore( + Collections.max( + injectExpectation.getResults().stream() + .map(InjectExpectationResult::getScore) + .filter(Objects::nonNull) + .toList())); + } } + injectExpectation.setUpdatedAt(now()); + InjectExpectation updated = this.injectExpectationRepository.save(injectExpectation); - public InjectExpectation updateInjectExpectation( - @NotBlank final String expectationId, - @NotNull final ExpectationUpdateInput input) { - InjectExpectation injectExpectation = this.injectExpectationRepository.findById(expectationId).orElseThrow(); - Optional exists = injectExpectation.getResults() - .stream() - .filter(r -> input.getSourceId().equals(r.getSourceId())) - .findAny(); - - String result = ""; - if (injectExpectation.getType() == EXPECTATION_TYPE.MANUAL) { - result = input.getScore() >= injectExpectation.getExpectedScore() ? "Success" : "Failed"; - injectExpectation.getResults().clear(); - exists = Optional.empty(); - } else if (injectExpectation.getType() == EXPECTATION_TYPE.DETECTION) { - if (input.getScore() >= injectExpectation.getExpectedScore()) { - result = "Detected"; - } else if (input.getScore() > 0) { - result = "Partially Detected"; - } else { - result = "Not Detected"; - } - } else if (injectExpectation.getType() == EXPECTATION_TYPE.PREVENTION) { - if (input.getScore() >= injectExpectation.getExpectedScore()) { - result = "Prevented"; - } else if (input.getScore() > 0) { - result = "Partially Prevented"; - } else { - result = "Not Prevented"; - } - } - if (exists.isPresent()) { - exists.get().setResult(result); - exists.get().setScore(input.getScore()); - exists.get().setDate(now().toString()); - } else { - injectExpectation.getResults().add( - buildInjectExpectationResult(input.getSourceType(),result, input.getScore()) - ); - } - if (injectExpectation.getScore() == null) { - injectExpectation.setScore(input.getScore()); - } else { - if (input.getScore() > injectExpectation.getScore() || injectExpectation.getType() == EXPECTATION_TYPE.MANUAL) { - injectExpectation.setScore(input.getScore()); - } else { - injectExpectation.setScore(Collections.max(injectExpectation.getResults().stream().map(InjectExpectationResult::getScore).filter(Objects::nonNull).toList())); - } - } - injectExpectation.setUpdatedAt(now()); - InjectExpectation updated = this.injectExpectationRepository.save(injectExpectation); + // If The expectation is type manual, We should update expectations for teams and players + if (updated.getType() == EXPECTATION_TYPE.MANUAL && updated.getTeam() != null) { + computeExpectationsForTeamsAndPlayer(updated, result); + } + return updated; + } + + public InjectExpectation deleteInjectExpectationResult( + @NotBlank final String expectationId, @NotBlank final String sourceId) { + InjectExpectation injectExpectation = + this.injectExpectationRepository.findById(expectationId).orElseThrow(); + Optional exists = + injectExpectation.getResults().stream() + .filter(r -> sourceId.equals(r.getSourceId())) + .findAny(); + if (exists.isPresent()) { + injectExpectation.setResults( + injectExpectation.getResults().stream() + .filter(r -> !sourceId.equals(r.getSourceId())) + .toList()); + if (injectExpectation.getType() == EXPECTATION_TYPE.MANUAL) { + injectExpectation.setScore(null); + } else { + List scores = + injectExpectation.getResults().stream() + .map(InjectExpectationResult::getScore) + .filter(Objects::nonNull) + .toList(); + injectExpectation.setScore(!scores.isEmpty() ? Collections.max(scores) : 0.0); + } + } + injectExpectation.setUpdatedAt(now()); + InjectExpectation updated = this.injectExpectationRepository.save(injectExpectation); - // If The expectation is type manual, We should update expectations for teams and players - if (updated.getType() == EXPECTATION_TYPE.MANUAL && updated.getTeam() != null) { - computeExpectationsForTeamsAndPlayer(updated, result); - } - return updated; + // If The expectation is type manual, We should update expectations for teams and players + if (updated.getType() == EXPECTATION_TYPE.MANUAL && updated.getTeam() != null) { + computeExpectationsForTeamsAndPlayer(updated, null); } - public InjectExpectation deleteInjectExpectationResult( - @NotBlank final String expectationId, - @NotBlank final String sourceId) { - InjectExpectation injectExpectation = this.injectExpectationRepository.findById(expectationId).orElseThrow(); - Optional exists = injectExpectation.getResults() - .stream() - .filter(r -> sourceId.equals(r.getSourceId())) - .findAny(); - if (exists.isPresent()) { - injectExpectation.setResults(injectExpectation.getResults() - .stream() - .filter(r -> !sourceId.equals(r.getSourceId())).toList()); - if (injectExpectation.getType() == EXPECTATION_TYPE.MANUAL) { - injectExpectation.setScore(null); - } else { - List scores = injectExpectation.getResults().stream().map(InjectExpectationResult::getScore).filter(Objects::nonNull).toList(); - injectExpectation.setScore(!scores.isEmpty() ? Collections.max(scores) : 0.0); - } + return updated; + } + + // -- VALIDATION TYPE -- + private void computeExpectationsForTeamsAndPlayer(InjectExpectation updated, String result) { + // If the updated expectation was a player expectation, We have to update the team expectation + // using player expectations (based on validation type) + if (updated.getUser() != null) { + List toProcess = + injectExpectationRepository.findAllByInjectAndTeamAndExpectationName( + updated.getInject().getId(), updated.getTeam().getId(), updated.getName()); + InjectExpectation parentExpectation = + toProcess.stream() + .filter(exp -> exp.getUser() == null) + .findFirst() + .orElseThrow(ElementNotFoundException::new); + List playersExpectations = + toProcess.stream().filter(exp -> exp.getUser() != null).toList(); + List playersAnsweredExpectations = + playersExpectations.stream().filter(exp -> exp.getScore() != null).toList(); + + if (updated.isExpectationGroup()) { // If At least one player + List successPlayerExpectations = + playersExpectations.stream() + .filter(exp -> exp.getScore() != null) + .filter(exp -> exp.getScore() >= updated.getExpectedScore()) + .toList(); + + if (!successPlayerExpectations.isEmpty()) { // At least one player success + result = "Success"; + OptionalDouble avgSuccessPlayer = + successPlayerExpectations.stream().mapToDouble(InjectExpectation::getScore).average(); + parentExpectation.setScore(avgSuccessPlayer.getAsDouble()); + } else if (playersAnsweredExpectations.size() + == playersExpectations.size()) { // All players had answers and no one success + result = "Failed"; + parentExpectation.setScore(0.0); + } else { + result = "Pending"; + parentExpectation.setScore(null); } - injectExpectation.setUpdatedAt(now()); - InjectExpectation updated = this.injectExpectationRepository.save(injectExpectation); - // If The expectation is type manual, We should update expectations for teams and players - if (updated.getType() == EXPECTATION_TYPE.MANUAL && updated.getTeam() != null) { - computeExpectationsForTeamsAndPlayer(updated, null); + } else { // All Player + boolean hasFailedPlayer = + playersExpectations.stream() + .filter(exp -> exp.getScore() != null) + .anyMatch(exp -> exp.getScore() < updated.getExpectedScore()); + + if (hasFailedPlayer) { + result = "Failed"; + } else if (playersAnsweredExpectations.size() + == playersExpectations.size()) { // All players answered and no failures + result = "Success"; + } else { // Some players haven't answered yet + result = "Pending"; + parentExpectation.setScore(null); } - return updated; - } - - // -- VALIDATION TYPE -- - private void computeExpectationsForTeamsAndPlayer(InjectExpectation updated, String result) { - //If the updated expectation was a player expectation, We have to update the team expectation using player expectations (based on validation type) - if (updated.getUser() != null) { - List toProcess = injectExpectationRepository.findAllByInjectAndTeamAndExpectationName(updated.getInject().getId(), updated.getTeam().getId(), updated.getName()); - InjectExpectation parentExpectation = toProcess.stream().filter(exp -> exp.getUser() == null).findFirst().orElseThrow(ElementNotFoundException::new); - List playersExpectations = toProcess.stream().filter(exp -> exp.getUser() != null).toList(); - List playersAnsweredExpectations = playersExpectations.stream().filter(exp -> exp.getScore() != null).toList(); - - if (updated.isExpectationGroup()) { // If At least one player - List successPlayerExpectations = playersExpectations.stream().filter(exp -> exp.getScore() != null).filter(exp -> exp.getScore() >= updated.getExpectedScore()).toList(); - - if(!successPlayerExpectations.isEmpty()){ // At least one player success - result = "Success"; - OptionalDouble avgSuccessPlayer = successPlayerExpectations.stream().mapToDouble(InjectExpectation::getScore).average(); - parentExpectation.setScore(avgSuccessPlayer.getAsDouble()); - } else if (playersAnsweredExpectations.size() == playersExpectations.size()){ // All players had answers and no one success - result = "Failed"; - parentExpectation.setScore(0.0); - } else { - result = "Pending"; - parentExpectation.setScore(null); - } - - } else { // All Player - boolean hasFailedPlayer = playersExpectations.stream() - .filter(exp -> exp.getScore() != null) - .anyMatch(exp -> exp.getScore() < updated.getExpectedScore()); - - if (hasFailedPlayer) { - result = "Failed"; - } else if (playersAnsweredExpectations.size() == playersExpectations.size()) { // All players answered and no failures - result = "Success"; - } else { // Some players haven't answered yet - result = "Pending"; - parentExpectation.setScore(null); - } - - if (!result.equals("Pending")){ - OptionalDouble avgAllPlayer = playersAnsweredExpectations.stream().mapToDouble(InjectExpectation::getScore).average(); - parentExpectation.setScore(avgAllPlayer.orElse(0.0)); - } - } - - parentExpectation.setUpdatedAt(Instant.now()); - parentExpectation.getResults().clear(); - parentExpectation.getResults().add( - buildInjectExpectationResult("player-manual-validation", result, parentExpectation.getScore()) - ); - injectExpectationRepository.save(parentExpectation); - - } else { - // If I update the expectation team: What happens with children? -> update expectation score for all children -> set score from InjectExpectation - List toProcess = injectExpectationRepository.findAllByInjectAndTeamAndExpectationNameAndUserIsNotNull(updated.getInject().getId(), updated.getTeam().getId(), updated.getName()); - for (InjectExpectation expectation : toProcess) { - expectation.setScore(updated.getScore()); - expectation.setUpdatedAt(Instant.now()); - expectation.getResults().clear(); - if(result != null) { - expectation.getResults().add( - buildInjectExpectationResult("team-manual-validation", result, updated.getScore())); - } - injectExpectationRepository.save(expectation); - } + if (!result.equals("Pending")) { + OptionalDouble avgAllPlayer = + playersAnsweredExpectations.stream() + .mapToDouble(InjectExpectation::getScore) + .average(); + parentExpectation.setScore(avgAllPlayer.orElse(0.0)); + } + } + + parentExpectation.setUpdatedAt(Instant.now()); + parentExpectation.getResults().clear(); + parentExpectation + .getResults() + .add( + buildInjectExpectationResult( + "player-manual-validation", result, parentExpectation.getScore())); + injectExpectationRepository.save(parentExpectation); + + } else { + // If I update the expectation team: What happens with children? -> update expectation score + // for all children -> set score from InjectExpectation + List toProcess = + injectExpectationRepository.findAllByInjectAndTeamAndExpectationNameAndUserIsNotNull( + updated.getInject().getId(), updated.getTeam().getId(), updated.getName()); + for (InjectExpectation expectation : toProcess) { + expectation.setScore(updated.getScore()); + expectation.setUpdatedAt(Instant.now()); + expectation.getResults().clear(); + if (result != null) { + expectation + .getResults() + .add( + buildInjectExpectationResult( + "team-manual-validation", result, updated.getScore())); } + injectExpectationRepository.save(expectation); + } } - - private InjectExpectationResult buildInjectExpectationResult(String type, String resultStatus, Double score ){ - return InjectExpectationResult.builder() - .sourceId(type) - .sourceType(type) - .sourceName(transformExpectationResultTypeToName(type)) - .result(resultStatus) - .date(now().toString()) - .score(score) - .build(); + } + + private InjectExpectationResult buildInjectExpectationResult( + String type, String resultStatus, Double score) { + return InjectExpectationResult.builder() + .sourceId(type) + .sourceType(type) + .sourceName(transformExpectationResultTypeToName(type)) + .result(resultStatus) + .date(now().toString()) + .score(score) + .build(); + } + + private String transformExpectationResultTypeToName(String type) { + if (type == null) { + return ""; } + String[] words = type.split("-"); - private String transformExpectationResultTypeToName(String type){ - if (type==null) { - return ""; - } - String[] words = type.split("-"); - - // Capitalize each word and join them with a space - StringBuilder result = new StringBuilder(); - for (String word : words) { - result.append(Character.toUpperCase(word.charAt(0))) - .append(word.substring(1)) - .append(" "); - } - return result.toString().trim(); + // Capitalize each word and join them with a space + StringBuilder result = new StringBuilder(); + for (String word : words) { + result.append(Character.toUpperCase(word.charAt(0))).append(word.substring(1)).append(" "); } + return result.toString().trim(); + } } diff --git a/openbas-api/src/main/java/io/openbas/service/GrantService.java b/openbas-api/src/main/java/io/openbas/service/GrantService.java index e3d3e78aef..73a01f3ab5 100644 --- a/openbas-api/src/main/java/io/openbas/service/GrantService.java +++ b/openbas-api/src/main/java/io/openbas/service/GrantService.java @@ -1,5 +1,7 @@ package io.openbas.service; +import static io.openbas.helper.StreamHelper.fromIterable; + import io.openbas.database.model.Exercise; import io.openbas.database.model.Grant; import io.openbas.database.model.Group; @@ -7,14 +9,11 @@ import io.openbas.database.repository.GrantRepository; import io.openbas.database.repository.GroupRepository; import jakarta.validation.constraints.NotNull; +import java.util.List; import lombok.RequiredArgsConstructor; import org.springframework.stereotype.Service; import reactor.util.function.Tuples; -import java.util.List; - -import static io.openbas.helper.StreamHelper.fromIterable; - @Service @RequiredArgsConstructor public class GrantService { @@ -25,15 +24,20 @@ public class GrantService { public void computeGrant(@NotNull Exercise exercise) { // Find automatic groups to grants List groups = fromIterable(this.groupRepository.findAll()); - List grants = groups.stream() - .filter(group -> !group.getExercisesDefaultGrants().isEmpty()) - .flatMap(group -> group.getExercisesDefaultGrants().stream().map(s -> Tuples.of(group, s))).map(tuple -> { - Grant grant = new Grant(); - grant.setGroup(tuple.getT1()); - grant.setName(tuple.getT2()); - grant.setExercise(exercise); - return grant; - }).toList(); + List grants = + groups.stream() + .filter(group -> !group.getExercisesDefaultGrants().isEmpty()) + .flatMap( + group -> group.getExercisesDefaultGrants().stream().map(s -> Tuples.of(group, s))) + .map( + tuple -> { + Grant grant = new Grant(); + grant.setGroup(tuple.getT1()); + grant.setName(tuple.getT2()); + grant.setExercise(exercise); + return grant; + }) + .toList(); if (!grants.isEmpty()) { Iterable exerciseGrants = this.grantRepository.saveAll(grants); exercise.setGrants(fromIterable(exerciseGrants)); @@ -43,19 +47,23 @@ public void computeGrant(@NotNull Exercise exercise) { public void computeGrant(@NotNull Scenario scenario) { // Find automatic groups to grants List groups = fromIterable(this.groupRepository.findAll()); - List grants = groups.stream() - .filter(group -> !group.getScenariosDefaultGrants().isEmpty()) - .flatMap(group -> group.getScenariosDefaultGrants().stream().map(s -> Tuples.of(group, s))).map(tuple -> { - Grant grant = new Grant(); - grant.setGroup(tuple.getT1()); - grant.setName(tuple.getT2()); - grant.setScenario(scenario); - return grant; - }).toList(); + List grants = + groups.stream() + .filter(group -> !group.getScenariosDefaultGrants().isEmpty()) + .flatMap( + group -> group.getScenariosDefaultGrants().stream().map(s -> Tuples.of(group, s))) + .map( + tuple -> { + Grant grant = new Grant(); + grant.setGroup(tuple.getT1()); + grant.setName(tuple.getT2()); + grant.setScenario(scenario); + return grant; + }) + .toList(); if (!grants.isEmpty()) { Iterable scenarioGrants = this.grantRepository.saveAll(grants); scenario.setGrants(fromIterable(scenarioGrants)); } } - } diff --git a/openbas-api/src/main/java/io/openbas/service/ImportEntry.java b/openbas-api/src/main/java/io/openbas/service/ImportEntry.java index 42f2cbfa26..2f455a612d 100644 --- a/openbas-api/src/main/java/io/openbas/service/ImportEntry.java +++ b/openbas-api/src/main/java/io/openbas/service/ImportEntry.java @@ -5,28 +5,28 @@ public class ImportEntry { - private ZipEntry entry; + private ZipEntry entry; - private InputStream data; + private InputStream data; - public ImportEntry(ZipEntry entry, InputStream data) { - this.entry = entry; - this.data = data; - } + public ImportEntry(ZipEntry entry, InputStream data) { + this.entry = entry; + this.data = data; + } - public ZipEntry getEntry() { - return entry; - } + public ZipEntry getEntry() { + return entry; + } - public void setEntry(ZipEntry entry) { - this.entry = entry; - } + public void setEntry(ZipEntry entry) { + this.entry = entry; + } - public InputStream getData() { - return data; - } + public InputStream getData() { + return data; + } - public void setData(InputStream data) { - this.data = data; - } + public void setData(InputStream data) { + this.data = data; + } } diff --git a/openbas-api/src/main/java/io/openbas/service/ImportRow.java b/openbas-api/src/main/java/io/openbas/service/ImportRow.java index 464ba1c133..bf46138533 100644 --- a/openbas-api/src/main/java/io/openbas/service/ImportRow.java +++ b/openbas-api/src/main/java/io/openbas/service/ImportRow.java @@ -2,14 +2,13 @@ import io.openbas.database.model.Inject; import io.openbas.rest.scenario.response.ImportMessage; -import lombok.Data; - import java.util.ArrayList; import java.util.List; +import lombok.Data; @Data public class ImportRow { - private InjectTime injectTime; - private List importMessages = new ArrayList<>(); - private Inject inject; + private InjectTime injectTime; + private List importMessages = new ArrayList<>(); + private Inject inject; } diff --git a/openbas-api/src/main/java/io/openbas/service/ImportService.java b/openbas-api/src/main/java/io/openbas/service/ImportService.java index 1e76406206..57fbc3ae02 100644 --- a/openbas-api/src/main/java/io/openbas/service/ImportService.java +++ b/openbas-api/src/main/java/io/openbas/service/ImportService.java @@ -1,15 +1,13 @@ package io.openbas.service; +import static java.io.File.createTempFile; +import static java.time.Instant.now; + import com.fasterxml.jackson.databind.JsonNode; import com.fasterxml.jackson.databind.ObjectMapper; import io.openbas.importer.ImportException; import io.openbas.importer.Importer; import io.openbas.importer.V1_DataImporter; -import org.apache.commons.io.FileUtils; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.stereotype.Service; -import org.springframework.web.multipart.MultipartFile; - import jakarta.annotation.Resource; import jakarta.transaction.Transactional; import java.io.File; @@ -17,73 +15,76 @@ import java.util.*; import java.util.zip.ZipEntry; import java.util.zip.ZipFile; - -import static java.io.File.createTempFile; -import static java.time.Instant.now; +import org.apache.commons.io.FileUtils; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Service; +import org.springframework.web.multipart.MultipartFile; @Service public class ImportService { - public final static String EXPORT_ENTRY_EXERCISE = "Exercise"; - public final static String EXPORT_ENTRY_SCENARIO = "Scenario"; - public final static String EXPORT_ENTRY_ATTACHMENT = "Attachment"; + public static final String EXPORT_ENTRY_EXERCISE = "Exercise"; + public static final String EXPORT_ENTRY_SCENARIO = "Scenario"; + public static final String EXPORT_ENTRY_ATTACHMENT = "Attachment"; - private final Map dataImporters = new HashMap<>(); + private final Map dataImporters = new HashMap<>(); - @Resource - protected ObjectMapper mapper; + @Resource protected ObjectMapper mapper; - @Autowired - public void setV1_dataImporter(V1_DataImporter v1_dataImporter) { - dataImporters.put(1, v1_dataImporter); - } + @Autowired + public void setV1_dataImporter(V1_DataImporter v1_dataImporter) { + dataImporters.put(1, v1_dataImporter); + } - private void handleDataImport(InputStream inputStream, Map docReferences) { - try { - JsonNode importNode = mapper.readTree(inputStream); - int importVersion = importNode.get("export_version").asInt(); - Importer importer = dataImporters.get(importVersion); - if (importer != null) { - importer.importData(importNode, docReferences); - } else { - throw new ImportException("Export with version " + importVersion + " is not supported"); - } - } catch (Exception e) { - throw new ImportException(e); - } + private void handleDataImport(InputStream inputStream, Map docReferences) { + try { + JsonNode importNode = mapper.readTree(inputStream); + int importVersion = importNode.get("export_version").asInt(); + Importer importer = dataImporters.get(importVersion); + if (importer != null) { + importer.importData(importNode, docReferences); + } else { + throw new ImportException("Export with version " + importVersion + " is not supported"); + } + } catch (Exception e) { + throw new ImportException(e); } + } - @Transactional(rollbackOn = Exception.class) - public void handleFileImport(MultipartFile file) throws Exception { - // 01. Use a temporary file. - File tempFile = createTempFile("openbas-import-" + now().getEpochSecond(), ".zip"); - FileUtils.copyInputStreamToFile(file.getInputStream(), tempFile); + @Transactional(rollbackOn = Exception.class) + public void handleFileImport(MultipartFile file) throws Exception { + // 01. Use a temporary file. + File tempFile = createTempFile("openbas-import-" + now().getEpochSecond(), ".zip"); + FileUtils.copyInputStreamToFile(file.getInputStream(), tempFile); - try(ZipFile zipFile = new ZipFile(tempFile)) { - // 02. Use this file to load zip with information - Enumeration entries = zipFile.entries(); - // 01. Iter on each document to create it - List dataImports = new ArrayList<>(); - Map docReferences = new HashMap<>(); - while (entries.hasMoreElements()) { - ZipEntry entry = entries.nextElement(); - String entryType = entry.getComment(); - if (entryType == null) { - throw new UnsupportedOperationException("Import file is using an incorrect format."); - } - InputStream zipInputStream = zipFile.getInputStream(entry); - switch (entryType) { - case EXPORT_ENTRY_EXERCISE, EXPORT_ENTRY_SCENARIO -> dataImports.add(zipInputStream); - case EXPORT_ENTRY_ATTACHMENT -> docReferences.put(entry.getName(), new ImportEntry(entry, zipInputStream)); - default -> throw new UnsupportedOperationException("Import file contains an unsupported type: " + entryType); - } - } - // 02. Iter on each element to import - dataImports.forEach(dataStream -> handleDataImport(dataStream, docReferences)); - } finally { - // 03. Delete the temporary file - //noinspection ResultOfMethodCallIgnored - tempFile.delete(); + try (ZipFile zipFile = new ZipFile(tempFile)) { + // 02. Use this file to load zip with information + Enumeration entries = zipFile.entries(); + // 01. Iter on each document to create it + List dataImports = new ArrayList<>(); + Map docReferences = new HashMap<>(); + while (entries.hasMoreElements()) { + ZipEntry entry = entries.nextElement(); + String entryType = entry.getComment(); + if (entryType == null) { + throw new UnsupportedOperationException("Import file is using an incorrect format."); + } + InputStream zipInputStream = zipFile.getInputStream(entry); + switch (entryType) { + case EXPORT_ENTRY_EXERCISE, EXPORT_ENTRY_SCENARIO -> dataImports.add(zipInputStream); + case EXPORT_ENTRY_ATTACHMENT -> + docReferences.put(entry.getName(), new ImportEntry(entry, zipInputStream)); + default -> + throw new UnsupportedOperationException( + "Import file contains an unsupported type: " + entryType); } + } + // 02. Iter on each element to import + dataImports.forEach(dataStream -> handleDataImport(dataStream, docReferences)); + } finally { + // 03. Delete the temporary file + //noinspection ResultOfMethodCallIgnored + tempFile.delete(); } + } } diff --git a/openbas-api/src/main/java/io/openbas/service/InjectService.java b/openbas-api/src/main/java/io/openbas/service/InjectService.java index d1c6c905fc..826d161954 100644 --- a/openbas-api/src/main/java/io/openbas/service/InjectService.java +++ b/openbas-api/src/main/java/io/openbas/service/InjectService.java @@ -1,5 +1,12 @@ package io.openbas.service; +import static io.openbas.config.SessionHelper.currentUser; +import static io.openbas.database.criteria.GenericCriteria.countQuery; +import static io.openbas.utils.JpaUtils.createJoinArrayAggOnId; +import static io.openbas.utils.JpaUtils.createLeftJoin; +import static io.openbas.utils.pagination.SortUtilsCriteriaBuilder.toSortCriteriaBuilder; +import static java.time.Instant.now; + import com.fasterxml.jackson.databind.JsonNode; import com.fasterxml.jackson.databind.ObjectMapper; import com.fasterxml.jackson.databind.node.ArrayNode; @@ -24,22 +31,6 @@ import jakarta.persistence.criteria.*; import jakarta.transaction.Transactional; import jakarta.validation.constraints.NotBlank; -import lombok.RequiredArgsConstructor; -import lombok.extern.java.Log; -import org.apache.commons.io.FilenameUtils; -import org.apache.commons.lang3.time.DateFormatUtils; -import org.apache.logging.log4j.util.Strings; -import org.apache.poi.ss.usermodel.*; -import org.apache.poi.ss.util.CellReference; -import org.jetbrains.annotations.NotNull; -import org.springframework.data.domain.Page; -import org.springframework.data.domain.PageImpl; -import org.springframework.data.domain.Pageable; -import org.springframework.data.jpa.domain.Specification; -import org.springframework.stereotype.Service; -import org.springframework.util.CollectionUtils; -import org.springframework.web.multipart.MultipartFile; - import java.io.IOException; import java.io.InputStream; import java.nio.file.FileSystems; @@ -62,82 +53,99 @@ import java.util.stream.Collectors; import java.util.stream.Stream; import java.util.stream.StreamSupport; - -import static io.openbas.config.SessionHelper.currentUser; -import static io.openbas.database.criteria.GenericCriteria.countQuery; -import static io.openbas.utils.JpaUtils.createJoinArrayAggOnId; -import static io.openbas.utils.JpaUtils.createLeftJoin; -import static io.openbas.utils.pagination.SortUtilsCriteriaBuilder.toSortCriteriaBuilder; -import static java.time.Instant.now; +import lombok.RequiredArgsConstructor; +import lombok.extern.java.Log; +import org.apache.commons.io.FilenameUtils; +import org.apache.commons.lang3.time.DateFormatUtils; +import org.apache.logging.log4j.util.Strings; +import org.apache.poi.ss.usermodel.*; +import org.apache.poi.ss.util.CellReference; +import org.jetbrains.annotations.NotNull; +import org.springframework.data.domain.Page; +import org.springframework.data.domain.PageImpl; +import org.springframework.data.domain.Pageable; +import org.springframework.data.jpa.domain.Specification; +import org.springframework.stereotype.Service; +import org.springframework.util.CollectionUtils; +import org.springframework.web.multipart.MultipartFile; @RequiredArgsConstructor @Service @Log public class InjectService { - private final InjectRepository injectRepository; - private final InjectDocumentRepository injectDocumentRepository; - private final InjectExpectationRepository injectExpectationRepository; - private final AssetRepository assetRepository; - private final AssetGroupRepository assetGroupRepository; - private final ScenarioTeamUserRepository scenarioTeamUserRepository; - private final ExerciseTeamUserRepository exerciseTeamUserRepository; - private final TeamRepository teamRepository; - private final UserRepository userRepository; - - private final List importReservedField = List.of("description", "title", "trigger_time"); - - @Resource - protected ObjectMapper mapper; - @PersistenceContext - private EntityManager entityManager; - - final Pattern relativeDayPattern = Pattern.compile("^.*[DJ]([+\\-]?[0-9]*)(.*)$"); - final Pattern relativeHourPattern = Pattern.compile("^.*[HT]([+\\-]?[0-9]*).*$"); - final Pattern relativeMinutePattern = Pattern.compile("^.*[M]([+\\-]?[0-9]*).*$"); - - final String pathSeparator = FileSystems.getDefault().getSeparator(); - - final int FILE_STORAGE_DURATION = 60; - - public void cleanInjectsDocExercise(String exerciseId, String documentId) { - // Delete document from all exercise injects - List exerciseInjects = injectRepository.findAllForExerciseAndDoc(exerciseId, documentId); - List updatedInjects = exerciseInjects.stream().flatMap(inject -> { - @SuppressWarnings("UnnecessaryLocalVariable") - Stream filterDocuments = inject.getDocuments().stream() - .filter(document -> document.getDocument().getId().equals(documentId)); - return filterDocuments; - }).toList(); - injectDocumentRepository.deleteAll(updatedInjects); - } - - public void cleanInjectsDocScenario(String scenarioId, String documentId) { - // Delete document from all scenario injects - List scenarioInjects = injectRepository.findAllForScenarioAndDoc(scenarioId, documentId); - List updatedInjects = scenarioInjects.stream().flatMap(inject -> { - @SuppressWarnings("UnnecessaryLocalVariable") - Stream filterDocuments = inject.getDocuments().stream() - .filter(document -> document.getDocument().getId().equals(documentId)); - return filterDocuments; - }).toList(); - injectDocumentRepository.deleteAll(updatedInjects); - } + private final InjectRepository injectRepository; + private final InjectDocumentRepository injectDocumentRepository; + private final InjectExpectationRepository injectExpectationRepository; + private final AssetRepository assetRepository; + private final AssetGroupRepository assetGroupRepository; + private final ScenarioTeamUserRepository scenarioTeamUserRepository; + private final ExerciseTeamUserRepository exerciseTeamUserRepository; + private final TeamRepository teamRepository; + private final UserRepository userRepository; + + private final List importReservedField = List.of("description", "title", "trigger_time"); + + @Resource protected ObjectMapper mapper; + @PersistenceContext private EntityManager entityManager; + + final Pattern relativeDayPattern = Pattern.compile("^.*[DJ]([+\\-]?[0-9]*)(.*)$"); + final Pattern relativeHourPattern = Pattern.compile("^.*[HT]([+\\-]?[0-9]*).*$"); + final Pattern relativeMinutePattern = Pattern.compile("^.*[M]([+\\-]?[0-9]*).*$"); + + final String pathSeparator = FileSystems.getDefault().getSeparator(); + + final int FILE_STORAGE_DURATION = 60; + + public void cleanInjectsDocExercise(String exerciseId, String documentId) { + // Delete document from all exercise injects + List exerciseInjects = + injectRepository.findAllForExerciseAndDoc(exerciseId, documentId); + List updatedInjects = + exerciseInjects.stream() + .flatMap( + inject -> { + @SuppressWarnings("UnnecessaryLocalVariable") + Stream filterDocuments = + inject.getDocuments().stream() + .filter(document -> document.getDocument().getId().equals(documentId)); + return filterDocuments; + }) + .toList(); + injectDocumentRepository.deleteAll(updatedInjects); + } - @Transactional(rollbackOn = Exception.class) - public Inject updateInjectStatus(String injectId, InjectUpdateStatusInput input) { - Inject inject = injectRepository.findById(injectId).orElseThrow(); - // build status - InjectStatus injectStatus = new InjectStatus(); - injectStatus.setInject(inject); - injectStatus.setTrackingSentDate(now()); - injectStatus.setName(ExecutionStatus.valueOf(input.getStatus())); - injectStatus.setTrackingTotalExecutionTime(0L); - // Save status for inject - inject.setStatus(injectStatus); - return injectRepository.save(inject); - } + public void cleanInjectsDocScenario(String scenarioId, String documentId) { + // Delete document from all scenario injects + List scenarioInjects = + injectRepository.findAllForScenarioAndDoc(scenarioId, documentId); + List updatedInjects = + scenarioInjects.stream() + .flatMap( + inject -> { + @SuppressWarnings("UnnecessaryLocalVariable") + Stream filterDocuments = + inject.getDocuments().stream() + .filter(document -> document.getDocument().getId().equals(documentId)); + return filterDocuments; + }) + .toList(); + injectDocumentRepository.deleteAll(updatedInjects); + } + @Transactional(rollbackOn = Exception.class) + public Inject updateInjectStatus(String injectId, InjectUpdateStatusInput input) { + Inject inject = injectRepository.findById(injectId).orElseThrow(); + // build status + InjectStatus injectStatus = new InjectStatus(); + injectStatus.setInject(inject); + injectStatus.setTrackingSentDate(now()); + injectStatus.setName(ExecutionStatus.valueOf(input.getStatus())); + injectStatus.setTrackingTotalExecutionTime(0L); + // Save status for inject + inject.setStatus(injectStatus); + return injectRepository.save(inject); + } @Transactional(rollbackOn = Exception.class) public void deleteAllByIds(List injectIds) { @@ -147,8 +155,9 @@ public void deleteAllByIds(List injectIds) { } public Inject inject(@NotBlank final String injectId) { - return this.injectRepository.findById(injectId) - .orElseThrow(() -> new ElementNotFoundException("Inject not found")); + return this.injectRepository + .findById(injectId) + .orElseThrow(() -> new ElementNotFoundException("Inject not found")); } @Tracing(name = "Fetch injects with criteria builder", layer = "service", operation = "GET") @@ -177,967 +186,1270 @@ public List injects(Specification specification) { return execInject(query); } - public Page injects( - Specification specification, - Specification specificationCount, - Pageable pageable) { - CriteriaBuilder cb = this.entityManager.getCriteriaBuilder(); - - CriteriaQuery cq = cb.createTupleQuery(); - Root injectRoot = cq.from(Inject.class); - selectForInject(cb, cq, injectRoot); - - // -- Text Search and Filters -- - if (specification != null) { - Predicate predicate = specification.toPredicate(injectRoot, cq, cb); - if (predicate != null) { - cq.where(predicate); - } - } + public Page injects( + Specification specification, + Specification specificationCount, + Pageable pageable) { + CriteriaBuilder cb = this.entityManager.getCriteriaBuilder(); - // -- Sorting -- - List orders = toSortCriteriaBuilder(cb, injectRoot, pageable.getSort()); - cq.orderBy(orders); + CriteriaQuery cq = cb.createTupleQuery(); + Root injectRoot = cq.from(Inject.class); + selectForInject(cb, cq, injectRoot); - // Type Query - TypedQuery query = this.entityManager.createQuery(cq); + // -- Text Search and Filters -- + if (specification != null) { + Predicate predicate = specification.toPredicate(injectRoot, cq, cb); + if (predicate != null) { + cq.where(predicate); + } + } - // -- Pagination -- - query.setFirstResult((int) pageable.getOffset()); - query.setMaxResults(pageable.getPageSize()); + // -- Sorting -- + List orders = toSortCriteriaBuilder(cb, injectRoot, pageable.getSort()); + cq.orderBy(orders); - // -- EXECUTION -- - List injects = execInject(query); + // Type Query + TypedQuery query = this.entityManager.createQuery(cq); - // -- Count Query -- - Long total = countQuery(cb, this.entityManager, Inject.class, specificationCount); + // -- Pagination -- + query.setFirstResult((int) pageable.getOffset()); + query.setMaxResults(pageable.getPageSize()); - return new PageImpl<>(injects, pageable, total); - } + // -- EXECUTION -- + List injects = execInject(query); - /** - * Create inject programmatically based on rawInject, rawInjectExpectation, rawAsset, rawAssetGroup, rawTeam - */ - public Map mapOfInjects(@NotNull final List injectIds) { - List listOfInjects = new ArrayList<>(); - - List listOfRawInjects = this.injectRepository.findRawByIds(injectIds); - // From the list of injects, we get all the inject expectationsIds that we then get - // and put into a map with the expections ids as key - Map mapOfInjectsExpectations = mapOfInjectsExpectations(listOfRawInjects); - - // We get the asset groups from the injects AND the injects expectations as those can also have asset groups - // We then make a map out of it for faster access - Map mapOfAssetGroups = mapOfAssetGroups(listOfRawInjects, mapOfInjectsExpectations.values()); - - // We get all the assets that are - // 1 - linked to an inject - // 2 - linked to an asset group linked to an inject - // 3 - linked to an inject expectation - // 4 - linked to an asset group linked to an inject expectations - // We then make a map out of it - Map mapOfAssets = mapOfAssets(listOfRawInjects, mapOfInjectsExpectations, mapOfAssetGroups); - - // We get all the teams that are linked to an inject or an asset group - // Then we make a map out of it for faster access - Map mapOfRawTeams = mapOfRawTeams(listOfRawInjects, mapOfInjectsExpectations); - - // Once we have all of this, we create an Inject for each InjectRaw that we have using all the Raw objects we got - // Then we make a map out of it for faster access - listOfRawInjects.stream().map((inject) -> Inject.fromRawInject(inject, mapOfRawTeams, mapOfInjectsExpectations, mapOfAssetGroups, mapOfAssets)).forEach(listOfInjects::add); - return listOfInjects.stream().collect(Collectors.toMap(Inject::getId, Function.identity())); - } + // -- Count Query -- + Long total = countQuery(cb, this.entityManager, Inject.class, specificationCount); - /** - * Store an xls file for ulterior import. The file will be deleted on exit. - * @param file - * @return - */ - public ImportPostSummary storeXlsFileForImport(MultipartFile file) { - ImportPostSummary result = new ImportPostSummary(); - result.setAvailableSheets(new ArrayList<>()); - // Generating an UUID for identifying the file - String fileID = UUID.randomUUID().toString(); - result.setImportId(fileID); - try { - // We're opening the file and listing the names of the sheets - Workbook workbook = WorkbookFactory.create(file.getInputStream()); - for (int i = 0; i < workbook.getNumberOfSheets(); i++) { - result.getAvailableSheets().add(workbook.getSheetName(i)); - } - // Writing the file in a temp dir - Path tempDir = Files.createDirectory(Path.of(System.getProperty("java.io.tmpdir"), fileID)); - Path tempFile = Files.createTempFile(tempDir, null, "." + FilenameUtils.getExtension(file.getOriginalFilename())); - Files.write(tempFile, file.getBytes()); + return new PageImpl<>(injects, pageable, total); + } - CompletableFuture.delayedExecutor(FILE_STORAGE_DURATION, TimeUnit.MINUTES).execute(() -> { + /** + * Create inject programmatically based on rawInject, rawInjectExpectation, rawAsset, + * rawAssetGroup, rawTeam + */ + public Map mapOfInjects(@NotNull final List injectIds) { + List listOfInjects = new ArrayList<>(); + + List listOfRawInjects = this.injectRepository.findRawByIds(injectIds); + // From the list of injects, we get all the inject expectationsIds that we then get + // and put into a map with the expections ids as key + Map mapOfInjectsExpectations = + mapOfInjectsExpectations(listOfRawInjects); + + // We get the asset groups from the injects AND the injects expectations as those can also have + // asset groups + // We then make a map out of it for faster access + Map mapOfAssetGroups = + mapOfAssetGroups(listOfRawInjects, mapOfInjectsExpectations.values()); + + // We get all the assets that are + // 1 - linked to an inject + // 2 - linked to an asset group linked to an inject + // 3 - linked to an inject expectation + // 4 - linked to an asset group linked to an inject expectations + // We then make a map out of it + Map mapOfAssets = + mapOfAssets(listOfRawInjects, mapOfInjectsExpectations, mapOfAssetGroups); + + // We get all the teams that are linked to an inject or an asset group + // Then we make a map out of it for faster access + Map mapOfRawTeams = mapOfRawTeams(listOfRawInjects, mapOfInjectsExpectations); + + // Once we have all of this, we create an Inject for each InjectRaw that we have using all the + // Raw objects we got + // Then we make a map out of it for faster access + listOfRawInjects.stream() + .map( + (inject) -> + Inject.fromRawInject( + inject, mapOfRawTeams, mapOfInjectsExpectations, mapOfAssetGroups, mapOfAssets)) + .forEach(listOfInjects::add); + return listOfInjects.stream().collect(Collectors.toMap(Inject::getId, Function.identity())); + } + + /** + * Store an xls file for ulterior import. The file will be deleted on exit. + * + * @param file + * @return + */ + public ImportPostSummary storeXlsFileForImport(MultipartFile file) { + ImportPostSummary result = new ImportPostSummary(); + result.setAvailableSheets(new ArrayList<>()); + // Generating an UUID for identifying the file + String fileID = UUID.randomUUID().toString(); + result.setImportId(fileID); + try { + // We're opening the file and listing the names of the sheets + Workbook workbook = WorkbookFactory.create(file.getInputStream()); + for (int i = 0; i < workbook.getNumberOfSheets(); i++) { + result.getAvailableSheets().add(workbook.getSheetName(i)); + } + // Writing the file in a temp dir + Path tempDir = Files.createDirectory(Path.of(System.getProperty("java.io.tmpdir"), fileID)); + Path tempFile = + Files.createTempFile( + tempDir, null, "." + FilenameUtils.getExtension(file.getOriginalFilename())); + Files.write(tempFile, file.getBytes()); + + CompletableFuture.delayedExecutor(FILE_STORAGE_DURATION, TimeUnit.MINUTES) + .execute( + () -> { tempFile.toFile().delete(); tempDir.toFile().delete(); - }); - - // We're making sure the files are deleted when the backend restart - tempDir.toFile().deleteOnExit(); - tempFile.toFile().deleteOnExit(); - } catch (Exception ex) { - log.severe("Error while importing an xls file"); - log.severe(Arrays.toString(ex.getStackTrace())); - throw new BadRequestException("File seems to be corrupt"); - } - - return result; + }); + + // We're making sure the files are deleted when the backend restart + tempDir.toFile().deleteOnExit(); + tempFile.toFile().deleteOnExit(); + } catch (Exception ex) { + log.severe("Error while importing an xls file"); + log.severe(Arrays.toString(ex.getStackTrace())); + throw new BadRequestException("File seems to be corrupt"); } - public ImportTestSummary importInjectIntoScenarioFromXLS(Scenario scenario, ImportMapper importMapper, String importId, String sheetName, int timezoneOffset, boolean saveAll) { - return importInjectIntoFromXLS(scenario, null, importMapper, importId, sheetName, timezoneOffset, saveAll); - } + return result; + } - public ImportTestSummary importInjectIntoExerciseFromXLS(Exercise exercise, ImportMapper importMapper, String importId, String sheetName, int timezoneOffset, boolean saveAll) { - return importInjectIntoFromXLS(null, exercise, importMapper, importId, sheetName, timezoneOffset, saveAll); - } + public ImportTestSummary importInjectIntoScenarioFromXLS( + Scenario scenario, + ImportMapper importMapper, + String importId, + String sheetName, + int timezoneOffset, + boolean saveAll) { + return importInjectIntoFromXLS( + scenario, null, importMapper, importId, sheetName, timezoneOffset, saveAll); + } - public ImportTestSummary importInjectIntoFromXLS(Scenario scenario, Exercise exercise, ImportMapper importMapper, String importId, String sheetName, int timezoneOffset, boolean saveAll) { - // We call the inject service to get the injects to create as well as messages on how things went - ImportTestSummary importTestSummary = importXls(importId, scenario, exercise, importMapper, sheetName, timezoneOffset); - Optional hasCritical = importTestSummary.getImportMessage().stream() - .filter(importMessage -> importMessage.getMessageLevel() == ImportMessage.MessageLevel.CRITICAL) - .findAny(); - importTestSummary.setTotalNumberOfInjects(importTestSummary.getInjects().size()); - if(hasCritical.isPresent()) { - // If there are critical errors, we do not save and we - // empty the list of injects, we just keep the messages - importTestSummary.setTotalNumberOfInjects(0); - importTestSummary.setInjects(new ArrayList<>()); - } else if(saveAll) { - importTestSummary.setInjects(importTestSummary.getInjects().stream().map(inject -> { - inject.setListened(false); - return inject; - }).toList()); - Iterable newInjects = injectRepository.saveAll(importTestSummary.getInjects()); - if (exercise != null) { - computeInjectInExercise(exercise, newInjects); - } else if (scenario != null) { - computeInjectInScenario(scenario, newInjects); - } else { - throw new IllegalArgumentException("At least one of exercise or scenario should be present"); - } - importTestSummary.setInjects(new ArrayList<>()); - } else { - importTestSummary.setInjects(importTestSummary.getInjects().stream().limit(5).toList()); - } + public ImportTestSummary importInjectIntoExerciseFromXLS( + Exercise exercise, + ImportMapper importMapper, + String importId, + String sheetName, + int timezoneOffset, + boolean saveAll) { + return importInjectIntoFromXLS( + null, exercise, importMapper, importId, sheetName, timezoneOffset, saveAll); + } - return importTestSummary; + public ImportTestSummary importInjectIntoFromXLS( + Scenario scenario, + Exercise exercise, + ImportMapper importMapper, + String importId, + String sheetName, + int timezoneOffset, + boolean saveAll) { + // We call the inject service to get the injects to create as well as messages on how things + // went + ImportTestSummary importTestSummary = + importXls(importId, scenario, exercise, importMapper, sheetName, timezoneOffset); + Optional hasCritical = + importTestSummary.getImportMessage().stream() + .filter( + importMessage -> + importMessage.getMessageLevel() == ImportMessage.MessageLevel.CRITICAL) + .findAny(); + importTestSummary.setTotalNumberOfInjects(importTestSummary.getInjects().size()); + if (hasCritical.isPresent()) { + // If there are critical errors, we do not save and we + // empty the list of injects, we just keep the messages + importTestSummary.setTotalNumberOfInjects(0); + importTestSummary.setInjects(new ArrayList<>()); + } else if (saveAll) { + importTestSummary.setInjects( + importTestSummary.getInjects().stream() + .map( + inject -> { + inject.setListened(false); + return inject; + }) + .toList()); + Iterable newInjects = injectRepository.saveAll(importTestSummary.getInjects()); + if (exercise != null) { + computeInjectInExercise(exercise, newInjects); + } else if (scenario != null) { + computeInjectInScenario(scenario, newInjects); + } else { + throw new IllegalArgumentException( + "At least one of exercise or scenario should be present"); + } + importTestSummary.setInjects(new ArrayList<>()); + } else { + importTestSummary.setInjects(importTestSummary.getInjects().stream().limit(5).toList()); } - private void computeInjectInExercise(@NotNull Exercise exercise, @NotNull Iterable newInjects) { - newInjects.forEach(inject -> { - exercise.getInjects().add(inject); - inject.getTeams().forEach(team -> { - if (!exercise.getTeams().contains(team)) { - exercise.getTeams().add(team); - } - }); - inject.getTeams().forEach(team -> team.getUsers().forEach(user -> { - if(!exercise.getTeamUsers().contains(user)) { - ExerciseTeamUserId compositeId = new ExerciseTeamUserId(); - compositeId.setExerciseId(exercise.getId()); - compositeId.setTeamId(team.getId()); - compositeId.setUserId(user.getId()); - boolean exists = exerciseTeamUserRepository.findById(compositeId).isPresent(); - - if(!exists) { - ExerciseTeamUser exerciseTeamUser = new ExerciseTeamUser(); - exerciseTeamUser.setExercise(exercise); - exerciseTeamUser.setTeam(team); - exerciseTeamUser.setUser(user); - exerciseTeamUserRepository.save(exerciseTeamUser); - exercise.getTeamUsers().add(exerciseTeamUser); + return importTestSummary; + } + + private void computeInjectInExercise( + @NotNull Exercise exercise, @NotNull Iterable newInjects) { + newInjects.forEach( + inject -> { + exercise.getInjects().add(inject); + inject + .getTeams() + .forEach( + team -> { + if (!exercise.getTeams().contains(team)) { + exercise.getTeams().add(team); } - } - })); + }); + inject + .getTeams() + .forEach( + team -> + team.getUsers() + .forEach( + user -> { + if (!exercise.getTeamUsers().contains(user)) { + ExerciseTeamUserId compositeId = new ExerciseTeamUserId(); + compositeId.setExerciseId(exercise.getId()); + compositeId.setTeamId(team.getId()); + compositeId.setUserId(user.getId()); + boolean exists = + exerciseTeamUserRepository.findById(compositeId).isPresent(); + + if (!exists) { + ExerciseTeamUser exerciseTeamUser = new ExerciseTeamUser(); + exerciseTeamUser.setExercise(exercise); + exerciseTeamUser.setTeam(team); + exerciseTeamUser.setUser(user); + exerciseTeamUserRepository.save(exerciseTeamUser); + exercise.getTeamUsers().add(exerciseTeamUser); + } + } + })); }); - } + } - private void computeInjectInScenario(@NotNull Scenario scenario, @NotNull Iterable newInjects) { - newInjects.forEach(inject -> { - scenario.getInjects().add(inject); - inject.getTeams().forEach(team -> { - if (!scenario.getTeams().contains(team)) { - scenario.getTeams().add(team); - } - }); - inject.getTeams().forEach(team -> team.getUsers().forEach(user -> { - if(!scenario.getTeamUsers().contains(user)) { - ScenarioTeamUserId compositeId = new ScenarioTeamUserId(); - compositeId.setScenarioId(scenario.getId()); - compositeId.setTeamId(team.getId()); - compositeId.setUserId(user.getId()); - boolean exists = scenarioTeamUserRepository.findById(compositeId).isPresent(); - - if(!exists) { - ScenarioTeamUser scenarioTeamUser = new ScenarioTeamUser(); - scenarioTeamUser.setScenario(scenario); - scenarioTeamUser.setTeam(team); - scenarioTeamUser.setUser(user); - scenarioTeamUserRepository.save(scenarioTeamUser); - scenario.getTeamUsers().add(scenarioTeamUser); + private void computeInjectInScenario( + @NotNull Scenario scenario, @NotNull Iterable newInjects) { + newInjects.forEach( + inject -> { + scenario.getInjects().add(inject); + inject + .getTeams() + .forEach( + team -> { + if (!scenario.getTeams().contains(team)) { + scenario.getTeams().add(team); } - } - })); + }); + inject + .getTeams() + .forEach( + team -> + team.getUsers() + .forEach( + user -> { + if (!scenario.getTeamUsers().contains(user)) { + ScenarioTeamUserId compositeId = new ScenarioTeamUserId(); + compositeId.setScenarioId(scenario.getId()); + compositeId.setTeamId(team.getId()); + compositeId.setUserId(user.getId()); + boolean exists = + scenarioTeamUserRepository.findById(compositeId).isPresent(); + + if (!exists) { + ScenarioTeamUser scenarioTeamUser = new ScenarioTeamUser(); + scenarioTeamUser.setScenario(scenario); + scenarioTeamUser.setTeam(team); + scenarioTeamUser.setUser(user); + scenarioTeamUserRepository.save(scenarioTeamUser); + scenario.getTeamUsers().add(scenarioTeamUser); + } + } + })); }); - } - - private ImportTestSummary importXls(String importId, Scenario scenario, Exercise exercise, ImportMapper importMapper, String sheetName, int timezoneOffset) { - ImportTestSummary importTestSummary = new ImportTestSummary(); + } - try { - // We open the previously saved file - String tmpdir = System.getProperty("java.io.tmpdir"); - Path file = Files.list(Path.of(tmpdir, pathSeparator, importId, pathSeparator)).findFirst().orElseThrow(); - - // We open the file and convert it to an apache POI object - InputStream xlsFile = Files.newInputStream(file); - Workbook workbook = WorkbookFactory.create(xlsFile); - Sheet selectedSheet = workbook.getSheet(sheetName); - - Map mapInstantByRowIndex = new HashMap<>(); - - // For performance reasons, we compile the pattern of the Inject Importers only once - Map mapPatternByInjectImport = importMapper - .getInjectImporters().stream().collect( - Collectors.toMap(InjectImporter::getId, - injectImporter -> Pattern.compile(injectImporter.getImportTypeValue()) - )); - - Map mapPatternByAllTeams = importMapper.getInjectImporters().stream() - .flatMap(injectImporter -> injectImporter.getRuleAttributes().stream()) - .filter(ruleAttribute -> Objects.equals(ruleAttribute.getName(), "teams")) - .filter(ruleAttribute -> ruleAttribute.getAdditionalConfig() != null && !Strings.isBlank(ruleAttribute.getAdditionalConfig().get("allTeamsValue"))) - .collect( - Collectors.toMap(ruleAttribute -> ruleAttribute.getAdditionalConfig().get("allTeamsValue"), - ruleAttribute -> Pattern.compile(ruleAttribute.getAdditionalConfig().get("allTeamsValue")), - (first, second) -> first - )); - - // We also get the list of teams into a map to be able to get them easily later on - // First, all the teams that are non-contextual - Map mapTeamByName = - StreamSupport.stream(teamRepository.findAll().spliterator(), false) - .filter(team -> !team.getContextual()) - .collect(Collectors.toMap(Team::getName, Function.identity(), (first, second) -> first)); - - // Then we add the contextual teams of the scenario - List teams; - if (exercise != null) { - teams = exercise.getTeams(); - } else if (scenario != null) { - teams = scenario.getTeams(); - } else { - throw new IllegalArgumentException("At least one of exercise or scenario should be present"); - } - mapTeamByName.putAll( - teams.stream() - .filter(Team::getContextual) - .collect(Collectors.toMap(Team::getName, Function.identity(), (first, second) -> first)) - ); - - ZoneOffset zoneOffset = ZoneOffset.ofTotalSeconds(timezoneOffset * 60); - - // For each rows of the selected sheet - selectedSheet.rowIterator().forEachRemaining(row -> { - Instant start; - if (scenario != null) { - start = scenario.getRecurrenceStart(); - } else if(exercise != null) { - start = exercise.getStart().orElse(null); - } else { - throw new IllegalArgumentException("At least one of exercise or scenario should be present"); - } - ImportRow rowSummary = importRow( - row, importMapper, start, mapPatternByInjectImport, mapTeamByName, mapPatternByAllTeams, zoneOffset - ); - // We set the exercise or scenario - Inject inject = rowSummary.getInject(); - if (scenario != null && inject != null) { - inject.setScenario(scenario); - } else if (exercise != null && inject != null) { - inject.setExercise(exercise); - } - rowSummary.setInject(inject); + private ImportTestSummary importXls( + String importId, + Scenario scenario, + Exercise exercise, + ImportMapper importMapper, + String sheetName, + int timezoneOffset) { + ImportTestSummary importTestSummary = new ImportTestSummary(); + + try { + // We open the previously saved file + String tmpdir = System.getProperty("java.io.tmpdir"); + Path file = + Files.list(Path.of(tmpdir, pathSeparator, importId, pathSeparator)) + .findFirst() + .orElseThrow(); + + // We open the file and convert it to an apache POI object + InputStream xlsFile = Files.newInputStream(file); + Workbook workbook = WorkbookFactory.create(xlsFile); + Sheet selectedSheet = workbook.getSheet(sheetName); + + Map mapInstantByRowIndex = new HashMap<>(); + + // For performance reasons, we compile the pattern of the Inject Importers only once + Map mapPatternByInjectImport = + importMapper.getInjectImporters().stream() + .collect( + Collectors.toMap( + InjectImporter::getId, + injectImporter -> Pattern.compile(injectImporter.getImportTypeValue()))); + + Map mapPatternByAllTeams = + importMapper.getInjectImporters().stream() + .flatMap(injectImporter -> injectImporter.getRuleAttributes().stream()) + .filter(ruleAttribute -> Objects.equals(ruleAttribute.getName(), "teams")) + .filter( + ruleAttribute -> + ruleAttribute.getAdditionalConfig() != null + && !Strings.isBlank( + ruleAttribute.getAdditionalConfig().get("allTeamsValue"))) + .collect( + Collectors.toMap( + ruleAttribute -> ruleAttribute.getAdditionalConfig().get("allTeamsValue"), + ruleAttribute -> + Pattern.compile(ruleAttribute.getAdditionalConfig().get("allTeamsValue")), + (first, second) -> first)); + + // We also get the list of teams into a map to be able to get them easily later on + // First, all the teams that are non-contextual + Map mapTeamByName = + StreamSupport.stream(teamRepository.findAll().spliterator(), false) + .filter(team -> !team.getContextual()) + .collect( + Collectors.toMap(Team::getName, Function.identity(), (first, second) -> first)); + + // Then we add the contextual teams of the scenario + List teams; + if (exercise != null) { + teams = exercise.getTeams(); + } else if (scenario != null) { + teams = scenario.getTeams(); + } else { + throw new IllegalArgumentException( + "At least one of exercise or scenario should be present"); + } + mapTeamByName.putAll( + teams.stream() + .filter(Team::getContextual) + .collect( + Collectors.toMap(Team::getName, Function.identity(), (first, second) -> first))); + + ZoneOffset zoneOffset = ZoneOffset.ofTotalSeconds(timezoneOffset * 60); + + // For each rows of the selected sheet + selectedSheet + .rowIterator() + .forEachRemaining( + row -> { + Instant start; + if (scenario != null) { + start = scenario.getRecurrenceStart(); + } else if (exercise != null) { + start = exercise.getStart().orElse(null); + } else { + throw new IllegalArgumentException( + "At least one of exercise or scenario should be present"); + } + ImportRow rowSummary = + importRow( + row, + importMapper, + start, + mapPatternByInjectImport, + mapTeamByName, + mapPatternByAllTeams, + zoneOffset); + // We set the exercise or scenario + Inject inject = rowSummary.getInject(); + if (scenario != null && inject != null) { + inject.setScenario(scenario); + } else if (exercise != null && inject != null) { + inject.setExercise(exercise); + } + rowSummary.setInject(inject); importTestSummary.getImportMessage().addAll(rowSummary.getImportMessages()); - if(rowSummary.getInject() != null) { - importTestSummary.getInjects().add(rowSummary.getInject()); + if (rowSummary.getInject() != null) { + importTestSummary.getInjects().add(rowSummary.getInject()); } - if(rowSummary.getInjectTime() != null) { - mapInstantByRowIndex.put(row.getRowNum(), rowSummary.getInjectTime()); + if (rowSummary.getInjectTime() != null) { + mapInstantByRowIndex.put(row.getRowNum(), rowSummary.getInjectTime()); } - }); + }); + + // Now that we did our first pass, we do another one real quick to find out + // the date relative to each others + importTestSummary.getImportMessage().addAll(updateInjectDates(mapInstantByRowIndex)); + + // We get the earliest date + Optional earliestDate = + mapInstantByRowIndex.values().stream() + .map(InjectTime::getDate) + .filter(Objects::nonNull) + .min(Comparator.naturalOrder()); + + // If there is one, we update the date + earliestDate.ifPresent( + date -> { + ZonedDateTime zonedDateTime = date.atZone(ZoneId.of("UTC")); + Instant dayOfStart = + ZonedDateTime.of( + zonedDateTime.getYear(), + zonedDateTime.getMonthValue(), + zonedDateTime.getDayOfMonth(), + 0, + 0, + 0, + 0, + ZoneId.of("UTC")) + .toInstant(); + if (scenario != null) { + scenario.setRecurrenceStart(dayOfStart); + scenario.setRecurrence( + "0 " + + zonedDateTime.getMinute() + + " " + + zonedDateTime.getHour() + + " * * *"); // Every day now + 1 hour + scenario.setRecurrenceEnd(dayOfStart.plus(1, ChronoUnit.DAYS)); + } else if (exercise != null) { + exercise.setStart(dayOfStart); + } else { + throw new IllegalArgumentException( + "At least one of exercise or scenario should be present"); + } + }); + } catch (IOException ex) { + log.severe("Error while importing an xls file"); + log.severe(Arrays.toString(ex.getStackTrace())); + throw new BadRequestException(); + } - // Now that we did our first pass, we do another one real quick to find out - // the date relative to each others - importTestSummary.getImportMessage().addAll(updateInjectDates(mapInstantByRowIndex)); - - // We get the earliest date - Optional earliestDate = mapInstantByRowIndex.values().stream() - .map(InjectTime::getDate) - .filter(Objects::nonNull) - .min(Comparator.naturalOrder()); - - // If there is one, we update the date - earliestDate.ifPresent(date -> { - ZonedDateTime zonedDateTime = date.atZone(ZoneId.of("UTC")); - Instant dayOfStart = ZonedDateTime.of( - zonedDateTime.getYear(), zonedDateTime.getMonthValue(), zonedDateTime.getDayOfMonth(), - 0, 0, 0, 0, ZoneId.of("UTC")).toInstant(); - if (scenario != null) { - scenario.setRecurrenceStart(dayOfStart); - scenario.setRecurrence("0 " + zonedDateTime.getMinute() + " " + zonedDateTime.getHour() + " * * *"); // Every day now + 1 hour - scenario.setRecurrenceEnd(dayOfStart.plus(1, ChronoUnit.DAYS)); - } else if(exercise != null) { - exercise.setStart(dayOfStart); - } else { - throw new IllegalArgumentException("At least one of exercise or scenario should be present"); - } - }); - } catch (IOException ex) { - log.severe("Error while importing an xls file"); - log.severe(Arrays.toString(ex.getStackTrace())); - throw new BadRequestException(); - } + // Sorting by the order of the enum declaration to have error messages first, then warn and then + // info + importTestSummary.getImportMessage().sort(Comparator.comparing(ImportMessage::getMessageLevel)); - // Sorting by the order of the enum declaration to have error messages first, then warn and then info - importTestSummary.getImportMessage().sort(Comparator.comparing(ImportMessage::getMessageLevel)); + return importTestSummary; + } - return importTestSummary; + private ImportRow importRow( + Row row, + ImportMapper importMapper, + Instant start, + Map mapPatternByInjectImport, + Map mapTeamByName, + Map mapPatternByAllTeams, + ZoneOffset timezoneOffset) { + ImportRow importTestSummary = new ImportRow(); + // The column that differenciate the importer is the same for all so we get it right now + int colTypeIdx = CellReference.convertColStringToIndex(importMapper.getInjectTypeColumn()); + if (colTypeIdx < 0) { + // If there are no values, we add an info message so they know there is a potential issue here + importTestSummary + .getImportMessages() + .add( + new ImportMessage( + ImportMessage.MessageLevel.INFO, + ImportMessage.ErrorCode.NO_POTENTIAL_MATCH_FOUND, + Map.of( + "column_type_num", + importMapper.getInjectTypeColumn(), + "row_num", + String.valueOf(row.getRowNum())))); + return importTestSummary; } - private ImportRow importRow( - Row row, ImportMapper importMapper, Instant start, - Map mapPatternByInjectImport, Map mapTeamByName, - Map mapPatternByAllTeams,ZoneOffset timezoneOffset) { - ImportRow importTestSummary = new ImportRow(); - // The column that differenciate the importer is the same for all so we get it right now - int colTypeIdx = CellReference.convertColStringToIndex(importMapper.getInjectTypeColumn()); - if (colTypeIdx < 0) { - // If there are no values, we add an info message so they know there is a potential issue here - importTestSummary.getImportMessages().add( - new ImportMessage(ImportMessage.MessageLevel.INFO, - ImportMessage.ErrorCode.NO_POTENTIAL_MATCH_FOUND, - Map.of("column_type_num", importMapper.getInjectTypeColumn(), - "row_num", String.valueOf(row.getRowNum())) - ) - ); - return importTestSummary; - } - - //If the row is completely empty, we ignore it altogether and do not send a warn message - if (InjectUtils.checkIfRowIsEmpty(row)) { - return importTestSummary; - } - // First of all, we get the value of the differentiation cell - Cell typeCell = row.getCell(colTypeIdx); - if (typeCell == null) { - // If there are no values, we add an info message so they know there is a potential issue here - importTestSummary.getImportMessages().add( - new ImportMessage(ImportMessage.MessageLevel.INFO, - ImportMessage.ErrorCode.NO_POTENTIAL_MATCH_FOUND, - Map.of("column_type_num", importMapper.getInjectTypeColumn(), - "row_num", String.valueOf(row.getRowNum())) - ) - ); - return importTestSummary; - } + // If the row is completely empty, we ignore it altogether and do not send a warn message + if (InjectUtils.checkIfRowIsEmpty(row)) { + return importTestSummary; + } + // First of all, we get the value of the differentiation cell + Cell typeCell = row.getCell(colTypeIdx); + if (typeCell == null) { + // If there are no values, we add an info message so they know there is a potential issue here + importTestSummary + .getImportMessages() + .add( + new ImportMessage( + ImportMessage.MessageLevel.INFO, + ImportMessage.ErrorCode.NO_POTENTIAL_MATCH_FOUND, + Map.of( + "column_type_num", + importMapper.getInjectTypeColumn(), + "row_num", + String.valueOf(row.getRowNum())))); + return importTestSummary; + } - // We find the matching importers on the inject - List matchingInjectImporters = importMapper.getInjectImporters().stream() - .filter(injectImporter -> { - Matcher matcher = mapPatternByInjectImport.get(injectImporter.getId()) - .matcher(getValueAsString(row, importMapper.getInjectTypeColumn())); - return matcher.find(); - }).toList(); - - // If there are no match, we add a message for the user and we go to the next row - if (matchingInjectImporters.isEmpty()) { - importTestSummary.getImportMessages().add( - new ImportMessage(ImportMessage.MessageLevel.INFO, - ImportMessage.ErrorCode.NO_POTENTIAL_MATCH_FOUND, - Map.of("column_type_num", importMapper.getInjectTypeColumn(), - "row_num", String.valueOf(row.getRowNum())) - ) - ); - return importTestSummary; - } + // We find the matching importers on the inject + List matchingInjectImporters = + importMapper.getInjectImporters().stream() + .filter( + injectImporter -> { + Matcher matcher = + mapPatternByInjectImport + .get(injectImporter.getId()) + .matcher(getValueAsString(row, importMapper.getInjectTypeColumn())); + return matcher.find(); + }) + .toList(); + + // If there are no match, we add a message for the user and we go to the next row + if (matchingInjectImporters.isEmpty()) { + importTestSummary + .getImportMessages() + .add( + new ImportMessage( + ImportMessage.MessageLevel.INFO, + ImportMessage.ErrorCode.NO_POTENTIAL_MATCH_FOUND, + Map.of( + "column_type_num", + importMapper.getInjectTypeColumn(), + "row_num", + String.valueOf(row.getRowNum())))); + return importTestSummary; + } - // If there are more than one match, we add a message for the user and use the first match - if (matchingInjectImporters.size() > 1) { - String listMatchers = matchingInjectImporters.stream().map(InjectImporter::getImportTypeValue).collect(Collectors.joining(", ")); - importTestSummary.getImportMessages().add( - new ImportMessage(ImportMessage.MessageLevel.WARN, - ImportMessage.ErrorCode.SEVERAL_MATCHES, - Map.of("column_type_num", importMapper.getInjectTypeColumn(), - "row_num", String.valueOf(row.getRowNum()), - "possible_matches", listMatchers) - ) - ); - return importTestSummary; - } + // If there are more than one match, we add a message for the user and use the first match + if (matchingInjectImporters.size() > 1) { + String listMatchers = + matchingInjectImporters.stream() + .map(InjectImporter::getImportTypeValue) + .collect(Collectors.joining(", ")); + importTestSummary + .getImportMessages() + .add( + new ImportMessage( + ImportMessage.MessageLevel.WARN, + ImportMessage.ErrorCode.SEVERAL_MATCHES, + Map.of( + "column_type_num", + importMapper.getInjectTypeColumn(), + "row_num", + String.valueOf(row.getRowNum()), + "possible_matches", + listMatchers))); + return importTestSummary; + } - InjectImporter matchingInjectImporter = matchingInjectImporters.get(0); - InjectorContract injectorContract = matchingInjectImporter.getInjectorContract(); + InjectImporter matchingInjectImporter = matchingInjectImporters.get(0); + InjectorContract injectorContract = matchingInjectImporter.getInjectorContract(); - // Creating the inject - Inject inject = new Inject(); - inject.setDependsDuration(0L); + // Creating the inject + Inject inject = new Inject(); + inject.setDependsDuration(0L); - // Adding the description - setAttributeValue(row, matchingInjectImporter, "description", inject::setDescription); + // Adding the description + setAttributeValue(row, matchingInjectImporter, "description", inject::setDescription); - // Adding the title - setAttributeValue(row, matchingInjectImporter, "title", inject::setTitle); + // Adding the title + setAttributeValue(row, matchingInjectImporter, "title", inject::setTitle); - // Adding the trigger time - RuleAttribute triggerTimeRuleAttribute = matchingInjectImporter.getRuleAttributes().stream() + // Adding the trigger time + RuleAttribute triggerTimeRuleAttribute = + matchingInjectImporter.getRuleAttributes().stream() .filter(ruleAttribute -> ruleAttribute.getName().equals("trigger_time")) - .findFirst().orElseGet(() -> { - RuleAttribute ruleAttributeDefault = new RuleAttribute(); - ruleAttributeDefault.setAdditionalConfig( - Map.of("timePattern", "") - ); - return ruleAttributeDefault; - }); - - String timePattern = triggerTimeRuleAttribute.getAdditionalConfig() - .get("timePattern"); - String dateAsString = Strings.EMPTY; - if(triggerTimeRuleAttribute.getColumns() != null) { - dateAsString = Arrays.stream(triggerTimeRuleAttribute.getColumns().split("\\+")) - .map(column -> getDateAsStringFromCell(row, column, timePattern)) - .collect(Collectors.joining()); - } - if (dateAsString.isBlank()) { - dateAsString = triggerTimeRuleAttribute.getDefaultValue(); - } + .findFirst() + .orElseGet( + () -> { + RuleAttribute ruleAttributeDefault = new RuleAttribute(); + ruleAttributeDefault.setAdditionalConfig(Map.of("timePattern", "")); + return ruleAttributeDefault; + }); - Matcher relativeDayMatcher = relativeDayPattern.matcher(dateAsString); - Matcher relativeHourMatcher = relativeHourPattern.matcher(dateAsString); - Matcher relativeMinuteMatcher = relativeMinutePattern.matcher(dateAsString); + String timePattern = triggerTimeRuleAttribute.getAdditionalConfig().get("timePattern"); + String dateAsString = Strings.EMPTY; + if (triggerTimeRuleAttribute.getColumns() != null) { + dateAsString = + Arrays.stream(triggerTimeRuleAttribute.getColumns().split("\\+")) + .map(column -> getDateAsStringFromCell(row, column, timePattern)) + .collect(Collectors.joining()); + } + if (dateAsString.isBlank()) { + dateAsString = triggerTimeRuleAttribute.getDefaultValue(); + } + Matcher relativeDayMatcher = relativeDayPattern.matcher(dateAsString); + Matcher relativeHourMatcher = relativeHourPattern.matcher(dateAsString); + Matcher relativeMinuteMatcher = relativeMinutePattern.matcher(dateAsString); - boolean relativeDays = relativeDayMatcher.matches(); - boolean relativeHour = relativeHourMatcher.matches(); - boolean relativeMinute = relativeMinuteMatcher.matches(); + boolean relativeDays = relativeDayMatcher.matches(); + boolean relativeHour = relativeHourMatcher.matches(); + boolean relativeMinute = relativeMinuteMatcher.matches(); - InjectTime injectTime = new InjectTime(); - injectTime.setUnformattedDate(dateAsString); - injectTime.setLinkedInject(inject); + InjectTime injectTime = new InjectTime(); + injectTime.setUnformattedDate(dateAsString); + injectTime.setLinkedInject(inject); - Temporal dateTime = getInjectDate(injectTime, timePattern); + Temporal dateTime = getInjectDate(injectTime, timePattern); - if (dateTime == null) { - injectTime.setRelativeDay(relativeDays); - if(relativeDays && relativeDayMatcher.groupCount() > 0 && !relativeDayMatcher.group(1).isBlank()) { - injectTime.setRelativeDayNumber(Integer.parseInt(relativeDayMatcher.group(1))); - } - injectTime.setRelativeHour(relativeHour); - if(relativeHour && relativeHourMatcher.groupCount() > 0 && !relativeHourMatcher.group(1).isBlank()) { - injectTime.setRelativeHourNumber(Integer.parseInt(relativeHourMatcher.group(1))); - } - injectTime.setRelativeMinute(relativeMinute); - if(relativeMinute && relativeMinuteMatcher.groupCount() > 0 && !relativeMinuteMatcher.group(1).isBlank()) { - injectTime.setRelativeMinuteNumber(Integer.parseInt(relativeMinuteMatcher.group(1))); - } + if (dateTime == null) { + injectTime.setRelativeDay(relativeDays); + if (relativeDays + && relativeDayMatcher.groupCount() > 0 + && !relativeDayMatcher.group(1).isBlank()) { + injectTime.setRelativeDayNumber(Integer.parseInt(relativeDayMatcher.group(1))); + } + injectTime.setRelativeHour(relativeHour); + if (relativeHour + && relativeHourMatcher.groupCount() > 0 + && !relativeHourMatcher.group(1).isBlank()) { + injectTime.setRelativeHourNumber(Integer.parseInt(relativeHourMatcher.group(1))); + } + injectTime.setRelativeMinute(relativeMinute); + if (relativeMinute + && relativeMinuteMatcher.groupCount() > 0 + && !relativeMinuteMatcher.group(1).isBlank()) { + injectTime.setRelativeMinuteNumber(Integer.parseInt(relativeMinuteMatcher.group(1))); + } - // Special case : a mix of relative day and absolute hour - if(relativeDays && relativeDayMatcher.groupCount() > 1 && !relativeDayMatcher.group(2).isBlank()) { - Temporal date = null; - try { - date = LocalTime.parse(relativeDayMatcher.group(2).trim(), injectTime.getFormatter()); - } catch (DateTimeParseException firstException) { - try { - date = LocalTime.parse(relativeDayMatcher.group(2).trim(), DateTimeFormatter.ISO_TIME); - } catch (DateTimeParseException exception) { - // This is a "probably" a relative date - } - } - if(date != null) { - if(start != null) { - injectTime.setDate( - start.atZone(timezoneOffset).toLocalDateTime() - .withHour(date.get(ChronoField.HOUR_OF_DAY)) - .withMinute(date.get(ChronoField.MINUTE_OF_HOUR)) - .toInstant(timezoneOffset) - ); - } else { - importTestSummary.getImportMessages().add( - new ImportMessage(ImportMessage.MessageLevel.CRITICAL, - ImportMessage.ErrorCode.ABSOLUTE_TIME_WITHOUT_START_DATE, - Map.of("column_type_num", importMapper.getInjectTypeColumn(), - "row_num", String.valueOf(row.getRowNum())) - ) - ); - } - } - } + // Special case : a mix of relative day and absolute hour + if (relativeDays + && relativeDayMatcher.groupCount() > 1 + && !relativeDayMatcher.group(2).isBlank()) { + Temporal date = null; + try { + date = LocalTime.parse(relativeDayMatcher.group(2).trim(), injectTime.getFormatter()); + } catch (DateTimeParseException firstException) { + try { + date = LocalTime.parse(relativeDayMatcher.group(2).trim(), DateTimeFormatter.ISO_TIME); + } catch (DateTimeParseException exception) { + // This is a "probably" a relative date + } } - injectTime.setSpecifyDays(relativeDays || injectTime.getFormatter().equals(DateTimeFormatter.ISO_DATE_TIME)); - - // We get the absolute dates available on our first pass - if(!injectTime.isRelativeDay() && !injectTime.isRelativeHour() && !injectTime.isRelativeMinute() && dateTime != null) { - if (dateTime instanceof LocalDateTime) { - Instant injectDate = Instant.ofEpochSecond( - ((LocalDateTime)dateTime).toEpochSecond(timezoneOffset)); - injectTime.setDate(injectDate); - } else if (dateTime instanceof LocalTime) { - if(start != null) { - injectTime.setDate(start - .atZone(timezoneOffset) - .withHour(((LocalTime) dateTime).getHour()) - .withMinute(((LocalTime) dateTime).getMinute()) - .toInstant()); - } else { - importTestSummary.getImportMessages().add( - new ImportMessage(ImportMessage.MessageLevel.CRITICAL, - ImportMessage.ErrorCode.ABSOLUTE_TIME_WITHOUT_START_DATE, - Map.of("column_type_num", importMapper.getInjectTypeColumn(), - "row_num", String.valueOf(row.getRowNum())) - ) - ); - return importTestSummary; - } - } + if (date != null) { + if (start != null) { + injectTime.setDate( + start + .atZone(timezoneOffset) + .toLocalDateTime() + .withHour(date.get(ChronoField.HOUR_OF_DAY)) + .withMinute(date.get(ChronoField.MINUTE_OF_HOUR)) + .toInstant(timezoneOffset)); + } else { + importTestSummary + .getImportMessages() + .add( + new ImportMessage( + ImportMessage.MessageLevel.CRITICAL, + ImportMessage.ErrorCode.ABSOLUTE_TIME_WITHOUT_START_DATE, + Map.of( + "column_type_num", + importMapper.getInjectTypeColumn(), + "row_num", + String.valueOf(row.getRowNum())))); + } } - - // Initializing the content with a root node - ObjectMapper mapper = new ObjectMapper(); - inject.setContent(mapper.createObjectNode()); - - // Once it's done, we set the injectorContract - inject.setInjectorContract(injectorContract); - - // So far, we only support one expectation - AtomicReference expectation = new AtomicReference<>(); - - // For each rule attributes of the importer - matchingInjectImporter.getRuleAttributes().forEach(ruleAttribute -> { - importTestSummary.getImportMessages().addAll( - addFields(inject, ruleAttribute, - row, mapTeamByName, expectation, importMapper, mapPatternByAllTeams)); - }); - // The user is the one doing the import - inject.setUser(userRepository.findById(currentUser().getId()).orElseThrow()); - // No exercise yet - inject.setExercise(null); - // No dependencies - inject.setDependsOn(null); - - if(expectation.get() != null) { - // We set the expectation - ArrayNode expectationsNode = mapper.createArrayNode(); - ObjectNode expectationNode = mapper.createObjectNode(); - expectationNode.put("expectation_description", expectation.get().getDescription()); - expectationNode.put("expectation_name", expectation.get().getName()); - expectationNode.put("expectation_score", expectation.get().getExpectedScore()); - expectationNode.put("expectation_type", expectation.get().getType().name()); - expectationNode.put("expectation_expectation_group", false); - expectationsNode.add(expectationNode); - inject.getContent().set("expectations", expectationsNode); + } + } + injectTime.setSpecifyDays( + relativeDays || injectTime.getFormatter().equals(DateTimeFormatter.ISO_DATE_TIME)); + + // We get the absolute dates available on our first pass + if (!injectTime.isRelativeDay() + && !injectTime.isRelativeHour() + && !injectTime.isRelativeMinute() + && dateTime != null) { + if (dateTime instanceof LocalDateTime) { + Instant injectDate = + Instant.ofEpochSecond(((LocalDateTime) dateTime).toEpochSecond(timezoneOffset)); + injectTime.setDate(injectDate); + } else if (dateTime instanceof LocalTime) { + if (start != null) { + injectTime.setDate( + start + .atZone(timezoneOffset) + .withHour(((LocalTime) dateTime).getHour()) + .withMinute(((LocalTime) dateTime).getMinute()) + .toInstant()); + } else { + importTestSummary + .getImportMessages() + .add( + new ImportMessage( + ImportMessage.MessageLevel.CRITICAL, + ImportMessage.ErrorCode.ABSOLUTE_TIME_WITHOUT_START_DATE, + Map.of( + "column_type_num", + importMapper.getInjectTypeColumn(), + "row_num", + String.valueOf(row.getRowNum())))); + return importTestSummary; } - - importTestSummary.setInject(inject); - importTestSummary.setInjectTime(injectTime); - return importTestSummary; + } } - private void setAttributeValue(Row row, InjectImporter matchingInjectImporter, String attributeName, Consumer setter) { - RuleAttribute ruleAttribute = matchingInjectImporter.getRuleAttributes().stream() - .filter(attr -> attr.getName().equals(attributeName)) - .findFirst() - .orElseThrow(ElementNotFoundException::new); + // Initializing the content with a root node + ObjectMapper mapper = new ObjectMapper(); + inject.setContent(mapper.createObjectNode()); + + // Once it's done, we set the injectorContract + inject.setInjectorContract(injectorContract); + + // So far, we only support one expectation + AtomicReference expectation = new AtomicReference<>(); + + // For each rule attributes of the importer + matchingInjectImporter + .getRuleAttributes() + .forEach( + ruleAttribute -> { + importTestSummary + .getImportMessages() + .addAll( + addFields( + inject, + ruleAttribute, + row, + mapTeamByName, + expectation, + importMapper, + mapPatternByAllTeams)); + }); + // The user is the one doing the import + inject.setUser(userRepository.findById(currentUser().getId()).orElseThrow()); + // No exercise yet + inject.setExercise(null); + // No dependencies + inject.setDependsOn(null); + + if (expectation.get() != null) { + // We set the expectation + ArrayNode expectationsNode = mapper.createArrayNode(); + ObjectNode expectationNode = mapper.createObjectNode(); + expectationNode.put("expectation_description", expectation.get().getDescription()); + expectationNode.put("expectation_name", expectation.get().getName()); + expectationNode.put("expectation_score", expectation.get().getExpectedScore()); + expectationNode.put("expectation_type", expectation.get().getType().name()); + expectationNode.put("expectation_expectation_group", false); + expectationsNode.add(expectationNode); + inject.getContent().set("expectations", expectationsNode); + } - if(ruleAttribute.getColumns() != null) { - int colIndex = CellReference.convertColStringToIndex(ruleAttribute.getColumns()); - if(colIndex == -1) return; - Cell valueCell = row.getCell(colIndex); + importTestSummary.setInject(inject); + importTestSummary.setInjectTime(injectTime); + return importTestSummary; + } - if (valueCell == null) { - setter.accept(ruleAttribute.getDefaultValue()); - } else { - String cellValue = getValueAsString(row, ruleAttribute.getColumns()); - setter.accept(cellValue.isBlank() ? ruleAttribute.getDefaultValue() : cellValue); - } - } + private void setAttributeValue( + Row row, + InjectImporter matchingInjectImporter, + String attributeName, + Consumer setter) { + RuleAttribute ruleAttribute = + matchingInjectImporter.getRuleAttributes().stream() + .filter(attr -> attr.getName().equals(attributeName)) + .findFirst() + .orElseThrow(ElementNotFoundException::new); + + if (ruleAttribute.getColumns() != null) { + int colIndex = CellReference.convertColStringToIndex(ruleAttribute.getColumns()); + if (colIndex == -1) return; + Cell valueCell = row.getCell(colIndex); + + if (valueCell == null) { + setter.accept(ruleAttribute.getDefaultValue()); + } else { + String cellValue = getValueAsString(row, ruleAttribute.getColumns()); + setter.accept(cellValue.isBlank() ? ruleAttribute.getDefaultValue() : cellValue); + } + } + } + private List addFields( + Inject inject, + RuleAttribute ruleAttribute, + Row row, + Map mapTeamByName, + AtomicReference expectation, + ImportMapper importMapper, + Map mapPatternByAllTeams) { + // If it's a reserved field, it's already taken care of + if (importReservedField.contains(ruleAttribute.getName())) { + return Collections.emptyList(); } - private List addFields(Inject inject, RuleAttribute ruleAttribute, - Row row, Map mapTeamByName, - AtomicReference expectation, - ImportMapper importMapper, - Map mapPatternByAllTeams) { - // If it's a reserved field, it's already taken care of - if(importReservedField.contains(ruleAttribute.getName())) { - return Collections.emptyList(); + // For ease of use, we create a map of the available keys for the injector + Map mapFieldByKey = + StreamSupport.stream( + (Objects.requireNonNull( + inject + .getInjectorContract() + .map( + injectorContract -> + injectorContract.getConvertedContent().get("fields").spliterator()) + .orElse(null))), + false) + .collect( + Collectors.toMap(jsonNode -> jsonNode.get("key").asText(), Function.identity())); + + // Otherwise, the default type is text, but it can be overriden + String type = "text"; + if (mapFieldByKey.get(ruleAttribute.getName()) != null) { + type = mapFieldByKey.get(ruleAttribute.getName()).get("type").asText(); + } else if (ruleAttribute.getName().startsWith("expectation")) { + type = "expectation"; + } + switch (type) { + case "text": + case "textarea": + // If text, we get the columns, split by "+" if there is a concatenation of columns + // and then joins the result of the cells + String columnValue = Strings.EMPTY; + if (ruleAttribute.getColumns() != null) { + columnValue = + Arrays.stream(ruleAttribute.getColumns().split("\\+")) + .map(column -> getValueAsString(row, column)) + .collect(Collectors.joining()); } - - // For ease of use, we create a map of the available keys for the injector - Map mapFieldByKey = - StreamSupport.stream((Objects.requireNonNull(inject.getInjectorContract().map(injectorContract -> injectorContract.getConvertedContent().get("fields").spliterator()).orElse(null))), false) - .collect(Collectors.toMap(jsonNode -> jsonNode.get("key").asText(), Function.identity())); - - // Otherwise, the default type is text, but it can be overriden - String type = "text"; - if (mapFieldByKey.get(ruleAttribute.getName()) != null) { - type = mapFieldByKey.get(ruleAttribute.getName()).get("type").asText(); - } else if(ruleAttribute.getName().startsWith("expectation")) { - type = "expectation"; + if (columnValue.isBlank()) { + inject.getContent().put(ruleAttribute.getDefaultValue(), columnValue); + } else { + inject.getContent().put(ruleAttribute.getName(), columnValue); } - switch (type) { - case "text": - case "textarea": - // If text, we get the columns, split by "+" if there is a concatenation of columns - // and then joins the result of the cells - String columnValue = Strings.EMPTY; - if(ruleAttribute.getColumns() != null) { - columnValue = Arrays.stream(ruleAttribute.getColumns().split("\\+")) - .map(column -> getValueAsString(row, column)) - .collect(Collectors.joining()); - } - if (columnValue.isBlank()) { - inject.getContent().put(ruleAttribute.getDefaultValue(), columnValue); - } else { - inject.getContent().put(ruleAttribute.getName(), columnValue); - } - break; - case "team": - // If the rule type is on a team field, we split by "+" if there is a concatenation of columns - // and then joins the result, split again by "," and use the list of results to get the teams by their name - List columnValues = new ArrayList<>(); - String allTeamsValue = ruleAttribute.getAdditionalConfig() != null ? ruleAttribute.getAdditionalConfig().get("allTeamsValue") : null; - if(ruleAttribute.getColumns() != null) { - columnValues = Arrays.stream(Arrays.stream(ruleAttribute.getColumns().split("\\+")) - .map(column -> getValueAsString(row, column)) - .collect(Collectors.joining(",")) - .split(",")) - .toList(); + break; + case "team": + // If the rule type is on a team field, we split by "+" if there is a concatenation of + // columns + // and then joins the result, split again by "," and use the list of results to get the + // teams by their name + List columnValues = new ArrayList<>(); + String allTeamsValue = + ruleAttribute.getAdditionalConfig() != null + ? ruleAttribute.getAdditionalConfig().get("allTeamsValue") + : null; + if (ruleAttribute.getColumns() != null) { + columnValues = + Arrays.stream( + Arrays.stream(ruleAttribute.getColumns().split("\\+")) + .map(column -> getValueAsString(row, column)) + .collect(Collectors.joining(",")) + .split(",")) + .toList(); + } + if (columnValues.isEmpty() || columnValues.stream().allMatch(String::isEmpty)) { + List defaultValues = + Arrays.stream(ruleAttribute.getDefaultValue().split(",")).toList(); + inject + .getTeams() + .addAll( + mapTeamByName.entrySet().stream() + .filter(nameTeamEntry -> defaultValues.contains(nameTeamEntry.getKey())) + .map(Map.Entry::getValue) + .toList()); + } else { + List importMessages = new ArrayList<>(); + columnValues.forEach( + teamName -> { + inject.setAllTeams(false); + Matcher allTeamsMatcher = null; + if (mapPatternByAllTeams.get(allTeamsValue) != null) { + allTeamsMatcher = mapPatternByAllTeams.get(allTeamsValue).matcher(teamName); } - if (columnValues.isEmpty() || columnValues.stream().allMatch(String::isEmpty)) { - List defaultValues = Arrays.stream(ruleAttribute.getDefaultValue().split(",")).toList(); - inject.getTeams().addAll(mapTeamByName.entrySet().stream() - .filter(nameTeamEntry -> defaultValues.contains(nameTeamEntry.getKey())) - .map(Map.Entry::getValue) - .toList() - ); + if (allTeamsValue != null && allTeamsMatcher != null && allTeamsMatcher.find()) { + inject.setAllTeams(true); + } else if (mapTeamByName.containsKey(teamName)) { + inject.getTeams().add(mapTeamByName.get(teamName)); } else { - List importMessages = new ArrayList<>(); - columnValues.forEach(teamName -> { - inject.setAllTeams(false); - Matcher allTeamsMatcher = null; - if(mapPatternByAllTeams.get(allTeamsValue) != null) { - allTeamsMatcher = mapPatternByAllTeams.get(allTeamsValue).matcher(teamName); - } - if (allTeamsValue != null && allTeamsMatcher != null && allTeamsMatcher.find()) { - inject.setAllTeams(true); - } else if(mapTeamByName.containsKey(teamName)) { - inject.getTeams().add(mapTeamByName.get(teamName)); - } else { - // The team does not exist, we create a new one - Team team = new Team(); - team.setName(teamName); - team.setContextual(true); - teamRepository.save(team); - mapTeamByName.put(team.getName(), team); - inject.getTeams().add(team); - - // We aldo add a message so the user knows there was a new team created - importMessages.add(new ImportMessage(ImportMessage.MessageLevel.WARN, - ImportMessage.ErrorCode.NO_TEAM_FOUND, - Map.of("column_type_num", importMapper.getInjectTypeColumn(), - "row_num", String.valueOf(row.getRowNum()), - "team_name", teamName) - )); - } - }); - if(!importMessages.isEmpty()) { - return importMessages; - } - } - break; - case "expectation": - // If the rule type is of an expectation, - if (expectation.get() == null) { - expectation.set(new InjectExpectation()); - expectation.get().setType(InjectExpectation.EXPECTATION_TYPE.MANUAL); - } - if (ruleAttribute.getName().contains("_")) { - if("score".equals(ruleAttribute.getName().split("_")[1])) { - if(ruleAttribute.getColumns() != null) { - List columns = Arrays.stream(ruleAttribute.getColumns().split("\\+")) - .filter(column -> column != null && !column.isBlank()).toList(); - if(!columns.isEmpty() && columns.stream().allMatch(column -> - row.getCell(CellReference.convertColStringToIndex(column)).getCellType()== CellType.NUMERIC)) { - Double columnValueExpectation = columns.stream() - .map(column -> getValueAsDouble(row, column)) - .reduce(0.0, Double::sum); - expectation.get().setExpectedScore(columnValueExpectation.doubleValue()); - } else { - try { - expectation.get().setExpectedScore(Double.parseDouble(ruleAttribute.getDefaultValue())); - } catch (NumberFormatException exception) { - List importMessages = new ArrayList<>(); - importMessages.add(new ImportMessage(ImportMessage.MessageLevel.WARN, - ImportMessage.ErrorCode.EXPECTATION_SCORE_UNDEFINED, - Map.of("column_type_num", String.join(", ", columns), - "row_num", String.valueOf(row.getRowNum())) - )); - return importMessages; - } - } - } else { - expectation.get().setExpectedScore(Double.parseDouble(ruleAttribute.getDefaultValue())); - } - } else if ("name".equals(ruleAttribute.getName().split("_")[1])) { - if(ruleAttribute.getColumns() != null) { - String columnValueExpectation = Arrays.stream(ruleAttribute.getColumns().split("\\+")) - .map(column -> getValueAsString(row, column)) - .collect(Collectors.joining()); - expectation.get().setName(columnValueExpectation.isBlank() ? ruleAttribute.getDefaultValue() : columnValueExpectation); - } else { - expectation.get().setName(ruleAttribute.getDefaultValue()); - } - } else if ("description".equals(ruleAttribute.getName().split("_")[1])) { - if(ruleAttribute.getColumns() != null) { - String columnValueExpectation = Arrays.stream(ruleAttribute.getColumns().split("\\+")) - .map(column -> getValueAsString(row, column)) - .collect(Collectors.joining()); - expectation.get().setDescription(columnValueExpectation.isBlank() ? ruleAttribute.getDefaultValue() : columnValueExpectation); - } else { - expectation.get().setDescription(ruleAttribute.getDefaultValue()); - } - } + // The team does not exist, we create a new one + Team team = new Team(); + team.setName(teamName); + team.setContextual(true); + teamRepository.save(team); + mapTeamByName.put(team.getName(), team); + inject.getTeams().add(team); + + // We aldo add a message so the user knows there was a new team created + importMessages.add( + new ImportMessage( + ImportMessage.MessageLevel.WARN, + ImportMessage.ErrorCode.NO_TEAM_FOUND, + Map.of( + "column_type_num", + importMapper.getInjectTypeColumn(), + "row_num", + String.valueOf(row.getRowNum()), + "team_name", + teamName))); } - - break; - default: - throw new UnsupportedOperationException(); + }); + if (!importMessages.isEmpty()) { + return importMessages; + } } - return Collections.emptyList(); - } - - private Temporal getInjectDate(InjectTime injectTime, String timePattern) { - DateTimeFormatter dateTimeFormatter = DateTimeFormatter.ISO_DATE_TIME; - if(timePattern != null && !timePattern.isEmpty()) { - dateTimeFormatter = DateTimeFormatter.ofPattern(timePattern); - try { - return LocalDateTime.parse(injectTime.getUnformattedDate(), dateTimeFormatter); - } catch (DateTimeParseException firstException) { + break; + case "expectation": + // If the rule type is of an expectation, + if (expectation.get() == null) { + expectation.set(new InjectExpectation()); + expectation.get().setType(InjectExpectation.EXPECTATION_TYPE.MANUAL); + } + if (ruleAttribute.getName().contains("_")) { + if ("score".equals(ruleAttribute.getName().split("_")[1])) { + if (ruleAttribute.getColumns() != null) { + List columns = + Arrays.stream(ruleAttribute.getColumns().split("\\+")) + .filter(column -> column != null && !column.isBlank()) + .toList(); + if (!columns.isEmpty() + && columns.stream() + .allMatch( + column -> + row.getCell(CellReference.convertColStringToIndex(column)) + .getCellType() + == CellType.NUMERIC)) { + Double columnValueExpectation = + columns.stream() + .map(column -> getValueAsDouble(row, column)) + .reduce(0.0, Double::sum); + expectation.get().setExpectedScore(columnValueExpectation.doubleValue()); + } else { try { - return LocalTime.parse(injectTime.getUnformattedDate(), dateTimeFormatter); - } catch (DateTimeParseException exception) { - // This is a "probably" a relative date + expectation + .get() + .setExpectedScore(Double.parseDouble(ruleAttribute.getDefaultValue())); + } catch (NumberFormatException exception) { + List importMessages = new ArrayList<>(); + importMessages.add( + new ImportMessage( + ImportMessage.MessageLevel.WARN, + ImportMessage.ErrorCode.EXPECTATION_SCORE_UNDEFINED, + Map.of( + "column_type_num", + String.join(", ", columns), + "row_num", + String.valueOf(row.getRowNum())))); + return importMessages; } + } + } else { + expectation + .get() + .setExpectedScore(Double.parseDouble(ruleAttribute.getDefaultValue())); } - } else { - try { - return LocalDateTime.parse(injectTime.getUnformattedDate(), dateTimeFormatter); - } catch (DateTimeParseException firstException) { - // The date is not in ISO_DATE_TIME. Trying just the ISO_TIME - dateTimeFormatter = DateTimeFormatter.ISO_TIME; - try { - return LocalDateTime.parse(injectTime.getUnformattedDate(), dateTimeFormatter); - } catch (DateTimeParseException secondException) { - // Neither ISO_DATE_TIME nor ISO_TIME - } + } else if ("name".equals(ruleAttribute.getName().split("_")[1])) { + if (ruleAttribute.getColumns() != null) { + String columnValueExpectation = + Arrays.stream(ruleAttribute.getColumns().split("\\+")) + .map(column -> getValueAsString(row, column)) + .collect(Collectors.joining()); + expectation + .get() + .setName( + columnValueExpectation.isBlank() + ? ruleAttribute.getDefaultValue() + : columnValueExpectation); + } else { + expectation.get().setName(ruleAttribute.getDefaultValue()); } - } - injectTime.setFormatter(dateTimeFormatter); - return null; - } - - private List updateInjectDates(Map mapInstantByRowIndex) { - List importMessages = new ArrayList<>(); - // First of all, are there any absolute date - boolean allDatesAreAbsolute = mapInstantByRowIndex.values().stream().noneMatch( - injectTime -> injectTime.getDate() == null || injectTime.isRelativeDay() || injectTime.isRelativeHour() || injectTime.isRelativeMinute() - ); - boolean allDatesAreRelative = mapInstantByRowIndex.values().stream().allMatch( - injectTime -> injectTime.getDate() == null && (injectTime.isRelativeDay() || injectTime.isRelativeHour() || injectTime.isRelativeMinute()) - ); - - if(allDatesAreAbsolute) { - processDateToAbsolute(mapInstantByRowIndex); - } else if (allDatesAreRelative) { - // All is relative and we just need to set depends relative to each others - // First of all, we find the minimal relative number of days and hour - int earliestDay = mapInstantByRowIndex.values().stream() - .min(Comparator.comparing(InjectTime::getRelativeDayNumber)) - .map(InjectTime::getRelativeDayNumber).orElse(0); - int earliestHourOfThatDay = mapInstantByRowIndex.values().stream() - .filter(injectTime -> injectTime.getRelativeDayNumber() == earliestDay) - .min(Comparator.comparing(InjectTime::getRelativeHourNumber)) - .map(InjectTime::getRelativeHourNumber).orElse(0); - int earliestMinuteOfThatHour = mapInstantByRowIndex.values().stream() - .filter(injectTime -> injectTime.getRelativeDayNumber() == earliestDay - && injectTime.getRelativeHourNumber() == earliestHourOfThatDay) - .min(Comparator.comparing(InjectTime::getRelativeMinuteNumber)) - .map(InjectTime::getRelativeMinuteNumber).orElse(0); - long offsetAsMinutes = (((earliestDay * 24L) + earliestHourOfThatDay) * 60 + earliestMinuteOfThatHour) * -1; - mapInstantByRowIndex.values().stream() - .filter(injectTime -> injectTime.getDate() == null && (injectTime.isRelativeDay() || injectTime.isRelativeHour() || injectTime.isRelativeMinute())) - .forEach(injectTime -> { - long injectTimeAsMinutes = - (((injectTime.getRelativeDayNumber() * 24L) + injectTime.getRelativeHourNumber()) * 60) - + injectTime.getRelativeMinuteNumber() + offsetAsMinutes; - injectTime.getLinkedInject().setDependsDuration(injectTimeAsMinutes * 60); - }); - } else { - // Worst case scenario : there is a mix of relative and absolute dates - // We will need to resolve this row by row in the order they are in the import file - Optional> sortedInstantMap = - mapInstantByRowIndex.entrySet().stream().min(Map.Entry.comparingByKey()); - int firstRow; - if(sortedInstantMap.isPresent()) { - firstRow = sortedInstantMap.get().getKey(); + } else if ("description".equals(ruleAttribute.getName().split("_")[1])) { + if (ruleAttribute.getColumns() != null) { + String columnValueExpectation = + Arrays.stream(ruleAttribute.getColumns().split("\\+")) + .map(column -> getValueAsString(row, column)) + .collect(Collectors.joining()); + expectation + .get() + .setDescription( + columnValueExpectation.isBlank() + ? ruleAttribute.getDefaultValue() + : columnValueExpectation); } else { - firstRow = 0; + expectation.get().setDescription(ruleAttribute.getDefaultValue()); } - mapInstantByRowIndex.entrySet().stream().sorted(Map.Entry.comparingByKey()).forEachOrdered( - integerInjectTimeEntry -> { - InjectTime injectTime = integerInjectTimeEntry.getValue(); - - if(injectTime.getDate() != null) { - // Special case : we have an absolute time but a relative day - if(injectTime.isRelativeDay()) { - injectTime.setDate(injectTime.getDate().plus(injectTime.getRelativeDayNumber(), ChronoUnit.DAYS)); - } - // Great, we already have an absolute date for this one - // If we are the first, good, nothing more to do - // Otherwise, we need to get the date of the first row to set the depends on - if(integerInjectTimeEntry.getKey() != firstRow) { - Instant firstDate = mapInstantByRowIndex.get(firstRow).getDate(); - injectTime.getLinkedInject().setDependsDuration(injectTime.getDate().getEpochSecond() - firstDate.getEpochSecond()); - } - } else { - // We don't have an absolute date so we need to deduce it from another row - if(injectTime.getRelativeDayNumber() < 0 - || (injectTime.getRelativeDayNumber() == 0 && injectTime.getRelativeHourNumber() < 0) - || (injectTime.getRelativeDayNumber() == 0 && injectTime.getRelativeHourNumber() == 0 && injectTime.getRelativeMinuteNumber() < 0)) { - // We are in the past, so we need to explore the future to find the next absolute date - Optional> firstFutureWithAbsolute = - mapInstantByRowIndex.entrySet().stream() - .sorted(Map.Entry.comparingByKey()) - .filter(entry -> entry.getKey() > integerInjectTimeEntry.getKey() - && entry.getValue().getDate() != null) - .findFirst(); - if(firstFutureWithAbsolute.isPresent()) { - injectTime.setDate(firstFutureWithAbsolute.get().getValue() - .getDate() - .plus(injectTime.getRelativeDayNumber(), ChronoUnit.DAYS) - .plus(injectTime.getRelativeHourNumber(), ChronoUnit.HOURS) - .plus(injectTime.getRelativeMinuteNumber(), ChronoUnit.MINUTES) - ); - } else { - importMessages.add(new ImportMessage(ImportMessage.MessageLevel.ERROR, - ImportMessage.ErrorCode.DATE_SET_IN_PAST, - Map.of("row_num", String.valueOf(integerInjectTimeEntry.getKey())))); - } - } else { - // We are in the future, so we need to explore the past to find an absolute date - Optional> firstPastWithAbsolute = - mapInstantByRowIndex.entrySet().stream() - .sorted(Map.Entry.comparingByKey()) - .filter(entry -> entry.getKey() < integerInjectTimeEntry.getKey() - && entry.getValue().getDate() != null) - .min(Map.Entry.comparingByKey(Comparator.reverseOrder())); - if(firstPastWithAbsolute.isPresent()) { - injectTime.setDate(firstPastWithAbsolute.get().getValue() - .getDate() - .plus(injectTime.getRelativeDayNumber(), ChronoUnit.DAYS) - .plus(injectTime.getRelativeHourNumber(), ChronoUnit.HOURS) - .plus(injectTime.getRelativeMinuteNumber(), ChronoUnit.MINUTES) - ); - } else { - importMessages.add(new ImportMessage(ImportMessage.MessageLevel.ERROR, - ImportMessage.ErrorCode.DATE_SET_IN_FUTURE, - Map.of("row_num", String.valueOf(integerInjectTimeEntry.getKey())))); - } - } - } - } - ); - - processDateToAbsolute(mapInstantByRowIndex); + } } - return importMessages; + break; + default: + throw new UnsupportedOperationException(); } + return Collections.emptyList(); + } - private void processDateToAbsolute(Map mapInstantByRowIndex) { - Optional earliestAbsoluteDate = mapInstantByRowIndex.values().stream() - .map(InjectTime::getDate) - .filter(Objects::nonNull) - .min(Comparator.naturalOrder()); - - // If we have an earliest date, we calculate the dates depending on the earliest one - earliestAbsoluteDate.ifPresent( - earliestInstant -> mapInstantByRowIndex.values().stream().filter(injectTime -> injectTime.getDate() != null) - .forEach(injectTime -> { - injectTime.getLinkedInject().setDependsDuration(injectTime.getDate().getEpochSecond() - earliestInstant.getEpochSecond()); - }) - ); + private Temporal getInjectDate(InjectTime injectTime, String timePattern) { + DateTimeFormatter dateTimeFormatter = DateTimeFormatter.ISO_DATE_TIME; + if (timePattern != null && !timePattern.isEmpty()) { + dateTimeFormatter = DateTimeFormatter.ofPattern(timePattern); + try { + return LocalDateTime.parse(injectTime.getUnformattedDate(), dateTimeFormatter); + } catch (DateTimeParseException firstException) { + try { + return LocalTime.parse(injectTime.getUnformattedDate(), dateTimeFormatter); + } catch (DateTimeParseException exception) { + // This is a "probably" a relative date + } + } + } else { + try { + return LocalDateTime.parse(injectTime.getUnformattedDate(), dateTimeFormatter); + } catch (DateTimeParseException firstException) { + // The date is not in ISO_DATE_TIME. Trying just the ISO_TIME + dateTimeFormatter = DateTimeFormatter.ISO_TIME; + try { + return LocalDateTime.parse(injectTime.getUnformattedDate(), dateTimeFormatter); + } catch (DateTimeParseException secondException) { + // Neither ISO_DATE_TIME nor ISO_TIME + } + } } + injectTime.setFormatter(dateTimeFormatter); + return null; + } - private String getDateAsStringFromCell(Row row, String cellColumn, String timePattern) { - if(cellColumn != null && !cellColumn.isBlank() - && row.getCell(CellReference.convertColStringToIndex(cellColumn)) != null) { - Cell cell = row.getCell(CellReference.convertColStringToIndex(cellColumn)); - if(cell.getCellType() == CellType.STRING) { - return cell.getStringCellValue(); - } else if(cell.getCellType() == CellType.NUMERIC) { - if(timePattern == null || timePattern.isEmpty()) { - return cell.getDateCellValue().toString(); + private List updateInjectDates(Map mapInstantByRowIndex) { + List importMessages = new ArrayList<>(); + // First of all, are there any absolute date + boolean allDatesAreAbsolute = + mapInstantByRowIndex.values().stream() + .noneMatch( + injectTime -> + injectTime.getDate() == null + || injectTime.isRelativeDay() + || injectTime.isRelativeHour() + || injectTime.isRelativeMinute()); + boolean allDatesAreRelative = + mapInstantByRowIndex.values().stream() + .allMatch( + injectTime -> + injectTime.getDate() == null + && (injectTime.isRelativeDay() + || injectTime.isRelativeHour() + || injectTime.isRelativeMinute())); + + if (allDatesAreAbsolute) { + processDateToAbsolute(mapInstantByRowIndex); + } else if (allDatesAreRelative) { + // All is relative and we just need to set depends relative to each others + // First of all, we find the minimal relative number of days and hour + int earliestDay = + mapInstantByRowIndex.values().stream() + .min(Comparator.comparing(InjectTime::getRelativeDayNumber)) + .map(InjectTime::getRelativeDayNumber) + .orElse(0); + int earliestHourOfThatDay = + mapInstantByRowIndex.values().stream() + .filter(injectTime -> injectTime.getRelativeDayNumber() == earliestDay) + .min(Comparator.comparing(InjectTime::getRelativeHourNumber)) + .map(InjectTime::getRelativeHourNumber) + .orElse(0); + int earliestMinuteOfThatHour = + mapInstantByRowIndex.values().stream() + .filter( + injectTime -> + injectTime.getRelativeDayNumber() == earliestDay + && injectTime.getRelativeHourNumber() == earliestHourOfThatDay) + .min(Comparator.comparing(InjectTime::getRelativeMinuteNumber)) + .map(InjectTime::getRelativeMinuteNumber) + .orElse(0); + long offsetAsMinutes = + (((earliestDay * 24L) + earliestHourOfThatDay) * 60 + earliestMinuteOfThatHour) * -1; + mapInstantByRowIndex.values().stream() + .filter( + injectTime -> + injectTime.getDate() == null + && (injectTime.isRelativeDay() + || injectTime.isRelativeHour() + || injectTime.isRelativeMinute())) + .forEach( + injectTime -> { + long injectTimeAsMinutes = + (((injectTime.getRelativeDayNumber() * 24L) + + injectTime.getRelativeHourNumber()) + * 60) + + injectTime.getRelativeMinuteNumber() + + offsetAsMinutes; + injectTime.getLinkedInject().setDependsDuration(injectTimeAsMinutes * 60); + }); + } else { + // Worst case scenario : there is a mix of relative and absolute dates + // We will need to resolve this row by row in the order they are in the import file + Optional> sortedInstantMap = + mapInstantByRowIndex.entrySet().stream().min(Map.Entry.comparingByKey()); + int firstRow; + if (sortedInstantMap.isPresent()) { + firstRow = sortedInstantMap.get().getKey(); + } else { + firstRow = 0; + } + mapInstantByRowIndex.entrySet().stream() + .sorted(Map.Entry.comparingByKey()) + .forEachOrdered( + integerInjectTimeEntry -> { + InjectTime injectTime = integerInjectTimeEntry.getValue(); + + if (injectTime.getDate() != null) { + // Special case : we have an absolute time but a relative day + if (injectTime.isRelativeDay()) { + injectTime.setDate( + injectTime + .getDate() + .plus(injectTime.getRelativeDayNumber(), ChronoUnit.DAYS)); + } + // Great, we already have an absolute date for this one + // If we are the first, good, nothing more to do + // Otherwise, we need to get the date of the first row to set the depends on + if (integerInjectTimeEntry.getKey() != firstRow) { + Instant firstDate = mapInstantByRowIndex.get(firstRow).getDate(); + injectTime + .getLinkedInject() + .setDependsDuration( + injectTime.getDate().getEpochSecond() - firstDate.getEpochSecond()); + } } else { - return DateFormatUtils.format(cell.getDateCellValue(), timePattern); + // We don't have an absolute date so we need to deduce it from another row + if (injectTime.getRelativeDayNumber() < 0 + || (injectTime.getRelativeDayNumber() == 0 + && injectTime.getRelativeHourNumber() < 0) + || (injectTime.getRelativeDayNumber() == 0 + && injectTime.getRelativeHourNumber() == 0 + && injectTime.getRelativeMinuteNumber() < 0)) { + // We are in the past, so we need to explore the future to find the next + // absolute date + Optional> firstFutureWithAbsolute = + mapInstantByRowIndex.entrySet().stream() + .sorted(Map.Entry.comparingByKey()) + .filter( + entry -> + entry.getKey() > integerInjectTimeEntry.getKey() + && entry.getValue().getDate() != null) + .findFirst(); + if (firstFutureWithAbsolute.isPresent()) { + injectTime.setDate( + firstFutureWithAbsolute + .get() + .getValue() + .getDate() + .plus(injectTime.getRelativeDayNumber(), ChronoUnit.DAYS) + .plus(injectTime.getRelativeHourNumber(), ChronoUnit.HOURS) + .plus(injectTime.getRelativeMinuteNumber(), ChronoUnit.MINUTES)); + } else { + importMessages.add( + new ImportMessage( + ImportMessage.MessageLevel.ERROR, + ImportMessage.ErrorCode.DATE_SET_IN_PAST, + Map.of("row_num", String.valueOf(integerInjectTimeEntry.getKey())))); + } + } else { + // We are in the future, so we need to explore the past to find an absolute date + Optional> firstPastWithAbsolute = + mapInstantByRowIndex.entrySet().stream() + .sorted(Map.Entry.comparingByKey()) + .filter( + entry -> + entry.getKey() < integerInjectTimeEntry.getKey() + && entry.getValue().getDate() != null) + .min(Map.Entry.comparingByKey(Comparator.reverseOrder())); + if (firstPastWithAbsolute.isPresent()) { + injectTime.setDate( + firstPastWithAbsolute + .get() + .getValue() + .getDate() + .plus(injectTime.getRelativeDayNumber(), ChronoUnit.DAYS) + .plus(injectTime.getRelativeHourNumber(), ChronoUnit.HOURS) + .plus(injectTime.getRelativeMinuteNumber(), ChronoUnit.MINUTES)); + } else { + importMessages.add( + new ImportMessage( + ImportMessage.MessageLevel.ERROR, + ImportMessage.ErrorCode.DATE_SET_IN_FUTURE, + Map.of("row_num", String.valueOf(integerInjectTimeEntry.getKey())))); + } + } } - } - } - return ""; + }); + + processDateToAbsolute(mapInstantByRowIndex); } - private String getValueAsString(Row row, String cellColumn) { - if(cellColumn != null && !cellColumn.isBlank() - && row.getCell(CellReference.convertColStringToIndex(cellColumn)) != null) { - Cell cell = row.getCell(CellReference.convertColStringToIndex(cellColumn)); - if(cell.getCellType() == CellType.STRING) { - return cell.getStringCellValue(); - } else if(cell.getCellType() == CellType.NUMERIC) { - return Double.valueOf(cell.getNumericCellValue()).toString(); - } + return importMessages; + } + + private void processDateToAbsolute(Map mapInstantByRowIndex) { + Optional earliestAbsoluteDate = + mapInstantByRowIndex.values().stream() + .map(InjectTime::getDate) + .filter(Objects::nonNull) + .min(Comparator.naturalOrder()); + + // If we have an earliest date, we calculate the dates depending on the earliest one + earliestAbsoluteDate.ifPresent( + earliestInstant -> + mapInstantByRowIndex.values().stream() + .filter(injectTime -> injectTime.getDate() != null) + .forEach( + injectTime -> { + injectTime + .getLinkedInject() + .setDependsDuration( + injectTime.getDate().getEpochSecond() + - earliestInstant.getEpochSecond()); + })); + } + + private String getDateAsStringFromCell(Row row, String cellColumn, String timePattern) { + if (cellColumn != null + && !cellColumn.isBlank() + && row.getCell(CellReference.convertColStringToIndex(cellColumn)) != null) { + Cell cell = row.getCell(CellReference.convertColStringToIndex(cellColumn)); + if (cell.getCellType() == CellType.STRING) { + return cell.getStringCellValue(); + } else if (cell.getCellType() == CellType.NUMERIC) { + if (timePattern == null || timePattern.isEmpty()) { + return cell.getDateCellValue().toString(); + } else { + return DateFormatUtils.format(cell.getDateCellValue(), timePattern); } - return ""; + } } + return ""; + } - private Double getValueAsDouble(Row row, String cellColumn) { - if(cellColumn != null && !cellColumn.isBlank() - && row.getCell(CellReference.convertColStringToIndex(cellColumn)) != null) { - Cell cell = row.getCell(CellReference.convertColStringToIndex(cellColumn)); - if(cell.getCellType() == CellType.STRING) { - return Double.valueOf(cell.getStringCellValue()); - } else if(cell.getCellType() == CellType.NUMERIC) { - return cell.getNumericCellValue(); - } - } - return 0.0; + private String getValueAsString(Row row, String cellColumn) { + if (cellColumn != null + && !cellColumn.isBlank() + && row.getCell(CellReference.convertColStringToIndex(cellColumn)) != null) { + Cell cell = row.getCell(CellReference.convertColStringToIndex(cellColumn)); + if (cell.getCellType() == CellType.STRING) { + return cell.getStringCellValue(); + } else if (cell.getCellType() == CellType.NUMERIC) { + return Double.valueOf(cell.getNumericCellValue()).toString(); + } + } + return ""; + } + + private Double getValueAsDouble(Row row, String cellColumn) { + if (cellColumn != null + && !cellColumn.isBlank() + && row.getCell(CellReference.convertColStringToIndex(cellColumn)) != null) { + Cell cell = row.getCell(CellReference.convertColStringToIndex(cellColumn)); + if (cell.getCellType() == CellType.STRING) { + return Double.valueOf(cell.getStringCellValue()); + } else if (cell.getCellType() == CellType.NUMERIC) { + return cell.getNumericCellValue(); + } } + return 0.0; + } // -- TEST -- - private Map mapOfInjectsExpectations(@NotNull final List rawInjects) { + private Map mapOfInjectsExpectations( + @NotNull final List rawInjects) { return this.injectExpectationRepository .rawByIds( - rawInjects.stream().flatMap(rawInject -> rawInject.getInject_expectations().stream()).toList() - ) + rawInjects.stream() + .flatMap(rawInject -> rawInject.getInject_expectations().stream()) + .toList()) .stream() - .collect(Collectors.toMap(RawInjectExpectation::getInject_expectation_id, Function.identity())); + .collect( + Collectors.toMap(RawInjectExpectation::getInject_expectation_id, Function.identity())); } private Map mapOfAssetGroups( @@ -1149,9 +1461,7 @@ private Map mapOfAssetGroups( rawInjectExpectations.stream() .map(RawInjectExpectation::getAsset_group_id) .filter(Objects::nonNull), - rawInjects.stream() - .map(RawInject::getAsset_group_id) - .filter(Objects::nonNull)) + rawInjects.stream().map(RawInject::getAsset_group_id).filter(Objects::nonNull)) .toList()) .stream() .collect(Collectors.toMap(RawAssetGroup::getAsset_group_id, Function.identity())); @@ -1162,100 +1472,130 @@ private Map mapOfAssets( @NotNull final Map mapOfInjectsExpectations, @NotNull final Map mapOfAssetGroups) { return this.assetRepository - .rawByIds(rawInjects.stream().flatMap(rawInject -> Stream.concat(Stream.concat( - rawInject.getInject_asset_groups().stream() - .flatMap(assetGroup -> Optional.ofNullable(mapOfAssetGroups.get(assetGroup)) - .map(ag -> ag.getAsset_ids().stream()) - .orElse(Stream.empty())), - rawInject.getInject_assets().stream() - ), Stream.concat( - rawInject.getInject_expectations().stream() - .map(mapOfInjectsExpectations::get) - .map(RawInjectExpectation::getAsset_id), - rawInject.getInject_expectations().stream() - .map(mapOfInjectsExpectations::get) - .flatMap(injectExpectation -> injectExpectation.getAsset_group_id() != null ? mapOfAssetGroups.get(injectExpectation.getAsset_group_id()).getAsset_ids().stream() : Stream.empty())) - )).filter(Objects::nonNull).toList()).stream() + .rawByIds( + rawInjects.stream() + .flatMap( + rawInject -> + Stream.concat( + Stream.concat( + rawInject.getInject_asset_groups().stream() + .flatMap( + assetGroup -> + Optional.ofNullable(mapOfAssetGroups.get(assetGroup)) + .map(ag -> ag.getAsset_ids().stream()) + .orElse(Stream.empty())), + rawInject.getInject_assets().stream()), + Stream.concat( + rawInject.getInject_expectations().stream() + .map(mapOfInjectsExpectations::get) + .map(RawInjectExpectation::getAsset_id), + rawInject.getInject_expectations().stream() + .map(mapOfInjectsExpectations::get) + .flatMap( + injectExpectation -> + injectExpectation.getAsset_group_id() != null + ? mapOfAssetGroups + .get(injectExpectation.getAsset_group_id()) + .getAsset_ids() + .stream() + : Stream.empty())))) + .filter(Objects::nonNull) + .toList()) + .stream() .collect(Collectors.toMap(RawAsset::getAsset_id, Function.identity())); } private Map mapOfRawTeams( @NotNull final List rawInjects, @NotNull final Map mapOfInjectsExpectations) { - return this.teamRepository.rawTeamByIds(rawInjects.stream() - .flatMap( - rawInject -> Stream.concat( - rawInject.getInject_teams().stream(), - rawInject.getInject_expectations().stream().map(expectationId -> mapOfInjectsExpectations.get(expectationId).getTeam_id()) - ).filter(Objects::nonNull) - ).distinct().toList()).stream().collect(Collectors.toMap(RawTeam::getTeam_id, Function.identity())); + return this.teamRepository + .rawTeamByIds( + rawInjects.stream() + .flatMap( + rawInject -> + Stream.concat( + rawInject.getInject_teams().stream(), + rawInject.getInject_expectations().stream() + .map( + expectationId -> + mapOfInjectsExpectations + .get(expectationId) + .getTeam_id())) + .filter(Objects::nonNull)) + .distinct() + .toList()) + .stream() + .collect(Collectors.toMap(RawTeam::getTeam_id, Function.identity())); } - // -- CRITERIA BUILDER -- - - private void selectForInject(CriteriaBuilder cb, CriteriaQuery cq, Root injectRoot) { - // Joins - Join injectExerciseJoin = createLeftJoin(injectRoot, "exercise"); - Join injectScenarioJoin = createLeftJoin(injectRoot, "scenario"); - Join injectorContractJoin = createLeftJoin(injectRoot, "injectorContract"); - Join injectorJoin = injectorContractJoin.join("injector", JoinType.LEFT); - Join injectDependsJoin = createLeftJoin(injectRoot, "dependsOn"); - // Array aggregations - Expression tagIdsExpression = createJoinArrayAggOnId(cb, injectRoot, "tags"); - Expression teamIdsExpression = createJoinArrayAggOnId(cb, injectRoot, "teams"); - Expression assetIdsExpression = createJoinArrayAggOnId(cb, injectRoot, "assets"); - Expression assetGroupIdsExpression = createJoinArrayAggOnId(cb, injectRoot, "assetGroups"); - - // SELECT - cq.multiselect( - injectRoot.get("id").alias("inject_id"), - injectRoot.get("title").alias("inject_title"), - injectRoot.get("enabled").alias("inject_enabled"), - injectRoot.get("content").alias("inject_content"), - injectRoot.get("allTeams").alias("inject_all_teams"), - injectExerciseJoin.get("id").alias("inject_exercise"), - injectScenarioJoin.get("id").alias("inject_scenario"), - injectRoot.get("dependsDuration").alias("inject_depends_duration"), - injectDependsJoin.get("id").alias("inject_depends_from_another"), - injectorContractJoin.alias("inject_injector_contract"), - tagIdsExpression.alias("inject_tags"), - teamIdsExpression.alias("inject_teams"), - assetIdsExpression.alias("inject_assets"), - assetGroupIdsExpression.alias("inject_asset_groups"), - injectorJoin.get("type").alias("inject_type") - ).distinct(true); - - // GROUP BY - cq.groupBy(Arrays.asList( - injectRoot.get("id"), - injectExerciseJoin.get("id"), - injectScenarioJoin.get("id"), - injectorContractJoin.get("id"), - injectorJoin.get("id") - )); - } - - private List execInject(TypedQuery query) { - return query.getResultList() - .stream() - .map(tuple -> new InjectOutput( - tuple.get("inject_id", String.class), - tuple.get("inject_title", String.class), - tuple.get("inject_enabled", Boolean.class), - tuple.get("inject_content", ObjectNode.class), - tuple.get("inject_all_teams", Boolean.class), - tuple.get("inject_exercise", String.class), - tuple.get("inject_scenario", String.class), - tuple.get("inject_depends_duration", Long.class), - tuple.get("inject_depends_from_another", String.class), - tuple.get("inject_injector_contract", InjectorContract.class), - tuple.get("inject_tags", String[].class), - tuple.get("inject_teams", String[].class), - tuple.get("inject_assets", String[].class), - tuple.get("inject_asset_groups", String[].class), - tuple.get("inject_type", String.class) - )) - .toList(); - } + // -- CRITERIA BUILDER -- + + private void selectForInject( + CriteriaBuilder cb, CriteriaQuery cq, Root injectRoot) { + // Joins + Join injectExerciseJoin = createLeftJoin(injectRoot, "exercise"); + Join injectScenarioJoin = createLeftJoin(injectRoot, "scenario"); + Join injectorContractJoin = + createLeftJoin(injectRoot, "injectorContract"); + Join injectorJoin = + injectorContractJoin.join("injector", JoinType.LEFT); + Join injectDependsJoin = createLeftJoin(injectRoot, "dependsOn"); + // Array aggregations + Expression tagIdsExpression = createJoinArrayAggOnId(cb, injectRoot, "tags"); + Expression teamIdsExpression = createJoinArrayAggOnId(cb, injectRoot, "teams"); + Expression assetIdsExpression = createJoinArrayAggOnId(cb, injectRoot, "assets"); + Expression assetGroupIdsExpression = + createJoinArrayAggOnId(cb, injectRoot, "assetGroups"); + + // SELECT + cq.multiselect( + injectRoot.get("id").alias("inject_id"), + injectRoot.get("title").alias("inject_title"), + injectRoot.get("enabled").alias("inject_enabled"), + injectRoot.get("content").alias("inject_content"), + injectRoot.get("allTeams").alias("inject_all_teams"), + injectExerciseJoin.get("id").alias("inject_exercise"), + injectScenarioJoin.get("id").alias("inject_scenario"), + injectRoot.get("dependsDuration").alias("inject_depends_duration"), + injectDependsJoin.get("id").alias("inject_depends_from_another"), + injectorContractJoin.alias("inject_injector_contract"), + tagIdsExpression.alias("inject_tags"), + teamIdsExpression.alias("inject_teams"), + assetIdsExpression.alias("inject_assets"), + assetGroupIdsExpression.alias("inject_asset_groups"), + injectorJoin.get("type").alias("inject_type")) + .distinct(true); + + // GROUP BY + cq.groupBy( + Arrays.asList( + injectRoot.get("id"), + injectExerciseJoin.get("id"), + injectScenarioJoin.get("id"), + injectorContractJoin.get("id"), + injectorJoin.get("id"))); + } + private List execInject(TypedQuery query) { + return query.getResultList().stream() + .map( + tuple -> + new InjectOutput( + tuple.get("inject_id", String.class), + tuple.get("inject_title", String.class), + tuple.get("inject_enabled", Boolean.class), + tuple.get("inject_content", ObjectNode.class), + tuple.get("inject_all_teams", Boolean.class), + tuple.get("inject_exercise", String.class), + tuple.get("inject_scenario", String.class), + tuple.get("inject_depends_duration", Long.class), + tuple.get("inject_depends_from_another", String.class), + tuple.get("inject_injector_contract", InjectorContract.class), + tuple.get("inject_tags", String[].class), + tuple.get("inject_teams", String[].class), + tuple.get("inject_assets", String[].class), + tuple.get("inject_asset_groups", String[].class), + tuple.get("inject_type", String.class))) + .toList(); + } } diff --git a/openbas-api/src/main/java/io/openbas/service/InjectTestStatusService.java b/openbas-api/src/main/java/io/openbas/service/InjectTestStatusService.java index 76ccba4f29..be80b257d1 100644 --- a/openbas-api/src/main/java/io/openbas/service/InjectTestStatusService.java +++ b/openbas-api/src/main/java/io/openbas/service/InjectTestStatusService.java @@ -1,5 +1,11 @@ package io.openbas.service; +import static io.openbas.config.SessionHelper.currentUser; +import static io.openbas.database.specification.InjectSpecification.byIds; +import static io.openbas.database.specification.InjectSpecification.testable; +import static io.openbas.helper.StreamHelper.fromIterable; +import static io.openbas.utils.pagination.PaginationUtils.buildPaginationJPA; + import io.openbas.database.model.Execution; import io.openbas.database.model.Inject; import io.openbas.database.model.InjectTestStatus; @@ -15,6 +21,8 @@ import io.openbas.utils.pagination.SearchPaginationInput; import jakarta.persistence.EntityNotFoundException; import jakarta.transaction.Transactional; +import java.util.ArrayList; +import java.util.List; import lombok.RequiredArgsConstructor; import lombok.extern.java.Log; import org.springframework.beans.factory.annotation.Autowired; @@ -24,15 +32,6 @@ import org.springframework.data.jpa.domain.Specification; import org.springframework.stereotype.Service; -import java.util.ArrayList; -import java.util.List; - -import static io.openbas.config.SessionHelper.currentUser; -import static io.openbas.database.specification.InjectSpecification.byIds; -import static io.openbas.database.specification.InjectSpecification.testable; -import static io.openbas.helper.StreamHelper.fromIterable; -import static io.openbas.utils.pagination.PaginationUtils.buildPaginationJPA; - @Service @Log @RequiredArgsConstructor @@ -51,49 +50,60 @@ public void setContext(ApplicationContext context) { @Transactional public InjectTestStatus testInject(String injectId) { - Inject inject = this.injectRepository.findById(injectId).orElseThrow(() -> new EntityNotFoundException("Inject not found")); + Inject inject = + this.injectRepository + .findById(injectId) + .orElseThrow(() -> new EntityNotFoundException("Inject not found")); if (!inject.getInjectTestable()) { throw new IllegalArgumentException("Inject: " + injectId + " is not testable"); } - User user = this.userRepository.findById(currentUser().getId()).orElseThrow(() -> new EntityNotFoundException("User not found")); + User user = + this.userRepository + .findById(currentUser().getId()) + .orElseThrow(() -> new EntityNotFoundException("User not found")); return testInject(inject, user); } - @Transactional public List bulkTestInjects(List injectIds) { - List injects = fromIterable(this.injectRepository.findAll(byIds(injectIds).and(testable()))); + List injects = + fromIterable(this.injectRepository.findAll(byIds(injectIds).and(testable()))); if (injects.isEmpty()) { throw new IllegalArgumentException("No inject ID is testable"); } - User user = this.userRepository.findById(currentUser().getId()).orElseThrow(() -> new EntityNotFoundException("User not found")); + User user = + this.userRepository + .findById(currentUser().getId()) + .orElseThrow(() -> new EntityNotFoundException("User not found")); List results = new ArrayList<>(); injects.forEach(inject -> results.add(testInject(inject, user))); return results; } - public Page findAllInjectTestsByExerciseId(String exerciseId, - SearchPaginationInput searchPaginationInput) { + public Page findAllInjectTestsByExerciseId( + String exerciseId, SearchPaginationInput searchPaginationInput) { return buildPaginationJPA( - (Specification specification, Pageable pageable) -> injectTestStatusRepository.findAll( - InjectTestSpecification.findInjectTestInExercise(exerciseId).and(specification), pageable), + (Specification specification, Pageable pageable) -> + injectTestStatusRepository.findAll( + InjectTestSpecification.findInjectTestInExercise(exerciseId).and(specification), + pageable), searchPaginationInput, - InjectTestStatus.class - ); + InjectTestStatus.class); } - public Page findAllInjectTestsByScenarioId(String scenarioId, - SearchPaginationInput searchPaginationInput) { + public Page findAllInjectTestsByScenarioId( + String scenarioId, SearchPaginationInput searchPaginationInput) { return buildPaginationJPA( - (Specification specification, Pageable pageable) -> injectTestStatusRepository.findAll( - InjectTestSpecification.findInjectTestInScenario(scenarioId).and(specification), pageable), + (Specification specification, Pageable pageable) -> + injectTestStatusRepository.findAll( + InjectTestSpecification.findInjectTestInScenario(scenarioId).and(specification), + pageable), searchPaginationInput, - InjectTestStatus.class - ); + InjectTestStatus.class); } public InjectTestStatus findInjectTestStatusById(String testId) { @@ -103,35 +113,45 @@ public InjectTestStatus findInjectTestStatusById(String testId) { // -- PRIVATE -- private InjectTestStatus testInject(Inject inject, User user) { - ExecutionContext userInjectContext = this.executionContextService.executionContext(user, inject, "Direct test"); - - Injector executor = context.getBean( - inject.getInjectorContract() - .map(contract -> contract.getInjector().getType()) - .orElseThrow(() -> new EntityNotFoundException("Injector contract not found")), - Injector.class - ); - - ExecutableInject injection = new ExecutableInject( - false, true, inject, List.of(), - inject.getAssets(), inject.getAssetGroups(), - List.of(userInjectContext) - ); + ExecutionContext userInjectContext = + this.executionContextService.executionContext(user, inject, "Direct test"); + + Injector executor = + context.getBean( + inject + .getInjectorContract() + .map(contract -> contract.getInjector().getType()) + .orElseThrow(() -> new EntityNotFoundException("Injector contract not found")), + Injector.class); + + ExecutableInject injection = + new ExecutableInject( + false, + true, + inject, + List.of(), + inject.getAssets(), + inject.getAssetGroups(), + List.of(userInjectContext)); Execution execution = executor.executeInjection(injection); - InjectTestStatus injectTestStatus = this.injectTestStatusRepository.findByInject(inject) - .map(existingStatus -> { - InjectTestStatus updatedStatus = InjectTestStatus.fromExecutionTest(execution); - updatedStatus.setId(existingStatus.getId()); - updatedStatus.setTestCreationDate(existingStatus.getTestCreationDate()); - updatedStatus.setInject(inject); - return updatedStatus; - }) - .orElseGet(() -> { - InjectTestStatus newStatus = InjectTestStatus.fromExecutionTest(execution); - newStatus.setInject(inject); - return newStatus; - }); + InjectTestStatus injectTestStatus = + this.injectTestStatusRepository + .findByInject(inject) + .map( + existingStatus -> { + InjectTestStatus updatedStatus = InjectTestStatus.fromExecutionTest(execution); + updatedStatus.setId(existingStatus.getId()); + updatedStatus.setTestCreationDate(existingStatus.getTestCreationDate()); + updatedStatus.setInject(inject); + return updatedStatus; + }) + .orElseGet( + () -> { + InjectTestStatus newStatus = InjectTestStatus.fromExecutionTest(execution); + newStatus.setInject(inject); + return newStatus; + }); return this.injectTestStatusRepository.save(injectTestStatus); } @@ -139,5 +159,4 @@ private InjectTestStatus testInject(Inject inject, User user) { public void deleteInjectTest(String testId) { injectTestStatusRepository.deleteById(testId); } - } diff --git a/openbas-api/src/main/java/io/openbas/service/InjectTime.java b/openbas-api/src/main/java/io/openbas/service/InjectTime.java index 55bcb1eeec..6058aaefd9 100644 --- a/openbas-api/src/main/java/io/openbas/service/InjectTime.java +++ b/openbas-api/src/main/java/io/openbas/service/InjectTime.java @@ -1,22 +1,21 @@ package io.openbas.service; import io.openbas.database.model.Inject; -import lombok.Data; - import java.time.Instant; import java.time.format.DateTimeFormatter; +import lombok.Data; @Data public class InjectTime { - private boolean isRelativeDay = false; - private boolean isRelativeHour = false; - private boolean isRelativeMinute = false; - private boolean specifyDays = true; - private DateTimeFormatter formatter = DateTimeFormatter.ISO_DATE_TIME; - private Instant date; - private String unformattedDate; - private int relativeDayNumber; - private int relativeHourNumber; - private int relativeMinuteNumber; - private Inject linkedInject; + private boolean isRelativeDay = false; + private boolean isRelativeHour = false; + private boolean isRelativeMinute = false; + private boolean specifyDays = true; + private DateTimeFormatter formatter = DateTimeFormatter.ISO_DATE_TIME; + private Instant date; + private String unformattedDate; + private int relativeDayNumber; + private int relativeHourNumber; + private int relativeMinuteNumber; + private Inject linkedInject; } diff --git a/openbas-api/src/main/java/io/openbas/service/MailingService.java b/openbas-api/src/main/java/io/openbas/service/MailingService.java index d6ff347460..a1f12906d7 100644 --- a/openbas-api/src/main/java/io/openbas/service/MailingService.java +++ b/openbas-api/src/main/java/io/openbas/service/MailingService.java @@ -1,5 +1,7 @@ package io.openbas.service; +import static io.openbas.config.SessionHelper.currentUser; + import com.fasterxml.jackson.databind.ObjectMapper; import io.openbas.database.model.Exercise; import io.openbas.database.model.Inject; @@ -15,73 +17,84 @@ import io.openbas.rest.exception.ElementNotFoundException; import jakarta.annotation.Resource; import jakarta.validation.constraints.NotNull; +import java.util.List; +import java.util.Optional; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.context.ApplicationContext; import org.springframework.stereotype.Service; -import java.util.List; -import java.util.Optional; - -import static io.openbas.config.SessionHelper.currentUser; - - @Service public class MailingService { - @Resource - protected ObjectMapper mapper; - - private ApplicationContext context; - - private UserRepository userRepository; - - private InjectorContractRepository injectorContractRepository; - - private ExecutionContextService executionContextService; - - @Autowired - public void setUserRepository(UserRepository userRepository) { - this.userRepository = userRepository; - } - - @Autowired - public void setInjectorContractRepository(InjectorContractRepository injectorContractRepository) { - this.injectorContractRepository = injectorContractRepository; - } - - @Autowired - public void setContext(ApplicationContext context) { - this.context = context; - } - - @Autowired - public void setExecutionContextService(@NotNull final ExecutionContextService executionContextService) { - this.executionContextService = executionContextService; - } - - public void sendEmail(String subject, String body, List users, Optional exercise) { - EmailContent emailContent = new EmailContent(); - emailContent.setSubject(subject); - emailContent.setBody(body); - - Inject inject = new Inject(); - inject.setInjectorContract(this.injectorContractRepository.findById(EmailContract.EMAIL_DEFAULT).orElseThrow(ElementNotFoundException::new)); - - inject.getInjectorContract().ifPresent(injectorContract -> { - inject.setContent(this.mapper.valueToTree(emailContent)); - inject.setUser(this.userRepository.findById(currentUser().getId()).orElseThrow()); - - exercise.ifPresent(inject::setExercise); - - List userInjectContexts = users.stream().distinct() - .map(user -> this.executionContextService.executionContext(user, inject, "Direct execution")).toList(); - ExecutableInject injection = new ExecutableInject(false, true, inject, userInjectContexts); - Injector executor = this.context.getBean(injectorContract.getInjector().getType(), Injector.class); - executor.executeInjection(injection); - }); - } - - public void sendEmail(String subject, String body, List users) { - sendEmail(subject, body, users, Optional.empty()); - } + @Resource protected ObjectMapper mapper; + + private ApplicationContext context; + + private UserRepository userRepository; + + private InjectorContractRepository injectorContractRepository; + + private ExecutionContextService executionContextService; + + @Autowired + public void setUserRepository(UserRepository userRepository) { + this.userRepository = userRepository; + } + + @Autowired + public void setInjectorContractRepository(InjectorContractRepository injectorContractRepository) { + this.injectorContractRepository = injectorContractRepository; + } + + @Autowired + public void setContext(ApplicationContext context) { + this.context = context; + } + + @Autowired + public void setExecutionContextService( + @NotNull final ExecutionContextService executionContextService) { + this.executionContextService = executionContextService; + } + + public void sendEmail( + String subject, String body, List users, Optional exercise) { + EmailContent emailContent = new EmailContent(); + emailContent.setSubject(subject); + emailContent.setBody(body); + + Inject inject = new Inject(); + inject.setInjectorContract( + this.injectorContractRepository + .findById(EmailContract.EMAIL_DEFAULT) + .orElseThrow(ElementNotFoundException::new)); + + inject + .getInjectorContract() + .ifPresent( + injectorContract -> { + inject.setContent(this.mapper.valueToTree(emailContent)); + inject.setUser(this.userRepository.findById(currentUser().getId()).orElseThrow()); + + exercise.ifPresent(inject::setExercise); + + List userInjectContexts = + users.stream() + .distinct() + .map( + user -> + this.executionContextService.executionContext( + user, inject, "Direct execution")) + .toList(); + ExecutableInject injection = + new ExecutableInject(false, true, inject, userInjectContexts); + Injector executor = + this.context.getBean(injectorContract.getInjector().getType(), Injector.class); + executor.executeInjection(injection); + }); + } + + public void sendEmail(String subject, String body, List users) { + sendEmail(subject, body, users, Optional.empty()); + } } diff --git a/openbas-api/src/main/java/io/openbas/service/MapperService.java b/openbas-api/src/main/java/io/openbas/service/MapperService.java index 896c4b74c9..e043b5e7ec 100644 --- a/openbas-api/src/main/java/io/openbas/service/MapperService.java +++ b/openbas-api/src/main/java/io/openbas/service/MapperService.java @@ -1,5 +1,8 @@ package io.openbas.service; +import static io.openbas.utils.StringUtils.duplicateString; +import static java.util.stream.StreamSupport.stream; + import com.fasterxml.jackson.core.JsonProcessingException; import com.fasterxml.jackson.databind.ObjectMapper; import io.openbas.database.model.*; @@ -11,20 +14,16 @@ import io.openbas.rest.mapper.form.*; import io.openbas.utils.CopyObjectListUtils; import jakarta.validation.constraints.NotBlank; -import lombok.RequiredArgsConstructor; -import org.apache.commons.lang3.StringUtils; -import org.jetbrains.annotations.NotNull; -import org.springframework.stereotype.Service; -import org.springframework.transaction.annotation.Transactional; - import java.time.Instant; import java.util.*; import java.util.function.Function; import java.util.stream.Collectors; import java.util.stream.StreamSupport; - -import static io.openbas.utils.StringUtils.duplicateString; -import static java.util.stream.StreamSupport.stream; +import lombok.RequiredArgsConstructor; +import org.apache.commons.lang3.StringUtils; +import org.jetbrains.annotations.NotNull; +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; @RequiredArgsConstructor @Service @@ -36,6 +35,7 @@ public class MapperService { /** * Create and save an ImportMapper object from a MapperAddInput one + * * @param importMapperAddInput The input from the call * @return The created ImportMapper */ @@ -50,166 +50,225 @@ public ImportMapper createImportMapper(ImportMapperAddInput importMapperAddInput importMapper.setUpdateAttributes(importMapperAddInput); importMapper.setInjectImporters(new ArrayList<>()); - Map mapInjectorContracts = getMapOfInjectorContracts( - importMapperAddInput.getImporters() - .stream() - .map(InjectImporterAddInput::getInjectorContractId) - .toList() - ); - - importMapperAddInput.getImporters().forEach( - injectImporterInput -> { - InjectImporter injectImporter = new InjectImporter(); - injectImporter.setInjectorContract(mapInjectorContracts.get(injectImporterInput.getInjectorContractId())); - injectImporter.setImportTypeValue(injectImporterInput.getInjectTypeValue()); - - injectImporter.setRuleAttributes(new ArrayList<>()); - injectImporterInput.getRuleAttributes().forEach(ruleAttributeInput -> { - injectImporter.getRuleAttributes().add(CopyObjectListUtils.copyObjectWithoutId(ruleAttributeInput, RuleAttribute.class)); - }); - importMapper.getInjectImporters().add(injectImporter); - } - ); + Map mapInjectorContracts = + getMapOfInjectorContracts( + importMapperAddInput.getImporters().stream() + .map(InjectImporterAddInput::getInjectorContractId) + .toList()); + + importMapperAddInput + .getImporters() + .forEach( + injectImporterInput -> { + InjectImporter injectImporter = new InjectImporter(); + injectImporter.setInjectorContract( + mapInjectorContracts.get(injectImporterInput.getInjectorContractId())); + injectImporter.setImportTypeValue(injectImporterInput.getInjectTypeValue()); + + injectImporter.setRuleAttributes(new ArrayList<>()); + injectImporterInput + .getRuleAttributes() + .forEach( + ruleAttributeInput -> { + injectImporter + .getRuleAttributes() + .add( + CopyObjectListUtils.copyObjectWithoutId( + ruleAttributeInput, RuleAttribute.class)); + }); + importMapper.getInjectImporters().add(injectImporter); + }); return importMapper; } /** * Duplicate importMapper by id + * * @param importMapperId id of the mapper that need to be duplicated * @return The duplicated ImportMapper */ @Transactional public ImportMapper getDuplicateImportMapper(@NotBlank String importMapperId) { if (StringUtils.isNotBlank(importMapperId)) { - ImportMapper importMapperOrigin = importMapperRepository.findById(UUID.fromString(importMapperId)).orElseThrow(); - ImportMapper importMapper = CopyObjectListUtils.copyObjectWithoutId(importMapperOrigin, ImportMapper.class); + ImportMapper importMapperOrigin = + importMapperRepository.findById(UUID.fromString(importMapperId)).orElseThrow(); + ImportMapper importMapper = + CopyObjectListUtils.copyObjectWithoutId(importMapperOrigin, ImportMapper.class); importMapper.setName(duplicateString(importMapperOrigin.getName())); - List injectImporters = getInjectImportersDuplicated(importMapperOrigin.getInjectImporters()); + List injectImporters = + getInjectImportersDuplicated(importMapperOrigin.getInjectImporters()); importMapper.setInjectImporters(injectImporters); return importMapperRepository.save(importMapper); } throw new ElementNotFoundException(); } - private List getInjectImportersDuplicated(List injectImportersOrigin) { - List injectImporters = CopyObjectListUtils.copyWithoutIds(injectImportersOrigin, InjectImporter.class); - injectImporters.forEach(injectImport -> { - List ruleAttributes = CopyObjectListUtils.copyWithoutIds(injectImport.getRuleAttributes(), RuleAttribute.class); - injectImport.setRuleAttributes(ruleAttributes); - }); + private List getInjectImportersDuplicated( + List injectImportersOrigin) { + List injectImporters = + CopyObjectListUtils.copyWithoutIds(injectImportersOrigin, InjectImporter.class); + injectImporters.forEach( + injectImport -> { + List ruleAttributes = + CopyObjectListUtils.copyWithoutIds( + injectImport.getRuleAttributes(), RuleAttribute.class); + injectImport.setRuleAttributes(ruleAttributes); + }); return injectImporters; } /** * Update an ImportMapper object from a MapperUpdateInput one + * * @param mapperId the id of the mapper that needs to be updated * @param importMapperUpdateInput The input from the call * @return The updated ImportMapper */ - public ImportMapper updateImportMapper(String mapperId, ImportMapperUpdateInput importMapperUpdateInput) { - ImportMapper importMapper = importMapperRepository.findById(UUID.fromString(mapperId)).orElseThrow(ElementNotFoundException::new); + public ImportMapper updateImportMapper( + String mapperId, ImportMapperUpdateInput importMapperUpdateInput) { + ImportMapper importMapper = + importMapperRepository + .findById(UUID.fromString(mapperId)) + .orElseThrow(ElementNotFoundException::new); importMapper.setUpdateAttributes(importMapperUpdateInput); importMapper.setUpdateDate(Instant.now()); - Map mapInjectorContracts = getMapOfInjectorContracts( - importMapperUpdateInput.getImporters() - .stream() - .map(InjectImporterUpdateInput::getInjectorContractId) - .toList() - ); + Map mapInjectorContracts = + getMapOfInjectorContracts( + importMapperUpdateInput.getImporters().stream() + .map(InjectImporterUpdateInput::getInjectorContractId) + .toList()); - updateInjectImporter(importMapperUpdateInput.getImporters(), importMapper.getInjectImporters(), mapInjectorContracts); + updateInjectImporter( + importMapperUpdateInput.getImporters(), + importMapper.getInjectImporters(), + mapInjectorContracts); return importMapperRepository.save(importMapper); } /** * Gets a map of injector contracts by ids + * * @param ids The ids of the injector contracts we want * @return The map of injector contracts by ids */ private Map getMapOfInjectorContracts(List ids) { return stream(injectorContractRepository.findAllById(ids).spliterator(), false) - .collect(Collectors.toMap(InjectorContract::getId, Function.identity())); + .collect(Collectors.toMap(InjectorContract::getId, Function.identity())); } /** * Updates rule attributes from a list of input + * * @param ruleAttributesInput the list of rule attributes input * @param ruleAttributes the list of rule attributes to update */ - private void updateRuleAttributes(List ruleAttributesInput, List ruleAttributes) { + private void updateRuleAttributes( + List ruleAttributesInput, List ruleAttributes) { // First, we remove the entities that are no longer linked to the mapper - ruleAttributes.removeIf(ruleAttribute -> ruleAttributesInput.stream().noneMatch(importerInput -> ruleAttribute.getId().equals(importerInput.getId()))); + ruleAttributes.removeIf( + ruleAttribute -> + ruleAttributesInput.stream() + .noneMatch(importerInput -> ruleAttribute.getId().equals(importerInput.getId()))); // Then we update the existing ones - ruleAttributes.forEach(ruleAttribute -> { - RuleAttributeUpdateInput ruleAttributeInput = ruleAttributesInput.stream() - .filter(ruleAttributeUpdateInput -> ruleAttribute.getId().equals(ruleAttributeUpdateInput.getId())) - .findFirst() - .orElseThrow(ElementNotFoundException::new); - ruleAttribute.setUpdateAttributes(ruleAttributeInput); - }); + ruleAttributes.forEach( + ruleAttribute -> { + RuleAttributeUpdateInput ruleAttributeInput = + ruleAttributesInput.stream() + .filter( + ruleAttributeUpdateInput -> + ruleAttribute.getId().equals(ruleAttributeUpdateInput.getId())) + .findFirst() + .orElseThrow(ElementNotFoundException::new); + ruleAttribute.setUpdateAttributes(ruleAttributeInput); + }); // Then we add the new ones - ruleAttributesInput.forEach(ruleAttributeUpdateInput -> { - if (ruleAttributeUpdateInput.getId() == null || ruleAttributeUpdateInput.getId().isBlank()) { - RuleAttribute ruleAttribute = new RuleAttribute(); - ruleAttribute.setColumns(ruleAttributeUpdateInput.getColumns()); - ruleAttribute.setName(ruleAttributeUpdateInput.getName()); - ruleAttribute.setDefaultValue(ruleAttributeUpdateInput.getDefaultValue()); - ruleAttribute.setAdditionalConfig(ruleAttributeUpdateInput.getAdditionalConfig()); - ruleAttributes.add(ruleAttribute); - } - }); + ruleAttributesInput.forEach( + ruleAttributeUpdateInput -> { + if (ruleAttributeUpdateInput.getId() == null + || ruleAttributeUpdateInput.getId().isBlank()) { + RuleAttribute ruleAttribute = new RuleAttribute(); + ruleAttribute.setColumns(ruleAttributeUpdateInput.getColumns()); + ruleAttribute.setName(ruleAttributeUpdateInput.getName()); + ruleAttribute.setDefaultValue(ruleAttributeUpdateInput.getDefaultValue()); + ruleAttribute.setAdditionalConfig(ruleAttributeUpdateInput.getAdditionalConfig()); + ruleAttributes.add(ruleAttribute); + } + }); } /** * Updates a list of inject importers from an input one + * * @param injectImportersInput the input * @param injectImporters the inject importers to update * @param mapInjectorContracts a map of injector contracts by contract id */ - private void updateInjectImporter(List injectImportersInput, List injectImporters, Map mapInjectorContracts) { + private void updateInjectImporter( + List injectImportersInput, + List injectImporters, + Map mapInjectorContracts) { // First, we remove the entities that are no longer linked to the mapper - injectImporters.removeIf(importer -> !injectImportersInput.stream().anyMatch(importerInput -> importer.getId().equals(importerInput.getId()))); + injectImporters.removeIf( + importer -> + !injectImportersInput.stream() + .anyMatch(importerInput -> importer.getId().equals(importerInput.getId()))); // Then we update the existing ones - injectImporters.forEach(injectImporter -> { - InjectImporterUpdateInput injectImporterInput = injectImportersInput.stream() - .filter(injectImporterUpdateInput -> injectImporter.getId().equals(injectImporterUpdateInput.getId())) - .findFirst() - .orElseThrow(ElementNotFoundException::new); - injectImporter.setUpdateAttributes(injectImporterInput); - updateRuleAttributes(injectImporterInput.getRuleAttributes(), injectImporter.getRuleAttributes()); - }); + injectImporters.forEach( + injectImporter -> { + InjectImporterUpdateInput injectImporterInput = + injectImportersInput.stream() + .filter( + injectImporterUpdateInput -> + injectImporter.getId().equals(injectImporterUpdateInput.getId())) + .findFirst() + .orElseThrow(ElementNotFoundException::new); + injectImporter.setUpdateAttributes(injectImporterInput); + updateRuleAttributes( + injectImporterInput.getRuleAttributes(), injectImporter.getRuleAttributes()); + }); // Then we add the new ones - injectImportersInput.forEach(injectImporterUpdateInput -> { - if (injectImporterUpdateInput.getId() == null || injectImporterUpdateInput.getId().isBlank()) { - InjectImporter injectImporter = new InjectImporter(); - injectImporter.setInjectorContract(mapInjectorContracts.get(injectImporterUpdateInput.getInjectorContractId())); - injectImporter.setImportTypeValue(injectImporterUpdateInput.getInjectTypeValue()); - injectImporter.setRuleAttributes(new ArrayList<>()); - injectImporterUpdateInput.getRuleAttributes().forEach(ruleAttributeInput -> { - RuleAttribute ruleAttribute = new RuleAttribute(); - ruleAttribute.setColumns(ruleAttributeInput.getColumns()); - ruleAttribute.setName(ruleAttributeInput.getName()); - ruleAttribute.setDefaultValue(ruleAttributeInput.getDefaultValue()); - ruleAttribute.setAdditionalConfig(ruleAttributeInput.getAdditionalConfig()); - injectImporter.getRuleAttributes().add(ruleAttribute); + injectImportersInput.forEach( + injectImporterUpdateInput -> { + if (injectImporterUpdateInput.getId() == null + || injectImporterUpdateInput.getId().isBlank()) { + InjectImporter injectImporter = new InjectImporter(); + injectImporter.setInjectorContract( + mapInjectorContracts.get(injectImporterUpdateInput.getInjectorContractId())); + injectImporter.setImportTypeValue(injectImporterUpdateInput.getInjectTypeValue()); + injectImporter.setRuleAttributes(new ArrayList<>()); + injectImporterUpdateInput + .getRuleAttributes() + .forEach( + ruleAttributeInput -> { + RuleAttribute ruleAttribute = new RuleAttribute(); + ruleAttribute.setColumns(ruleAttributeInput.getColumns()); + ruleAttribute.setName(ruleAttributeInput.getName()); + ruleAttribute.setDefaultValue(ruleAttributeInput.getDefaultValue()); + ruleAttribute.setAdditionalConfig(ruleAttributeInput.getAdditionalConfig()); + injectImporter.getRuleAttributes().add(ruleAttribute); + }); + injectImporters.add(injectImporter); + } }); - injectImporters.add(injectImporter); - } - }); } - public String exportMappers(@NotNull final List idsToExport) throws JsonProcessingException { + public String exportMappers(@NotNull final List idsToExport) + throws JsonProcessingException { ObjectMapper objectMapper = ObjectMapperHelper.openBASJsonMapper(); - List mappersList = StreamSupport.stream( - importMapperRepository.findAllById(idsToExport.stream().map(UUID::fromString).toList()).spliterator(), false - ).toList(); + List mappersList = + StreamSupport.stream( + importMapperRepository + .findAllById(idsToExport.stream().map(UUID::fromString).toList()) + .spliterator(), + false) + .toList(); objectMapper.addMixIn(ImportMapper.class, MapperExportMixins.ImportMapper.class); objectMapper.addMixIn(InjectImporter.class, MapperExportMixins.InjectImporter.class); @@ -223,7 +282,6 @@ public void importMappers(List mappers) { mappers.stream() .map(this::createImportMapper) .peek((m) -> m.setName(m.getName() + " (Import)")) - .toList() - ); + .toList()); } } diff --git a/openbas-api/src/main/java/io/openbas/service/PlatformSettingsService.java b/openbas-api/src/main/java/io/openbas/service/PlatformSettingsService.java index 64ee7ac7de..51051cb457 100644 --- a/openbas-api/src/main/java/io/openbas/service/PlatformSettingsService.java +++ b/openbas-api/src/main/java/io/openbas/service/PlatformSettingsService.java @@ -1,5 +1,10 @@ package io.openbas.service; +import static io.openbas.config.SessionHelper.currentUser; +import static io.openbas.database.model.SettingKeys.*; +import static io.openbas.helper.StreamHelper.fromIterable; +import static java.util.Optional.ofNullable; + import io.openbas.config.OpenBASConfig; import io.openbas.config.OpenBASPrincipal; import io.openbas.config.RabbitmqConfig; @@ -17,6 +22,9 @@ import io.openbas.rest.stream.ai.AiConfig; import jakarta.annotation.Resource; import jakarta.validation.constraints.NotBlank; +import java.util.*; +import java.util.function.Function; +import java.util.stream.Collectors; import lombok.extern.java.Log; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.boot.autoconfigure.security.oauth2.client.OAuth2ClientProperties; @@ -26,15 +34,6 @@ import org.springframework.stereotype.Service; import org.springframework.util.StringUtils; -import java.util.*; -import java.util.function.Function; -import java.util.stream.Collectors; - -import static io.openbas.config.SessionHelper.currentUser; -import static io.openbas.database.model.SettingKeys.*; -import static io.openbas.helper.StreamHelper.fromIterable; -import static java.util.Optional.ofNullable; - @Service @Log public class PlatformSettingsService { @@ -49,12 +48,9 @@ public class PlatformSettingsService { private AiConfig aiConfig; private CalderaExecutorConfig calderaExecutorConfig; - @Resource - private OpenBASConfig openBASConfig; - @Resource - private ExpectationPropertiesConfig expectationPropertiesConfig; - @Resource - private RabbitmqConfig rabbitmqConfig; + @Resource private OpenBASConfig openBASConfig; + @Resource private ExpectationPropertiesConfig expectationPropertiesConfig; + @Resource private RabbitmqConfig rabbitmqConfig; @Autowired public void setOpenCTIConfig(OpenCTIConfig openCTIConfig) { @@ -95,15 +91,17 @@ private List buildOpenIdProviders() { OAuth2ClientProperties properties = this.context.getBean(OAuth2ClientProperties.class); Map providers = properties.getRegistration(); return providers.entrySet().stream() - .map(entry -> { - String uri = "/oauth2/authorization/" + entry.getKey(); - String clientName = env.getProperty("openbas.provider." + entry.getKey() + ".login"); - // In case of missing name configuration, generate a generic name - if (clientName == null) { - clientName = "Login with " + entry.getKey(); - } - return new OAuthProvider(entry.getKey(), uri, clientName); - }) + .map( + entry -> { + String uri = "/oauth2/authorization/" + entry.getKey(); + String clientName = + env.getProperty("openbas.provider." + entry.getKey() + ".login"); + // In case of missing name configuration, generate a generic name + if (clientName == null) { + clientName = "Login with " + entry.getKey(); + } + return new OAuthProvider(entry.getKey(), uri, clientName); + }) .toList(); } catch (Exception e) { // No provider defined in the configuration @@ -116,18 +114,22 @@ private List buildSaml2Providers() { return new ArrayList<>(); } try { - Saml2RelyingPartyProperties properties = this.context.getBean(Saml2RelyingPartyProperties.class); - Map providers = properties.getRegistration(); + Saml2RelyingPartyProperties properties = + this.context.getBean(Saml2RelyingPartyProperties.class); + Map providers = + properties.getRegistration(); return providers.entrySet().stream() - .map(entry -> { - String uri = "/saml2/authenticate/" + entry.getKey(); - String clientName = env.getProperty("openbas.provider." + entry.getKey() + ".login"); - // In case of missing name configuration, generate a generic name - if (clientName == null) { - clientName = "Login with " + entry.getKey(); - } - return new OAuthProvider(entry.getKey(), uri, clientName); - }) + .map( + entry -> { + String uri = "/saml2/authenticate/" + entry.getKey(); + String clientName = + env.getProperty("openbas.provider." + entry.getKey() + ".login"); + // In case of missing name configuration, generate a generic name + if (clientName == null) { + clientName = "Login with " + entry.getKey(); + } + return new OAuthProvider(entry.getKey(), uri, clientName); + }) .toList(); } catch (Exception e) { // No provider defined in the configuration @@ -135,13 +137,13 @@ private List buildSaml2Providers() { } } - // -- MAP UTILS -- private Map mapOfSettings(@NotBlank List settings) { return settings.stream().collect(Collectors.toMap(Setting::getKey, Function.identity())); } - private String getValueFromMapOfSettings(@NotBlank Map dbSettings, @NotBlank final String key) { + private String getValueFromMapOfSettings( + @NotBlank Map dbSettings, @NotBlank final String key) { return Optional.ofNullable(dbSettings.get(key)).map(Setting::getValue).orElse(null); } @@ -159,7 +161,6 @@ private Setting resolve(Optional optionalSetting, String themeKey, Stri return new Setting(themeKey, value); } - // -- FIND SETTINGS -- public PlatformSettings findSettings() { Map dbSettings = mapOfSettings(fromIterable(this.settingRepository.findAll())); @@ -172,28 +173,31 @@ public PlatformSettings findSettings() { platformSettings.setAuthSaml2Enable(openBASConfig.isAuthSaml2Enable()); platformSettings.setAuthLocalEnable(openBASConfig.isAuthLocalEnable()); platformSettings.setPlatformTheme( - ofNullable(dbSettings.get(DEFAULT_THEME.key())).map(Setting::getValue).orElse(DEFAULT_THEME.defaultValue()) - ); + ofNullable(dbSettings.get(DEFAULT_THEME.key())) + .map(Setting::getValue) + .orElse(DEFAULT_THEME.defaultValue())); platformSettings.setPlatformLang( - ofNullable(dbSettings.get(DEFAULT_LANG.key())).map(Setting::getValue).orElse(DEFAULT_LANG.defaultValue()) - ); + ofNullable(dbSettings.get(DEFAULT_LANG.key())) + .map(Setting::getValue) + .orElse(DEFAULT_LANG.defaultValue())); // Build authenticated user settings OpenBASPrincipal user = currentUser(); if (user != null) { platformSettings.setPlatformEnterpriseEdition( - ofNullable(dbSettings.get(PLATFORM_ENTERPRISE_EDITION.key())).map(Setting::getValue) - .orElse(PLATFORM_ENTERPRISE_EDITION.defaultValue()) - ); + ofNullable(dbSettings.get(PLATFORM_ENTERPRISE_EDITION.key())) + .map(Setting::getValue) + .orElse(PLATFORM_ENTERPRISE_EDITION.defaultValue())); platformSettings.setPlatformWhitemark( - ofNullable(dbSettings.get(PLATFORM_WHITEMARK.key())).map(Setting::getValue) - .orElse(PLATFORM_WHITEMARK.defaultValue()) - ); + ofNullable(dbSettings.get(PLATFORM_WHITEMARK.key())) + .map(Setting::getValue) + .orElse(PLATFORM_WHITEMARK.defaultValue())); platformSettings.setMapTileServerLight(openBASConfig.getMapTileServerLight()); platformSettings.setMapTileServerDark(openBASConfig.getMapTileServerDark()); platformSettings.setPlatformName( - ofNullable(dbSettings.get(PLATFORM_NAME.key())).map(Setting::getValue).orElse(PLATFORM_NAME.defaultValue()) - ); + ofNullable(dbSettings.get(PLATFORM_NAME.key())) + .map(Setting::getValue) + .orElse(PLATFORM_NAME.defaultValue())); platformSettings.setPlatformBaseUrl(openBASConfig.getBaseUrl()); platformSettings.setPlatformAgentUrl(openBASConfig.getBaseUrlForAgent()); platformSettings.setXtmOpenctiEnable(openCTIConfig.getEnable()); @@ -225,24 +229,26 @@ public PlatformSettings findSettings() { // POLICIES PolicyInput policies = new PolicyInput(); policies.setLoginMessage(getValueFromMapOfSettings(dbSettings, PLATFORM_LOGIN_MESSAGE.key())); - policies.setConsentMessage(getValueFromMapOfSettings(dbSettings, PLATFORM_CONSENT_MESSAGE.key())); - policies.setConsentConfirmText(getValueFromMapOfSettings(dbSettings, PLATFORM_CONSENT_CONFIRM_TEXT.key())); + policies.setConsentMessage( + getValueFromMapOfSettings(dbSettings, PLATFORM_CONSENT_MESSAGE.key())); + policies.setConsentConfirmText( + getValueFromMapOfSettings(dbSettings, PLATFORM_CONSENT_CONFIRM_TEXT.key())); platformSettings.setPolicies(policies); // FEATURE FLAG if (!openBASConfig.getDisabledDevFeatures().isEmpty()) { platformSettings.setDisabledDevFeatures( - Arrays.stream(openBASConfig.getDisabledDevFeatures().split(",")).toList() - ); + Arrays.stream(openBASConfig.getDisabledDevFeatures().split(",")).toList()); } // PLATFORM MESSAGE Map> platformBannerByLevel = new HashMap<>(); for (BannerMessage.BANNER_KEYS bannerKey : BannerMessage.BANNER_KEYS.values()) { String value = getValueFromMapOfSettings(dbSettings, PLATFORM_BANNER + "." + bannerKey.key()); - if(value != null) { - if(platformBannerByLevel.get(bannerKey.level().name()) == null) { - platformBannerByLevel.put(bannerKey.level().name(), new ArrayList<>(Arrays.asList(bannerKey.message()))); + if (value != null) { + if (platformBannerByLevel.get(bannerKey.level().name()) == null) { + platformBannerByLevel.put( + bannerKey.level().name(), new ArrayList<>(Arrays.asList(bannerKey.message()))); } else { platformBannerByLevel.get(bannerKey.level().name()).add(bannerKey.message()); } @@ -251,27 +257,49 @@ public PlatformSettings findSettings() { platformSettings.setPlatformBannerByLevel(platformBannerByLevel); // EXPECTATION - platformSettings.setDetectionExpirationTime(expectationPropertiesConfig.getDetectionExpirationTime()); - platformSettings.setPreventionExpirationTime(expectationPropertiesConfig.getPreventionExpirationTime()); - platformSettings.setChallengeExpirationTime(expectationPropertiesConfig.getChallengeExpirationTime()); - platformSettings.setArticleExpirationTime(expectationPropertiesConfig.getArticleExpirationTime()); + platformSettings.setDetectionExpirationTime( + expectationPropertiesConfig.getDetectionExpirationTime()); + platformSettings.setPreventionExpirationTime( + expectationPropertiesConfig.getPreventionExpirationTime()); + platformSettings.setChallengeExpirationTime( + expectationPropertiesConfig.getChallengeExpirationTime()); + platformSettings.setArticleExpirationTime( + expectationPropertiesConfig.getArticleExpirationTime()); platformSettings.setManualExpirationTime(expectationPropertiesConfig.getManualExpirationTime()); - platformSettings.setExpectationDefaultScoreValue(expectationPropertiesConfig.getDefaultExpectationScoreValue()); + platformSettings.setExpectationDefaultScoreValue( + expectationPropertiesConfig.getDefaultExpectationScoreValue()); return platformSettings; } private ThemeInput createThemeInput(Map dbSettings, String themeType) { ThemeInput themeInput = new ThemeInput(); - themeInput.setBackgroundColor(getValueFromMapOfSettings(dbSettings, themeType + "." + Theme.THEME_KEYS.BACKGROUND_COLOR.key())); - themeInput.setPaperColor(getValueFromMapOfSettings(dbSettings, themeType + "." + Theme.THEME_KEYS.PAPER_COLOR.key())); - themeInput.setNavigationColor(getValueFromMapOfSettings(dbSettings, themeType + "." + Theme.THEME_KEYS.NAVIGATION_COLOR.key())); - themeInput.setPrimaryColor(getValueFromMapOfSettings(dbSettings, themeType + "." + Theme.THEME_KEYS.PRIMARY_COLOR.key())); - themeInput.setSecondaryColor(getValueFromMapOfSettings(dbSettings, themeType + "." + Theme.THEME_KEYS.SECONDARY_COLOR.key())); - themeInput.setAccentColor(getValueFromMapOfSettings(dbSettings, themeType + "." + Theme.THEME_KEYS.ACCENT_COLOR.key())); - themeInput.setLogoUrl(getValueFromMapOfSettings(dbSettings, themeType + "." + Theme.THEME_KEYS.LOGO_URL.key())); - themeInput.setLogoLoginUrl(getValueFromMapOfSettings(dbSettings, themeType + "." + Theme.THEME_KEYS.LOGO_LOGIN_URL.key())); - themeInput.setLogoUrlCollapsed(getValueFromMapOfSettings(dbSettings, themeType + "." + Theme.THEME_KEYS.LOGO_URL_COLLAPSED.key())); + themeInput.setBackgroundColor( + getValueFromMapOfSettings( + dbSettings, themeType + "." + Theme.THEME_KEYS.BACKGROUND_COLOR.key())); + themeInput.setPaperColor( + getValueFromMapOfSettings( + dbSettings, themeType + "." + Theme.THEME_KEYS.PAPER_COLOR.key())); + themeInput.setNavigationColor( + getValueFromMapOfSettings( + dbSettings, themeType + "." + Theme.THEME_KEYS.NAVIGATION_COLOR.key())); + themeInput.setPrimaryColor( + getValueFromMapOfSettings( + dbSettings, themeType + "." + Theme.THEME_KEYS.PRIMARY_COLOR.key())); + themeInput.setSecondaryColor( + getValueFromMapOfSettings( + dbSettings, themeType + "." + Theme.THEME_KEYS.SECONDARY_COLOR.key())); + themeInput.setAccentColor( + getValueFromMapOfSettings( + dbSettings, themeType + "." + Theme.THEME_KEYS.ACCENT_COLOR.key())); + themeInput.setLogoUrl( + getValueFromMapOfSettings(dbSettings, themeType + "." + Theme.THEME_KEYS.LOGO_URL.key())); + themeInput.setLogoLoginUrl( + getValueFromMapOfSettings( + dbSettings, themeType + "." + Theme.THEME_KEYS.LOGO_LOGIN_URL.key())); + themeInput.setLogoUrlCollapsed( + getValueFromMapOfSettings( + dbSettings, themeType + "." + Theme.THEME_KEYS.LOGO_URL_COLLAPSED.key())); return themeInput; } @@ -287,18 +315,23 @@ public PlatformSettings updateBasicConfigurationSettings(SettingsUpdateInput inp return findSettings(); } - public PlatformSettings updateSettingsEnterpriseEdition(SettingsEnterpriseEditionUpdateInput input) { + public PlatformSettings updateSettingsEnterpriseEdition( + SettingsEnterpriseEditionUpdateInput input) { Map dbSettings = mapOfSettings(fromIterable(this.settingRepository.findAll())); List settingsToSave = new ArrayList<>(); - settingsToSave.add(resolveFromMap(dbSettings, PLATFORM_ENTERPRISE_EDITION.key(), input.getEnterpriseEdition())); + settingsToSave.add( + resolveFromMap( + dbSettings, PLATFORM_ENTERPRISE_EDITION.key(), input.getEnterpriseEdition())); settingRepository.saveAll(settingsToSave); return findSettings(); } - public PlatformSettings updateSettingsPlatformWhitemark(SettingsPlatformWhitemarkUpdateInput input) { + public PlatformSettings updateSettingsPlatformWhitemark( + SettingsPlatformWhitemarkUpdateInput input) { Map dbSettings = mapOfSettings(fromIterable(this.settingRepository.findAll())); List settingsToSave = new ArrayList<>(); - settingsToSave.add(resolveFromMap(dbSettings, PLATFORM_WHITEMARK.key(), input.getPlatformWhitemark())); + settingsToSave.add( + resolveFromMap(dbSettings, PLATFORM_WHITEMARK.key(), input.getPlatformWhitemark())); settingRepository.saveAll(settingsToSave); return findSettings(); } @@ -306,9 +339,13 @@ public PlatformSettings updateSettingsPlatformWhitemark(SettingsPlatformWhitemar public PlatformSettings updateSettingsPolicies(PolicyInput input) { Map dbSettings = mapOfSettings(fromIterable(this.settingRepository.findAll())); List settingsToSave = new ArrayList<>(); - settingsToSave.add(resolveFromMap(dbSettings, PLATFORM_LOGIN_MESSAGE.key(), input.getLoginMessage())); - settingsToSave.add(resolveFromMap(dbSettings, PLATFORM_CONSENT_MESSAGE.key(), input.getConsentMessage())); - settingsToSave.add(resolveFromMap(dbSettings, PLATFORM_CONSENT_CONFIRM_TEXT.key(), input.getConsentConfirmText())); + settingsToSave.add( + resolveFromMap(dbSettings, PLATFORM_LOGIN_MESSAGE.key(), input.getLoginMessage())); + settingsToSave.add( + resolveFromMap(dbSettings, PLATFORM_CONSENT_MESSAGE.key(), input.getConsentMessage())); + settingsToSave.add( + resolveFromMap( + dbSettings, PLATFORM_CONSENT_CONFIRM_TEXT.key(), input.getConsentConfirmText())); settingRepository.saveAll(settingsToSave); return findSettings(); } @@ -325,27 +362,63 @@ private PlatformSettings updateTheme(ThemeInput input, String themeType) { Map dbSettings = mapOfSettings(fromIterable(this.settingRepository.findAll())); List settingsToSave = new ArrayList<>(); - settingsToSave.add(resolveFromMap(dbSettings, themeType + "." + Theme.THEME_KEYS.BACKGROUND_COLOR.key(), input.getBackgroundColor())); - settingsToSave.add(resolveFromMap(dbSettings, themeType + "." + Theme.THEME_KEYS.PAPER_COLOR.key(), input.getPaperColor())); - settingsToSave.add(resolveFromMap(dbSettings, themeType + "." + Theme.THEME_KEYS.NAVIGATION_COLOR.key(), input.getNavigationColor())); - settingsToSave.add(resolveFromMap(dbSettings, themeType + "." + Theme.THEME_KEYS.PRIMARY_COLOR.key(), input.getPrimaryColor())); - settingsToSave.add(resolveFromMap(dbSettings, themeType + "." + Theme.THEME_KEYS.SECONDARY_COLOR.key(), input.getSecondaryColor())); - settingsToSave.add(resolveFromMap(dbSettings, themeType + "." + Theme.THEME_KEYS.ACCENT_COLOR.key(), input.getAccentColor())); - settingsToSave.add(resolveFromMap(dbSettings, themeType + "." + Theme.THEME_KEYS.LOGO_URL.key(), input.getLogoUrl())); - settingsToSave.add(resolveFromMap(dbSettings, themeType + "." + Theme.THEME_KEYS.LOGO_URL_COLLAPSED.key(), input.getLogoUrlCollapsed())); - settingsToSave.add(resolveFromMap(dbSettings, themeType + "." + Theme.THEME_KEYS.LOGO_LOGIN_URL.key(), input.getLogoLoginUrl())); + settingsToSave.add( + resolveFromMap( + dbSettings, + themeType + "." + Theme.THEME_KEYS.BACKGROUND_COLOR.key(), + input.getBackgroundColor())); + settingsToSave.add( + resolveFromMap( + dbSettings, + themeType + "." + Theme.THEME_KEYS.PAPER_COLOR.key(), + input.getPaperColor())); + settingsToSave.add( + resolveFromMap( + dbSettings, + themeType + "." + Theme.THEME_KEYS.NAVIGATION_COLOR.key(), + input.getNavigationColor())); + settingsToSave.add( + resolveFromMap( + dbSettings, + themeType + "." + Theme.THEME_KEYS.PRIMARY_COLOR.key(), + input.getPrimaryColor())); + settingsToSave.add( + resolveFromMap( + dbSettings, + themeType + "." + Theme.THEME_KEYS.SECONDARY_COLOR.key(), + input.getSecondaryColor())); + settingsToSave.add( + resolveFromMap( + dbSettings, + themeType + "." + Theme.THEME_KEYS.ACCENT_COLOR.key(), + input.getAccentColor())); + settingsToSave.add( + resolveFromMap( + dbSettings, themeType + "." + Theme.THEME_KEYS.LOGO_URL.key(), input.getLogoUrl())); + settingsToSave.add( + resolveFromMap( + dbSettings, + themeType + "." + Theme.THEME_KEYS.LOGO_URL_COLLAPSED.key(), + input.getLogoUrlCollapsed())); + settingsToSave.add( + resolveFromMap( + dbSettings, + themeType + "." + Theme.THEME_KEYS.LOGO_LOGIN_URL.key(), + input.getLogoLoginUrl())); List update = new ArrayList<>(); List delete = new ArrayList<>(); - settingsToSave.forEach(setting -> { - if (StringUtils.hasText(setting.getValue())) { - update.add(setting); - } else if (StringUtils.hasText(setting.getId())) { - delete.add(setting); - } - }); - - settingRepository.deleteAllById(delete.stream().map(Setting::getId).collect(Collectors.toList())); + settingsToSave.forEach( + setting -> { + if (StringUtils.hasText(setting.getValue())) { + update.add(setting); + } else if (StringUtils.hasText(setting.getId())) { + delete.add(setting); + } + }); + + settingRepository.deleteAllById( + delete.stream().map(Setting::getId).collect(Collectors.toList())); settingRepository.saveAll(update); return findSettings(); } @@ -357,11 +430,12 @@ public void cleanMessage(@NotBlank final BannerMessage.BANNER_KEYS banner) { } public void errorMessage(@NotBlank final BannerMessage.BANNER_KEYS banner) { - Optional bannerLevelOpt = this.settingRepository.findByKey(PLATFORM_BANNER + "." + banner.key()); - if(bannerLevelOpt.isEmpty()) { - Setting bannerLevel = resolve(bannerLevelOpt, PLATFORM_BANNER + "." + banner.key(), banner.level().name()); + Optional bannerLevelOpt = + this.settingRepository.findByKey(PLATFORM_BANNER + "." + banner.key()); + if (bannerLevelOpt.isEmpty()) { + Setting bannerLevel = + resolve(bannerLevelOpt, PLATFORM_BANNER + "." + banner.key(), banner.level().name()); settingRepository.save(bannerLevel); } } - } diff --git a/openbas-api/src/main/java/io/openbas/service/ReportService.java b/openbas-api/src/main/java/io/openbas/service/ReportService.java index 4333112498..5f7e35b98b 100644 --- a/openbas-api/src/main/java/io/openbas/service/ReportService.java +++ b/openbas-api/src/main/java/io/openbas/service/ReportService.java @@ -1,5 +1,7 @@ package io.openbas.service; +import static java.time.Instant.now; + import io.openbas.database.model.*; import io.openbas.database.repository.ReportRepository; import io.openbas.database.specification.ReportSpecification; @@ -8,67 +10,74 @@ import io.openbas.rest.report.form.ReportInput; import jakarta.validation.constraints.NotBlank; import jakarta.validation.constraints.NotNull; -import lombok.RequiredArgsConstructor; -import org.springframework.stereotype.Service; - import java.util.List; import java.util.Optional; import java.util.UUID; - -import static java.time.Instant.now; +import lombok.RequiredArgsConstructor; +import org.springframework.stereotype.Service; @RequiredArgsConstructor @Service public class ReportService { - private final ReportRepository reportRepository; + private final ReportRepository reportRepository; - public Report report(@NotNull final UUID reportId) { - return this.reportRepository.findById(reportId).orElseThrow(ElementNotFoundException::new); - } + public Report report(@NotNull final UUID reportId) { + return this.reportRepository.findById(reportId).orElseThrow(ElementNotFoundException::new); + } - public List reportsFromExercise(@NotNull final String exerciseId) { - return this.reportRepository.findAll(ReportSpecification.fromExercise(exerciseId)); - } + public List reportsFromExercise(@NotNull final String exerciseId) { + return this.reportRepository.findAll(ReportSpecification.fromExercise(exerciseId)); + } - public Report updateReport(@NotNull final Report report, @NotNull final ReportInput input){ - report.setUpdateAttributes(input); - report.setUpdateDate(now()); - input.getReportInformations().forEach(i -> { - ReportInformation reportInformation = report.getReportInformations().stream() - .filter(r -> r.getReportInformationsType().equals(i.getReportInformationsType())) - .findFirst() - .orElse(null); - if (reportInformation != null) { + public Report updateReport(@NotNull final Report report, @NotNull final ReportInput input) { + report.setUpdateAttributes(input); + report.setUpdateDate(now()); + input + .getReportInformations() + .forEach( + i -> { + ReportInformation reportInformation = + report.getReportInformations().stream() + .filter( + r -> r.getReportInformationsType().equals(i.getReportInformationsType())) + .findFirst() + .orElse(null); + if (reportInformation != null) { reportInformation.setReportInformationsDisplay(i.getReportInformationsDisplay()); - } else { + } else { reportInformation = new ReportInformation(); reportInformation.setReport(report); reportInformation.setReportInformationsDisplay(i.getReportInformationsDisplay()); reportInformation.setReportInformationsType(i.getReportInformationsType()); report.getReportInformations().add(reportInformation); - } - }); - return this.reportRepository.save(report); - } + } + }); + return this.reportRepository.save(report); + } - public List updateReportInjectComment(@NotNull final Report report, @NotNull final Inject inject, @NotNull final ReportInjectCommentInput input){ - Optional reportInjectComment = this.reportRepository.findReportInjectComment(UUID.fromString(report.getId()), inject.getId()); - ReportInjectComment injectComment; - if (reportInjectComment.isPresent()) { - injectComment = reportInjectComment.get(); - injectComment.setComment(input.getComment()); - } else { - injectComment = new ReportInjectComment(); - injectComment.setInject(inject); - injectComment.setReport(report); - injectComment.setComment(input.getComment()); - report.getReportInjectsComments().add(injectComment); - } - this.reportRepository.save(report); - return report.getReportInjectsComments(); + public List updateReportInjectComment( + @NotNull final Report report, + @NotNull final Inject inject, + @NotNull final ReportInjectCommentInput input) { + Optional reportInjectComment = + this.reportRepository.findReportInjectComment( + UUID.fromString(report.getId()), inject.getId()); + ReportInjectComment injectComment; + if (reportInjectComment.isPresent()) { + injectComment = reportInjectComment.get(); + injectComment.setComment(input.getComment()); + } else { + injectComment = new ReportInjectComment(); + injectComment.setInject(inject); + injectComment.setReport(report); + injectComment.setComment(input.getComment()); + report.getReportInjectsComments().add(injectComment); } + this.reportRepository.save(report); + return report.getReportInjectsComments(); + } - public void deleteReport(@NotBlank final UUID reportId) { - this.reportRepository.deleteById(reportId); - } + public void deleteReport(@NotBlank final UUID reportId) { + this.reportRepository.deleteById(reportId); + } } diff --git a/openbas-api/src/main/java/io/openbas/service/ScenarioService.java b/openbas-api/src/main/java/io/openbas/service/ScenarioService.java index 59fef43e04..b6991d34de 100644 --- a/openbas-api/src/main/java/io/openbas/service/ScenarioService.java +++ b/openbas-api/src/main/java/io/openbas/service/ScenarioService.java @@ -1,5 +1,19 @@ package io.openbas.service; +import static io.openbas.config.SessionHelper.currentUser; +import static io.openbas.database.criteria.GenericCriteria.countQuery; +import static io.openbas.database.specification.ScenarioSpecification.findGrantedFor; +import static io.openbas.helper.StreamHelper.fromIterable; +import static io.openbas.rest.scenario.utils.ScenarioUtils.handleCustomFilter; +import static io.openbas.service.ImportService.EXPORT_ENTRY_ATTACHMENT; +import static io.openbas.service.ImportService.EXPORT_ENTRY_SCENARIO; +import static io.openbas.utils.Constants.ARTICLES; +import static io.openbas.utils.StringUtils.duplicateString; +import static io.openbas.utils.pagination.PaginationUtils.buildPaginationCriteriaBuilder; +import static io.openbas.utils.pagination.SortUtilsCriteriaBuilder.toSortCriteriaBuilder; +import static java.time.Instant.now; +import static java.util.Optional.ofNullable; + import com.fasterxml.jackson.databind.JsonNode; import com.fasterxml.jackson.databind.ObjectMapper; import com.fasterxml.jackson.databind.node.ArrayNode; @@ -31,6 +45,15 @@ import jakarta.persistence.criteria.*; import jakarta.servlet.http.HttpServletResponse; import jakarta.validation.constraints.NotBlank; +import java.io.IOException; +import java.io.InputStream; +import java.time.Instant; +import java.util.*; +import java.util.function.UnaryOperator; +import java.util.logging.Level; +import java.util.stream.Collectors; +import java.util.zip.ZipEntry; +import java.util.zip.ZipOutputStream; import lombok.RequiredArgsConstructor; import lombok.extern.java.Log; import org.apache.commons.lang3.StringUtils; @@ -46,30 +69,6 @@ import org.springframework.transaction.annotation.Transactional; import org.springframework.validation.annotation.Validated; -import java.io.IOException; -import java.io.InputStream; -import java.time.Instant; -import java.util.*; -import java.util.function.UnaryOperator; -import java.util.logging.Level; -import java.util.stream.Collectors; -import java.util.zip.ZipEntry; -import java.util.zip.ZipOutputStream; - -import static io.openbas.config.SessionHelper.currentUser; -import static io.openbas.database.criteria.GenericCriteria.countQuery; -import static io.openbas.database.specification.ScenarioSpecification.findGrantedFor; -import static io.openbas.helper.StreamHelper.fromIterable; -import static io.openbas.rest.scenario.utils.ScenarioUtils.handleCustomFilter; -import static io.openbas.service.ImportService.EXPORT_ENTRY_ATTACHMENT; -import static io.openbas.service.ImportService.EXPORT_ENTRY_SCENARIO; -import static io.openbas.utils.Constants.ARTICLES; -import static io.openbas.utils.StringUtils.duplicateString; -import static io.openbas.utils.pagination.PaginationUtils.buildPaginationCriteriaBuilder; -import static io.openbas.utils.pagination.SortUtilsCriteriaBuilder.toSortCriteriaBuilder; -import static java.time.Instant.now; -import static java.util.Optional.ofNullable; - @RequiredArgsConstructor @Service @Log @@ -82,11 +81,9 @@ public class ScenarioService { @Value("${openbas.mail.imap.username}") private String imapUsername; - @Resource - private OpenBASConfig openBASConfig; + @Resource private OpenBASConfig openBASConfig; - @PersistenceContext - private EntityManager entityManager; + @PersistenceContext private EntityManager entityManager; private final ScenarioRepository scenarioRepository; private final TeamRepository teamRepository; @@ -104,7 +101,6 @@ public class ScenarioService { private final FileService fileService; private final InjectDuplicateService injectDuplicateService; - @Transactional public Scenario createScenario(@NotNull final Scenario scenario) { if (this.imapEnabled) { @@ -128,41 +124,44 @@ public List scenarios() { return scenarios.stream().map(ScenarioSimple::fromRawScenario).toList(); } - public Page scenarios(@NotNull final SearchPaginationInput searchPaginationInput) { + public Page scenarios( + @NotNull final SearchPaginationInput searchPaginationInput) { Map> joinMap = new HashMap<>(); // Compute custom filter - UnaryOperator> deepFilterSpecification = handleCustomFilter( - searchPaginationInput - ); + UnaryOperator> deepFilterSpecification = + handleCustomFilter(searchPaginationInput); // Compute find all method - TriFunction, Specification, Pageable, Page> findAll = getFindAllFunction( - deepFilterSpecification, joinMap - ); + TriFunction< + Specification, Specification, Pageable, Page> + findAll = getFindAllFunction(deepFilterSpecification, joinMap); // Compute pagination from find all - return buildPaginationCriteriaBuilder(findAll, - searchPaginationInput, Scenario.class, joinMap); + return buildPaginationCriteriaBuilder(findAll, searchPaginationInput, Scenario.class, joinMap); } - private TriFunction, Specification, Pageable, Page> getFindAllFunction( - UnaryOperator> deepFilterSpecification, - Map> joinMap) { + private TriFunction< + Specification, Specification, Pageable, Page> + getFindAllFunction( + UnaryOperator> deepFilterSpecification, + Map> joinMap) { if (currentUser().isAdmin()) { - return (specification, specificationCount, pageable) -> this.findAllWithCriteriaBuilder( - deepFilterSpecification.apply(specification), - deepFilterSpecification.apply(specificationCount), - pageable, - joinMap - ); + return (specification, specificationCount, pageable) -> + this.findAllWithCriteriaBuilder( + deepFilterSpecification.apply(specification), + deepFilterSpecification.apply(specificationCount), + pageable, + joinMap); } else { - return (specification, specificationCount, pageable) -> this.findAllWithCriteriaBuilder( - findGrantedFor(currentUser().getId()).and(deepFilterSpecification.apply(specification)), - findGrantedFor(currentUser().getId()).and(deepFilterSpecification.apply(specificationCount)), - pageable, - joinMap - ); + return (specification, specificationCount, pageable) -> + this.findAllWithCriteriaBuilder( + findGrantedFor(currentUser().getId()) + .and(deepFilterSpecification.apply(specification)), + findGrantedFor(currentUser().getId()) + .and(deepFilterSpecification.apply(specificationCount)), + pageable, + joinMap); } } @@ -185,30 +184,25 @@ private Page findAllWithCriteriaBuilder( "array_remove", String[].class, cb.function("array_agg", String[].class, scenarioTagsJoin.get("id")), - cb.nullLiteral(String.class) - ); + cb.nullLiteral(String.class)); // Join on INJECT and INJECTOR CONTRACT Join injectsJoin = scenarioRoot.join("injects", JoinType.LEFT); joinMap.put("injects", injectsJoin); Join injectorsContractsJoin = injectsJoin.join("injectorContract", JoinType.LEFT); joinMap.put("injects.injectorContract", injectorsContractsJoin); Expression platformExpression = - cb.function( - "array_union_agg", - String[].class, - injectorsContractsJoin.get("platforms") - ); + cb.function("array_union_agg", String[].class, injectorsContractsJoin.get("platforms")); // SELECT cq.multiselect( - scenarioRoot.get("id").alias("scenario_id"), - scenarioRoot.get("name").alias("scenario_name"), - scenarioRoot.get("severity").alias("scenario_severity"), - scenarioRoot.get("category").alias("scenario_category"), - scenarioRoot.get("recurrence").alias("scenario_recurrence"), - scenarioRoot.get("updatedAt").alias("scenario_updated_at"), - tagIdsExpression.alias("scenario_tags"), - platformExpression.alias("scenario_platforms") - ).distinct(true); + scenarioRoot.get("id").alias("scenario_id"), + scenarioRoot.get("name").alias("scenario_name"), + scenarioRoot.get("severity").alias("scenario_severity"), + scenarioRoot.get("category").alias("scenario_category"), + scenarioRoot.get("recurrence").alias("scenario_recurrence"), + scenarioRoot.get("updatedAt").alias("scenario_updated_at"), + tagIdsExpression.alias("scenario_tags"), + platformExpression.alias("scenario_platforms")) + .distinct(true); // Group By cq.groupBy(scenarioRoot.get("id")); @@ -232,19 +226,20 @@ private Page findAllWithCriteriaBuilder( query.setMaxResults(pageable.getPageSize()); // -- EXECUTION -- - List scenarios = query.getResultList() - .stream() - .map(tuple -> new RawPaginationScenario( - tuple.get("scenario_id", String.class), - tuple.get("scenario_name", String.class), - tuple.get("scenario_severity", Scenario.SEVERITY.class), - tuple.get("scenario_category", String.class), - tuple.get("scenario_recurrence", String.class), - tuple.get("scenario_updated_at", Instant.class), - tuple.get("scenario_tags", String[].class), - tuple.get("scenario_platforms", String[].class) - )) - .toList(); + List scenarios = + query.getResultList().stream() + .map( + tuple -> + new RawPaginationScenario( + tuple.get("scenario_id", String.class), + tuple.get("scenario_name", String.class), + tuple.get("scenario_severity", Scenario.SEVERITY.class), + tuple.get("scenario_category", String.class), + tuple.get("scenario_recurrence", String.class), + tuple.get("scenario_updated_at", Instant.class), + tuple.get("scenario_tags", String[].class), + tuple.get("scenario_platforms", String[].class))) + .toList(); // -- Count Query -- Long total = countQuery(cb, this.entityManager, Scenario.class, specificationCount); @@ -252,41 +247,36 @@ private Page findAllWithCriteriaBuilder( return new PageImpl<>(scenarios, pageable, total); } - /** - * Scenario is recurring AND start date is before now AND end date is after now - */ + /** Scenario is recurring AND start date is before now AND end date is after now */ public List recurringScenarios(@NotNull final Instant instant) { return this.scenarioRepository.findAll( ScenarioSpecification.isRecurring() .and(ScenarioSpecification.recurrenceStartDateBefore(instant)) - .and(ScenarioSpecification.recurrenceStopDateAfter(instant)) - ); + .and(ScenarioSpecification.recurrenceStopDateAfter(instant))); } - /** - * Scenario is recurring AND start date is before now OR stop date is before now - */ + /** Scenario is recurring AND start date is before now OR stop date is before now */ public List potentialOutdatedRecurringScenario(@NotNull final Instant instant) { return this.scenarioRepository.findAll( ScenarioSpecification.isRecurring() .and( ScenarioSpecification.recurrenceStartDateBefore(instant) - .or(ScenarioSpecification.recurrenceStopDateBefore(instant)) - ) - ); + .or(ScenarioSpecification.recurrenceStopDateBefore(instant)))); } public Scenario scenario(@NotBlank final String scenarioId) { - return this.scenarioRepository.findById(scenarioId) + return this.scenarioRepository + .findById(scenarioId) .orElseThrow(() -> new ElementNotFoundException("Scenario not found")); } @Transactional(readOnly = true) - public ExerciseSimple latestExerciseByExternalReference(@NotBlank final String scenarioExternalReference) { - Optional latestEndedExercise = scenarioRepository.rawAllByExternalReference(scenarioExternalReference) - .stream() - .filter(rawExercise -> rawExercise.getExercise_end_date() != null) - .max(Comparator.comparing(RawExerciseSimple::getExercise_end_date)); + public ExerciseSimple latestExerciseByExternalReference( + @NotBlank final String scenarioExternalReference) { + Optional latestEndedExercise = + scenarioRepository.rawAllByExternalReference(scenarioExternalReference).stream() + .filter(rawExercise -> rawExercise.getExercise_end_date() != null) + .max(Comparator.comparing(RawExerciseSimple::getExercise_end_date)); return latestEndedExercise .map(exerciseMapper::fromRawExerciseSimple) @@ -333,10 +323,10 @@ public void exportScenario( scenarioFileExport.setLessonsCategories(scenario.getLessonsCategories()); objectMapper.addMixIn(LessonsCategory.class, ExerciseExportMixins.LessonsCategory.class); // Add Lessons Questions - List lessonsQuestions = scenario.getLessonsCategories() - .stream() - .flatMap(category -> category.getQuestions().stream()) - .toList(); + List lessonsQuestions = + scenario.getLessonsCategories().stream() + .flatMap(category -> category.getQuestions().stream()) + .toList(); scenarioFileExport.setLessonsQuestions(lessonsQuestions); objectMapper.addMixIn(LessonsQuestion.class, ExerciseExportMixins.LessonsQuestion.class); // Add Variables @@ -351,71 +341,88 @@ public void exportScenario( // Add Documents scenarioFileExport.setDocuments(scenario.getDocuments()); objectMapper.addMixIn(Document.class, ExerciseExportMixins.Document.class); - scenarioTags.addAll(scenario.getDocuments().stream().flatMap(doc -> doc.getTags().stream()).toList()); - List documentIds = new ArrayList<>(scenario.getDocuments().stream().map(Document::getId).toList()); + scenarioTags.addAll( + scenario.getDocuments().stream().flatMap(doc -> doc.getTags().stream()).toList()); + List documentIds = + new ArrayList<>(scenario.getDocuments().stream().map(Document::getId).toList()); if (isWithTeams) { // Add Teams scenarioFileExport.setTeams(scenario.getTeams()); - objectMapper.addMixIn(Team.class, + objectMapper.addMixIn( + Team.class, isWithPlayers ? ExerciseExportMixins.Team.class : ExerciseExportMixins.EmptyTeam.class); - scenarioTags.addAll(scenario.getTeams().stream().flatMap(team -> team.getTags().stream()).toList()); + scenarioTags.addAll( + scenario.getTeams().stream().flatMap(team -> team.getTags().stream()).toList()); } if (isWithPlayers) { // Add players - List players = scenario.getTeams().stream().flatMap(team -> team.getUsers().stream()).distinct().toList(); + List players = + scenario.getTeams().stream() + .flatMap(team -> team.getUsers().stream()) + .distinct() + .toList(); scenarioFileExport.setUsers(players); objectMapper.addMixIn(User.class, ExerciseExportMixins.User.class); scenarioTags.addAll(players.stream().flatMap(user -> user.getTags().stream()).toList()); // organizations - List organizations = players.stream() - .map(User::getOrganization) - .filter(Objects::nonNull) - .toList(); + List organizations = + players.stream().map(User::getOrganization).filter(Objects::nonNull).toList(); scenarioFileExport.setOrganizations(organizations); objectMapper.addMixIn(Organization.class, ExerciseExportMixins.Organization.class); scenarioTags.addAll(organizations.stream().flatMap(org -> org.getTags().stream()).toList()); } else { - objectMapper.addMixIn(ExerciseFileExport.class, ScenarioExportMixins.ScenarioWithoutPlayers.class); + objectMapper.addMixIn( + ExerciseFileExport.class, ScenarioExportMixins.ScenarioWithoutPlayers.class); } // Add Injects objectMapper.addMixIn(Inject.class, ExerciseExportMixins.Inject.class); scenarioFileExport.setInjects(scenario.getInjects()); - scenarioTags.addAll(scenario.getInjects().stream().flatMap(inject -> inject.getTags().stream()).toList()); + scenarioTags.addAll( + scenario.getInjects().stream().flatMap(inject -> inject.getTags().stream()).toList()); // Add Articles objectMapper.addMixIn(Article.class, ExerciseExportMixins.Article.class); scenarioFileExport.setArticles(scenario.getArticles()); // Add Channels objectMapper.addMixIn(Channel.class, ExerciseExportMixins.Channel.class); - List channels = scenario.getArticles().stream().map(Article::getChannel).distinct().toList(); + List channels = + scenario.getArticles().stream().map(Article::getChannel).distinct().toList(); scenarioFileExport.setChannels(channels); documentIds.addAll( - channels.stream().flatMap(channel -> channel.getLogos().stream()).map(Document::getId).toList() - ); + channels.stream() + .flatMap(channel -> channel.getLogos().stream()) + .map(Document::getId) + .toList()); // Add Challenges objectMapper.addMixIn(Challenge.class, ExerciseExportMixins.Challenge.class); - List challenges = fromIterable(this.challengeService.getScenarioChallenges(scenario)); + List challenges = + fromIterable(this.challengeService.getScenarioChallenges(scenario)); scenarioFileExport.setChallenges(challenges); - scenarioTags.addAll(challenges.stream().flatMap(challenge -> challenge.getTags().stream()).toList()); + scenarioTags.addAll( + challenges.stream().flatMap(challenge -> challenge.getTags().stream()).toList()); documentIds.addAll( - challenges.stream().flatMap(challenge -> challenge.getDocuments().stream()).map(Document::getId).toList()); + challenges.stream() + .flatMap(challenge -> challenge.getDocuments().stream()) + .map(Document::getId) + .toList()); // Tags scenarioFileExport.setTags(scenarioTags.stream().distinct().toList()); objectMapper.addMixIn(Tag.class, ExerciseExportMixins.Tag.class); // Build the response - String infos = "(" + - (isWithTeams ? "with_teams" : "no_teams") + - " & " + - (isWithPlayers ? "with_players" : "no_players") + - " & " + - (isWithVariableValues ? "with_variable_values" : "no_variable_values") - + ")"; + String infos = + "(" + + (isWithTeams ? "with_teams" : "no_teams") + + " & " + + (isWithPlayers ? "with_players" : "no_players") + + " & " + + (isWithVariableValues ? "with_variable_values" : "no_variable_values") + + ")"; String zipName = (scenario.getName() + "_" + now().toString()) + "_" + infos + ".zip"; response.addHeader(HttpHeaders.CONTENT_DISPOSITION, "attachment; filename=" + zipName); response.addHeader(HttpHeaders.CONTENT_TYPE, "application/zip"); @@ -424,32 +431,37 @@ public void exportScenario( ZipEntry zipEntry = new ZipEntry(scenario.getName() + ".json"); zipEntry.setComment(EXPORT_ENTRY_SCENARIO); zipExport.putNextEntry(zipEntry); - zipExport.write(objectMapper.writerWithDefaultPrettyPrinter().writeValueAsBytes(scenarioFileExport)); + zipExport.write( + objectMapper.writerWithDefaultPrettyPrinter().writeValueAsBytes(scenarioFileExport)); zipExport.closeEntry(); // Add the documents - documentIds.stream().distinct().forEach(docId -> { - Document doc = this.documentRepository.findById(docId).orElseThrow(); - Optional docStream = this.fileService.getFile(doc); - if (docStream.isPresent()) { - try { - ZipEntry zipDoc = new ZipEntry(doc.getTarget()); - zipDoc.setComment(EXPORT_ENTRY_ATTACHMENT); - byte[] data = docStream.get().readAllBytes(); - zipExport.putNextEntry(zipDoc); - zipExport.write(data); - zipExport.closeEntry(); - } catch (IOException e) { - log.log(Level.SEVERE, e.getMessage(), e); - } - } - }); + documentIds.stream() + .distinct() + .forEach( + docId -> { + Document doc = this.documentRepository.findById(docId).orElseThrow(); + Optional docStream = this.fileService.getFile(doc); + if (docStream.isPresent()) { + try { + ZipEntry zipDoc = new ZipEntry(doc.getTarget()); + zipDoc.setComment(EXPORT_ENTRY_ATTACHMENT); + byte[] data = docStream.get().readAllBytes(); + zipExport.putNextEntry(zipDoc); + zipExport.write(data); + zipExport.closeEntry(); + } catch (IOException e) { + log.log(Level.SEVERE, e.getMessage(), e); + } + } + }); zipExport.finish(); zipExport.close(); } // -- TEAMS -- - public Iterable addTeams(@NotBlank final String scenarioId, @NotNull final List teamIds) { + public Iterable addTeams( + @NotBlank final String scenarioId, @NotNull final List teamIds) { Scenario scenario = this.scenario(scenarioId); List teams = scenario.getTeams(); List teamsToAdd = fromIterable(this.teamRepository.findAllById(teamIds)); @@ -460,9 +472,11 @@ public Iterable addTeams(@NotBlank final String scenarioId, @NotNull final return teamsToAdd; } - public Iterable removeTeams(@NotBlank final String scenarioId, @NotNull final List teamIds) { + public Iterable removeTeams( + @NotBlank final String scenarioId, @NotNull final List teamIds) { Scenario scenario = this.scenario(scenarioId); - List teams = scenario.getTeams().stream().filter(team -> !teamIds.contains(team.getId())).toList(); + List teams = + scenario.getTeams().stream().filter(team -> !teamIds.contains(team.getId())).toList(); scenario.setTeams(new ArrayList<>(teams)); this.updateScenario(scenario); // Remove all association between users / exercises / teams @@ -470,7 +484,8 @@ public Iterable removeTeams(@NotBlank final String scenarioId, @NotNull fi return teamRepository.findAllById(teamIds); } - public Iterable replaceTeams(@NotBlank final String scenarioId, @NotNull final List teamIds) { + public Iterable replaceTeams( + @NotBlank final String scenarioId, @NotNull final List teamIds) { Scenario scenario = this.scenario(scenarioId); // Replace teams from exercise List teams = fromIterable(this.teamRepository.findAllById(teamIds)); @@ -479,29 +494,35 @@ public Iterable replaceTeams(@NotBlank final String scenarioId, @NotNull f return teams; } - public Scenario enablePlayers(@NotBlank final String scenarioId, @NotBlank final String teamId, + public Scenario enablePlayers( + @NotBlank final String scenarioId, + @NotBlank final String teamId, @NotNull final List playerIds) { Scenario scenario = this.scenario(scenarioId); Team team = this.teamRepository.findById(teamId).orElseThrow(); - playerIds.forEach(playerId -> { - ScenarioTeamUser scenarioTeamUser = new ScenarioTeamUser(); - scenarioTeamUser.setScenario(scenario); - scenarioTeamUser.setTeam(team); - scenarioTeamUser.setUser(this.userRepository.findById(playerId).orElseThrow()); - this.scenarioTeamUserRepository.save(scenarioTeamUser); - }); + playerIds.forEach( + playerId -> { + ScenarioTeamUser scenarioTeamUser = new ScenarioTeamUser(); + scenarioTeamUser.setScenario(scenario); + scenarioTeamUser.setTeam(team); + scenarioTeamUser.setUser(this.userRepository.findById(playerId).orElseThrow()); + this.scenarioTeamUserRepository.save(scenarioTeamUser); + }); return scenario; } - public Scenario disablePlayers(@NotBlank final String scenarioId, @NotBlank final String teamId, + public Scenario disablePlayers( + @NotBlank final String scenarioId, + @NotBlank final String teamId, @NotNull final List playerIds) { - playerIds.forEach(playerId -> { - ScenarioTeamUserId scenarioTeamUserId = new ScenarioTeamUserId(); - scenarioTeamUserId.setScenarioId(scenarioId); - scenarioTeamUserId.setTeamId(teamId); - scenarioTeamUserId.setUserId(playerId); - this.scenarioTeamUserRepository.deleteById(scenarioTeamUserId); - }); + playerIds.forEach( + playerId -> { + ScenarioTeamUserId scenarioTeamUserId = new ScenarioTeamUserId(); + scenarioTeamUserId.setScenarioId(scenarioId); + scenarioTeamUserId.setTeamId(teamId); + scenarioTeamUserId.setUserId(playerId); + this.scenarioTeamUserRepository.deleteById(scenarioTeamUserId); + }); return this.scenario(scenarioId); } @@ -522,33 +543,41 @@ public Scenario getDuplicateScenario(@NotBlank String scenarioId) { throw new ElementNotFoundException(); } - private void getListOfScenarioTeams(@NotNull Scenario scenario, @NotNull Scenario scenarioOrigin) { + private void getListOfScenarioTeams( + @NotNull Scenario scenario, @NotNull Scenario scenarioOrigin) { Map contextualTeams = new HashMap<>(); List scenarioTeams = new ArrayList<>(); - scenarioOrigin.getTeams().forEach(scenarioTeam -> { - if (scenarioTeam.getContextual()) { - Team team = teamService.copyContextualTeam(scenarioTeam); - Team teamSaved = this.teamRepository.save(team); - scenarioTeams.add(teamSaved); - contextualTeams.put(scenarioTeam.getId(), teamSaved); - } else { - scenarioTeams.add(scenarioTeam); - } - }); + scenarioOrigin + .getTeams() + .forEach( + scenarioTeam -> { + if (scenarioTeam.getContextual()) { + Team team = teamService.copyContextualTeam(scenarioTeam); + Team teamSaved = this.teamRepository.save(team); + scenarioTeams.add(teamSaved); + contextualTeams.put(scenarioTeam.getId(), teamSaved); + } else { + scenarioTeams.add(scenarioTeam); + } + }); scenario.setTeams(new ArrayList<>(scenarioTeams)); List scenarioInjects = scenario.getInjects(); - scenarioInjects.forEach(scenarioInject -> { - List teams = new ArrayList<>(); - scenarioInject.getTeams().forEach(team -> { - if (team.getContextual()) { - teams.add(contextualTeams.get(team.getId())); - } else { - teams.add(team); - } - }); - scenarioInject.setTeams(teams); - }); + scenarioInjects.forEach( + scenarioInject -> { + List teams = new ArrayList<>(); + scenarioInject + .getTeams() + .forEach( + team -> { + if (team.getContextual()) { + teams.add(contextualTeams.get(team.getId())); + } else { + teams.add(team); + } + }); + scenarioInject.setTeams(teams); + }); } private Scenario copyScenario(Scenario scenario) { @@ -573,31 +602,39 @@ private Scenario copyScenario(Scenario scenario) { return scenarioDuplicate; } - private void getListOfDuplicatedInjects(@NotNull Scenario scenario, @NotNull Scenario scenarioOrign) { - Set injectListForScenario = scenarioOrign.getInjects() - .stream().map(inject -> injectDuplicateService.createInjectForScenario(scenario.getId(), inject.getId(), false)) - .collect(Collectors.toSet()); + private void getListOfDuplicatedInjects( + @NotNull Scenario scenario, @NotNull Scenario scenarioOrign) { + Set injectListForScenario = + scenarioOrign.getInjects().stream() + .map( + inject -> + injectDuplicateService.createInjectForScenario( + scenario.getId(), inject.getId(), false)) + .collect(Collectors.toSet()); scenario.setInjects(new HashSet<>(injectListForScenario)); } private void getListOfArticles(@NotNull Scenario scenario, @NotNull Scenario scenarioOrign) { Map mapIdArticleOriginNew = new HashMap<>(); List
articleList = new ArrayList<>(); - scenarioOrign.getArticles().forEach(article -> { - Article scenarioArticle = new Article(); - scenarioArticle.setName(article.getName()); - scenarioArticle.setContent(article.getContent()); - scenarioArticle.setAuthor(article.getAuthor()); - scenarioArticle.setShares(article.getShares()); - scenarioArticle.setLikes(article.getLikes()); - scenarioArticle.setComments(article.getComments()); - scenarioArticle.setChannel(article.getChannel()); - scenarioArticle.setDocuments(new ArrayList<>(article.getDocuments())); - scenarioArticle.setScenario(scenario); - Article save = articleRepository.save(scenarioArticle); - articleList.add(save); - mapIdArticleOriginNew.put(article.getId(), scenarioArticle.getId()); - }); + scenarioOrign + .getArticles() + .forEach( + article -> { + Article scenarioArticle = new Article(); + scenarioArticle.setName(article.getName()); + scenarioArticle.setContent(article.getContent()); + scenarioArticle.setAuthor(article.getAuthor()); + scenarioArticle.setShares(article.getShares()); + scenarioArticle.setLikes(article.getLikes()); + scenarioArticle.setComments(article.getComments()); + scenarioArticle.setChannel(article.getChannel()); + scenarioArticle.setDocuments(new ArrayList<>(article.getDocuments())); + scenarioArticle.setScenario(scenario); + Article save = articleRepository.save(scenarioArticle); + articleList.add(save); + mapIdArticleOriginNew.put(article.getId(), scenarioArticle.getId()); + }); scenario.setArticles(articleList); for (Inject inject : scenario.getInjects()) { if (ofNullable(inject.getContent()).map(c -> c.has(ARTICLES)).orElse(Boolean.FALSE)) { @@ -619,15 +656,19 @@ private void getListOfArticles(@NotNull Scenario scenario, @NotNull Scenario sce private void getListOfVariables(Scenario scenario, Scenario scenarioOrigin) { List variables = variableService.variablesFromScenario(scenarioOrigin.getId()); - List variableList = variables.stream().map(variable -> { - Variable variable1 = new Variable(); - variable1.setKey(variable.getKey()); - variable1.setDescription(variable.getDescription()); - variable1.setValue(variable.getValue()); - variable1.setType(variable.getType()); - variable1.setScenario(scenario); - return variable1; - }).toList(); + List variableList = + variables.stream() + .map( + variable -> { + Variable variable1 = new Variable(); + variable1.setKey(variable.getKey()); + variable1.setDescription(variable.getDescription()); + variable1.setValue(variable.getValue()); + variable1.setType(variable.getType()); + variable1.setScenario(scenario); + return variable1; + }) + .toList(); variableService.createVariables(variableList); } @@ -690,5 +731,4 @@ private void getObjectives(Scenario scenario, Scenario scenarioOrigin) { } scenario.setObjectives(duplicatedObjectives); } - } diff --git a/openbas-api/src/main/java/io/openbas/service/ScenarioToExerciseService.java b/openbas-api/src/main/java/io/openbas/service/ScenarioToExerciseService.java index 7669482a2c..74801ecf4f 100644 --- a/openbas-api/src/main/java/io/openbas/service/ScenarioToExerciseService.java +++ b/openbas-api/src/main/java/io/openbas/service/ScenarioToExerciseService.java @@ -11,15 +11,14 @@ import jakarta.annotation.Resource; import jakarta.validation.constraints.NotBlank; import jakarta.validation.constraints.NotNull; +import java.lang.reflect.InvocationTargetException; +import java.time.Instant; +import java.util.*; import lombok.RequiredArgsConstructor; import org.apache.commons.beanutils.BeanUtils; import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; -import java.lang.reflect.InvocationTargetException; -import java.time.Instant; -import java.util.*; - @Service @RequiredArgsConstructor public class ScenarioToExerciseService { @@ -37,14 +36,11 @@ public class ScenarioToExerciseService { private final InjectDocumentRepository injectDocumentRepository; private final VariableService variableService; private final TeamService teamService; - @Resource - protected ObjectMapper mapper; + @Resource protected ObjectMapper mapper; @Transactional(rollbackFor = Exception.class) public Exercise toExercise( - @NotBlank final Scenario scenario, - @Nullable final Instant start, - final boolean isRunning) { + @NotBlank final Scenario scenario, @Nullable final Instant start, final boolean isRunning) { Exercise exercise = new Exercise(); exercise.setScenario(scenario); exercise.setName(scenario.getName()); @@ -68,86 +64,103 @@ public Exercise toExercise( Exercise exerciseSaved = this.exerciseRepository.save(exercise); // Grants - List exerciseGrants = scenario.getGrants().stream() - .map(scenarioGrant -> { - Grant grant = new Grant(); - grant.setName(scenarioGrant.getName()); - grant.setGroup(scenarioGrant.getGroup()); - grant.setExercise(exerciseSaved); - return this.grantRepository.save(grant); - }) - .toList(); + List exerciseGrants = + scenario.getGrants().stream() + .map( + scenarioGrant -> { + Grant grant = new Grant(); + grant.setName(scenarioGrant.getName()); + grant.setGroup(scenarioGrant.getGroup()); + grant.setExercise(exerciseSaved); + return this.grantRepository.save(grant); + }) + .toList(); exerciseSaved.setGrants(exerciseGrants); // Teams Map contextualTeams = new HashMap<>(); - scenario.getTeams().forEach(scenarioTeam -> { - if (scenarioTeam.getContextual()) { - Team team = teamService.copyContextualTeam(scenarioTeam); - team.setExercises(new ArrayList<>() {{ - add(exerciseSaved); - }}); - Team teamSaved = this.teamRepository.save(team); - contextualTeams.put(scenarioTeam.getId(), teamSaved); - } else { - List exercises = scenarioTeam.getExercises(); - exercises.add(exercise); - scenarioTeam.setExercises(exercises); - this.teamRepository.save(scenarioTeam); - } - }); + scenario + .getTeams() + .forEach( + scenarioTeam -> { + if (scenarioTeam.getContextual()) { + Team team = teamService.copyContextualTeam(scenarioTeam); + team.setExercises( + new ArrayList<>() { + { + add(exerciseSaved); + } + }); + Team teamSaved = this.teamRepository.save(team); + contextualTeams.put(scenarioTeam.getId(), teamSaved); + } else { + List exercises = scenarioTeam.getExercises(); + exercises.add(exercise); + scenarioTeam.setExercises(exercises); + this.teamRepository.save(scenarioTeam); + } + }); // TeamUsers - List exerciseTeamUsers = scenario.getTeamUsers().stream() - .map(scenarioTeamUser -> { - ExerciseTeamUser exerciseTeamUser = new ExerciseTeamUser(); - exerciseTeamUser.setExercise(exerciseSaved); - exerciseTeamUser.setUser(scenarioTeamUser.getUser()); - exerciseTeamUser.setTeam(computeTeam(scenarioTeamUser.getTeam(), contextualTeams)); - return exerciseTeamUser; - }) - .toList(); + List exerciseTeamUsers = + scenario.getTeamUsers().stream() + .map( + scenarioTeamUser -> { + ExerciseTeamUser exerciseTeamUser = new ExerciseTeamUser(); + exerciseTeamUser.setExercise(exerciseSaved); + exerciseTeamUser.setUser(scenarioTeamUser.getUser()); + exerciseTeamUser.setTeam( + computeTeam(scenarioTeamUser.getTeam(), contextualTeams)); + return exerciseTeamUser; + }) + .toList(); this.exerciseTeamUserRepository.saveAll(exerciseTeamUsers); // Objectives List scenarioObjectives = scenario.getObjectives(); - List exerciseObjectives = scenarioObjectives.stream() - .map(scenarioObjective -> { - Objective exerciseObjective = new Objective(); - exerciseObjective.setExercise(exerciseSaved); - exerciseObjective.setTitle(scenarioObjective.getTitle()); - exerciseObjective.setDescription(scenarioObjective.getDescription()); - exerciseObjective.setPriority(scenarioObjective.getPriority()); - return exerciseObjective; - }) - .toList(); + List exerciseObjectives = + scenarioObjectives.stream() + .map( + scenarioObjective -> { + Objective exerciseObjective = new Objective(); + exerciseObjective.setExercise(exerciseSaved); + exerciseObjective.setTitle(scenarioObjective.getTitle()); + exerciseObjective.setDescription(scenarioObjective.getDescription()); + exerciseObjective.setPriority(scenarioObjective.getPriority()); + return exerciseObjective; + }) + .toList(); this.objectiveRepository.saveAll(exerciseObjectives); // Documents - List scenarioDocuments = addExerciseToDocuments(scenario.getDocuments(), exerciseSaved); + List scenarioDocuments = + addExerciseToDocuments(scenario.getDocuments(), exerciseSaved); this.documentRepository.saveAll(scenarioDocuments); // Articles Map articles = new HashMap<>(); List
scenarioArticles = scenario.getArticles(); - List
exerciseArticles = scenarioArticles.stream() - .map(scenarioArticle -> { - Article exerciseArticle = new Article(); - exerciseArticle.setName(scenarioArticle.getName()); - exerciseArticle.setContent(scenarioArticle.getContent()); - exerciseArticle.setAuthor(scenarioArticle.getAuthor()); - exerciseArticle.setShares(scenarioArticle.getShares()); - exerciseArticle.setLikes(scenarioArticle.getLikes()); - exerciseArticle.setComments(scenarioArticle.getComments()); - exerciseArticle.setExercise(exerciseSaved); - exerciseArticle.setChannel(scenarioArticle.getChannel()); - - List articleDocuments = addExerciseToDocuments(scenarioArticle.getDocuments(), exerciseSaved); - exerciseArticle.setDocuments(articleDocuments); - articles.put(scenarioArticle.getId(), exerciseArticle); - return exerciseArticle; - }) - .toList(); + List
exerciseArticles = + scenarioArticles.stream() + .map( + scenarioArticle -> { + Article exerciseArticle = new Article(); + exerciseArticle.setName(scenarioArticle.getName()); + exerciseArticle.setContent(scenarioArticle.getContent()); + exerciseArticle.setAuthor(scenarioArticle.getAuthor()); + exerciseArticle.setShares(scenarioArticle.getShares()); + exerciseArticle.setLikes(scenarioArticle.getLikes()); + exerciseArticle.setComments(scenarioArticle.getComments()); + exerciseArticle.setExercise(exerciseSaved); + exerciseArticle.setChannel(scenarioArticle.getChannel()); + + List articleDocuments = + addExerciseToDocuments(scenarioArticle.getDocuments(), exerciseSaved); + exerciseArticle.setDocuments(articleDocuments); + articles.put(scenarioArticle.getId(), exerciseArticle); + return exerciseArticle; + }) + .toList(); this.articleRepository.saveAll(exerciseArticles); // Lessons @@ -155,147 +168,167 @@ public Exercise toExercise( // Lessons categories List scenarioLessonCategories = scenario.getLessonsCategories(); - scenarioLessonCategories.forEach(scenarioLessonCategory -> { - LessonsCategory exerciseLessonCategory = new LessonsCategory(); - exerciseLessonCategory.setExercise(exerciseSaved); - exerciseLessonCategory.setName(scenarioLessonCategory.getName()); - exerciseLessonCategory.setDescription(scenarioLessonCategory.getDescription()); - exerciseLessonCategory.setOrder(scenarioLessonCategory.getOrder()); - - // Teams - List teams = new ArrayList<>(); - scenarioLessonCategory.getTeams().forEach(team -> teams.add(computeTeam(team, contextualTeams))); - exerciseLessonCategory.setTeams(teams); - - LessonsCategory exerciseLessonCategorySaved = this.lessonsCategoryRepository.save(exerciseLessonCategory); - - // Lessons questions - List exerciseLessonsQuestions = scenarioLessonCategory.getQuestions() - .stream() - .map(scenarioLessonsQuestion -> { - LessonsQuestion exerciseLessonsQuestion = new LessonsQuestion(); - exerciseLessonsQuestion.setContent(scenarioLessonsQuestion.getContent()); - exerciseLessonsQuestion.setExplanation(scenarioLessonsQuestion.getExplanation()); - exerciseLessonsQuestion.setOrder(scenarioLessonsQuestion.getOrder()); - exerciseLessonsQuestion.setCategory(exerciseLessonCategorySaved); - return exerciseLessonsQuestion; - }) - .toList(); - this.lessonsQuestionRepository.saveAll(exerciseLessonsQuestions); - }); + scenarioLessonCategories.forEach( + scenarioLessonCategory -> { + LessonsCategory exerciseLessonCategory = new LessonsCategory(); + exerciseLessonCategory.setExercise(exerciseSaved); + exerciseLessonCategory.setName(scenarioLessonCategory.getName()); + exerciseLessonCategory.setDescription(scenarioLessonCategory.getDescription()); + exerciseLessonCategory.setOrder(scenarioLessonCategory.getOrder()); + + // Teams + List teams = new ArrayList<>(); + scenarioLessonCategory + .getTeams() + .forEach(team -> teams.add(computeTeam(team, contextualTeams))); + exerciseLessonCategory.setTeams(teams); + + LessonsCategory exerciseLessonCategorySaved = + this.lessonsCategoryRepository.save(exerciseLessonCategory); + + // Lessons questions + List exerciseLessonsQuestions = + scenarioLessonCategory.getQuestions().stream() + .map( + scenarioLessonsQuestion -> { + LessonsQuestion exerciseLessonsQuestion = new LessonsQuestion(); + exerciseLessonsQuestion.setContent(scenarioLessonsQuestion.getContent()); + exerciseLessonsQuestion.setExplanation( + scenarioLessonsQuestion.getExplanation()); + exerciseLessonsQuestion.setOrder(scenarioLessonsQuestion.getOrder()); + exerciseLessonsQuestion.setCategory(exerciseLessonCategorySaved); + return exerciseLessonsQuestion; + }) + .toList(); + this.lessonsQuestionRepository.saveAll(exerciseLessonsQuestions); + }); // Injects List scenarioInjects = scenario.getInjects(); Map mapExerciseInjectsByScenarioInject = new HashMap<>(); - scenarioInjects.forEach(scenarioInject -> { - Inject exerciseInject = new Inject(); - exerciseInject.setTitle(scenarioInject.getTitle()); - exerciseInject.setDescription(scenarioInject.getDescription()); - exerciseInject.setInjectorContract(scenarioInject.getInjectorContract().orElse(null)); - exerciseInject.setCountry(scenarioInject.getCountry()); - exerciseInject.setCity(scenarioInject.getCity()); - exerciseInject.setEnabled(scenarioInject.isEnabled()); - exerciseInject.setAllTeams(scenarioInject.isAllTeams()); - exerciseInject.setExercise(exerciseSaved); - exerciseInject.setDependsDuration(scenarioInject.getDependsDuration()); - exerciseInject.setUser(scenarioInject.getUser()); - exerciseInject.setStatus(scenarioInject.getStatus().orElse(null)); - exerciseInject.setTags(CopyObjectListUtils.copy(scenarioInject.getTags(), Tag.class)); - exerciseInject.setContent(scenarioInject.getContent()); - - // Content - scenarioInject.getInjectorContract().ifPresentOrElse(injectorContract -> { - if (ChannelContract.TYPE.equals(injectorContract.getInjector().getType())) { - try { - ChannelContent content = mapper.treeToValue(scenarioInject.getContent(), ChannelContent.class); - content.setArticles( - content.getArticles().stream().map(articleId -> articles.get(articleId).getId()).toList() - ); - exerciseInject.setContent(mapper.valueToTree(content)); - } catch (JsonProcessingException e) { - throw new RuntimeException(e); - } - } - }, () -> exerciseInject.setContent(scenarioInject.getContent()) - ); - - // Teams - List teams = new ArrayList<>(); - scenarioInject.getTeams().forEach(team -> teams.add(computeTeam(team, contextualTeams))); - exerciseInject.setTeams(teams); - - // Assets & Asset Groups - exerciseInject.setAssets(CopyObjectListUtils.copy(scenarioInject.getAssets(), Asset.class)); - exerciseInject.setAssetGroups(CopyObjectListUtils.copy(scenarioInject.getAssetGroups(), AssetGroup.class)); - Inject injectSaved = this.injectRepository.save(exerciseInject); - - mapExerciseInjectsByScenarioInject.put(scenarioInject.getId(), injectSaved); - - // Documents - List exerciseInjectDocuments = new ArrayList<>(); - scenarioInject.getDocuments().forEach(injectDocument -> { - InjectDocument exerciseInjectDocument = new InjectDocument(); - exerciseInjectDocument.setInject(injectSaved); - exerciseInjectDocument.setDocument(injectDocument.getDocument()); - exerciseInjectDocument.setAttached(injectDocument.isAttached()); - exerciseInjectDocuments.add(exerciseInjectDocument); - }); - this.injectDocumentRepository.saveAll(exerciseInjectDocuments); - }); + scenarioInjects.forEach( + scenarioInject -> { + Inject exerciseInject = new Inject(); + exerciseInject.setTitle(scenarioInject.getTitle()); + exerciseInject.setDescription(scenarioInject.getDescription()); + exerciseInject.setInjectorContract(scenarioInject.getInjectorContract().orElse(null)); + exerciseInject.setCountry(scenarioInject.getCountry()); + exerciseInject.setCity(scenarioInject.getCity()); + exerciseInject.setEnabled(scenarioInject.isEnabled()); + exerciseInject.setAllTeams(scenarioInject.isAllTeams()); + exerciseInject.setExercise(exerciseSaved); + exerciseInject.setDependsDuration(scenarioInject.getDependsDuration()); + exerciseInject.setUser(scenarioInject.getUser()); + exerciseInject.setStatus(scenarioInject.getStatus().orElse(null)); + exerciseInject.setTags(CopyObjectListUtils.copy(scenarioInject.getTags(), Tag.class)); + exerciseInject.setContent(scenarioInject.getContent()); + + // Content + scenarioInject + .getInjectorContract() + .ifPresentOrElse( + injectorContract -> { + if (ChannelContract.TYPE.equals(injectorContract.getInjector().getType())) { + try { + ChannelContent content = + mapper.treeToValue(scenarioInject.getContent(), ChannelContent.class); + content.setArticles( + content.getArticles().stream() + .map(articleId -> articles.get(articleId).getId()) + .toList()); + exerciseInject.setContent(mapper.valueToTree(content)); + } catch (JsonProcessingException e) { + throw new RuntimeException(e); + } + } + }, + () -> exerciseInject.setContent(scenarioInject.getContent())); + + // Teams + List teams = new ArrayList<>(); + scenarioInject.getTeams().forEach(team -> teams.add(computeTeam(team, contextualTeams))); + exerciseInject.setTeams(teams); + + // Assets & Asset Groups + exerciseInject.setAssets( + CopyObjectListUtils.copy(scenarioInject.getAssets(), Asset.class)); + exerciseInject.setAssetGroups( + CopyObjectListUtils.copy(scenarioInject.getAssetGroups(), AssetGroup.class)); + Inject injectSaved = this.injectRepository.save(exerciseInject); + + mapExerciseInjectsByScenarioInject.put(scenarioInject.getId(), injectSaved); + + // Documents + List exerciseInjectDocuments = new ArrayList<>(); + scenarioInject + .getDocuments() + .forEach( + injectDocument -> { + InjectDocument exerciseInjectDocument = new InjectDocument(); + exerciseInjectDocument.setInject(injectSaved); + exerciseInjectDocument.setDocument(injectDocument.getDocument()); + exerciseInjectDocument.setAttached(injectDocument.isAttached()); + exerciseInjectDocuments.add(exerciseInjectDocument); + }); + this.injectDocumentRepository.saveAll(exerciseInjectDocuments); + }); // Second pass to add the correct links - scenarioInjects.forEach(scenarioInject -> { - if(scenarioInject.getDependsOn() != null) { - Inject injectToUpdate = mapExerciseInjectsByScenarioInject.get(scenarioInject.getId()); - injectToUpdate.setDependsOn(mapExerciseInjectsByScenarioInject.get(scenarioInject.getDependsOn().getId())); - this.injectRepository.save(injectToUpdate); - } - }); + scenarioInjects.forEach( + scenarioInject -> { + if (scenarioInject.getDependsOn() != null) { + Inject injectToUpdate = mapExerciseInjectsByScenarioInject.get(scenarioInject.getId()); + injectToUpdate.setDependsOn( + mapExerciseInjectsByScenarioInject.get(scenarioInject.getDependsOn().getId())); + this.injectRepository.save(injectToUpdate); + } + }); // Variables List scenarioVariables = this.variableService.variablesFromScenario(scenario.getId()); - List exerciseVariables = scenarioVariables.stream() - .map(scenarioVariable -> { - Variable exerciseVariable = new Variable(); - exerciseVariable.setKey(scenarioVariable.getKey()); - exerciseVariable.setValue(scenarioVariable.getValue()); - exerciseVariable.setDescription(scenarioVariable.getDescription()); - exerciseVariable.setType(scenarioVariable.getType()); - exerciseVariable.setExercise(exerciseSaved); - return exerciseVariable; - }) - .toList(); + List exerciseVariables = + scenarioVariables.stream() + .map( + scenarioVariable -> { + Variable exerciseVariable = new Variable(); + exerciseVariable.setKey(scenarioVariable.getKey()); + exerciseVariable.setValue(scenarioVariable.getValue()); + exerciseVariable.setDescription(scenarioVariable.getDescription()); + exerciseVariable.setType(scenarioVariable.getType()); + exerciseVariable.setExercise(exerciseSaved); + return exerciseVariable; + }) + .toList(); this.variableService.createVariables(exerciseVariables); return exerciseSaved; } - private List addExerciseToDocuments( - @NotNull final List origDocuments, - @NotNull final Exercise exercise) { + @NotNull final List origDocuments, @NotNull final Exercise exercise) { List destDocuments = new ArrayList<>(); - origDocuments.forEach(origDocument -> { - try { - Document destDocument = new Document(); - BeanUtils.copyProperties(destDocument, origDocument); - Set exercises = destDocument.getExercises(); - exercises.add(exercise); - destDocument.setExercises(exercises); - destDocuments.add(destDocument); - } catch (IllegalAccessException | InvocationTargetException e) { - throw new RuntimeException(e); - } - }); + origDocuments.forEach( + origDocument -> { + try { + Document destDocument = new Document(); + BeanUtils.copyProperties(destDocument, origDocument); + Set exercises = destDocument.getExercises(); + exercises.add(exercise); + destDocument.setExercises(exercises); + destDocuments.add(destDocument); + } catch (IllegalAccessException | InvocationTargetException e) { + throw new RuntimeException(e); + } + }); return destDocuments; } - private Team computeTeam(@NotNull final Team origTeam, @NotNull final Map contextualTeams) { + private Team computeTeam( + @NotNull final Team origTeam, @NotNull final Map contextualTeams) { if (origTeam.getContextual()) { return contextualTeams.get(origTeam.getId()); } else { return origTeam; } } - } diff --git a/openbas-api/src/main/java/io/openbas/service/TeamService.java b/openbas-api/src/main/java/io/openbas/service/TeamService.java index 5d774f2a5e..1ecf0e568d 100644 --- a/openbas-api/src/main/java/io/openbas/service/TeamService.java +++ b/openbas-api/src/main/java/io/openbas/service/TeamService.java @@ -1,5 +1,13 @@ package io.openbas.service; +import static io.openbas.config.SessionHelper.currentUser; +import static io.openbas.database.criteria.GenericCriteria.countQuery; +import static io.openbas.database.specification.TeamSpecification.teamsAccessibleFromOrganizations; +import static io.openbas.rest.team.TeamQueryHelper.execution; +import static io.openbas.rest.team.TeamQueryHelper.select; +import static io.openbas.utils.pagination.PaginationUtils.buildPaginationCriteriaBuilder; +import static io.openbas.utils.pagination.SortUtilsCriteriaBuilder.toSortCriteriaBuilder; + import io.openbas.config.OpenBASPrincipal; import io.openbas.database.model.Organization; import io.openbas.database.model.Tag; @@ -16,6 +24,7 @@ import jakarta.persistence.Tuple; import jakarta.persistence.TypedQuery; import jakarta.persistence.criteria.*; +import java.util.List; import lombok.RequiredArgsConstructor; import org.apache.commons.lang3.function.TriFunction; import org.jetbrains.annotations.NotNull; @@ -25,22 +34,11 @@ import org.springframework.data.jpa.domain.Specification; import org.springframework.stereotype.Service; -import java.util.List; - -import static io.openbas.config.SessionHelper.currentUser; -import static io.openbas.database.criteria.GenericCriteria.countQuery; -import static io.openbas.database.specification.TeamSpecification.teamsAccessibleFromOrganizations; -import static io.openbas.rest.team.TeamQueryHelper.execution; -import static io.openbas.rest.team.TeamQueryHelper.select; -import static io.openbas.utils.pagination.PaginationUtils.buildPaginationCriteriaBuilder; -import static io.openbas.utils.pagination.SortUtilsCriteriaBuilder.toSortCriteriaBuilder; - @Service @RequiredArgsConstructor public class TeamService { - @PersistenceContext - private EntityManager entityManager; + @PersistenceContext private EntityManager entityManager; private final UserRepository userRepository; @@ -62,29 +60,38 @@ public Page teamPagination( TriFunction, Specification, Pageable, Page> teamsFunction; OpenBASPrincipal currentUser = currentUser(); if (currentUser.isAdmin()) { - teamsFunction = (Specification specification, Specification specificationCount, Pageable pageable) -> this.paginate( - teamSpecification.and(specification), - teamSpecification.and(specificationCount), - pageable - ); + teamsFunction = + (Specification specification, + Specification specificationCount, + Pageable pageable) -> + this.paginate( + teamSpecification.and(specification), + teamSpecification.and(specificationCount), + pageable); } else { - User user = this.userRepository.findById(currentUser.getId()).orElseThrow(ElementNotFoundException::new); - List organizationIds = user.getGroups() - .stream() - .flatMap(group -> group.getOrganizations().stream()) - .map(Organization::getId) - .toList(); - teamsFunction = (Specification specification, Specification specificationCount, Pageable pageable) -> this.paginate( - teamSpecification.and(teamsAccessibleFromOrganizations(organizationIds)).and(specification), - teamSpecification.and(teamsAccessibleFromOrganizations(organizationIds)).and(specificationCount), - pageable - ); + User user = + this.userRepository + .findById(currentUser.getId()) + .orElseThrow(ElementNotFoundException::new); + List organizationIds = + user.getGroups().stream() + .flatMap(group -> group.getOrganizations().stream()) + .map(Organization::getId) + .toList(); + teamsFunction = + (Specification specification, + Specification specificationCount, + Pageable pageable) -> + this.paginate( + teamSpecification + .and(teamsAccessibleFromOrganizations(organizationIds)) + .and(specification), + teamSpecification + .and(teamsAccessibleFromOrganizations(organizationIds)) + .and(specificationCount), + pageable); } - return buildPaginationCriteriaBuilder( - teamsFunction, - searchPaginationInput, - Team.class - ); + return buildPaginationCriteriaBuilder(teamsFunction, searchPaginationInput, Team.class); } private Page paginate( @@ -142,5 +149,4 @@ public List find(Specification specification) { TypedQuery query = entityManager.createQuery(cq); return execution(query); } - } diff --git a/openbas-api/src/main/java/io/openbas/service/UserService.java b/openbas-api/src/main/java/io/openbas/service/UserService.java index df6073ebf4..269ddcb3c9 100644 --- a/openbas-api/src/main/java/io/openbas/service/UserService.java +++ b/openbas-api/src/main/java/io/openbas/service/UserService.java @@ -1,5 +1,11 @@ package io.openbas.service; +import static io.openbas.database.model.User.ROLE_ADMIN; +import static io.openbas.database.model.User.ROLE_USER; +import static io.openbas.helper.DatabaseHelper.updateRelation; +import static io.openbas.helper.StreamHelper.iterableToSet; +import static java.time.Instant.now; + import io.openbas.config.OpenBASPrincipal; import io.openbas.database.model.Group; import io.openbas.database.model.Token; @@ -9,6 +15,10 @@ import io.openbas.rest.user.form.user.CreateUserInput; import jakarta.validation.constraints.NotBlank; import jakarta.validation.constraints.NotNull; +import java.util.ArrayList; +import java.util.Collection; +import java.util.List; +import java.util.UUID; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.security.core.Authentication; import org.springframework.security.core.GrantedAuthority; @@ -20,21 +30,11 @@ import org.springframework.stereotype.Service; import org.springframework.util.StringUtils; -import java.util.ArrayList; -import java.util.Collection; -import java.util.List; -import java.util.UUID; - -import static io.openbas.database.model.User.ROLE_ADMIN; -import static io.openbas.database.model.User.ROLE_USER; -import static io.openbas.helper.DatabaseHelper.updateRelation; -import static io.openbas.helper.StreamHelper.iterableToSet; -import static java.time.Instant.now; - @Service public class UserService { - private final Argon2PasswordEncoder passwordEncoder = Argon2PasswordEncoder.defaultsForSpringSecurity_v5_8(); + private final Argon2PasswordEncoder passwordEncoder = + Argon2PasswordEncoder.defaultsForSpringSecurity_v5_8(); private UserRepository userRepository; private TokenRepository tokenRepository; private TagRepository tagRepository; @@ -102,9 +102,11 @@ public User createUser(CreateUserInput input, int status) { user.setPassword(encodeUserPassword(input.getPassword())); } user.setTags(iterableToSet(tagRepository.findAllById(input.getTagIds()))); - user.setOrganization(updateRelation(input.getOrganizationId(), user.getOrganization(), organizationRepository)); + user.setOrganization( + updateRelation(input.getOrganizationId(), user.getOrganization(), organizationRepository)); // Find automatic groups to assign - List assignableGroups = groupRepository.findAll(GroupSpecification.defaultUserAssignable()); + List assignableGroups = + groupRepository.findAll(GroupSpecification.defaultUserAssignable()); user.setGroups(assignableGroups); // Save the user User savedUser = userRepository.save(user); @@ -118,32 +120,36 @@ public User user(@NotBlank final String userId) { // endregion - public static PreAuthenticatedAuthenticationToken buildAuthenticationToken(@NotNull final User user) { + public static PreAuthenticatedAuthenticationToken buildAuthenticationToken( + @NotNull final User user) { List roles = new ArrayList<>(); roles.add(new SimpleGrantedAuthority(ROLE_USER)); if (user.isAdmin()) { roles.add(new SimpleGrantedAuthority(ROLE_ADMIN)); } - return new PreAuthenticatedAuthenticationToken(new OpenBASPrincipal() { - @Override - public String getId() { - return user.getId(); - } - - @Override - public Collection getAuthorities() { - return roles; - } - - @Override - public boolean isAdmin() { - return user.isAdmin(); - } - - @Override - public String getLang() { - return user.getLang(); - } - }, "", roles); + return new PreAuthenticatedAuthenticationToken( + new OpenBASPrincipal() { + @Override + public String getId() { + return user.getId(); + } + + @Override + public Collection getAuthorities() { + return roles; + } + + @Override + public boolean isAdmin() { + return user.isAdmin(); + } + + @Override + public String getLang() { + return user.getLang(); + } + }, + "", + roles); } } diff --git a/openbas-api/src/main/java/io/openbas/service/VariableService.java b/openbas-api/src/main/java/io/openbas/service/VariableService.java index 4897ea67ba..0d21b1ee10 100644 --- a/openbas-api/src/main/java/io/openbas/service/VariableService.java +++ b/openbas-api/src/main/java/io/openbas/service/VariableService.java @@ -1,18 +1,17 @@ package io.openbas.service; +import static io.openbas.helper.StreamHelper.fromIterable; +import static java.time.Instant.now; + import io.openbas.database.model.Variable; import io.openbas.database.repository.VariableRepository; import io.openbas.database.specification.VariableSpecification; import jakarta.validation.constraints.NotBlank; import jakarta.validation.constraints.NotNull; +import java.util.List; import lombok.RequiredArgsConstructor; import org.springframework.stereotype.Service; -import java.util.List; - -import static io.openbas.helper.StreamHelper.fromIterable; -import static java.time.Instant.now; - @RequiredArgsConstructor @Service public class VariableService { @@ -47,5 +46,4 @@ public Variable updateVariable(@NotNull final Variable variable) { public void deleteVariable(@NotBlank final String variableId) { this.variableRepository.deleteById(variableId); } - } diff --git a/openbas-api/src/main/java/io/openbas/telemetry/OpenTelemetryConfig.java b/openbas-api/src/main/java/io/openbas/telemetry/OpenTelemetryConfig.java index dce9331e91..ec162b47a5 100644 --- a/openbas-api/src/main/java/io/openbas/telemetry/OpenTelemetryConfig.java +++ b/openbas-api/src/main/java/io/openbas/telemetry/OpenTelemetryConfig.java @@ -1,5 +1,8 @@ package io.openbas.telemetry; +import static io.opentelemetry.api.common.AttributeKey.stringKey; +import static java.util.Objects.requireNonNull; + import io.opentelemetry.api.OpenTelemetry; import io.opentelemetry.api.common.Attributes; import io.opentelemetry.api.trace.Tracer; @@ -12,6 +15,9 @@ import io.opentelemetry.semconv.ServerAttributes; import io.opentelemetry.semconv.ServiceAttributes; import jakarta.validation.constraints.NotBlank; +import java.net.InetAddress; +import java.net.UnknownHostException; +import java.util.UUID; import lombok.RequiredArgsConstructor; import lombok.extern.java.Log; import org.jetbrains.annotations.NotNull; @@ -20,13 +26,6 @@ import org.springframework.core.env.Environment; import org.springframework.stereotype.Service; -import java.net.InetAddress; -import java.net.UnknownHostException; -import java.util.UUID; - -import static io.opentelemetry.api.common.AttributeKey.stringKey; -import static java.util.Objects.requireNonNull; - @ConditionalOnProperty(prefix = "telemetry", name = "enable") @Log @Service @@ -39,14 +38,13 @@ public class OpenTelemetryConfig { public OpenTelemetry openTelemetry() { Resource resource = buildResource(); - SdkTracerProvider tracerProvider = SdkTracerProvider.builder() - .addSpanProcessor(SimpleSpanProcessor.create(OtlpGrpcSpanExporter.builder().build())) - .setResource(resource) - .build(); + SdkTracerProvider tracerProvider = + SdkTracerProvider.builder() + .addSpanProcessor(SimpleSpanProcessor.create(OtlpGrpcSpanExporter.builder().build())) + .setResource(resource) + .build(); - return OpenTelemetrySdk.builder() - .setTracerProvider(tracerProvider) - .buildAndRegisterGlobal(); + return OpenTelemetrySdk.builder().setTracerProvider(tracerProvider).buildAndRegisterGlobal(); } @Bean @@ -57,10 +55,11 @@ public Tracer tracer(@NotNull final OpenTelemetry openTelemetry) { // -- PRIVATE -- private Resource buildResource() { - ResourceBuilder resourceBuilder = Resource.getDefault().toBuilder() - .put(ServiceAttributes.SERVICE_NAME, getRequiredProperty("info.app.name")) - .put(ServiceAttributes.SERVICE_VERSION, getRequiredProperty("info.app.version")) - .put(stringKey("instance.id"), UUID.randomUUID().toString()); + ResourceBuilder resourceBuilder = + Resource.getDefault().toBuilder() + .put(ServiceAttributes.SERVICE_NAME, getRequiredProperty("info.app.name")) + .put(ServiceAttributes.SERVICE_VERSION, getRequiredProperty("info.app.version")) + .put(stringKey("instance.id"), UUID.randomUUID().toString()); try { String hostAddress = InetAddress.getLocalHost().getHostAddress(); diff --git a/openbas-api/src/main/java/io/openbas/telemetry/Tracing.java b/openbas-api/src/main/java/io/openbas/telemetry/Tracing.java index f061b56630..b8cfb80835 100644 --- a/openbas-api/src/main/java/io/openbas/telemetry/Tracing.java +++ b/openbas-api/src/main/java/io/openbas/telemetry/Tracing.java @@ -9,6 +9,8 @@ @Target(ElementType.METHOD) public @interface Tracing { String name(); + String layer() default ""; + String operation() default ""; } diff --git a/openbas-api/src/main/java/io/openbas/telemetry/TracingAspect.java b/openbas-api/src/main/java/io/openbas/telemetry/TracingAspect.java index 6817e314a3..5cff64f683 100644 --- a/openbas-api/src/main/java/io/openbas/telemetry/TracingAspect.java +++ b/openbas-api/src/main/java/io/openbas/telemetry/TracingAspect.java @@ -1,8 +1,11 @@ package io.openbas.telemetry; +import static io.openbas.config.SessionHelper.currentUser; + import io.opentelemetry.api.trace.Span; import io.opentelemetry.api.trace.Tracer; import io.opentelemetry.context.Scope; +import java.lang.reflect.Method; import lombok.RequiredArgsConstructor; import org.aspectj.lang.ProceedingJoinPoint; import org.aspectj.lang.annotation.Around; @@ -11,10 +14,6 @@ import org.springframework.boot.autoconfigure.condition.ConditionalOnBean; import org.springframework.stereotype.Component; -import java.lang.reflect.Method; - -import static io.openbas.config.SessionHelper.currentUser; - @Aspect @Component @RequiredArgsConstructor @@ -29,12 +28,14 @@ public Object tracing(ProceedingJoinPoint proceedingJoinPoint) throws Throwable Method method = signature.getMethod(); Tracing tracing = method.getAnnotation(Tracing.class); - Span span = tracer.spanBuilder(tracing.name()) - .setAttribute("USER", getCurrentUser()) - .setAttribute("LAYER", tracing.layer()) - .setAttribute("OPERATION", tracing.operation()) - .setAttribute("METHOD", method.getName()) - .startSpan(); + Span span = + tracer + .spanBuilder(tracing.name()) + .setAttribute("USER", getCurrentUser()) + .setAttribute("LAYER", tracing.layer()) + .setAttribute("OPERATION", tracing.operation()) + .setAttribute("METHOD", method.getName()) + .startSpan(); try (Scope ignored = span.makeCurrent()) { return proceedingJoinPoint.proceed(); } finally { diff --git a/openbas-api/src/main/java/io/openbas/utils/AtomicTestingMapper.java b/openbas-api/src/main/java/io/openbas/utils/AtomicTestingMapper.java index 6bdddc162b..fe86f359a2 100644 --- a/openbas-api/src/main/java/io/openbas/utils/AtomicTestingMapper.java +++ b/openbas-api/src/main/java/io/openbas/utils/AtomicTestingMapper.java @@ -1,69 +1,72 @@ package io.openbas.utils; +import static io.openbas.database.model.InjectStatus.draftInjectStatus; +import static io.openbas.utils.AtomicTestingUtils.getRefinedExpectations; + import io.openbas.database.model.*; import io.openbas.expectation.ExpectationType; import io.openbas.rest.atomic_testing.form.InjectResultDTO; import io.openbas.rest.atomic_testing.form.InjectResultDTO.InjectResultDTOBuilder; import io.openbas.rest.atomic_testing.form.InjectTargetWithResult; import jakarta.validation.constraints.NotNull; - import java.util.List; -import static io.openbas.database.model.InjectStatus.draftInjectStatus; -import static io.openbas.utils.AtomicTestingUtils.getRefinedExpectations; - public class AtomicTestingMapper { - public static InjectResultDTO toDtoWithTargetResults(Inject inject) { - List targets = AtomicTestingUtils.getTargetsWithResults(inject); - List targetIds = targets.stream().map(InjectTargetWithResult::getId).toList(); - - return getAtomicTestingOutputBuilder(inject) - .targets(targets) - .expectationResultByTypes(AtomicTestingUtils.getExpectationResultByTypes( - getRefinedExpectations(inject, targetIds) - )) - .build(); - } - - public static InjectResultDTO toDto(Inject inject, List targets) { - List targetIds = targets.stream().map(InjectTargetWithResult::getId).toList(); - - return getAtomicTestingOutputBuilder(inject) - .targets(targets) - .expectationResultByTypes(AtomicTestingUtils.getExpectationResultByTypes( - getRefinedExpectations(inject, targetIds) - )) - .build(); - } + public static InjectResultDTO toDtoWithTargetResults(Inject inject) { + List targets = AtomicTestingUtils.getTargetsWithResults(inject); + List targetIds = targets.stream().map(InjectTargetWithResult::getId).toList(); - private static InjectResultDTOBuilder getAtomicTestingOutputBuilder(Inject inject) { - return InjectResultDTO - .builder() - .id(inject.getId()) - .title(inject.getTitle()) - .description(inject.getDescription()) - .content(inject.getContent()) - .expectations(inject.getExpectations()) - .type(inject.getInjectorContract().map(injectorContract -> injectorContract.getInjector().getType()).orElse(null)) - .tagIds(inject.getTags().stream().map(Tag::getId).toList()) - .documents(inject.getDocuments().stream().map(InjectDocument::getDocument).map(Document::getId).toList()) - .injectorContract(inject.getInjectorContract().orElse(null)) - .status(inject.getStatus().orElse(draftInjectStatus())) - .killChainPhases(inject.getKillChainPhases()) - .attackPatterns(inject.getAttackPatterns()) - .isReady(inject.isReady()) - .updatedAt(inject.getUpdatedAt()); - } + return getAtomicTestingOutputBuilder(inject) + .targets(targets) + .expectationResultByTypes( + AtomicTestingUtils.getExpectationResultByTypes( + getRefinedExpectations(inject, targetIds))) + .build(); + } - public record ExpectationResultsByType(@NotNull ExpectationType type, - @NotNull InjectExpectation.EXPECTATION_STATUS avgResult, - @NotNull List distribution) { + public static InjectResultDTO toDto(Inject inject, List targets) { + List targetIds = targets.stream().map(InjectTargetWithResult::getId).toList(); - } + return getAtomicTestingOutputBuilder(inject) + .targets(targets) + .expectationResultByTypes( + AtomicTestingUtils.getExpectationResultByTypes( + getRefinedExpectations(inject, targetIds))) + .build(); + } - public record ResultDistribution(@NotNull String id, @NotNull String label, @NotNull Integer value) { + private static InjectResultDTOBuilder getAtomicTestingOutputBuilder(Inject inject) { + return InjectResultDTO.builder() + .id(inject.getId()) + .title(inject.getTitle()) + .description(inject.getDescription()) + .content(inject.getContent()) + .expectations(inject.getExpectations()) + .type( + inject + .getInjectorContract() + .map(injectorContract -> injectorContract.getInjector().getType()) + .orElse(null)) + .tagIds(inject.getTags().stream().map(Tag::getId).toList()) + .documents( + inject.getDocuments().stream() + .map(InjectDocument::getDocument) + .map(Document::getId) + .toList()) + .injectorContract(inject.getInjectorContract().orElse(null)) + .status(inject.getStatus().orElse(draftInjectStatus())) + .killChainPhases(inject.getKillChainPhases()) + .attackPatterns(inject.getAttackPatterns()) + .isReady(inject.isReady()) + .updatedAt(inject.getUpdatedAt()); + } - } + public record ExpectationResultsByType( + @NotNull ExpectationType type, + @NotNull InjectExpectation.EXPECTATION_STATUS avgResult, + @NotNull List distribution) {} + public record ResultDistribution( + @NotNull String id, @NotNull String label, @NotNull Integer value) {} } diff --git a/openbas-api/src/main/java/io/openbas/utils/AtomicTestingUtils.java b/openbas-api/src/main/java/io/openbas/utils/AtomicTestingUtils.java index f9a2dd8db3..f978bf3812 100644 --- a/openbas-api/src/main/java/io/openbas/utils/AtomicTestingUtils.java +++ b/openbas-api/src/main/java/io/openbas/utils/AtomicTestingUtils.java @@ -9,33 +9,43 @@ import io.openbas.utils.AtomicTestingMapper.ExpectationResultsByType; import io.openbas.utils.AtomicTestingMapper.ResultDistribution; import jakarta.validation.constraints.NotNull; -import org.hibernate.Hibernate; - import java.util.*; import java.util.stream.Collectors; +import org.hibernate.Hibernate; public class AtomicTestingUtils { - // -- TARGETS WITHOUT RESULTS -- public static List getTargets( - final List teams, - final List assets, - final List assetGroups) { + final List teams, final List assets, final List assetGroups) { List targets = new ArrayList<>(); - targets.addAll(teams - .stream() - .map(t -> new InjectTargetWithResult(TargetType.TEAMS, t.getId(), t.getName(), List.of(), null)) - .toList()); - targets.addAll(assets - .stream() - .map(t -> new InjectTargetWithResult(TargetType.ASSETS, t.getId(), t.getName(), List.of(), - Objects.equals(t.getType(), "Endpoint") ? ((Endpoint) Hibernate.unproxy(t)).getPlatform() : null)) - .toList()); - targets.addAll(assetGroups - .stream() - .map(t -> new InjectTargetWithResult(TargetType.ASSETS_GROUPS, t.getId(), t.getName(), List.of(), null)) - .toList()); + targets.addAll( + teams.stream() + .map( + t -> + new InjectTargetWithResult( + TargetType.TEAMS, t.getId(), t.getName(), List.of(), null)) + .toList()); + targets.addAll( + assets.stream() + .map( + t -> + new InjectTargetWithResult( + TargetType.ASSETS, + t.getId(), + t.getName(), + List.of(), + Objects.equals(t.getType(), "Endpoint") + ? ((Endpoint) Hibernate.unproxy(t)).getPlatform() + : null)) + .toList()); + targets.addAll( + assetGroups.stream() + .map( + t -> + new InjectTargetWithResult( + TargetType.ASSETS_GROUPS, t.getId(), t.getName(), List.of(), null)) + .toList()); return targets; } @@ -45,28 +55,45 @@ public static List getTargetsFromRaw( final List assets, final List assetGroups) { List targets = new ArrayList<>(); - targets.addAll(teams - .stream() - .map(t -> new InjectTargetWithResult(TargetType.TEAMS, t.getTeam_id(), t.getTeam_name(), List.of(), null)) - .toList()); - targets.addAll(assets - .stream() - .map(t -> new InjectTargetWithResult(TargetType.ASSETS, t.getAsset_id(), t.getAsset_name(), List.of(), - Objects.equals(t.getAsset_type(), "Endpoint") ? Endpoint.PLATFORM_TYPE.valueOf(t.getEndpoint_platform()) - : null)) - .toList()); - targets.addAll(assetGroups - .stream() - .map(t -> new InjectTargetWithResult(TargetType.ASSETS_GROUPS, t.getAsset_group_id(), t.getAsset_group_name(), - List.of(), null)) - .toList()); + targets.addAll( + teams.stream() + .map( + t -> + new InjectTargetWithResult( + TargetType.TEAMS, t.getTeam_id(), t.getTeam_name(), List.of(), null)) + .toList()); + targets.addAll( + assets.stream() + .map( + t -> + new InjectTargetWithResult( + TargetType.ASSETS, + t.getAsset_id(), + t.getAsset_name(), + List.of(), + Objects.equals(t.getAsset_type(), "Endpoint") + ? Endpoint.PLATFORM_TYPE.valueOf(t.getEndpoint_platform()) + : null)) + .toList()); + targets.addAll( + assetGroups.stream() + .map( + t -> + new InjectTargetWithResult( + TargetType.ASSETS_GROUPS, + t.getAsset_group_id(), + t.getAsset_group_name(), + List.of(), + null)) + .toList()); return targets; } // -- TARGETS WITH RESULTS -- public static List getTargetsWithResults(Inject inject) { - List defaultExpectationResultsByTypes = getDefaultExpectationResultsByTypes(); + List defaultExpectationResultsByTypes = + getDefaultExpectationResultsByTypes(); List expectations = inject.getExpectations(); List teamExpectations = new ArrayList<>(); @@ -74,218 +101,269 @@ public static List getTargetsWithResults(Inject inject) List assetExpectations = new ArrayList<>(); List assetGroupExpectations = new ArrayList<>(); - expectations.forEach(expectation -> { - if (expectation.getTeam() != null) { - if (expectation.getUser() != null) { - playerExpectations.add(expectation); - } else { - teamExpectations.add(expectation); - } - } - if (expectation.getAsset() != null) { - assetExpectations.add(expectation); - } - if (expectation.getAssetGroup() != null) { - assetGroupExpectations.add(expectation); - } - }); + expectations.forEach( + expectation -> { + if (expectation.getTeam() != null) { + if (expectation.getUser() != null) { + playerExpectations.add(expectation); + } else { + teamExpectations.add(expectation); + } + } + if (expectation.getAsset() != null) { + assetExpectations.add(expectation); + } + if (expectation.getAssetGroup() != null) { + assetGroupExpectations.add(expectation); + } + }); List targets = new ArrayList<>(); List assetsToRefine = new ArrayList<>(); // Players - Map>> groupedByTeamAndUser = playerExpectations.stream() - .collect(Collectors.groupingBy( - InjectExpectation::getTeam, - Collectors.groupingBy(InjectExpectation::getUser) - )); + Map>> groupedByTeamAndUser = + playerExpectations.stream() + .collect( + Collectors.groupingBy( + InjectExpectation::getTeam, Collectors.groupingBy(InjectExpectation::getUser))); /* Match Target with expectations * */ - inject.getTeams().forEach(team -> { - // Check if there are no expectations matching the current team (t) - boolean noMatchingExpectations = teamExpectations.stream() - .noneMatch(exp -> exp.getTeam().getId().equals(team.getId())); - if (noMatchingExpectations) { - InjectTargetWithResult target = new InjectTargetWithResult( - TargetType.TEAMS, - team.getId(), - team.getName(), - defaultExpectationResultsByTypes, - null - ); - targets.add(target); - } - }); - inject.getAssets().forEach(asset -> { - // Check if there are no expectations matching the current asset (t) - boolean noMatchingExpectations = assetExpectations.stream() - .noneMatch(exp -> exp.getAsset().getId().equals(asset.getId())); - if (noMatchingExpectations) { - InjectTargetWithResult target = new InjectTargetWithResult( - TargetType.ASSETS, - asset.getId(), - asset.getName(), - defaultExpectationResultsByTypes, - Objects.equals(asset.getType(), "Endpoint") ? ((Endpoint) Hibernate.unproxy(asset)).getPlatform() : null - ); - - targets.add(target); - } - }); - inject.getAssetGroups().forEach(assetGroup -> { - // Check if there are no expectations matching the current assetgroup (t) - boolean noMatchingExpectations = assetGroupExpectations.stream() - .noneMatch(exp -> exp.getAssetGroup().getId().equals(assetGroup.getId())); - - List children = new ArrayList<>(); - - assetGroup.getAssets().forEach(asset -> { - children.add(new InjectTargetWithResult( - TargetType.ASSETS, - asset.getId(), - asset.getName(), - defaultExpectationResultsByTypes, - Objects.equals(asset.getType(), "Endpoint") ? ((Endpoint) Hibernate.unproxy(asset)).getPlatform() : null - )); - }); - // Add dynamic assets as children - assetGroup.getDynamicAssets().forEach(asset -> { - children.add(new InjectTargetWithResult( - TargetType.ASSETS, - asset.getId(), - asset.getName(), - defaultExpectationResultsByTypes, - Objects.equals(asset.getType(), "Endpoint") ? ((Endpoint) Hibernate.unproxy(asset)).getPlatform() : null - )); - }); - - if (noMatchingExpectations) { - InjectTargetWithResult target = new InjectTargetWithResult( - TargetType.ASSETS_GROUPS, - assetGroup.getId(), - assetGroup.getName(), - defaultExpectationResultsByTypes, - children, - null - ); - - targets.add(target); - } - }); + inject + .getTeams() + .forEach( + team -> { + // Check if there are no expectations matching the current team (t) + boolean noMatchingExpectations = + teamExpectations.stream() + .noneMatch(exp -> exp.getTeam().getId().equals(team.getId())); + if (noMatchingExpectations) { + InjectTargetWithResult target = + new InjectTargetWithResult( + TargetType.TEAMS, + team.getId(), + team.getName(), + defaultExpectationResultsByTypes, + null); + targets.add(target); + } + }); + inject + .getAssets() + .forEach( + asset -> { + // Check if there are no expectations matching the current asset (t) + boolean noMatchingExpectations = + assetExpectations.stream() + .noneMatch(exp -> exp.getAsset().getId().equals(asset.getId())); + if (noMatchingExpectations) { + InjectTargetWithResult target = + new InjectTargetWithResult( + TargetType.ASSETS, + asset.getId(), + asset.getName(), + defaultExpectationResultsByTypes, + Objects.equals(asset.getType(), "Endpoint") + ? ((Endpoint) Hibernate.unproxy(asset)).getPlatform() + : null); + + targets.add(target); + } + }); + inject + .getAssetGroups() + .forEach( + assetGroup -> { + // Check if there are no expectations matching the current assetgroup (t) + boolean noMatchingExpectations = + assetGroupExpectations.stream() + .noneMatch(exp -> exp.getAssetGroup().getId().equals(assetGroup.getId())); + + List children = new ArrayList<>(); + + assetGroup + .getAssets() + .forEach( + asset -> { + children.add( + new InjectTargetWithResult( + TargetType.ASSETS, + asset.getId(), + asset.getName(), + defaultExpectationResultsByTypes, + Objects.equals(asset.getType(), "Endpoint") + ? ((Endpoint) Hibernate.unproxy(asset)).getPlatform() + : null)); + }); + // Add dynamic assets as children + assetGroup + .getDynamicAssets() + .forEach( + asset -> { + children.add( + new InjectTargetWithResult( + TargetType.ASSETS, + asset.getId(), + asset.getName(), + defaultExpectationResultsByTypes, + Objects.equals(asset.getType(), "Endpoint") + ? ((Endpoint) Hibernate.unproxy(asset)).getPlatform() + : null)); + }); + + if (noMatchingExpectations) { + InjectTargetWithResult target = + new InjectTargetWithResult( + TargetType.ASSETS_GROUPS, + assetGroup.getId(), + assetGroup.getName(), + defaultExpectationResultsByTypes, + children, + null); + + targets.add(target); + } + }); /* Build results for expectations with scores */ if (!teamExpectations.isEmpty()) { targets.addAll( - teamExpectations - .stream() + teamExpectations.stream() .collect( - Collectors.groupingBy(InjectExpectation::getTeam, + Collectors.groupingBy( + InjectExpectation::getTeam, Collectors.collectingAndThen( - Collectors.toList(), AtomicTestingUtils::getExpectationResultByTypes) - ) - ) - .entrySet().stream() - .map(entry -> new InjectTargetWithResult(TargetType.TEAMS, entry.getKey().getId(), - entry.getKey().getName(), entry.getValue(), playerExpectations.isEmpty() ? List.of() - : calculateResultsforPlayers(groupedByTeamAndUser.get(entry.getKey())), null)) - .toList() - ); + Collectors.toList(), AtomicTestingUtils::getExpectationResultByTypes))) + .entrySet() + .stream() + .map( + entry -> + new InjectTargetWithResult( + TargetType.TEAMS, + entry.getKey().getId(), + entry.getKey().getName(), + entry.getValue(), + playerExpectations.isEmpty() + ? List.of() + : calculateResultsforPlayers( + groupedByTeamAndUser.get(entry.getKey())), + null)) + .toList()); } if (!assetExpectations.isEmpty()) { assetsToRefine.addAll( - assetExpectations - .stream() + assetExpectations.stream() .collect( - Collectors.groupingBy(InjectExpectation::getAsset, + Collectors.groupingBy( + InjectExpectation::getAsset, Collectors.collectingAndThen( - Collectors.toList(), AtomicTestingUtils::getExpectationResultByTypes) - ) - ) - .entrySet().stream() - .map(entry -> new InjectTargetWithResult(TargetType.ASSETS, entry.getKey().getId(), - entry.getKey().getName(), entry.getValue(), - Objects.equals(entry.getKey().getType(), "Endpoint") ? ((Endpoint) Hibernate.unproxy( - entry.getKey())).getPlatform() : null)) - .toList() - ); + Collectors.toList(), AtomicTestingUtils::getExpectationResultByTypes))) + .entrySet() + .stream() + .map( + entry -> + new InjectTargetWithResult( + TargetType.ASSETS, + entry.getKey().getId(), + entry.getKey().getName(), + entry.getValue(), + Objects.equals(entry.getKey().getType(), "Endpoint") + ? ((Endpoint) Hibernate.unproxy(entry.getKey())).getPlatform() + : null)) + .toList()); } List assetsToRemove = new ArrayList<>(); if (!assetGroupExpectations.isEmpty()) { - targets.addAll(assetGroupExpectations - .stream() - .collect( - Collectors.groupingBy(InjectExpectation::getAssetGroup, - Collectors.collectingAndThen( - Collectors.toList(), AtomicTestingUtils::getExpectationResultByTypes) - ) - ) - .entrySet().stream() - .map(entry -> { - List children = new ArrayList<>(); - - for (InjectTargetWithResult asset : assetsToRefine) { - // Verify if any expectation is related to a dynamic assets - boolean foundExpectationForAsset = entry.getKey().getAssets().stream() - .anyMatch(assetChild -> assetChild.getId().equals(asset.getId())); - boolean foundExpectationForDynamicAssets = entry.getKey().getDynamicAssets().stream() - .anyMatch(assetChild -> assetChild.getId().equals(asset.getId())); - if (foundExpectationForAsset || foundExpectationForDynamicAssets) { - children.add(asset); - assetsToRemove.add(asset); - } - } - - // Other children without expectations are added with a default result - entry.getKey().getAssets().forEach(asset -> { - boolean foundAssetsWithoutResults = children.stream() - .noneMatch(child -> child.getId().equals(asset.getId())); - if (foundAssetsWithoutResults) { - children.add(new InjectTargetWithResult( - TargetType.ASSETS, - asset.getId(), - asset.getName(), - defaultExpectationResultsByTypes, - Objects.equals(asset.getType(), "Endpoint") ? ((Endpoint) Hibernate.unproxy(asset)).getPlatform() - : null - )); - } - }); - - // For dynamicAssets - entry.getKey().getDynamicAssets().forEach(asset -> { - boolean foundDynamicAssetsWithoutResults = children.stream() - .noneMatch(child -> child.getId().equals(asset.getId())); - if (foundDynamicAssetsWithoutResults) { - children.add(new InjectTargetWithResult( - TargetType.ASSETS, - asset.getId(), - asset.getName(), - defaultExpectationResultsByTypes, - Objects.equals(asset.getType(), "Endpoint") ? ((Endpoint) Hibernate.unproxy(asset)).getPlatform() - : null - )); - } - }); - - return new InjectTargetWithResult(TargetType.ASSETS_GROUPS, entry.getKey().getId(), - entry.getKey().getName(), entry.getValue(), sortResults(children), null); - }) - .toList()); + targets.addAll( + assetGroupExpectations.stream() + .collect( + Collectors.groupingBy( + InjectExpectation::getAssetGroup, + Collectors.collectingAndThen( + Collectors.toList(), AtomicTestingUtils::getExpectationResultByTypes))) + .entrySet() + .stream() + .map( + entry -> { + List children = new ArrayList<>(); + + for (InjectTargetWithResult asset : assetsToRefine) { + // Verify if any expectation is related to a dynamic assets + boolean foundExpectationForAsset = + entry.getKey().getAssets().stream() + .anyMatch(assetChild -> assetChild.getId().equals(asset.getId())); + boolean foundExpectationForDynamicAssets = + entry.getKey().getDynamicAssets().stream() + .anyMatch(assetChild -> assetChild.getId().equals(asset.getId())); + if (foundExpectationForAsset || foundExpectationForDynamicAssets) { + children.add(asset); + assetsToRemove.add(asset); + } + } + + // Other children without expectations are added with a default result + entry + .getKey() + .getAssets() + .forEach( + asset -> { + boolean foundAssetsWithoutResults = + children.stream() + .noneMatch(child -> child.getId().equals(asset.getId())); + if (foundAssetsWithoutResults) { + children.add( + new InjectTargetWithResult( + TargetType.ASSETS, + asset.getId(), + asset.getName(), + defaultExpectationResultsByTypes, + Objects.equals(asset.getType(), "Endpoint") + ? ((Endpoint) Hibernate.unproxy(asset)).getPlatform() + : null)); + } + }); + + // For dynamicAssets + entry + .getKey() + .getDynamicAssets() + .forEach( + asset -> { + boolean foundDynamicAssetsWithoutResults = + children.stream() + .noneMatch(child -> child.getId().equals(asset.getId())); + if (foundDynamicAssetsWithoutResults) { + children.add( + new InjectTargetWithResult( + TargetType.ASSETS, + asset.getId(), + asset.getName(), + defaultExpectationResultsByTypes, + Objects.equals(asset.getType(), "Endpoint") + ? ((Endpoint) Hibernate.unproxy(asset)).getPlatform() + : null)); + } + }); + + return new InjectTargetWithResult( + TargetType.ASSETS_GROUPS, + entry.getKey().getId(), + entry.getKey().getName(), + entry.getValue(), + sortResults(children), + null); + }) + .toList()); } - List injectAssetIds = inject.getAssets().stream() - .map(Asset::getId) - .collect(Collectors.toList()); + List injectAssetIds = + inject.getAssets().stream().map(Asset::getId).collect(Collectors.toList()); assetsToRefine.removeAll( - assetsToRemove - .stream() - .filter( - asset -> !injectAssetIds.contains(asset.getId())) - .toList()); + assetsToRemove.stream().filter(asset -> !injectAssetIds.contains(asset.getId())).toList()); targets.addAll(assetsToRefine); return sortResults(targets); @@ -297,11 +375,11 @@ public static List getTargetsWithResultsFromRaw( Map rawUserMap, Map rawAssetMap, Map rawAssetGroupMap, - Map> dynamicAssetGroupMap - ) { + Map> dynamicAssetGroupMap) { // Get expectations with default values - List defaultExpectationResultsByTypes = getDefaultExpectationResultsByTypes(); + List defaultExpectationResultsByTypes = + getDefaultExpectationResultsByTypes(); List teamExpectations = new ArrayList<>(); List playerExpectations = new ArrayList<>(); @@ -310,289 +388,343 @@ public static List getTargetsWithResultsFromRaw( List injectAssetIds = new ArrayList<>(); // Loop through the expectations to separate them by target - expectations.forEach(expectation -> { - if (expectation.getTeam_id() != null && expectation.getTeam_id() != null) { - if (expectation.getUser_id() != null) { - playerExpectations.add(expectation); - } else { - teamExpectations.add(expectation); - } - } - if (expectation.getAsset_id() != null && expectation.getAsset_id() != null) { - assetExpectations.add(expectation); - } - if (expectation.getAsset_group_id() != null && expectation.getAsset_group_id() != null) { - assetGroupExpectations.add(expectation); - } - }); + expectations.forEach( + expectation -> { + if (expectation.getTeam_id() != null && expectation.getTeam_id() != null) { + if (expectation.getUser_id() != null) { + playerExpectations.add(expectation); + } else { + teamExpectations.add(expectation); + } + } + if (expectation.getAsset_id() != null && expectation.getAsset_id() != null) { + assetExpectations.add(expectation); + } + if (expectation.getAsset_group_id() != null && expectation.getAsset_group_id() != null) { + assetGroupExpectations.add(expectation); + } + }); // Build a map from the previous expectations list using targetId as the key Map teamExpectationMap = new LinkedHashMap<>(); teamExpectations.stream() .filter(expectation -> !teamExpectationMap.containsKey(expectation.getTeam_id())) - .forEach(expectation -> { - teamExpectationMap.put( - expectation.getTeam_id(), - expectation - ); - }); + .forEach( + expectation -> { + teamExpectationMap.put(expectation.getTeam_id(), expectation); + }); Map assetExpectationMap = new LinkedHashMap<>(); assetExpectations.stream() .filter(expectation -> !assetExpectationMap.containsKey(expectation.getAsset_id())) - .forEach(expectation -> { - assetExpectationMap.put( - expectation.getAsset_id(), - expectation - ); - }); + .forEach( + expectation -> { + assetExpectationMap.put(expectation.getAsset_id(), expectation); + }); Map assetGroupExpectationMap = new LinkedHashMap<>(); assetGroupExpectations.stream() - .filter(expectation -> !assetGroupExpectationMap.containsKey(expectation.getAsset_group_id())) - .forEach(expectation -> { - assetGroupExpectationMap.put( - expectation.getAsset_group_id(), - expectation - ); - }); + .filter( + expectation -> !assetGroupExpectationMap.containsKey(expectation.getAsset_group_id())) + .forEach( + expectation -> { + assetGroupExpectationMap.put(expectation.getAsset_group_id(), expectation); + }); // Results List targets = new ArrayList<>(); List assetsToRefine = new ArrayList<>(); // Players - Map>> groupedByTeamAndUser = playerExpectations.stream() - .collect(Collectors.groupingBy( - RawInjectExpectation::getTeam_id, - Collectors.groupingBy(RawInjectExpectation::getUser_id) - )); - - // Check if each team defined in an inject has an expectation. If not, create a result with default expectations + Map>> groupedByTeamAndUser = + playerExpectations.stream() + .collect( + Collectors.groupingBy( + RawInjectExpectation::getTeam_id, + Collectors.groupingBy(RawInjectExpectation::getUser_id))); + + // Check if each team defined in an inject has an expectation. If not, create a result with + // default expectations if (rawTeamMap != null) { - rawTeamMap.forEach((teamId, team) -> { - // Check if there are no expectations matching the current team - boolean noMatchingExpectations = teamExpectations.stream() - .noneMatch(exp -> exp.getTeam_id().equals(teamId)); - - if (noMatchingExpectations) { - InjectTargetWithResult target = new InjectTargetWithResult( - TargetType.TEAMS, - team.getTeam_id(), - team.getTeam_name(), - defaultExpectationResultsByTypes, - null - ); - targets.add(target); - } - }); + rawTeamMap.forEach( + (teamId, team) -> { + // Check if there are no expectations matching the current team + boolean noMatchingExpectations = + teamExpectations.stream().noneMatch(exp -> exp.getTeam_id().equals(teamId)); + + if (noMatchingExpectations) { + InjectTargetWithResult target = + new InjectTargetWithResult( + TargetType.TEAMS, + team.getTeam_id(), + team.getTeam_name(), + defaultExpectationResultsByTypes, + null); + targets.add(target); + } + }); } - // Check if each asset defined in an inject has an expectation. If not, create a result with default expectations + // Check if each asset defined in an inject has an expectation. If not, create a result with + // default expectations if (rawAssetMap != null) { - rawAssetMap.forEach((assetId, asset) -> { - // Check if there are no expectations matching the current asset - boolean noMatchingExpectations = assetExpectations.stream() - .noneMatch(exp -> exp.getAsset_id().equals(asset.getAsset_id())); - - if (noMatchingExpectations) { - InjectTargetWithResult target = new InjectTargetWithResult( - TargetType.ASSETS, - asset.getAsset_id(), - asset.getAsset_name(), - defaultExpectationResultsByTypes, - Objects.equals(asset.getAsset_type(), "Endpoint") - ? Endpoint.PLATFORM_TYPE.valueOf(asset.getEndpoint_platform()) - : null - ); - - targets.add(target); - injectAssetIds.add(assetId); - } - }); + rawAssetMap.forEach( + (assetId, asset) -> { + // Check if there are no expectations matching the current asset + boolean noMatchingExpectations = + assetExpectations.stream() + .noneMatch(exp -> exp.getAsset_id().equals(asset.getAsset_id())); + + if (noMatchingExpectations) { + InjectTargetWithResult target = + new InjectTargetWithResult( + TargetType.ASSETS, + asset.getAsset_id(), + asset.getAsset_name(), + defaultExpectationResultsByTypes, + Objects.equals(asset.getAsset_type(), "Endpoint") + ? Endpoint.PLATFORM_TYPE.valueOf(asset.getEndpoint_platform()) + : null); + + targets.add(target); + injectAssetIds.add(assetId); + } + }); } - // Check if each asset group defined in an inject has an expectation. If not, create a result with default expectations + // Check if each asset group defined in an inject has an expectation. If not, create a result + // with default expectations if (rawAssetGroupMap != null) { - rawAssetGroupMap.forEach((groupId, assetGroup) -> { - // Check if there are no expectations matching the current asset group - boolean noMatchingExpectations = assetGroupExpectations.stream() - .noneMatch(exp -> exp.getAsset_group_id().equals(assetGroup.getAsset_group_id())); - - List children = new ArrayList<>(); - - // Process each asset in the asset group - assetGroup.getAsset_ids().forEach(assetId -> { - RawAsset finalAsset = rawAssetMap.get(assetId); - if (finalAsset != null) { - children.add(new InjectTargetWithResult( - TargetType.ASSETS, - assetId, - finalAsset.getAsset_name(), - defaultExpectationResultsByTypes, - Objects.equals(finalAsset.getAsset_type(), "Endpoint") - ? Endpoint.PLATFORM_TYPE.valueOf(finalAsset.getEndpoint_platform()) - : null - )); - } - }); + rawAssetGroupMap.forEach( + (groupId, assetGroup) -> { + // Check if there are no expectations matching the current asset group + boolean noMatchingExpectations = + assetGroupExpectations.stream() + .noneMatch( + exp -> exp.getAsset_group_id().equals(assetGroup.getAsset_group_id())); + + List children = new ArrayList<>(); + + // Process each asset in the asset group + assetGroup + .getAsset_ids() + .forEach( + assetId -> { + RawAsset finalAsset = rawAssetMap.get(assetId); + if (finalAsset != null) { + children.add( + new InjectTargetWithResult( + TargetType.ASSETS, + assetId, + finalAsset.getAsset_name(), + defaultExpectationResultsByTypes, + Objects.equals(finalAsset.getAsset_type(), "Endpoint") + ? Endpoint.PLATFORM_TYPE.valueOf( + finalAsset.getEndpoint_platform()) + : null)); + } + }); + + // Add dynamic assets as children + if (dynamicAssetGroupMap.containsKey(assetGroup.getAsset_group_id())) { + dynamicAssetGroupMap + .get(assetGroup.getAsset_group_id()) + .forEach( + dynamicAsset -> { + children.add( + new InjectTargetWithResult( + TargetType.ASSETS, + dynamicAsset.getId(), + dynamicAsset.getName(), + defaultExpectationResultsByTypes, + Objects.equals(dynamicAsset.getType(), "Endpoint") + ? Endpoint.PLATFORM_TYPE.valueOf( + String.valueOf(dynamicAsset.getPlatform())) + : null)); + }); + } + + if (noMatchingExpectations) { + InjectTargetWithResult target = + new InjectTargetWithResult( + TargetType.ASSETS_GROUPS, + assetGroup.getAsset_group_id(), + assetGroup.getAsset_group_name(), + defaultExpectationResultsByTypes, + children, + null); - // Add dynamic assets as children - if(dynamicAssetGroupMap.containsKey(assetGroup.getAsset_group_id())) { - dynamicAssetGroupMap.get(assetGroup.getAsset_group_id()).forEach(dynamicAsset -> { - children.add(new InjectTargetWithResult( - TargetType.ASSETS, - dynamicAsset.getId(), - dynamicAsset.getName(), - defaultExpectationResultsByTypes, - Objects.equals(dynamicAsset.getType(), "Endpoint") ? Endpoint.PLATFORM_TYPE.valueOf( - String.valueOf(dynamicAsset.getPlatform())) - : null - )); + targets.add(target); + } }); - } - - if (noMatchingExpectations) { - InjectTargetWithResult target = new InjectTargetWithResult( - TargetType.ASSETS_GROUPS, - assetGroup.getAsset_group_id(), - assetGroup.getAsset_group_name(), - defaultExpectationResultsByTypes, - children, - null - ); - - targets.add(target); - } - }); } - // Calculate team results from expectations if (!teamExpectations.isEmpty()) { targets.addAll( - teamExpectations - .stream() + teamExpectations.stream() .collect( - Collectors.groupingBy(RawInjectExpectation::getTeam_id, + Collectors.groupingBy( + RawInjectExpectation::getTeam_id, Collectors.collectingAndThen( - Collectors.toList(), AtomicTestingUtils::getExpectationResultByTypesFromRaw) - ) - ) - .entrySet().stream() - .map(entry -> new InjectTargetWithResult(TargetType.TEAMS, entry.getKey(), - rawTeamMap.get(teamExpectationMap.get(entry.getKey()).getTeam_id()).getTeam_name(), entry.getValue(), - playerExpectations.isEmpty() ? List.of() - : calculateResultsforPlayersFromRaw(groupedByTeamAndUser.get(entry.getKey()), rawUserMap), null)) - .toList() - ); + Collectors.toList(), + AtomicTestingUtils::getExpectationResultByTypesFromRaw))) + .entrySet() + .stream() + .map( + entry -> + new InjectTargetWithResult( + TargetType.TEAMS, + entry.getKey(), + rawTeamMap + .get(teamExpectationMap.get(entry.getKey()).getTeam_id()) + .getTeam_name(), + entry.getValue(), + playerExpectations.isEmpty() + ? List.of() + : calculateResultsforPlayersFromRaw( + groupedByTeamAndUser.get(entry.getKey()), rawUserMap), + null)) + .toList()); } // Calculate asset results from expectations if (!assetExpectations.isEmpty()) { - // Assets are saves in assetsToRefine because we need check if the asset is linked to the inject and, at the same time, also linked to the asset group + // Assets are saves in assetsToRefine because we need check if the asset is linked to the + // inject and, at the same time, also linked to the asset group assetsToRefine.addAll( - assetExpectations - .stream() + assetExpectations.stream() .collect( - Collectors.groupingBy(RawInjectExpectation::getAsset_id, + Collectors.groupingBy( + RawInjectExpectation::getAsset_id, Collectors.collectingAndThen( - Collectors.toList(), AtomicTestingUtils::getExpectationResultByTypesFromRaw) - ) - ) - .entrySet().stream() - .map(entry -> new InjectTargetWithResult(TargetType.ASSETS, entry.getKey(), - rawAssetMap.get(assetExpectationMap.get(entry.getKey()).getAsset_id()).getAsset_name(), entry.getValue(), - Objects.equals(rawAssetMap.get(entry.getKey()).getAsset_type(), "Endpoint") - ? Endpoint.PLATFORM_TYPE.valueOf(rawAssetMap.get(entry.getKey()).getEndpoint_platform()) : null)) - .toList() - ); + Collectors.toList(), + AtomicTestingUtils::getExpectationResultByTypesFromRaw))) + .entrySet() + .stream() + .map( + entry -> + new InjectTargetWithResult( + TargetType.ASSETS, + entry.getKey(), + rawAssetMap + .get(assetExpectationMap.get(entry.getKey()).getAsset_id()) + .getAsset_name(), + entry.getValue(), + Objects.equals( + rawAssetMap.get(entry.getKey()).getAsset_type(), "Endpoint") + ? Endpoint.PLATFORM_TYPE.valueOf( + rawAssetMap.get(entry.getKey()).getEndpoint_platform()) + : null)) + .toList()); } - // -- ASSETS GROUPS - CHILDREN -- List assetsToRemove = new ArrayList<>(); // Calculate asset groups results from expectations if (!assetGroupExpectations.isEmpty()) { - targets.addAll(assetGroupExpectations - .stream() - .collect( - Collectors.groupingBy(RawInjectExpectation::getAsset_group_id, - Collectors.collectingAndThen( - Collectors.toList(), AtomicTestingUtils::getExpectationResultByTypesFromRaw) - ) - ) - .entrySet().stream() - .map(entry -> { - List children = new ArrayList<>(); - - // Loop into assetsToRefine to keep just assets linked to asset group - for (InjectTargetWithResult asset : assetsToRefine) { - boolean foundExpectationForAsset = rawAssetGroupMap.get(assetGroupExpectationMap.get(entry.getKey())).getAsset_ids().stream() - .anyMatch(assetChild -> assetChild.equals(asset.getId())); - - // Verify if any expectation is related to a dynamic assets - boolean foundExpectationForDynamicAssets = dynamicAssetGroupMap.get(entry.getKey()).stream() - .anyMatch(assetChild -> assetChild.equals(asset.getId())); - - if (foundExpectationForAsset || foundExpectationForDynamicAssets) { - children.add(asset); - // We add the assetId to the removal list for assets that are directly linked to the inject - assetsToRemove.add(asset); - } - } - - // Other children without expectations are added with a default result - rawAssetGroupMap.get(assetGroupExpectationMap.get(entry.getKey()).getAsset_group_id()).getAsset_ids().forEach(asset -> { - boolean foundAssetsWithoutResults = children.stream() - .noneMatch(child -> child.getId().equals(asset)); - if (foundAssetsWithoutResults) { - children.add(new InjectTargetWithResult( - TargetType.ASSETS, - asset, - rawAssetMap.get(asset).getAsset_name(), - defaultExpectationResultsByTypes, - Objects.equals(rawAssetMap.get(asset).getAsset_type(), "Endpoint") - ? Endpoint.PLATFORM_TYPE.valueOf(rawAssetMap.get(asset).getEndpoint_platform()) - : null - )); - } - }); - - // For dynamicAssets - if(dynamicAssetGroupMap.containsKey(entry.getKey())) { - dynamicAssetGroupMap.get(entry.getKey()).forEach(dynamicAsset -> { - boolean foundDynamicAssetsWithoutResults = children.stream() - .noneMatch(child -> child.getId().equals(dynamicAsset.getId())); - if (foundDynamicAssetsWithoutResults) { - children.add(new InjectTargetWithResult( - TargetType.ASSETS, - dynamicAsset.getId(), - dynamicAsset.getName(), - defaultExpectationResultsByTypes, - Objects.equals(dynamicAsset.getType(), "Endpoint") ? Endpoint.PLATFORM_TYPE.valueOf( - String.valueOf(dynamicAsset.getPlatform())) - : null - )); - } - }); - } - - return new InjectTargetWithResult(TargetType.ASSETS_GROUPS, entry.getKey(), - rawAssetGroupMap.get(assetGroupExpectationMap.get(entry.getKey()).getAsset_group_id()).getAsset_group_name(), entry.getValue(), - sortResults(children), null); - }) - .toList()); + targets.addAll( + assetGroupExpectations.stream() + .collect( + Collectors.groupingBy( + RawInjectExpectation::getAsset_group_id, + Collectors.collectingAndThen( + Collectors.toList(), + AtomicTestingUtils::getExpectationResultByTypesFromRaw))) + .entrySet() + .stream() + .map( + entry -> { + List children = new ArrayList<>(); + + // Loop into assetsToRefine to keep just assets linked to asset group + for (InjectTargetWithResult asset : assetsToRefine) { + boolean foundExpectationForAsset = + rawAssetGroupMap + .get(assetGroupExpectationMap.get(entry.getKey())) + .getAsset_ids() + .stream() + .anyMatch(assetChild -> assetChild.equals(asset.getId())); + + // Verify if any expectation is related to a dynamic assets + boolean foundExpectationForDynamicAssets = + dynamicAssetGroupMap.get(entry.getKey()).stream() + .anyMatch(assetChild -> assetChild.equals(asset.getId())); + + if (foundExpectationForAsset || foundExpectationForDynamicAssets) { + children.add(asset); + // We add the assetId to the removal list for assets that are directly + // linked to the inject + assetsToRemove.add(asset); + } + } + + // Other children without expectations are added with a default result + rawAssetGroupMap + .get(assetGroupExpectationMap.get(entry.getKey()).getAsset_group_id()) + .getAsset_ids() + .forEach( + asset -> { + boolean foundAssetsWithoutResults = + children.stream().noneMatch(child -> child.getId().equals(asset)); + if (foundAssetsWithoutResults) { + children.add( + new InjectTargetWithResult( + TargetType.ASSETS, + asset, + rawAssetMap.get(asset).getAsset_name(), + defaultExpectationResultsByTypes, + Objects.equals( + rawAssetMap.get(asset).getAsset_type(), "Endpoint") + ? Endpoint.PLATFORM_TYPE.valueOf( + rawAssetMap.get(asset).getEndpoint_platform()) + : null)); + } + }); + + // For dynamicAssets + if (dynamicAssetGroupMap.containsKey(entry.getKey())) { + dynamicAssetGroupMap + .get(entry.getKey()) + .forEach( + dynamicAsset -> { + boolean foundDynamicAssetsWithoutResults = + children.stream() + .noneMatch( + child -> child.getId().equals(dynamicAsset.getId())); + if (foundDynamicAssetsWithoutResults) { + children.add( + new InjectTargetWithResult( + TargetType.ASSETS, + dynamicAsset.getId(), + dynamicAsset.getName(), + defaultExpectationResultsByTypes, + Objects.equals(dynamicAsset.getType(), "Endpoint") + ? Endpoint.PLATFORM_TYPE.valueOf( + String.valueOf(dynamicAsset.getPlatform())) + : null)); + } + }); + } + + return new InjectTargetWithResult( + TargetType.ASSETS_GROUPS, + entry.getKey(), + rawAssetGroupMap + .get(assetGroupExpectationMap.get(entry.getKey()).getAsset_group_id()) + .getAsset_group_name(), + entry.getValue(), + sortResults(children), + null); + }) + .toList()); } - // Compare the assets directly linked to the inject {injectAssetIds} to retain only the results from these assets + // Compare the assets directly linked to the inject {injectAssetIds} to retain only the results + // from these assets assetsToRefine.removeAll( - assetsToRemove - .stream() - .filter( - asset -> !injectAssetIds.contains(asset.getId())) - .toList()); + assetsToRemove.stream().filter(asset -> !injectAssetIds.contains(asset.getId())).toList()); targets.addAll(assetsToRefine); return sortResults(targets); @@ -602,44 +734,56 @@ public static List getTargetsWithResultsFromRaw( private static List calculateResultsforPlayers( Map> expectationsByUser) { return expectationsByUser.entrySet().stream() - .map(userEntry -> new InjectTargetWithResult( - TargetType.PLAYER, - userEntry.getKey().getId(), - userEntry.getKey().getName(), - getExpectationResultByTypes(userEntry.getValue()), - null - )) + .map( + userEntry -> + new InjectTargetWithResult( + TargetType.PLAYER, + userEntry.getKey().getId(), + userEntry.getKey().getName(), + getExpectationResultByTypes(userEntry.getValue()), + null)) .toList(); } private static List calculateResultsforPlayersFromRaw( - Map> expectationsByUser, - Map rawUserMap - ) { + Map> expectationsByUser, Map rawUserMap) { return expectationsByUser.entrySet().stream() - .map(userEntry -> new InjectTargetWithResult( - TargetType.PLAYER, - userEntry.getKey(), - StringUtils.getName(rawUserMap.get(userEntry.getValue().get(0).getUser_id()).getUser_firstname(), rawUserMap.get(userEntry.getValue().get(0).getUser_id()).getUser_lastname()), - getExpectationResultByTypesFromRaw(userEntry.getValue()), - null - )) + .map( + userEntry -> + new InjectTargetWithResult( + TargetType.PLAYER, + userEntry.getKey(), + StringUtils.getName( + rawUserMap + .get(userEntry.getValue().get(0).getUser_id()) + .getUser_firstname(), + rawUserMap + .get(userEntry.getValue().get(0).getUser_id()) + .getUser_lastname()), + getExpectationResultByTypesFromRaw(userEntry.getValue()), + null)) .toList(); } // -- RESULTS BY EXPECTATION TYPE -- @NotNull - public static List getExpectationResultByTypes(final List expectations) { + public static List getExpectationResultByTypes( + final List expectations) { List preventionScores = getScores(List.of(EXPECTATION_TYPE.PREVENTION), expectations); List detectionScores = getScores(List.of(EXPECTATION_TYPE.DETECTION), expectations); - List humanScores = getScores( - List.of(EXPECTATION_TYPE.ARTICLE, EXPECTATION_TYPE.CHALLENGE, EXPECTATION_TYPE.MANUAL), expectations); + List humanScores = + getScores( + List.of(EXPECTATION_TYPE.ARTICLE, EXPECTATION_TYPE.CHALLENGE, EXPECTATION_TYPE.MANUAL), + expectations); List resultAvgOfExpectations = new ArrayList<>(); - getExpectationByType(ExpectationType.PREVENTION, preventionScores).map(resultAvgOfExpectations::add); - getExpectationByType(ExpectationType.DETECTION, detectionScores).map(resultAvgOfExpectations::add); - getExpectationByType(ExpectationType.HUMAN_RESPONSE, humanScores).map(resultAvgOfExpectations::add); + getExpectationByType(ExpectationType.PREVENTION, preventionScores) + .map(resultAvgOfExpectations::add); + getExpectationByType(ExpectationType.DETECTION, detectionScores) + .map(resultAvgOfExpectations::add); + getExpectationByType(ExpectationType.HUMAN_RESPONSE, humanScores) + .map(resultAvgOfExpectations::add); return resultAvgOfExpectations; } @@ -647,85 +791,92 @@ public static List getExpectationResultByTypes(final L @NotNull public static List getExpectationResultByTypesFromRaw( List expectations) { - List preventionScores = getScoresFromRaw(List.of(EXPECTATION_TYPE.PREVENTION), expectations); - List detectionScores = getScoresFromRaw(List.of(EXPECTATION_TYPE.DETECTION), expectations); - List humanScores = getScoresFromRaw( - List.of(EXPECTATION_TYPE.ARTICLE, EXPECTATION_TYPE.CHALLENGE, EXPECTATION_TYPE.MANUAL), expectations); + List preventionScores = + getScoresFromRaw(List.of(EXPECTATION_TYPE.PREVENTION), expectations); + List detectionScores = + getScoresFromRaw(List.of(EXPECTATION_TYPE.DETECTION), expectations); + List humanScores = + getScoresFromRaw( + List.of(EXPECTATION_TYPE.ARTICLE, EXPECTATION_TYPE.CHALLENGE, EXPECTATION_TYPE.MANUAL), + expectations); List resultAvgOfExpectations = new ArrayList<>(); - getExpectationByType(ExpectationType.PREVENTION, preventionScores).ifPresent(resultAvgOfExpectations::add); - getExpectationByType(ExpectationType.DETECTION, detectionScores).ifPresent(resultAvgOfExpectations::add); - getExpectationByType(ExpectationType.HUMAN_RESPONSE, humanScores).ifPresent(resultAvgOfExpectations::add); + getExpectationByType(ExpectationType.PREVENTION, preventionScores) + .ifPresent(resultAvgOfExpectations::add); + getExpectationByType(ExpectationType.DETECTION, detectionScores) + .ifPresent(resultAvgOfExpectations::add); + getExpectationByType(ExpectationType.HUMAN_RESPONSE, humanScores) + .ifPresent(resultAvgOfExpectations::add); return resultAvgOfExpectations; } - // -- NORMALIZED SCORES -- - public static List getScores(final List types, final List expectations) { - return expectations - .stream() + public static List getScores( + final List types, final List expectations) { + return expectations.stream() .filter(e -> types.contains(e.getType())) - .map(injectExpectation -> { - if (injectExpectation.getScore() == null) { - return null; - } - if (injectExpectation.getTeam() != null) { - if (injectExpectation.getScore() >= injectExpectation.getExpectedScore()) { - return 1.0; - } else { - return 0.0; - } - } else { - if (injectExpectation.getScore() >= injectExpectation.getExpectedScore()) { - return 1.0; - } - if (injectExpectation.getScore() == 0) { - return 0.0; - } - return 0.5; - } - }) + .map( + injectExpectation -> { + if (injectExpectation.getScore() == null) { + return null; + } + if (injectExpectation.getTeam() != null) { + if (injectExpectation.getScore() >= injectExpectation.getExpectedScore()) { + return 1.0; + } else { + return 0.0; + } + } else { + if (injectExpectation.getScore() >= injectExpectation.getExpectedScore()) { + return 1.0; + } + if (injectExpectation.getScore() == 0) { + return 0.0; + } + return 0.5; + } + }) .toList(); } - public static List getScoresFromRaw(List types, - List expectations) { - return expectations - .stream() + public static List getScoresFromRaw( + List types, List expectations) { + return expectations.stream() .filter(e -> types.contains(EXPECTATION_TYPE.valueOf(e.getInject_expectation_type()))) - .map(rawInjectExpectation -> { - if (rawInjectExpectation.getInject_expectation_score() == null) { - return null; - } - if (rawInjectExpectation.getTeam_id() != null) { - if (rawInjectExpectation.getInject_expectation_score() - >= rawInjectExpectation.getInject_expectation_expected_score()) { - return 1.0; - } else { - return 0.0; - } - } else { - if (rawInjectExpectation.getInject_expectation_score() - >= rawInjectExpectation.getInject_expectation_expected_score()) { - return 1.0; - } - if (rawInjectExpectation.getInject_expectation_score() == 0) { - return 0.0; - } - return 0.5; - } - }) + .map( + rawInjectExpectation -> { + if (rawInjectExpectation.getInject_expectation_score() == null) { + return null; + } + if (rawInjectExpectation.getTeam_id() != null) { + if (rawInjectExpectation.getInject_expectation_score() + >= rawInjectExpectation.getInject_expectation_expected_score()) { + return 1.0; + } else { + return 0.0; + } + } else { + if (rawInjectExpectation.getInject_expectation_score() + >= rawInjectExpectation.getInject_expectation_expected_score()) { + return 1.0; + } + if (rawInjectExpectation.getInject_expectation_score() == 0) { + return 0.0; + } + return 0.5; + } + }) .toList(); } - // -- UTILS -- @NotNull private static List getDefaultExpectationResultsByTypes() { - List types = List.of(ExpectationType.PREVENTION, ExpectationType.DETECTION, - ExpectationType.HUMAN_RESPONSE); + List types = + List.of( + ExpectationType.PREVENTION, ExpectationType.DETECTION, ExpectationType.HUMAN_RESPONSE); return types.stream() .map(type -> getExpectationByType(type, Collections.emptyList())) .filter(Optional::isPresent) @@ -733,46 +884,51 @@ private static List getDefaultExpectationResultsByType .toList(); } - public static Optional getExpectationByType(final ExpectationType type, - final List scores) { + public static Optional getExpectationByType( + final ExpectationType type, final List scores) { if (scores.isEmpty()) { return Optional.of( - new ExpectationResultsByType(type, InjectExpectation.EXPECTATION_STATUS.UNKNOWN, Collections.emptyList())); + new ExpectationResultsByType( + type, InjectExpectation.EXPECTATION_STATUS.UNKNOWN, Collections.emptyList())); } OptionalDouble avgResponse = calculateAverageFromExpectations(scores); if (avgResponse.isPresent()) { - return Optional.of(new ExpectationResultsByType(type, getResult(avgResponse), getResultDetail(type, scores))); + return Optional.of( + new ExpectationResultsByType( + type, getResult(avgResponse), getResultDetail(type, scores))); } - return Optional.of(new ExpectationResultsByType(type, InjectExpectation.EXPECTATION_STATUS.PENDING, - getResultDetail(type, scores))); + return Optional.of( + new ExpectationResultsByType( + type, InjectExpectation.EXPECTATION_STATUS.PENDING, getResultDetail(type, scores))); } - public static List getRefinedExpectations(Inject inject, List targetIds) { - return inject - .getExpectations() - .stream() + public static List getRefinedExpectations( + Inject inject, List targetIds) { + return inject.getExpectations().stream() .filter(expectation -> targetIds.contains(expectation.getTargetId())) - .filter(expectation -> expectation.getUser() - == null) // Filter expectations linked to players. For global results, We use Team expectations + .filter( + expectation -> + expectation.getUser() + == null) // Filter expectations linked to players. For global results, We use + // Team expectations .toList(); } public static InjectExpectation.EXPECTATION_STATUS getResult(final OptionalDouble avg) { Double avgAsDouble = avg.getAsDouble(); - return avgAsDouble == 0.0 ? InjectExpectation.EXPECTATION_STATUS.FAILED : - (avgAsDouble == 1.0 ? InjectExpectation.EXPECTATION_STATUS.SUCCESS : - InjectExpectation.EXPECTATION_STATUS.PARTIAL); + return avgAsDouble == 0.0 + ? InjectExpectation.EXPECTATION_STATUS.FAILED + : (avgAsDouble == 1.0 + ? InjectExpectation.EXPECTATION_STATUS.SUCCESS + : InjectExpectation.EXPECTATION_STATUS.PARTIAL); } public static OptionalDouble calculateAverageFromExpectations(final List scores) { - return scores.stream() - .filter(Objects::nonNull) - .mapToDouble(Double::doubleValue) - .average(); + return scores.stream().filter(Objects::nonNull).mapToDouble(Double::doubleValue).average(); } - public static List getResultDetail(final ExpectationType type, - final List normalizedScores) { + public static List getResultDetail( + final ExpectationType type, final List normalizedScores) { long successCount = normalizedScores.stream().filter(s -> s != null && s.equals(1.0)).count(); long partialCount = normalizedScores.stream().filter(s -> s != null && s.equals(0.5)).count(); long pendingCount = normalizedScores.stream().filter(Objects::isNull).count(); @@ -782,12 +938,10 @@ public static List getResultDetail(final ExpectationType typ new ResultDistribution(ExpectationType.SUCCESS_ID, type.successLabel, (int) successCount), new ResultDistribution(ExpectationType.PENDING_ID, type.pendingLabel, (int) pendingCount), new ResultDistribution(ExpectationType.PARTIAL_ID, type.partialLabel, (int) partialCount), - new ResultDistribution(ExpectationType.FAILED_ID, type.failureLabel, (int) failureCount) - ); + new ResultDistribution(ExpectationType.FAILED_ID, type.failureLabel, (int) failureCount)); } private static List sortResults(List targets) { return targets.stream().sorted(Comparator.comparing(InjectTargetWithResult::getName)).toList(); } - } diff --git a/openbas-api/src/main/java/io/openbas/utils/Constants.java b/openbas-api/src/main/java/io/openbas/utils/Constants.java index 66187d4721..6754402984 100644 --- a/openbas-api/src/main/java/io/openbas/utils/Constants.java +++ b/openbas-api/src/main/java/io/openbas/utils/Constants.java @@ -2,7 +2,7 @@ public class Constants { - private Constants () {} + private Constants() {} - public static final String ARTICLES = "articles"; + public static final String ARTICLES = "articles"; } diff --git a/openbas-api/src/main/java/io/openbas/utils/CopyObjectListUtils.java b/openbas-api/src/main/java/io/openbas/utils/CopyObjectListUtils.java index a286869ef6..4483b8598f 100644 --- a/openbas-api/src/main/java/io/openbas/utils/CopyObjectListUtils.java +++ b/openbas-api/src/main/java/io/openbas/utils/CopyObjectListUtils.java @@ -3,70 +3,74 @@ import io.openbas.database.model.Base; import jakarta.persistence.Id; import jakarta.validation.constraints.NotNull; -import org.apache.commons.beanutils.BeanUtils; - import java.lang.reflect.Field; import java.lang.reflect.InvocationTargetException; import java.util.*; +import org.apache.commons.beanutils.BeanUtils; public class CopyObjectListUtils { - public static List copyWithoutIds(@NotNull final List origins, Class clazz) { - List destinations = new ArrayList<>(); - return copyCollection(origins, clazz, destinations, true); - } - public static List copy(@NotNull final List origins, Class clazz) { - List destinations = new ArrayList<>(); - return copyCollection(origins, clazz, destinations, false); - } + public static List copyWithoutIds( + @NotNull final List origins, Class clazz) { + List destinations = new ArrayList<>(); + return copyCollection(origins, clazz, destinations, true); + } - public static Set copy(@NotNull final Set origins, Class clazz) { - Set destinations = new HashSet<>(); - return copyCollection(origins, clazz, destinations, false); - } + public static List copy(@NotNull final List origins, Class clazz) { + List destinations = new ArrayList<>(); + return copyCollection(origins, clazz, destinations, false); + } + + public static Set copy(@NotNull final Set origins, Class clazz) { + Set destinations = new HashSet<>(); + return copyCollection(origins, clazz, destinations, false); + } - public static > C copyCollection( - @NotNull final C origins, Class clazz, C destinations, Boolean withoutId) { - origins.forEach(origin -> { - try { - if (withoutId){ - destinations.add(copyObjectWithoutId(origin, clazz)); - } else { - T destination = clazz.getDeclaredConstructor().newInstance(); - BeanUtils.copyProperties(destination, origin); - destinations.add(destination); - } - } catch (IllegalAccessException | InvocationTargetException | InstantiationException | - NoSuchMethodException e) { - throw new RuntimeException("Failed to copy object", e); + public static > C copyCollection( + @NotNull final C origins, Class clazz, C destinations, Boolean withoutId) { + origins.forEach( + origin -> { + try { + if (withoutId) { + destinations.add(copyObjectWithoutId(origin, clazz)); + } else { + T destination = clazz.getDeclaredConstructor().newInstance(); + BeanUtils.copyProperties(destination, origin); + destinations.add(destination); } + } catch (IllegalAccessException + | InvocationTargetException + | InstantiationException + | NoSuchMethodException e) { + throw new RuntimeException("Failed to copy object", e); + } }); - return destinations; - } - - public static T copyObjectWithoutId(C origin, Class targetClass) { - try { - T target = targetClass.getDeclaredConstructor().newInstance(); + return destinations; + } - // Get all declared fields from the source object - Field[] fields = origin.getClass().getDeclaredFields(); + public static T copyObjectWithoutId(C origin, Class targetClass) { + try { + T target = targetClass.getDeclaredConstructor().newInstance(); - for (Field field : fields) { - field.setAccessible(true); + // Get all declared fields from the source object + Field[] fields = origin.getClass().getDeclaredFields(); - // Skip the 'id' field - if (field.isAnnotationPresent(Id.class)) { - continue; - } + for (Field field : fields) { + field.setAccessible(true); - // Copy the field value from source to target - Field targetField = target.getClass().getDeclaredField(field.getName()); - targetField.setAccessible(true); - targetField.set(target, field.get(origin)); - } - return target; - } catch (Exception e) { - throw new RuntimeException("Failed to copy object", e); + // Skip the 'id' field + if (field.isAnnotationPresent(Id.class)) { + continue; } + + // Copy the field value from source to target + Field targetField = target.getClass().getDeclaredField(field.getName()); + targetField.setAccessible(true); + targetField.set(target, field.get(origin)); + } + return target; + } catch (Exception e) { + throw new RuntimeException("Failed to copy object", e); } + } } diff --git a/openbas-api/src/main/java/io/openbas/utils/CustomFilterUtils.java b/openbas-api/src/main/java/io/openbas/utils/CustomFilterUtils.java index 5b131f9c30..99e1ddf651 100644 --- a/openbas-api/src/main/java/io/openbas/utils/CustomFilterUtils.java +++ b/openbas-api/src/main/java/io/openbas/utils/CustomFilterUtils.java @@ -3,16 +3,13 @@ import io.openbas.database.model.Base; import io.openbas.database.model.Filters; import io.openbas.utils.pagination.SearchPaginationInput; +import java.util.function.UnaryOperator; import org.jetbrains.annotations.NotNull; import org.springframework.data.jpa.domain.Specification; -import java.util.function.UnaryOperator; - public class CustomFilterUtils { - private CustomFilterUtils() { - - } + private CustomFilterUtils() {} public static UnaryOperator> computeMode( @NotNull final SearchPaginationInput searchPaginationInput, @@ -25,5 +22,4 @@ public static UnaryOperator> computeMode( return (Specification specification) -> specification; } } - } diff --git a/openbas-api/src/main/java/io/openbas/utils/ExerciseMapper.java b/openbas-api/src/main/java/io/openbas/utils/ExerciseMapper.java index e1f60514ef..5455711731 100644 --- a/openbas-api/src/main/java/io/openbas/utils/ExerciseMapper.java +++ b/openbas-api/src/main/java/io/openbas/utils/ExerciseMapper.java @@ -4,11 +4,10 @@ import io.openbas.database.model.Tag; import io.openbas.database.raw.RawExerciseSimple; import io.openbas.rest.exercise.form.ExerciseSimple; -import lombok.RequiredArgsConstructor; -import org.springframework.stereotype.Component; - import java.util.HashSet; import java.util.stream.Collectors; +import lombok.RequiredArgsConstructor; +import org.springframework.stereotype.Component; @RequiredArgsConstructor @Component @@ -16,18 +15,20 @@ public class ExerciseMapper { private final ResultUtils resultUtils; - public ExerciseSimple fromRawExerciseSimple(RawExerciseSimple rawExercise) { ExerciseSimple simple = new ExerciseSimple(); simple.setId(rawExercise.getExercise_id()); simple.setName(rawExercise.getExercise_name()); if (rawExercise.getExercise_tags() != null) { - simple.setTags(rawExercise.getExercise_tags().stream().map((tagId) -> { - Tag tag = new Tag(); - tag.setId(tagId); - return tag; - } - ).collect(Collectors.toSet())); + simple.setTags( + rawExercise.getExercise_tags().stream() + .map( + (tagId) -> { + Tag tag = new Tag(); + tag.setId(tagId); + return tag; + }) + .collect(Collectors.toSet())); } else { simple.setTags(new HashSet<>()); } diff --git a/openbas-api/src/main/java/io/openbas/utils/ExpectationUtils.java b/openbas-api/src/main/java/io/openbas/utils/ExpectationUtils.java index 66b29834b7..35d2057b7c 100644 --- a/openbas-api/src/main/java/io/openbas/utils/ExpectationUtils.java +++ b/openbas-api/src/main/java/io/openbas/utils/ExpectationUtils.java @@ -4,7 +4,6 @@ import io.openbas.database.model.InjectExpectationResult; import io.openbas.database.model.Team; import io.openbas.rest.exception.ElementNotFoundException; - import java.time.Instant; import java.util.ArrayList; import java.util.List; @@ -13,65 +12,88 @@ public class ExpectationUtils { - private ExpectationUtils() { - - } + private ExpectationUtils() {} - public static List processByValidationType(boolean isaNewExpectationResult, List childrenExpectations, List parentExpectations, Map> playerByTeam) { - List updatedExpectations = new ArrayList<>(); + public static List processByValidationType( + boolean isaNewExpectationResult, + List childrenExpectations, + List parentExpectations, + Map> playerByTeam) { + List updatedExpectations = new ArrayList<>(); - childrenExpectations.stream().findAny().ifPresentOrElse(process -> { - boolean isValidationAtLeastOneTarget = process.isExpectationGroup(); + childrenExpectations.stream() + .findAny() + .ifPresentOrElse( + process -> { + boolean isValidationAtLeastOneTarget = process.isExpectationGroup(); - parentExpectations.forEach(parentExpectation -> { - List toProcess = playerByTeam.get(parentExpectation.getTeam()); - int playersSize = toProcess.size(); // Without Parent expectation - long zeroPlayerResponses = toProcess.stream().filter(exp -> exp.getScore() != null).filter(exp -> exp.getScore() == 0.0).count(); - long nullPlayerResponses = toProcess.stream().filter(exp -> exp.getScore() == null).count(); + parentExpectations.forEach( + parentExpectation -> { + List toProcess = + playerByTeam.get(parentExpectation.getTeam()); + int playersSize = toProcess.size(); // Without Parent expectation + long zeroPlayerResponses = + toProcess.stream() + .filter(exp -> exp.getScore() != null) + .filter(exp -> exp.getScore() == 0.0) + .count(); + long nullPlayerResponses = + toProcess.stream().filter(exp -> exp.getScore() == null).count(); - if (isValidationAtLeastOneTarget) { // Type atLeast - OptionalDouble avgAtLeastOnePlayer = toProcess.stream().filter(exp -> exp.getScore() != null).filter(exp -> exp.getScore() > 0.0).mapToDouble(InjectExpectation::getScore).average(); - if (avgAtLeastOnePlayer.isPresent()) { //Any response is positive + if (isValidationAtLeastOneTarget) { // Type atLeast + OptionalDouble avgAtLeastOnePlayer = + toProcess.stream() + .filter(exp -> exp.getScore() != null) + .filter(exp -> exp.getScore() > 0.0) + .mapToDouble(InjectExpectation::getScore) + .average(); + if (avgAtLeastOnePlayer.isPresent()) { // Any response is positive parentExpectation.setScore(avgAtLeastOnePlayer.getAsDouble()); - } else { - if (zeroPlayerResponses == playersSize) { //All players had failed - parentExpectation.setScore(0.0); + } else { + if (zeroPlayerResponses == playersSize) { // All players had failed + parentExpectation.setScore(0.0); } else { - parentExpectation.setScore(null); + parentExpectation.setScore(null); } - } - } else { // type all - if(nullPlayerResponses == 0){ - OptionalDouble avgAllPlayer = toProcess.stream().mapToDouble(InjectExpectation::getScore).average(); + } + } else { // type all + if (nullPlayerResponses == 0) { + OptionalDouble avgAllPlayer = + toProcess.stream().mapToDouble(InjectExpectation::getScore).average(); parentExpectation.setScore(avgAllPlayer.getAsDouble()); - }else{ - if(zeroPlayerResponses == 0) { - parentExpectation.setScore(null); - }else{ - double sumAllPlayer = toProcess.stream().filter(exp->exp.getScore() != null).mapToDouble(InjectExpectation::getScore).sum(); - parentExpectation.setScore(sumAllPlayer/playersSize); + } else { + if (zeroPlayerResponses == 0) { + parentExpectation.setScore(null); + } else { + double sumAllPlayer = + toProcess.stream() + .filter(exp -> exp.getScore() != null) + .mapToDouble(InjectExpectation::getScore) + .sum(); + parentExpectation.setScore(sumAllPlayer / playersSize); } + } } - } - - if(isaNewExpectationResult) { - InjectExpectationResult result = InjectExpectationResult.builder() - .sourceId("media-pressure") - .sourceType("media-pressure") - .sourceName("Media pressure read") - .result(Instant.now().toString()) - .date(Instant.now().toString()) - .score(process.getExpectedScore()) - .build(); - parentExpectation.getResults().add(result); - } - parentExpectation.setUpdatedAt(Instant.now()); - updatedExpectations.add(parentExpectation); - }); - }, ElementNotFoundException::new); + if (isaNewExpectationResult) { + InjectExpectationResult result = + InjectExpectationResult.builder() + .sourceId("media-pressure") + .sourceType("media-pressure") + .sourceName("Media pressure read") + .result(Instant.now().toString()) + .date(Instant.now().toString()) + .score(process.getExpectedScore()) + .build(); + parentExpectation.getResults().add(result); + } - return updatedExpectations; - } + parentExpectation.setUpdatedAt(Instant.now()); + updatedExpectations.add(parentExpectation); + }); + }, + ElementNotFoundException::new); + return updatedExpectations; + } } diff --git a/openbas-api/src/main/java/io/openbas/utils/InjectUtils.java b/openbas-api/src/main/java/io/openbas/utils/InjectUtils.java index fd06a5caf2..9a4cdf8066 100644 --- a/openbas-api/src/main/java/io/openbas/utils/InjectUtils.java +++ b/openbas-api/src/main/java/io/openbas/utils/InjectUtils.java @@ -7,9 +7,7 @@ public class InjectUtils { - private InjectUtils() { - - } + private InjectUtils() {} public static boolean checkIfRowIsEmpty(Row row) { if (row == null) { @@ -20,7 +18,9 @@ public static boolean checkIfRowIsEmpty(Row row) { } for (int cellNum = row.getFirstCellNum(); cellNum < row.getLastCellNum(); cellNum++) { Cell cell = row.getCell(cellNum); - if (cell != null && cell.getCellType() != CellType.BLANK && StringUtils.isNotBlank(cell.toString())) { + if (cell != null + && cell.getCellType() != CellType.BLANK + && StringUtils.isNotBlank(cell.toString())) { return false; } } diff --git a/openbas-api/src/main/java/io/openbas/utils/ResultUtils.java b/openbas-api/src/main/java/io/openbas/utils/ResultUtils.java index 194a35aa08..2ac7ecc06d 100644 --- a/openbas-api/src/main/java/io/openbas/utils/ResultUtils.java +++ b/openbas-api/src/main/java/io/openbas/utils/ResultUtils.java @@ -1,5 +1,7 @@ package io.openbas.utils; +import static java.util.Collections.emptyList; + import io.openbas.asset.AssetGroupService; import io.openbas.database.model.AttackPattern; import io.openbas.database.model.Endpoint; @@ -10,14 +12,11 @@ import io.openbas.rest.inject.form.InjectExpectationResultsByAttackPattern; import io.openbas.utils.AtomicTestingMapper.ExpectationResultsByType; import jakarta.validation.constraints.NotNull; -import lombok.RequiredArgsConstructor; -import org.springframework.stereotype.Component; - import java.util.*; import java.util.stream.Collectors; import java.util.stream.Stream; - -import static java.util.Collections.emptyList; +import lombok.RequiredArgsConstructor; +import org.springframework.stereotype.Component; @RequiredArgsConstructor @Component @@ -31,7 +30,8 @@ public class ResultUtils { private final AssetGroupService assetGroupService; // -- UTILS -- - public List getResultsByTypes(List injectIds) { + public List getResultsByTypes( + List injectIds) { return computeGlobalExpectationResults(injectIds); } @@ -46,23 +46,27 @@ public List getInjectTargetWithResults(List inje public static List computeInjectExpectationResults( @NotNull final List injects) { - Map> groupedByAttackPattern = injects.stream() - .flatMap(inject -> inject.getInjectorContract() - .map(contract -> contract.getAttackPatterns().stream() - .map(attackPattern -> Map.entry(attackPattern, inject))) - .orElseGet(Stream::empty)) - .collect(Collectors.groupingBy( - Map.Entry::getKey, - Collectors.mapping(Map.Entry::getValue, Collectors.toList()) - )); - - return groupedByAttackPattern.entrySet() - .stream() + Map> groupedByAttackPattern = + injects.stream() + .flatMap( + inject -> + inject + .getInjectorContract() + .map( + contract -> + contract.getAttackPatterns().stream() + .map(attackPattern -> Map.entry(attackPattern, inject))) + .orElseGet(Stream::empty)) + .collect( + Collectors.groupingBy( + Map.Entry::getKey, + Collectors.mapping(Map.Entry::getValue, Collectors.toList()))); + + return groupedByAttackPattern.entrySet().stream() .map(entry -> new InjectExpectationResultsByAttackPattern(entry.getKey(), entry.getValue())) .toList(); } - // -- GLOBAL SCORE -- public List computeGlobalExpectationResults( @NotNull List injectIds) { @@ -71,67 +75,76 @@ public List computeGlobalExpectationResults( } // -- TARGETS WITH RESULTS -- - public List computeTargetResults( - @NotNull List injectIds) { + public List computeTargetResults(@NotNull List injectIds) { // -- EXPECTATIONS -- - List rawInjectExpectations = injectExpectationRepository.rawByInjectId(injectIds); - Map> expectationMap = rawInjectExpectations - .stream().collect(Collectors.groupingBy(RawInjectExpectation::getInject_id)); + List rawInjectExpectations = + injectExpectationRepository.rawByInjectId(injectIds); + Map> expectationMap = + rawInjectExpectations.stream() + .collect(Collectors.groupingBy(RawInjectExpectation::getInject_id)); // -- TEAMS INJECT -- - List teamIds = rawInjectExpectations - .stream() - .map(RawInjectExpectation::getTeam_id) - .filter(Objects::nonNull) - .distinct() - .toList(); + List teamIds = + rawInjectExpectations.stream() + .map(RawInjectExpectation::getTeam_id) + .filter(Objects::nonNull) + .distinct() + .toList(); List rawTeams = teamRepository.rawByIdsOrInjectIds(teamIds, injectIds); - Map teamMap = rawTeams.stream().collect(Collectors.toMap(RawTeam::getTeam_id, rawTeam ->rawTeam)); + Map teamMap = + rawTeams.stream().collect(Collectors.toMap(RawTeam::getTeam_id, rawTeam -> rawTeam)); // -- USER MAP FROM TEAMS -- - List userIds = rawInjectExpectations - .stream() - .map(RawInjectExpectation::getUser_id) - .filter(Objects::nonNull) - .distinct() - .toList(); + List userIds = + rawInjectExpectations.stream() + .map(RawInjectExpectation::getUser_id) + .filter(Objects::nonNull) + .distinct() + .toList(); List rawUsers = userRepository.rawUserByIds(userIds); - Map userMap = rawUsers.stream().collect(Collectors.toMap(RawUser::getUser_id, rawUser ->rawUser)); + Map userMap = + rawUsers.stream().collect(Collectors.toMap(RawUser::getUser_id, rawUser -> rawUser)); // -- ASSETS GROUPS INJECT -- - List assetGroupIds = rawInjectExpectations - .stream() - .map(RawInjectExpectation::getAsset_group_id) - .filter(Objects::nonNull) - .distinct() - .toList(); - - List rawAssetGroups = assetGroupRepository.rawByIdsOrInjectIds(assetGroupIds, injectIds); - Map assetGroupMap = rawAssetGroups.stream().collect(Collectors.toMap(RawAssetGroup::getAsset_group_id, rawAssetGroup ->rawAssetGroup)); + List assetGroupIds = + rawInjectExpectations.stream() + .map(RawInjectExpectation::getAsset_group_id) + .filter(Objects::nonNull) + .distinct() + .toList(); + + List rawAssetGroups = + assetGroupRepository.rawByIdsOrInjectIds(assetGroupIds, injectIds); + Map assetGroupMap = + rawAssetGroups.stream() + .collect( + Collectors.toMap(RawAssetGroup::getAsset_group_id, rawAssetGroup -> rawAssetGroup)); // -- ASSETS INJECT -- - List assetIds = rawInjectExpectations - .stream() - .map(RawInjectExpectation::getAsset_id) - .filter(Objects::nonNull) - .distinct() - .collect(Collectors.toList()); - - assetIds.addAll(rawAssetGroups - .stream() - .flatMap(rawAssetGroup -> rawAssetGroup.getAsset_ids().stream()) - .distinct().toList()); + List assetIds = + rawInjectExpectations.stream() + .map(RawInjectExpectation::getAsset_id) + .filter(Objects::nonNull) + .distinct() + .collect(Collectors.toList()); + + assetIds.addAll( + rawAssetGroups.stream() + .flatMap(rawAssetGroup -> rawAssetGroup.getAsset_ids().stream()) + .distinct() + .toList()); List rawAssets = assetRepository.rawByIdsOrInjectIds(assetIds, injectIds); - Map assetMap = rawAssets.stream().collect(Collectors.toMap(RawAsset::getAsset_id, rawAsset ->rawAsset)); + Map assetMap = + rawAssets.stream().collect(Collectors.toMap(RawAsset::getAsset_id, rawAsset -> rawAsset)); - Map> dynamicForAssetGroupMap = assetGroupService.computeDynamicAssetFromRaw( - rawAssetGroups); + Map> dynamicForAssetGroupMap = + assetGroupService.computeDynamicAssetFromRaw(rawAssetGroups); return injectIds.stream() .flatMap( @@ -142,11 +155,10 @@ public List computeTargetResults( userMap, assetMap, assetGroupMap, - dynamicForAssetGroupMap - ).stream(); + dynamicForAssetGroupMap) + .stream(); }) .distinct() .toList(); } - } diff --git a/openbas-api/src/main/java/io/openbas/utils/SortField.java b/openbas-api/src/main/java/io/openbas/utils/SortField.java index 0059140b1e..0724650ad8 100644 --- a/openbas-api/src/main/java/io/openbas/utils/SortField.java +++ b/openbas-api/src/main/java/io/openbas/utils/SortField.java @@ -1,9 +1,7 @@ package io.openbas.utils; -import lombok.Builder; - import javax.annotation.Nullable; +import lombok.Builder; @Builder -public record SortField(String property, @Nullable String direction) { -} +public record SortField(String property, @Nullable String direction) {} diff --git a/openbas-api/src/main/java/io/openbas/utils/Time.java b/openbas-api/src/main/java/io/openbas/utils/Time.java index 0a313cc88a..584665c62a 100644 --- a/openbas-api/src/main/java/io/openbas/utils/Time.java +++ b/openbas-api/src/main/java/io/openbas/utils/Time.java @@ -1,21 +1,20 @@ package io.openbas.utils; -import jakarta.validation.constraints.NotNull; +import static java.time.ZoneOffset.UTC; +import jakarta.validation.constraints.NotNull; import java.time.Instant; import java.time.LocalDateTime; import java.time.ZonedDateTime; import java.time.format.DateTimeFormatter; import java.util.Locale; -import static java.time.ZoneOffset.UTC; - public class Time { - public static Instant toInstant(@NotNull final String dateString) { - String pattern = "yyyy-MM-dd'T'HH:mm:ss'Z'"; - DateTimeFormatter dateTimeFormatter = DateTimeFormatter.ofPattern(pattern, Locale.getDefault()); - LocalDateTime localDateTime = LocalDateTime.parse(dateString, dateTimeFormatter); - ZonedDateTime zonedDateTime = localDateTime.atZone(UTC); - return zonedDateTime.toInstant(); - } + public static Instant toInstant(@NotNull final String dateString) { + String pattern = "yyyy-MM-dd'T'HH:mm:ss'Z'"; + DateTimeFormatter dateTimeFormatter = DateTimeFormatter.ofPattern(pattern, Locale.getDefault()); + LocalDateTime localDateTime = LocalDateTime.parse(dateString, dateTimeFormatter); + ZonedDateTime zonedDateTime = localDateTime.atZone(UTC); + return zonedDateTime.toInstant(); + } } diff --git a/openbas-api/src/main/java/io/openbas/utils/pagination/PaginationUtils.java b/openbas-api/src/main/java/io/openbas/utils/pagination/PaginationUtils.java index da564873da..d1e7efa451 100644 --- a/openbas-api/src/main/java/io/openbas/utils/pagination/PaginationUtils.java +++ b/openbas-api/src/main/java/io/openbas/utils/pagination/PaginationUtils.java @@ -1,27 +1,24 @@ package io.openbas.utils.pagination; +import static io.openbas.utils.FilterUtilsJpa.computeFilterGroupJpa; +import static io.openbas.utils.pagination.SearchUtilsJpa.computeSearchJpa; +import static io.openbas.utils.pagination.SortUtilsJpa.toSortJpa; + import io.openbas.database.model.Base; import jakarta.persistence.criteria.Join; import jakarta.validation.constraints.NotNull; +import java.util.HashMap; +import java.util.Map; +import java.util.function.BiFunction; import org.apache.commons.lang3.function.TriFunction; import org.springframework.data.domain.Page; import org.springframework.data.domain.PageRequest; import org.springframework.data.domain.Pageable; import org.springframework.data.jpa.domain.Specification; -import java.util.HashMap; -import java.util.Map; -import java.util.function.BiFunction; - -import static io.openbas.utils.FilterUtilsJpa.computeFilterGroupJpa; -import static io.openbas.utils.pagination.SearchUtilsJpa.computeSearchJpa; -import static io.openbas.utils.pagination.SortUtilsJpa.toSortJpa; - public class PaginationUtils { - private PaginationUtils() { - - } + private PaginationUtils() {} // -- JPA -- @@ -34,7 +31,8 @@ public static Page buildPaginationJPA( Specification searchSpecifications = computeSearchJpa(input.getTextSearch()); // Pageable - Pageable pageable = PageRequest.of(input.getPage(), input.getSize(), toSortJpa(input.getSorts(), clazz)); + Pageable pageable = + PageRequest.of(input.getPage(), input.getSize(), toSortJpa(input.getSorts(), clazz)); return findAll.apply(filterSpecifications.and(searchSpecifications), pageable); } @@ -48,48 +46,47 @@ public static Page buildPaginationCriteriaBuilder( Map> joinMap) { // Specification Specification filterSpecifications = computeFilterGroupJpa(input.getFilterGroup(), joinMap); - Specification filterSpecificationsForCount = computeFilterGroupJpa(input.getFilterGroup(), new HashMap<>()); + Specification filterSpecificationsForCount = + computeFilterGroupJpa(input.getFilterGroup(), new HashMap<>()); Specification searchSpecifications = computeSearchJpa(input.getTextSearch()); // Pageable - Pageable pageable = PageRequest.of(input.getPage(), input.getSize(), toSortJpa(input.getSorts(), clazz)); + Pageable pageable = + PageRequest.of(input.getPage(), input.getSize(), toSortJpa(input.getSorts(), clazz)); - return findAll.apply(filterSpecifications.and(searchSpecifications), filterSpecificationsForCount, pageable); + return findAll.apply( + filterSpecifications.and(searchSpecifications), filterSpecificationsForCount, pageable); } public static Page buildPaginationCriteriaBuilder( @NotNull final TriFunction, Specification, Pageable, Page> findAll, @NotNull final SearchPaginationInput input, @NotNull final Class clazz) { - return buildPaginationCriteriaBuilder( - findAll, - input, - clazz, - new HashMap<>() - ); + return buildPaginationCriteriaBuilder(findAll, input, clazz, new HashMap<>()); } /** * Build PaginationJPA with a specified search specifications that replace the default ones + * * @param findAll the find all method * @param input the search inputs * @param clazz the class that we're looking for - * @param specificSearchSpecification the specified - * search specification (will replace the default ones) + * @param specificSearchSpecification the specified search specification (will replace the default + * ones) * @return a Page of results */ public static Page buildPaginationJPA( - @NotNull final BiFunction, Pageable, Page> findAll, - @NotNull final SearchPaginationInput input, - @NotNull final Class clazz, - Specification specificSearchSpecification) { + @NotNull final BiFunction, Pageable, Page> findAll, + @NotNull final SearchPaginationInput input, + @NotNull final Class clazz, + Specification specificSearchSpecification) { // Specification Specification filterSpecifications = computeFilterGroupJpa(input.getFilterGroup()); // Pageable - Pageable pageable = PageRequest.of(input.getPage(), input.getSize(), toSortJpa(input.getSorts(), clazz)); + Pageable pageable = + PageRequest.of(input.getPage(), input.getSize(), toSortJpa(input.getSorts(), clazz)); return findAll.apply(filterSpecifications.and(specificSearchSpecification), pageable); } - } diff --git a/openbas-api/src/main/java/io/openbas/utils/pagination/SearchPaginationInput.java b/openbas-api/src/main/java/io/openbas/utils/pagination/SearchPaginationInput.java index 4ac0131372..dd5f5d364a 100644 --- a/openbas-api/src/main/java/io/openbas/utils/pagination/SearchPaginationInput.java +++ b/openbas-api/src/main/java/io/openbas/utils/pagination/SearchPaginationInput.java @@ -5,14 +5,13 @@ import jakarta.validation.constraints.Max; import jakarta.validation.constraints.Min; import jakarta.validation.constraints.NotNull; +import java.util.ArrayList; +import java.util.List; import lombok.AllArgsConstructor; import lombok.Builder; import lombok.Data; import lombok.NoArgsConstructor; -import java.util.ArrayList; -import java.util.List; - @AllArgsConstructor @NoArgsConstructor @Builder @@ -21,11 +20,13 @@ public class SearchPaginationInput { @Schema(description = "Page number to get") @NotNull - @Min(0) int page = 0; + @Min(0) + int page = 0; @Schema(description = "Element number by page") @NotNull - @Max(1000) int size = 20; + @Max(1000) + int size = 20; @Schema(description = "Filter object to search within filterable attributes") private FilterGroup filterGroup; @@ -33,7 +34,8 @@ public class SearchPaginationInput { @Schema(description = "Text to search within searchable attributes") private String textSearch; - @Schema(description = "List of sort fields : a field is composed of a property (for instance \"label\" and an optional direction (\"asc\" is assumed if no direction is specified) : (\"desc\", \"asc\")") + @Schema( + description = + "List of sort fields : a field is composed of a property (for instance \"label\" and an optional direction (\"asc\" is assumed if no direction is specified) : (\"desc\", \"asc\")") private List sorts = new ArrayList<>(); - } diff --git a/openbas-api/src/main/java/io/openbas/utils/pagination/SearchUtilsJpa.java b/openbas-api/src/main/java/io/openbas/utils/pagination/SearchUtilsJpa.java index 4c6ea0be8c..45469b6e35 100644 --- a/openbas-api/src/main/java/io/openbas/utils/pagination/SearchUtilsJpa.java +++ b/openbas-api/src/main/java/io/openbas/utils/pagination/SearchUtilsJpa.java @@ -1,5 +1,9 @@ package io.openbas.utils.pagination; +import static io.openbas.utils.JpaUtils.toPath; +import static io.openbas.utils.schema.SchemaUtils.getSearchableProperties; +import static org.springframework.util.StringUtils.hasText; + import io.openbas.utils.OperationUtilsJpa; import io.openbas.utils.schema.PropertySchema; import io.openbas.utils.schema.SchemaUtils; @@ -7,21 +11,14 @@ import jakarta.persistence.criteria.Expression; import jakarta.persistence.criteria.Predicate; import jakarta.validation.constraints.NotNull; -import org.springframework.data.jpa.domain.Specification; - -import javax.annotation.Nullable; import java.util.HashMap; import java.util.List; - -import static io.openbas.utils.JpaUtils.toPath; -import static io.openbas.utils.schema.SchemaUtils.getSearchableProperties; -import static org.springframework.util.StringUtils.hasText; +import javax.annotation.Nullable; +import org.springframework.data.jpa.domain.Specification; public class SearchUtilsJpa { - private SearchUtilsJpa() { - - } + private SearchUtilsJpa() {} private static final Specification EMPTY_SPECIFICATION = (root, query, cb) -> cb.conjunction(); @@ -34,12 +31,14 @@ public static Specification computeSearchJpa(@Nullable final String searc return (root, query, cb) -> { List propertySchemas = SchemaUtils.schema(root.getJavaType()); List searchableProperties = getSearchableProperties(propertySchemas); - List predicates = searchableProperties.stream() - .map(propertySchema -> { - Expression paths = toPath(propertySchema, root, new HashMap<>()); - return toPredicate(paths, search, cb, propertySchema.getType()); - }) - .toList(); + List predicates = + searchableProperties.stream() + .map( + propertySchema -> { + Expression paths = toPath(propertySchema, root, new HashMap<>()); + return toPredicate(paths, search, cb, propertySchema.getType()); + }) + .toList(); return cb.or(predicates.toArray(Predicate[]::new)); }; } diff --git a/openbas-api/src/main/java/io/openbas/utils/pagination/SortField.java b/openbas-api/src/main/java/io/openbas/utils/pagination/SortField.java index 26fbb44001..26cc874fdf 100644 --- a/openbas-api/src/main/java/io/openbas/utils/pagination/SortField.java +++ b/openbas-api/src/main/java/io/openbas/utils/pagination/SortField.java @@ -1,9 +1,7 @@ package io.openbas.utils.pagination; -import lombok.Builder; - import javax.annotation.Nullable; +import lombok.Builder; @Builder -public record SortField(String property, @Nullable String direction) { -} +public record SortField(String property, @Nullable String direction) {} diff --git a/openbas-api/src/main/java/io/openbas/utils/pagination/SortUtilsCriteriaBuilder.java b/openbas-api/src/main/java/io/openbas/utils/pagination/SortUtilsCriteriaBuilder.java index 430e33f00d..a44ff1c948 100644 --- a/openbas-api/src/main/java/io/openbas/utils/pagination/SortUtilsCriteriaBuilder.java +++ b/openbas-api/src/main/java/io/openbas/utils/pagination/SortUtilsCriteriaBuilder.java @@ -3,34 +3,31 @@ import jakarta.persistence.criteria.CriteriaBuilder; import jakarta.persistence.criteria.Order; import jakarta.persistence.criteria.Root; -import org.flywaydb.core.internal.util.StringUtils; -import org.springframework.data.domain.Sort; - import java.util.ArrayList; import java.util.List; +import org.flywaydb.core.internal.util.StringUtils; +import org.springframework.data.domain.Sort; public class SortUtilsCriteriaBuilder { - private SortUtilsCriteriaBuilder() { - - } + private SortUtilsCriteriaBuilder() {} public static List toSortCriteriaBuilder(CriteriaBuilder cb, Root root, Sort sort) { List orders = new ArrayList<>(); if (sort.isSorted()) { - sort.forEach(order -> { - if (StringUtils.hasText(order.getProperty())) { - if (order.isAscending()) { - orders.add(cb.asc(root.get(order.getProperty()))); - } else { - orders.add(cb.desc(root.get(order.getProperty()))); - } - } - }); + sort.forEach( + order -> { + if (StringUtils.hasText(order.getProperty())) { + if (order.isAscending()) { + orders.add(cb.asc(root.get(order.getProperty()))); + } else { + orders.add(cb.desc(root.get(order.getProperty()))); + } + } + }); } else { orders.add(cb.asc(root.get("id"))); // Default order by scenario_id } return orders; } - } diff --git a/openbas-api/src/main/java/io/openbas/utils/pagination/SortUtilsJpa.java b/openbas-api/src/main/java/io/openbas/utils/pagination/SortUtilsJpa.java index bd30f0423f..4d79dbfb2d 100644 --- a/openbas-api/src/main/java/io/openbas/utils/pagination/SortUtilsJpa.java +++ b/openbas-api/src/main/java/io/openbas/utils/pagination/SortUtilsJpa.java @@ -1,23 +1,21 @@ package io.openbas.utils.pagination; +import static io.openbas.utils.schema.SchemaUtils.getSortableProperties; +import static org.springframework.util.StringUtils.hasText; + import io.openbas.utils.schema.PropertySchema; import io.openbas.utils.schema.SchemaUtils; import jakarta.validation.constraints.NotNull; -import org.springframework.data.domain.Sort; - -import javax.annotation.Nullable; import java.util.List; - -import static io.openbas.utils.schema.SchemaUtils.getSortableProperties; -import static org.springframework.util.StringUtils.hasText; +import javax.annotation.Nullable; +import org.springframework.data.domain.Sort; public class SortUtilsJpa { - private SortUtilsJpa() { + private SortUtilsJpa() {} - } - - public static Sort toSortJpa(@Nullable final List sorts, @NotNull final Class clazz) { + public static Sort toSortJpa( + @Nullable final List sorts, @NotNull final Class clazz) { List propertySchemas = getSortableProperties(SchemaUtils.schema(clazz)); List orders; @@ -25,27 +23,38 @@ public static Sort toSortJpa(@Nullable final List sorts, @NotNull if (sorts == null || sorts.isEmpty()) { orders = List.of(); } else { - orders = sorts.stream() - .filter(s -> hasText(s.property())) - .map(field -> { - String property = field.property(); - Sort.Direction direction = Sort.DEFAULT_DIRECTION; - if (null != field.direction()) { - String directionString = field.direction(); - direction = Sort.Direction.fromOptionalString(directionString).orElse(Sort.DEFAULT_DIRECTION); - } - - // Retrieve java name property - String javaProperty = propertySchemas.stream() - .filter(p -> p.getJsonName().equals(property)) - .findFirst() - .map(PropertySchema::getName) - .orElseThrow(() -> new IllegalArgumentException("Property not sortable: " + property + " for class " + clazz)); - return new Sort.Order(direction, javaProperty); - }).toList(); + orders = + sorts.stream() + .filter(s -> hasText(s.property())) + .map( + field -> { + String property = field.property(); + Sort.Direction direction = Sort.DEFAULT_DIRECTION; + if (null != field.direction()) { + String directionString = field.direction(); + direction = + Sort.Direction.fromOptionalString(directionString) + .orElse(Sort.DEFAULT_DIRECTION); + } + + // Retrieve java name property + String javaProperty = + propertySchemas.stream() + .filter(p -> p.getJsonName().equals(property)) + .findFirst() + .map(PropertySchema::getName) + .orElseThrow( + () -> + new IllegalArgumentException( + "Property not sortable: " + + property + + " for class " + + clazz)); + return new Sort.Order(direction, javaProperty); + }) + .toList(); } return Sort.by(orders); } - } diff --git a/openbas-api/src/main/java/io/openbas/utils/pagination/SortUtilsRuntime.java b/openbas-api/src/main/java/io/openbas/utils/pagination/SortUtilsRuntime.java index c619ba1fbf..b683e0464a 100644 --- a/openbas-api/src/main/java/io/openbas/utils/pagination/SortUtilsRuntime.java +++ b/openbas-api/src/main/java/io/openbas/utils/pagination/SortUtilsRuntime.java @@ -1,9 +1,8 @@ package io.openbas.utils.pagination; -import org.springframework.data.domain.Sort; - -import javax.annotation.Nullable; import java.util.List; +import javax.annotation.Nullable; +import org.springframework.data.domain.Sort; public class SortUtilsRuntime { @@ -13,20 +12,23 @@ public static Sort toSortRuntime(@Nullable final List sorts) { if (sorts == null || sorts.isEmpty()) { orders = List.of(); } else { - orders = sorts.stream() - .map(field -> { - String property = field.property(); - Sort.Direction direction = Sort.DEFAULT_DIRECTION; - if (null != field.direction()) { - String directionString = field.direction(); - direction = Sort.Direction.fromOptionalString(directionString).orElse(Sort.DEFAULT_DIRECTION); - } - return new Sort.Order(direction, property); - }).toList(); + orders = + sorts.stream() + .map( + field -> { + String property = field.property(); + Sort.Direction direction = Sort.DEFAULT_DIRECTION; + if (null != field.direction()) { + String directionString = field.direction(); + direction = + Sort.Direction.fromOptionalString(directionString) + .orElse(Sort.DEFAULT_DIRECTION); + } + return new Sort.Order(direction, property); + }) + .toList(); } return Sort.by(orders); } - - } diff --git a/openbas-api/src/main/java/org/apache/commons/mail/util/MimeMessageParser.java b/openbas-api/src/main/java/org/apache/commons/mail/util/MimeMessageParser.java index 45396b7405..2467db08dc 100644 --- a/openbas-api/src/main/java/org/apache/commons/mail/util/MimeMessageParser.java +++ b/openbas-api/src/main/java/org/apache/commons/mail/util/MimeMessageParser.java @@ -16,20 +16,6 @@ */ package org.apache.commons.mail.util; -import java.io.BufferedInputStream; -import java.io.BufferedOutputStream; -import java.io.ByteArrayOutputStream; -import java.io.IOException; -import java.io.InputStream; -import java.io.UnsupportedEncodingException; -import java.util.ArrayList; -import java.util.Arrays; -import java.util.Collection; -import java.util.Collections; -import java.util.HashMap; -import java.util.List; -import java.util.Map; - import jakarta.activation.DataHandler; import jakarta.activation.DataSource; import jakarta.mail.Message; @@ -44,15 +30,27 @@ import jakarta.mail.internet.MimeUtility; import jakarta.mail.internet.ParseException; import jakarta.mail.util.ByteArrayDataSource; +import java.io.BufferedInputStream; +import java.io.BufferedOutputStream; +import java.io.ByteArrayOutputStream; +import java.io.IOException; +import java.io.InputStream; +import java.io.UnsupportedEncodingException; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Collection; +import java.util.Collections; +import java.util.HashMap; +import java.util.List; +import java.util.Map; /** - * Parses a MimeMessage and stores the individual parts such a plain text, - * HTML text and attachments. + * Parses a MimeMessage and stores the individual parts such a plain text, HTML text and + * attachments. * * @since 1.3 */ -public class MimeMessageParser -{ +public class MimeMessageParser { /** The MimeMessage to convert */ private final MimeMessage mimeMessage; @@ -76,8 +74,7 @@ public class MimeMessageParser * * @param message the message to parse */ - public MimeMessageParser(final MimeMessage message) - { + public MimeMessageParser(final MimeMessage message) { attachmentList = new ArrayList<>(); cidMap = new HashMap<>(); this.mimeMessage = message; @@ -90,8 +87,7 @@ public MimeMessageParser(final MimeMessage message) * @return this instance * @throws Exception parsing the mime message failed */ - public MimeMessageParser parse() throws Exception - { + public MimeMessageParser parse() throws Exception { this.parse(null, mimeMessage); return this; } @@ -100,9 +96,9 @@ public MimeMessageParser parse() throws Exception * @return the 'to' recipients of the message * @throws Exception determining the recipients failed */ - public List getTo() throws Exception - { - final jakarta.mail.Address[] recipients = this.mimeMessage.getRecipients(Message.RecipientType.TO); + public List getTo() throws Exception { + final jakarta.mail.Address[] recipients = + this.mimeMessage.getRecipients(Message.RecipientType.TO); return recipients != null ? Arrays.asList(recipients) : new ArrayList(); } @@ -110,9 +106,9 @@ public List getTo() throws Exception * @return the 'cc' recipients of the message * @throws Exception determining the recipients failed */ - public List getCc() throws Exception - { - final jakarta.mail.Address[] recipients = this.mimeMessage.getRecipients(Message.RecipientType.CC); + public List getCc() throws Exception { + final jakarta.mail.Address[] recipients = + this.mimeMessage.getRecipients(Message.RecipientType.CC); return recipients != null ? Arrays.asList(recipients) : new ArrayList(); } @@ -120,9 +116,9 @@ public List getCc() throws Exception * @return the 'bcc' recipients of the message * @throws Exception determining the recipients failed */ - public List getBcc() throws Exception - { - final jakarta.mail.Address[] recipients = this.mimeMessage.getRecipients(Message.RecipientType.BCC); + public List getBcc() throws Exception { + final jakarta.mail.Address[] recipients = + this.mimeMessage.getRecipients(Message.RecipientType.BCC); return recipients != null ? Arrays.asList(recipients) : new ArrayList(); } @@ -130,11 +126,9 @@ public List getBcc() throws Exception * @return the 'from' field of the message * @throws Exception parsing the mime message failed */ - public String getFrom() throws Exception - { + public String getFrom() throws Exception { final jakarta.mail.Address[] addresses = this.mimeMessage.getFrom(); - if (addresses == null || addresses.length == 0) - { + if (addresses == null || addresses.length == 0) { return null; } return ((InternetAddress) addresses[0]).getAddress(); @@ -144,11 +138,9 @@ public String getFrom() throws Exception * @return the 'replyTo' address of the email * @throws Exception parsing the mime message failed */ - public String getReplyTo() throws Exception - { + public String getReplyTo() throws Exception { final jakarta.mail.Address[] addresses = this.mimeMessage.getReplyTo(); - if (addresses == null || addresses.length == 0) - { + if (addresses == null || addresses.length == 0) { return null; } return ((InternetAddress) addresses[0]).getAddress(); @@ -158,8 +150,7 @@ public String getReplyTo() throws Exception * @return the mail subject * @throws Exception parsing the mime message failed */ - public String getSubject() throws Exception - { + public String getSubject() throws Exception { return this.mimeMessage.getSubject(); } @@ -167,46 +158,36 @@ public String getSubject() throws Exception * Extracts the content of a MimeMessage recursively. * * @param parent the parent multi-part - * @param part the current MimePart + * @param part the current MimePart * @throws MessagingException parsing the MimeMessage failed - * @throws IOException parsing the MimeMessage failed + * @throws IOException parsing the MimeMessage failed */ protected void parse(final Multipart parent, final MimePart part) - throws MessagingException, IOException - { - if (isMimeType(part, "text/plain") && plainContent == null - && !Part.ATTACHMENT.equalsIgnoreCase(part.getDisposition())) - { + throws MessagingException, IOException { + if (isMimeType(part, "text/plain") + && plainContent == null + && !Part.ATTACHMENT.equalsIgnoreCase(part.getDisposition())) { plainContent = (String) part.getContent(); - } - else - { - if (isMimeType(part, "text/html") && htmlContent == null - && !Part.ATTACHMENT.equalsIgnoreCase(part.getDisposition())) - { + } else { + if (isMimeType(part, "text/html") + && htmlContent == null + && !Part.ATTACHMENT.equalsIgnoreCase(part.getDisposition())) { htmlContent = (String) part.getContent(); - } - else - { - if (isMimeType(part, "multipart/*")) - { + } else { + if (isMimeType(part, "multipart/*")) { this.isMultiPart = true; final Multipart mp = (Multipart) part.getContent(); final int count = mp.getCount(); // iterate over all MimeBodyPart - for (int i = 0; i < count; i++) - { + for (int i = 0; i < count; i++) { parse(mp, (MimeBodyPart) mp.getBodyPart(i)); } - } - else - { + } else { final String cid = stripContentId(part.getContentID()); final DataSource ds = createDataSource(parent, part); - if (cid != null) - { + if (cid != null) { this.cidMap.put(cid, ds); } this.attachmentList.add(ds); @@ -217,13 +198,12 @@ protected void parse(final Multipart parent, final MimePart part) /** * Strips the content id of any whitespace and angle brackets. + * * @param contentId the string to strip * @return a stripped version of the content id */ - private String stripContentId(final String contentId) - { - if (contentId == null) - { + private String stripContentId(final String contentId) { + if (contentId == null) { return null; } return contentId.trim().replaceAll("[\\<\\>]", ""); @@ -232,25 +212,21 @@ private String stripContentId(final String contentId) /** * Checks whether the MimePart contains an object of the given mime type. * - * @param part the current MimePart + * @param part the current MimePart * @param mimeType the mime type to check * @return {@code true} if the MimePart matches the given mime type, {@code false} otherwise * @throws MessagingException parsing the MimeMessage failed - * @throws IOException parsing the MimeMessage failed + * @throws IOException parsing the MimeMessage failed */ private boolean isMimeType(final MimePart part, final String mimeType) - throws MessagingException, IOException - { + throws MessagingException, IOException { // Do not use part.isMimeType(String) as it is broken for MimeBodyPart // and does not really check the actual content type. - try - { + try { final ContentType ct = new ContentType(part.getDataHandler().getContentType()); return ct.match(mimeType); - } - catch (final ParseException ex) - { + } catch (final ParseException ex) { return part.getContentType().equalsIgnoreCase(mimeType); } } @@ -259,14 +235,13 @@ private boolean isMimeType(final MimePart part, final String mimeType) * Parses the MimePart to create a DataSource. * * @param parent the parent multi-part - * @param part the current part to be processed + * @param part the current part to be processed * @return the DataSource * @throws MessagingException creating the DataSource failed - * @throws IOException creating the DataSource failed + * @throws IOException creating the DataSource failed */ protected DataSource createDataSource(final Multipart parent, final MimePart part) - throws MessagingException, IOException - { + throws MessagingException, IOException { final DataHandler dataHandler = part.getDataHandler(); final DataSource dataSource = dataHandler.getDataSource(); final String contentType = getBaseMimeType(dataSource.getContentType()); @@ -278,65 +253,71 @@ protected DataSource createDataSource(final Multipart parent, final MimePart par return result; } - /** @return Returns the mimeMessage. */ - public MimeMessage getMimeMessage() - { + /** + * @return Returns the mimeMessage. + */ + public MimeMessage getMimeMessage() { return mimeMessage; } - /** @return Returns the isMultiPart. */ - public boolean isMultipart() - { + /** + * @return Returns the isMultiPart. + */ + public boolean isMultipart() { return isMultiPart; } - /** @return Returns the plainContent if any */ - public String getPlainContent() - { + /** + * @return Returns the plainContent if any + */ + public String getPlainContent() { return plainContent; } - /** @return Returns the attachmentList. */ - public List getAttachmentList() - { + /** + * @return Returns the attachmentList. + */ + public List getAttachmentList() { return attachmentList; } /** * Returns a collection of all content-ids in the parsed message. - *

- * The content-ids are stripped of any angle brackets, i.e. "part1" instead - * of "<part1>". + * + *

The content-ids are stripped of any angle brackets, i.e. "part1" instead of "<part1>". * * @return the collection of content ids. * @since 1.3.4 */ - public Collection getContentIds() - { + public Collection getContentIds() { return Collections.unmodifiableSet(cidMap.keySet()); } - /** @return Returns the htmlContent if any */ - public String getHtmlContent() - { + /** + * @return Returns the htmlContent if any + */ + public String getHtmlContent() { return htmlContent; } - /** @return true if a plain content is available */ - public boolean hasPlainContent() - { + /** + * @return true if a plain content is available + */ + public boolean hasPlainContent() { return this.plainContent != null; } - /** @return true if HTML content is available */ - public boolean hasHtmlContent() - { + /** + * @return true if HTML content is available + */ + public boolean hasHtmlContent() { return this.htmlContent != null; } - /** @return true if attachments are available */ - public boolean hasAttachments() - { + /** + * @return true if attachments are available + */ + public boolean hasAttachments() { return !this.attachmentList.isEmpty(); } @@ -346,14 +327,12 @@ public boolean hasAttachments() * @param name the name of the attachment * @return the corresponding datasource or null if nothing was found */ - public DataSource findAttachmentByName(final String name) - { + public DataSource findAttachmentByName(final String name) { DataSource dataSource; for (final DataSource element : getAttachmentList()) { dataSource = element; - if (name.equalsIgnoreCase(dataSource.getName())) - { + if (name.equalsIgnoreCase(dataSource.getName())) { return dataSource; } } @@ -363,16 +342,15 @@ public DataSource findAttachmentByName(final String name) /** * Find an attachment using its content-id. - *

- * The content-id must be stripped of any angle brackets, - * i.e. "part1" instead of "<part1>". + * + *

The content-id must be stripped of any angle brackets, i.e. "part1" instead of + * "<part1>". * * @param cid the content-id of the attachment * @return the corresponding datasource or null if nothing was found * @since 1.3.4 */ - public DataSource findAttachmentByCid(final String cid) - { + public DataSource findAttachmentByCid(final String cid) { final DataSource dataSource = cidMap.get(cid); return dataSource; } @@ -387,21 +365,16 @@ public DataSource findAttachmentByCid(final String cid) * @throws UnsupportedEncodingException decoding the text failed */ protected String getDataSourceName(final Part part, final DataSource dataSource) - throws MessagingException, UnsupportedEncodingException - { + throws MessagingException, UnsupportedEncodingException { String result = dataSource.getName(); - if (result == null || result.isEmpty()) - { + if (result == null || result.isEmpty()) { result = part.getFileName(); } - if (result != null && !result.isEmpty()) - { + if (result != null && !result.isEmpty()) { result = MimeUtility.decodeText(result); - } - else - { + } else { result = null; } @@ -415,9 +388,7 @@ protected String getDataSourceName(final Part part, final DataSource dataSource) * @return the content of the input stream * @throws IOException reading the input stream failed */ - private byte[] getContent(final InputStream is) - throws IOException - { + private byte[] getContent(final InputStream is) throws IOException { int ch; byte[] result; @@ -425,8 +396,7 @@ private byte[] getContent(final InputStream is) final BufferedInputStream isReader = new BufferedInputStream(is); final BufferedOutputStream osWriter = new BufferedOutputStream(os); - while ((ch = isReader.read()) != -1) - { + while ((ch = isReader.read()) != -1) { osWriter.write(ch); } @@ -443,11 +413,9 @@ private byte[] getContent(final InputStream is) * @param fullMimeType the mime type from the mail api * @return the real mime type */ - private String getBaseMimeType(final String fullMimeType) - { + private String getBaseMimeType(final String fullMimeType) { final int pos = fullMimeType.indexOf(';'); - if (pos >= 0) - { + if (pos >= 0) { return fullMimeType.substring(0, pos); } return fullMimeType; diff --git a/openbas-api/src/test/java/io/openbas/IntegrationTest.java b/openbas-api/src/test/java/io/openbas/IntegrationTest.java index 0090a18a95..95fa678471 100644 --- a/openbas-api/src/test/java/io/openbas/IntegrationTest.java +++ b/openbas-api/src/test/java/io/openbas/IntegrationTest.java @@ -6,5 +6,4 @@ @AutoConfigureMockMvc(print = MockMvcPrint.SYSTEM_ERR) @SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT) -public abstract class IntegrationTest { -} +public abstract class IntegrationTest {} diff --git a/openbas-api/src/test/java/io/openbas/helper/InjectHelperTest.java b/openbas-api/src/test/java/io/openbas/helper/InjectHelperTest.java index 50c6ad45e5..f9a51a131e 100644 --- a/openbas-api/src/test/java/io/openbas/helper/InjectHelperTest.java +++ b/openbas-api/src/test/java/io/openbas/helper/InjectHelperTest.java @@ -1,104 +1,96 @@ package io.openbas.helper; +import static io.openbas.database.model.ExerciseStatus.RUNNING; +import static io.openbas.injectors.email.EmailContract.EMAIL_DEFAULT; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertFalse; + import io.openbas.database.model.*; import io.openbas.database.repository.*; import io.openbas.execution.ExecutableInject; +import java.time.Instant; +import java.util.ArrayList; +import java.util.List; import org.junit.jupiter.api.Disabled; import org.junit.jupiter.api.DisplayName; import org.junit.jupiter.api.Test; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.boot.test.context.SpringBootTest; -import java.time.Instant; -import java.util.ArrayList; -import java.util.List; - -import static io.openbas.database.model.ExerciseStatus.RUNNING; -import static io.openbas.injectors.email.EmailContract.EMAIL_DEFAULT; -import static org.junit.jupiter.api.Assertions.assertEquals; -import static org.junit.jupiter.api.Assertions.assertFalse; - @SpringBootTest public class InjectHelperTest { - public static final String USER_EMAIL = "test@gmail.com"; - @Autowired - private InjectHelper injectHelper; - - @Autowired - private TeamRepository teamRepository; - - @Autowired - private ExerciseRepository exerciseRepository; - - @Autowired - private ExerciseTeamUserRepository exerciseTeamUserRepository; - - @Autowired - private InjectRepository injectRepository; - - @Autowired - private UserRepository userRepository; - - @Autowired - private InjectorContractRepository injectorContractRepository; - - @Disabled - @DisplayName("Retrieve simple inject to run") - @Test - void injectsToRunTest() { - // -- PREPARE -- - Exercise exercise = new Exercise(); - exercise.setName("Exercise name"); - exercise.setStart(Instant.now()); - exercise.setFrom("test@test.com"); - exercise.setReplyTos(List.of("test@test.com")); - exercise.setStatus(RUNNING); - Exercise exerciseSaved = this.exerciseRepository.save(exercise); - List exercises = new ArrayList<>(); - exercises.add(exerciseSaved); - User user = new User(); - user.setEmail(USER_EMAIL); - this.userRepository.save(user); - - Team team = new Team(); - team.setName("My team"); - team.setExercises(exercises); - team.setUsers(List.of(user)); - this.teamRepository.save(team); - - ExerciseTeamUser exerciseTeamUser = new ExerciseTeamUser(); - exerciseTeamUser.setExercise(exercise); - exerciseTeamUser.setTeam(team); - exerciseTeamUser.setUser(user); - this.exerciseTeamUserRepository.save(exerciseTeamUser); - - // Executable Inject - Inject inject = new Inject(); - inject.setTitle("Test inject"); - inject.setInjectorContract(this.injectorContractRepository.findById(EMAIL_DEFAULT).orElseThrow()); - inject.setEnabled(true); - inject.setExercise(exerciseSaved); - inject.setTeams(List.of(team)); - inject.setDependsDuration(0L); - this.injectRepository.save(inject); - - // -- EXECUTE -- - List executableInjects = this.injectHelper.getInjectsToRun(); - - // -- ASSERT -- - assertFalse(executableInjects.isEmpty()); - ExecutableInject executableInject = executableInjects.get(0); - assertEquals(1, executableInject.getTeamSize()); - assertEquals(1, executableInject.getUsers().size()); - assertEquals(USER_EMAIL, executableInject.getUsers().get(0).getUser().getEmail()); - - // -- CLEAN - - this.exerciseRepository.delete(exercise); - this.teamRepository.delete(team); - this.userRepository.delete(user); - this.exerciseTeamUserRepository.delete(exerciseTeamUser); - this.injectRepository.delete(inject); - } - + public static final String USER_EMAIL = "test@gmail.com"; + @Autowired private InjectHelper injectHelper; + + @Autowired private TeamRepository teamRepository; + + @Autowired private ExerciseRepository exerciseRepository; + + @Autowired private ExerciseTeamUserRepository exerciseTeamUserRepository; + + @Autowired private InjectRepository injectRepository; + + @Autowired private UserRepository userRepository; + + @Autowired private InjectorContractRepository injectorContractRepository; + + @Disabled + @DisplayName("Retrieve simple inject to run") + @Test + void injectsToRunTest() { + // -- PREPARE -- + Exercise exercise = new Exercise(); + exercise.setName("Exercise name"); + exercise.setStart(Instant.now()); + exercise.setFrom("test@test.com"); + exercise.setReplyTos(List.of("test@test.com")); + exercise.setStatus(RUNNING); + Exercise exerciseSaved = this.exerciseRepository.save(exercise); + List exercises = new ArrayList<>(); + exercises.add(exerciseSaved); + User user = new User(); + user.setEmail(USER_EMAIL); + this.userRepository.save(user); + + Team team = new Team(); + team.setName("My team"); + team.setExercises(exercises); + team.setUsers(List.of(user)); + this.teamRepository.save(team); + + ExerciseTeamUser exerciseTeamUser = new ExerciseTeamUser(); + exerciseTeamUser.setExercise(exercise); + exerciseTeamUser.setTeam(team); + exerciseTeamUser.setUser(user); + this.exerciseTeamUserRepository.save(exerciseTeamUser); + + // Executable Inject + Inject inject = new Inject(); + inject.setTitle("Test inject"); + inject.setInjectorContract( + this.injectorContractRepository.findById(EMAIL_DEFAULT).orElseThrow()); + inject.setEnabled(true); + inject.setExercise(exerciseSaved); + inject.setTeams(List.of(team)); + inject.setDependsDuration(0L); + this.injectRepository.save(inject); + + // -- EXECUTE -- + List executableInjects = this.injectHelper.getInjectsToRun(); + + // -- ASSERT -- + assertFalse(executableInjects.isEmpty()); + ExecutableInject executableInject = executableInjects.get(0); + assertEquals(1, executableInject.getTeamSize()); + assertEquals(1, executableInject.getUsers().size()); + assertEquals(USER_EMAIL, executableInject.getUsers().get(0).getUser().getEmail()); + + // -- CLEAN - + this.exerciseRepository.delete(exercise); + this.teamRepository.delete(team); + this.userRepository.delete(user); + this.exerciseTeamUserRepository.delete(exerciseTeamUser); + this.injectRepository.delete(inject); + } } diff --git a/openbas-api/src/test/java/io/openbas/importer/V1_DataImporterTest.java b/openbas-api/src/test/java/io/openbas/importer/V1_DataImporterTest.java index ee662ebfb6..a1c5bf5932 100644 --- a/openbas-api/src/test/java/io/openbas/importer/V1_DataImporterTest.java +++ b/openbas-api/src/test/java/io/openbas/importer/V1_DataImporterTest.java @@ -1,10 +1,18 @@ package io.openbas.importer; +import static org.junit.jupiter.api.Assertions.*; +import static org.junit.jupiter.api.TestInstance.Lifecycle.PER_CLASS; + import com.fasterxml.jackson.databind.JsonNode; import com.fasterxml.jackson.databind.ObjectMapper; import io.openbas.IntegrationTest; import io.openbas.database.model.*; import io.openbas.database.repository.*; +import java.nio.file.Files; +import java.nio.file.Paths; +import java.util.List; +import java.util.Map; +import java.util.Optional; import org.jetbrains.annotations.NotNull; import org.junit.jupiter.api.BeforeAll; import org.junit.jupiter.api.Test; @@ -14,35 +22,20 @@ import org.springframework.data.jpa.domain.Specification; import org.springframework.transaction.annotation.Transactional; -import java.nio.file.Files; -import java.nio.file.Paths; -import java.util.List; -import java.util.Map; -import java.util.Optional; - -import static org.junit.jupiter.api.Assertions.*; -import static org.junit.jupiter.api.TestInstance.Lifecycle.PER_CLASS; - @TestInstance(PER_CLASS) class V1_DataImporterTest extends IntegrationTest { - @Autowired - private V1_DataImporter importer; + @Autowired private V1_DataImporter importer; - @Autowired - private ExerciseRepository exerciseRepository; + @Autowired private ExerciseRepository exerciseRepository; - @Autowired - private TeamRepository teamRepository; + @Autowired private TeamRepository teamRepository; - @Autowired - private UserRepository userRepository; + @Autowired private UserRepository userRepository; - @Autowired - private OrganizationRepository organizationRepository; + @Autowired private OrganizationRepository organizationRepository; - @Autowired - private TagRepository tagRepository; + @Autowired private TagRepository tagRepository; private JsonNode importNode; @@ -56,7 +49,9 @@ class V1_DataImporterTest extends IntegrationTest { public void setUp() throws Exception { MockitoAnnotations.openMocks(this); ObjectMapper mapper = new ObjectMapper(); - String jsonContent = new String(Files.readAllBytes(Paths.get("src/test/resources/importer-v1/import-data.json"))); + String jsonContent = + new String( + Files.readAllBytes(Paths.get("src/test/resources/importer-v1/import-data.json"))); this.importNode = mapper.readTree(jsonContent); } @@ -81,7 +76,8 @@ void testImportData() { assertEquals(ORGANIZATION_NAME, user.get().getOrganization().getName()); assertEquals(1, user.get().getTags().size()); - List organization = this.organizationRepository.findByNameIgnoreCase(ORGANIZATION_NAME); + List organization = + this.organizationRepository.findByNameIgnoreCase(ORGANIZATION_NAME); assertFalse(organization.isEmpty()); assertEquals(ORGANIZATION_NAME, organization.getFirst().getName()); @@ -102,5 +98,4 @@ void testImportData() { private static Specification exerciseByName(@NotNull final String name) { return (root, query, cb) -> cb.equal(root.get("name"), name); } - } diff --git a/openbas-api/src/test/java/io/openbas/injector_contract/InjectorContratApiTest.java b/openbas-api/src/test/java/io/openbas/injector_contract/InjectorContratApiTest.java index 6b8e92e429..2396146ad9 100644 --- a/openbas-api/src/test/java/io/openbas/injector_contract/InjectorContratApiTest.java +++ b/openbas-api/src/test/java/io/openbas/injector_contract/InjectorContratApiTest.java @@ -1,10 +1,19 @@ package io.openbas.injector_contract; +import static io.openbas.database.model.Filters.FilterOperator.contains; +import static io.openbas.database.model.Filters.FilterOperator.eq; +import static io.openbas.utils.JsonUtils.asJsonString; +import static org.junit.jupiter.api.TestInstance.Lifecycle.PER_CLASS; +import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.post; +import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.jsonPath; +import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status; + import io.openbas.IntegrationTest; import io.openbas.utils.fixtures.PaginationFixture; import io.openbas.utils.mockUser.WithMockAdminUser; import io.openbas.utils.pagination.SearchPaginationInput; import io.openbas.utils.pagination.SortField; +import java.util.List; import org.junit.jupiter.api.DisplayName; import org.junit.jupiter.api.Nested; import org.junit.jupiter.api.Test; @@ -13,21 +22,10 @@ import org.springframework.http.MediaType; import org.springframework.test.web.servlet.MockMvc; -import java.util.List; - -import static io.openbas.database.model.Filters.FilterOperator.contains; -import static io.openbas.database.model.Filters.FilterOperator.eq; -import static io.openbas.utils.JsonUtils.asJsonString; -import static org.junit.jupiter.api.TestInstance.Lifecycle.PER_CLASS; -import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.post; -import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.jsonPath; -import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status; - @TestInstance(PER_CLASS) class InjectorContratApiTest extends IntegrationTest { - @Autowired - private MockMvc mvc; + @Autowired private MockMvc mvc; @Nested @WithMockAdminUser @@ -41,22 +39,24 @@ class FetchingPageOfContracts { @Test @DisplayName("Fetching first page of contracts succeed") void given_search_input_should_return_a_page_of_contrats() throws Exception { - mvc.perform(post("/api/injector_contracts/search") - .contentType(MediaType.APPLICATION_JSON) - .content(asJsonString(PaginationFixture.getDefault().build()))).andExpect(status().is2xxSuccessful()) + mvc.perform( + post("/api/injector_contracts/search") + .contentType(MediaType.APPLICATION_JSON) + .content(asJsonString(PaginationFixture.getDefault().build()))) + .andExpect(status().is2xxSuccessful()) .andExpect(jsonPath("$.numberOfElements").value(5)); } @Test @DisplayName("Fetching first page of contracts failed with bad request") void given_a_bad_search_input_should_throw_bad_request() throws Exception { - SearchPaginationInput searchPaginationInput = PaginationFixture.getDefault() - .size(1110) - .build(); + SearchPaginationInput searchPaginationInput = + PaginationFixture.getDefault().size(1110).build(); - mvc.perform(post("/api/injector_contracts/search") - .contentType(MediaType.APPLICATION_JSON) - .content(asJsonString(searchPaginationInput))) + mvc.perform( + post("/api/injector_contracts/search") + .contentType(MediaType.APPLICATION_JSON) + .content(asJsonString(searchPaginationInput))) .andExpect(status().isBadRequest()); } } @@ -67,44 +67,52 @@ class SearchingPageOfContracts { @DisplayName("Fetching first page of contracts by textsearch ignoring case") @Test - void given_search_input_with_textsearch_should_return_a_page_of_contrats_ignoring_case() throws Exception { - SearchPaginationInput searchPaginationInput = PaginationFixture.getDefault().textSearch("PubLish Chal").build(); - - mvc.perform(post("/api/injector_contracts/search") - .contentType(MediaType.APPLICATION_JSON) - .content(asJsonString(searchPaginationInput))) + void given_search_input_with_textsearch_should_return_a_page_of_contrats_ignoring_case() + throws Exception { + SearchPaginationInput searchPaginationInput = + PaginationFixture.getDefault().textSearch("PubLish Chal").build(); + + mvc.perform( + post("/api/injector_contracts/search") + .contentType(MediaType.APPLICATION_JSON) + .content(asJsonString(searchPaginationInput))) .andExpect(status().is2xxSuccessful()) .andExpect(jsonPath("$.numberOfElements").value(1)); } @DisplayName("Fetching first page of contracts by textsearch with spaces") @Test - void given_search_input_with_textsearch_with_spaces_should_return_a_page_of_contracts() throws Exception { - SearchPaginationInput searchPaginationInput = PaginationFixture.getDefault().textSearch("Pu bLish Ch al").build(); - - mvc.perform(post("/api/injector_contracts/search") - .contentType(MediaType.APPLICATION_JSON) - .content(asJsonString(searchPaginationInput))) + void given_search_input_with_textsearch_with_spaces_should_return_a_page_of_contracts() + throws Exception { + SearchPaginationInput searchPaginationInput = + PaginationFixture.getDefault().textSearch("Pu bLish Ch al").build(); + + mvc.perform( + post("/api/injector_contracts/search") + .contentType(MediaType.APPLICATION_JSON) + .content(asJsonString(searchPaginationInput))) .andExpect(status().is2xxSuccessful()) .andExpect(jsonPath("$.numberOfElements").value(0)); } - } @Nested @DisplayName("Filtering page of contracts") class FilteringPageOfContracts { - @DisplayName("Fetching first page of contracts by label type ignoring case and contains operator") + @DisplayName( + "Fetching first page of contracts by label type ignoring case and contains operator") @Test - void given_search_input_with_label_type_should_return_a_page_of_contrats_ignoring_case() throws Exception { - SearchPaginationInput searchPaginationInput = PaginationFixture.simpleFilter( - "injector_contract_labels", "multi-recipients", contains - ); - - mvc.perform(post("/api/injector_contracts/search") - .contentType(MediaType.APPLICATION_JSON) - .content(asJsonString(searchPaginationInput))) + void given_search_input_with_label_type_should_return_a_page_of_contrats_ignoring_case() + throws Exception { + SearchPaginationInput searchPaginationInput = + PaginationFixture.simpleFilter( + "injector_contract_labels", "multi-recipients", contains); + + mvc.perform( + post("/api/injector_contracts/search") + .contentType(MediaType.APPLICATION_JSON) + .content(asJsonString(searchPaginationInput))) .andExpect(status().is2xxSuccessful()) .andExpect(jsonPath("$.numberOfElements").value(1)); } @@ -112,27 +120,30 @@ void given_search_input_with_label_type_should_return_a_page_of_contrats_ignorin @DisplayName("Fetching first page of contracts by label and equals operator") @Test void given_search_input_with_label_should_return_a_page_of_contrats() throws Exception { - SearchPaginationInput searchPaginationInput = PaginationFixture.simpleFilter( - "injector_contract_labels", "Send multi-recipients mail", eq - ); - - mvc.perform(post("/api/injector_contracts/search") - .contentType(MediaType.APPLICATION_JSON) - .content(asJsonString(searchPaginationInput))) + SearchPaginationInput searchPaginationInput = + PaginationFixture.simpleFilter( + "injector_contract_labels", "Send multi-recipients mail", eq); + + mvc.perform( + post("/api/injector_contracts/search") + .contentType(MediaType.APPLICATION_JSON) + .content(asJsonString(searchPaginationInput))) .andExpect(status().is2xxSuccessful()) .andExpect(jsonPath("$.numberOfElements").value(1)); } @DisplayName("Fetching first page of contracts by label email ignoring case") @Test - void given_search_input_with_label_should_return_a_page_of_contrats_ignoring_case() throws Exception { - SearchPaginationInput searchPaginationInput = PaginationFixture.simpleFilter( - "injector_contract_labels", "send multi-recipients mail", eq - ); - - mvc.perform(post("/api/injector_contracts/search") - .contentType(MediaType.APPLICATION_JSON) - .content(asJsonString(searchPaginationInput))) + void given_search_input_with_label_should_return_a_page_of_contrats_ignoring_case() + throws Exception { + SearchPaginationInput searchPaginationInput = + PaginationFixture.simpleFilter( + "injector_contract_labels", "send multi-recipients mail", eq); + + mvc.perform( + post("/api/injector_contracts/search") + .contentType(MediaType.APPLICATION_JSON) + .content(asJsonString(searchPaginationInput))) .andExpect(status().is2xxSuccessful()) .andExpect(jsonPath("$.numberOfElements").value(1)); } @@ -145,33 +156,55 @@ class SortingPageOfContracts { @DisplayName("Sorting by label desc") @Test void given_sort_input_should_return_a_page_of_contrats_sort_by_label_desc() throws Exception { - SearchPaginationInput searchPaginationInput = PaginationFixture.getDefault() - .textSearch("mail") - .sorts(List.of(SortField.builder().property("injector_contract_labels").direction("desc").build())) - .build(); - - mvc.perform(post("/api/injector_contracts/search") - .contentType(MediaType.APPLICATION_JSON) - .content(asJsonString(searchPaginationInput))) + SearchPaginationInput searchPaginationInput = + PaginationFixture.getDefault() + .textSearch("mail") + .sorts( + List.of( + SortField.builder() + .property("injector_contract_labels") + .direction("desc") + .build())) + .build(); + + mvc.perform( + post("/api/injector_contracts/search") + .contentType(MediaType.APPLICATION_JSON) + .content(asJsonString(searchPaginationInput))) .andExpect(status().is2xxSuccessful()) - .andExpect(jsonPath("$.content.[0].injector_contract_labels.en").value("Send multi-recipients mail")) - .andExpect(jsonPath("$.content.[1].injector_contract_labels.en").value("Send individual mails")); + .andExpect( + jsonPath("$.content.[0].injector_contract_labels.en") + .value("Send multi-recipients mail")) + .andExpect( + jsonPath("$.content.[1].injector_contract_labels.en") + .value("Send individual mails")); } @DisplayName("Sorting by label asc") @Test void given_sort_input_should_return_a_page_of_contrats_sort_by_label_asc() throws Exception { - SearchPaginationInput searchPaginationInput = PaginationFixture.getDefault().textSearch("mail") - .sorts(List.of( - SortField.builder().property("injector_contract_labels").direction("asc").build() - )).build(); - - mvc.perform(post("/api/injector_contracts/search") - .contentType(MediaType.APPLICATION_JSON) - .content(asJsonString(searchPaginationInput))) + SearchPaginationInput searchPaginationInput = + PaginationFixture.getDefault() + .textSearch("mail") + .sorts( + List.of( + SortField.builder() + .property("injector_contract_labels") + .direction("asc") + .build())) + .build(); + + mvc.perform( + post("/api/injector_contracts/search") + .contentType(MediaType.APPLICATION_JSON) + .content(asJsonString(searchPaginationInput))) .andExpect(status().is2xxSuccessful()) - .andExpect(jsonPath("$.content.[0].injector_contract_labels.en").value("Send individual mails")) - .andExpect(jsonPath("$.content.[1].injector_contract_labels.en").value("Send multi-recipients mail")); + .andExpect( + jsonPath("$.content.[0].injector_contract_labels.en") + .value("Send individual mails")) + .andExpect( + jsonPath("$.content.[1].injector_contract_labels.en") + .value("Send multi-recipients mail")); } } } diff --git a/openbas-api/src/test/java/io/openbas/injects/InjectCrudTest.java b/openbas-api/src/test/java/io/openbas/injects/InjectCrudTest.java index b4db64de5a..4597c01410 100644 --- a/openbas-api/src/test/java/io/openbas/injects/InjectCrudTest.java +++ b/openbas-api/src/test/java/io/openbas/injects/InjectCrudTest.java @@ -1,31 +1,27 @@ package io.openbas.injects; +import static io.openbas.injectors.email.EmailContract.EMAIL_DEFAULT; +import static org.junit.jupiter.api.Assertions.assertNotNull; + import io.openbas.database.model.Exercise; import io.openbas.database.model.Inject; import io.openbas.database.repository.ExerciseRepository; import io.openbas.database.repository.InjectRepository; import io.openbas.database.repository.InjectorContractRepository; +import java.util.List; import org.junit.jupiter.api.DisplayName; import org.junit.jupiter.api.Test; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.boot.test.context.SpringBootTest; -import java.util.List; - -import static io.openbas.injectors.email.EmailContract.EMAIL_DEFAULT; -import static org.junit.jupiter.api.Assertions.assertNotNull; - @SpringBootTest class InjectCrudTest { - @Autowired - private InjectRepository injectRepository; + @Autowired private InjectRepository injectRepository; - @Autowired - private ExerciseRepository exerciseRepository; + @Autowired private ExerciseRepository exerciseRepository; - @Autowired - private InjectorContractRepository injectorContractRepository; + @Autowired private InjectorContractRepository injectorContractRepository; @DisplayName("Test inject creation with non null depends duration") @Test @@ -38,7 +34,8 @@ void createInjectSuccess() { Exercise exerciseCreated = this.exerciseRepository.save(exercise); Inject inject = new Inject(); inject.setTitle("test"); - inject.setInjectorContract(this.injectorContractRepository.findById(EMAIL_DEFAULT).orElseThrow()); + inject.setInjectorContract( + this.injectorContractRepository.findById(EMAIL_DEFAULT).orElseThrow()); inject.setExercise(exerciseCreated); inject.setDependsDuration(0L); @@ -50,5 +47,4 @@ void createInjectSuccess() { this.exerciseRepository.delete(exercise); this.injectRepository.delete(inject); } - } diff --git a/openbas-api/src/test/java/io/openbas/injects/email/EmailExecutorTest.java b/openbas-api/src/test/java/io/openbas/injects/email/EmailExecutorTest.java index d94dff667e..15d6d79870 100644 --- a/openbas-api/src/test/java/io/openbas/injects/email/EmailExecutorTest.java +++ b/openbas-api/src/test/java/io/openbas/injects/email/EmailExecutorTest.java @@ -1,5 +1,10 @@ package io.openbas.injects.email; +import static io.openbas.helper.StreamHelper.fromIterable; +import static io.openbas.injectors.email.EmailContract.EMAIL_DEFAULT; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertNotNull; + import com.fasterxml.jackson.databind.ObjectMapper; import io.openbas.database.model.Execution; import io.openbas.database.model.Inject; @@ -10,36 +15,24 @@ import io.openbas.execution.ExecutableInject; import io.openbas.execution.ExecutionContext; import io.openbas.execution.ExecutionContextService; -import io.openbas.injectors.email.EmailContract; import io.openbas.injectors.email.EmailExecutor; import io.openbas.injectors.email.model.EmailContent; import io.openbas.model.ExecutionProcess; import io.openbas.model.inject.form.Expectation; import jakarta.annotation.Resource; +import java.util.List; import org.junit.jupiter.api.Test; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.boot.test.context.SpringBootTest; -import java.util.List; - -import static io.openbas.injectors.email.EmailContract.EMAIL_DEFAULT; -import static io.openbas.helper.StreamHelper.fromIterable; -import static org.junit.jupiter.api.Assertions.assertEquals; -import static org.junit.jupiter.api.Assertions.assertNotNull; - @SpringBootTest public class EmailExecutorTest { - @Autowired - private EmailExecutor emailExecutor; - @Autowired - private UserRepository userRepository; - @Autowired - private InjectorContractRepository injectorContractRepository; - @Autowired - private ExecutionContextService executionContextService; - @Resource - protected ObjectMapper mapper; + @Autowired private EmailExecutor emailExecutor; + @Autowired private UserRepository userRepository; + @Autowired private InjectorContractRepository injectorContractRepository; + @Autowired private ExecutionContextService executionContextService; + @Resource protected ObjectMapper mapper; @Test void process() throws Exception { @@ -53,12 +46,18 @@ void process() throws Exception { expectation.setType(InjectExpectation.EXPECTATION_TYPE.MANUAL); content.setExpectations(List.of(expectation)); Inject inject = new Inject(); - inject.setInjectorContract(this.injectorContractRepository.findById(EMAIL_DEFAULT).orElseThrow()); + inject.setInjectorContract( + this.injectorContractRepository.findById(EMAIL_DEFAULT).orElseThrow()); inject.setContent(this.mapper.valueToTree(content)); Iterable users = this.userRepository.findAll(); - List userInjectContexts = fromIterable(users).stream() - .map(user -> this.executionContextService.executionContext(user, inject, "Direct execution")).toList(); - ExecutableInject executableInject = new ExecutableInject(true, true, inject, userInjectContexts); + List userInjectContexts = + fromIterable(users).stream() + .map( + user -> + this.executionContextService.executionContext(user, inject, "Direct execution")) + .toList(); + ExecutableInject executableInject = + new ExecutableInject(true, true, inject, userInjectContexts); Execution execution = new Execution(executableInject.isRuntime()); // -- EXECUTE -- @@ -68,5 +67,4 @@ void process() throws Exception { assertNotNull(executionProcess.getExpectations()); assertEquals(10, executionProcess.getExpectations().get(0).getScore()); } - } diff --git a/openbas-api/src/test/java/io/openbas/injects/manual/ManualExecutorTest.java b/openbas-api/src/test/java/io/openbas/injects/manual/ManualExecutorTest.java index a05cc56b81..a486a40f59 100644 --- a/openbas-api/src/test/java/io/openbas/injects/manual/ManualExecutorTest.java +++ b/openbas-api/src/test/java/io/openbas/injects/manual/ManualExecutorTest.java @@ -9,9 +9,7 @@ @SpringBootTest public class ManualExecutorTest { - @Autowired - private ManualExecutor manualExecutor; - + @Autowired private ManualExecutor manualExecutor; @Test void process() { @@ -24,5 +22,4 @@ void process() { Assertions.assertNotNull(error); Assertions.assertEquals("Manual inject cannot be executed", error.getMessage()); } - } diff --git a/openbas-api/src/test/java/io/openbas/killChainPhase/KillChainPhaseApiTest.java b/openbas-api/src/test/java/io/openbas/killChainPhase/KillChainPhaseApiTest.java index d54662dfb3..0307a90703 100644 --- a/openbas-api/src/test/java/io/openbas/killChainPhase/KillChainPhaseApiTest.java +++ b/openbas-api/src/test/java/io/openbas/killChainPhase/KillChainPhaseApiTest.java @@ -1,35 +1,32 @@ package io.openbas.killChainPhase; +import static io.openbas.database.model.Filters.FilterOperator.contains; +import static io.openbas.database.model.Filters.FilterOperator.eq; +import static io.openbas.utils.JsonUtils.asJsonString; +import static io.openbas.utils.fixtures.KillChainPhaseFixture.getKillChainPhase; +import static org.junit.jupiter.api.TestInstance.Lifecycle.PER_CLASS; +import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.post; +import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.jsonPath; +import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status; + import io.openbas.IntegrationTest; import io.openbas.database.repository.KillChainPhaseRepository; import io.openbas.utils.fixtures.PaginationFixture; import io.openbas.utils.mockUser.WithMockAdminUser; import io.openbas.utils.pagination.SearchPaginationInput; import io.openbas.utils.pagination.SortField; +import java.util.List; import org.junit.jupiter.api.*; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.http.MediaType; import org.springframework.test.web.servlet.MockMvc; -import java.util.List; - -import static io.openbas.database.model.Filters.FilterOperator.contains; -import static io.openbas.database.model.Filters.FilterOperator.eq; -import static io.openbas.utils.JsonUtils.asJsonString; -import static io.openbas.utils.fixtures.KillChainPhaseFixture.getKillChainPhase; -import static org.junit.jupiter.api.TestInstance.Lifecycle.PER_CLASS; -import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.post; -import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.jsonPath; -import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status; - @TestInstance(PER_CLASS) public class KillChainPhaseApiTest extends IntegrationTest { - @Autowired - private MockMvc mvc; + @Autowired private MockMvc mvc; - @Autowired - private KillChainPhaseRepository killChainPhaseRepository; + @Autowired private KillChainPhaseRepository killChainPhaseRepository; private static String KILL_CHAIN_PHASE_ID_1; private static String KILL_CHAIN_PHASE_ID_2; @@ -44,7 +41,8 @@ public void beforeAll() { @AfterAll public void afterAll() { - this.killChainPhaseRepository.deleteAllById(List.of(KILL_CHAIN_PHASE_ID_1, KILL_CHAIN_PHASE_ID_2, KILL_CHAIN_PHASE_ID_3)); + this.killChainPhaseRepository.deleteAllById( + List.of(KILL_CHAIN_PHASE_ID_1, KILL_CHAIN_PHASE_ID_2, KILL_CHAIN_PHASE_ID_3)); } @Nested @@ -55,22 +53,24 @@ class FetchingPageOfKillChainPhases { @Test @DisplayName("Fetching first page of kill chain phases succeed") void given_search_input_should_return_a_page_of_kill_chain_phases() throws Exception { - mvc.perform(post("/api/kill_chain_phases/search") - .contentType(MediaType.APPLICATION_JSON) - .content(asJsonString(PaginationFixture.getDefault().size(3).build()))).andExpect(status().is2xxSuccessful()) + mvc.perform( + post("/api/kill_chain_phases/search") + .contentType(MediaType.APPLICATION_JSON) + .content(asJsonString(PaginationFixture.getDefault().size(3).build()))) + .andExpect(status().is2xxSuccessful()) .andExpect(jsonPath("$.numberOfElements").value(3)); } @Test @DisplayName("Fetching first page of kill chain phases failed with bad request") void given_a_bad_search_input_should_throw_bad_request() throws Exception { - SearchPaginationInput searchPaginationInput = PaginationFixture.getDefault() - .size(1110) - .build(); + SearchPaginationInput searchPaginationInput = + PaginationFixture.getDefault().size(1110).build(); - mvc.perform(post("/api/kill_chain_phases/search") - .contentType(MediaType.APPLICATION_JSON) - .content(asJsonString(searchPaginationInput))) + mvc.perform( + post("/api/kill_chain_phases/search") + .contentType(MediaType.APPLICATION_JSON) + .content(asJsonString(searchPaginationInput))) .andExpect(status().isBadRequest()); } } @@ -82,40 +82,49 @@ class SearchingPageOfKillChainPhases { @DisplayName("Fetching first page of kill chain phases by textsearch") @Test - void given_search_input_with_textsearch_should_return_a_page_of_kill_chain_phases() throws Exception { - SearchPaginationInput searchPaginationInput = PaginationFixture.getDefault().textSearch("name2").build(); - - mvc.perform(post("/api/kill_chain_phases/search") - .contentType(MediaType.APPLICATION_JSON) - .content(asJsonString(searchPaginationInput))) + void given_search_input_with_textsearch_should_return_a_page_of_kill_chain_phases() + throws Exception { + SearchPaginationInput searchPaginationInput = + PaginationFixture.getDefault().textSearch("name2").build(); + + mvc.perform( + post("/api/kill_chain_phases/search") + .contentType(MediaType.APPLICATION_JSON) + .content(asJsonString(searchPaginationInput))) .andExpect(status().is2xxSuccessful()) .andExpect(jsonPath("$.numberOfElements").value(1)); } @DisplayName("Fetching first page of kill chain phases by textsearch ignoring case") @Test - void given_search_input_with_textsearch_should_return_a_page_of_kill_chain_phases_ignoring_case() throws Exception { - SearchPaginationInput searchPaginationInput = PaginationFixture.getDefault().textSearch("NAME2").build(); - - mvc.perform(post("/api/kill_chain_phases/search") - .contentType(MediaType.APPLICATION_JSON) - .content(asJsonString(searchPaginationInput))) + void + given_search_input_with_textsearch_should_return_a_page_of_kill_chain_phases_ignoring_case() + throws Exception { + SearchPaginationInput searchPaginationInput = + PaginationFixture.getDefault().textSearch("NAME2").build(); + + mvc.perform( + post("/api/kill_chain_phases/search") + .contentType(MediaType.APPLICATION_JSON) + .content(asJsonString(searchPaginationInput))) .andExpect(status().is2xxSuccessful()) .andExpect(jsonPath("$.numberOfElements").value(1)); } @DisplayName("Fetching first page of kill chain phases by textsearch with spaces") @Test - void given_search_input_with_textsearch_with_spaces_should_return_a_page_of_kill_chain_phases() throws Exception { - SearchPaginationInput searchPaginationInput = PaginationFixture.getDefault().textSearch("name 2").build(); - - mvc.perform(post("/api/kill_chain_phases/search") - .contentType(MediaType.APPLICATION_JSON) - .content(asJsonString(searchPaginationInput))) + void given_search_input_with_textsearch_with_spaces_should_return_a_page_of_kill_chain_phases() + throws Exception { + SearchPaginationInput searchPaginationInput = + PaginationFixture.getDefault().textSearch("name 2").build(); + + mvc.perform( + post("/api/kill_chain_phases/search") + .contentType(MediaType.APPLICATION_JSON) + .content(asJsonString(searchPaginationInput))) .andExpect(status().is2xxSuccessful()) .andExpect(jsonPath("$.numberOfElements").value(0)); } - } @Nested @@ -125,28 +134,35 @@ class FilteringPageOfKillChainPhases { @DisplayName("Fetching first page of kill chain phases by equals name") @Test - void given_search_input_with_name_and_equals_operator_should_return_a_page_of_kill_chain_phases() throws Exception { - SearchPaginationInput searchPaginationInput = PaginationFixture.simpleFilter("phase_name", "NAME2", eq); - - mvc.perform(post("/api/kill_chain_phases/search") - .contentType(MediaType.APPLICATION_JSON) - .content(asJsonString(searchPaginationInput))) + void + given_search_input_with_name_and_equals_operator_should_return_a_page_of_kill_chain_phases() + throws Exception { + SearchPaginationInput searchPaginationInput = + PaginationFixture.simpleFilter("phase_name", "NAME2", eq); + + mvc.perform( + post("/api/kill_chain_phases/search") + .contentType(MediaType.APPLICATION_JSON) + .content(asJsonString(searchPaginationInput))) .andExpect(status().is2xxSuccessful()) .andExpect(jsonPath("$.numberOfElements").value(1)); } @DisplayName("Fetching first page of kill chain phases by contains name") @Test - void given_search_input_with_name_and_contains_operator_should_return_a_page_of_kill_chain_phases() throws Exception { - SearchPaginationInput searchPaginationInput = PaginationFixture.simpleFilter("phase_name", "2", contains); - - mvc.perform(post("/api/kill_chain_phases/search") - .contentType(MediaType.APPLICATION_JSON) - .content(asJsonString(searchPaginationInput))) + void + given_search_input_with_name_and_contains_operator_should_return_a_page_of_kill_chain_phases() + throws Exception { + SearchPaginationInput searchPaginationInput = + PaginationFixture.simpleFilter("phase_name", "2", contains); + + mvc.perform( + post("/api/kill_chain_phases/search") + .contentType(MediaType.APPLICATION_JSON) + .content(asJsonString(searchPaginationInput))) .andExpect(status().is2xxSuccessful()) .andExpect(jsonPath("$.numberOfElements").value(1)); } - } @Nested @@ -156,12 +172,16 @@ class SortingPageOfKillCHainPhases { @DisplayName("Sorting by default") @Test - void given_search_input_without_sort_should_return_a_page_of_kill_chain_phases_with_default_sort() throws Exception { - SearchPaginationInput searchPaginationInput = PaginationFixture.getDefault().textSearch("name").build(); - - mvc.perform(post("/api/kill_chain_phases/search") - .contentType(MediaType.APPLICATION_JSON) - .content(asJsonString(searchPaginationInput))) + void + given_search_input_without_sort_should_return_a_page_of_kill_chain_phases_with_default_sort() + throws Exception { + SearchPaginationInput searchPaginationInput = + PaginationFixture.getDefault().textSearch("name").build(); + + mvc.perform( + post("/api/kill_chain_phases/search") + .contentType(MediaType.APPLICATION_JSON) + .content(asJsonString(searchPaginationInput))) .andExpect(status().is2xxSuccessful()) .andExpect(jsonPath("$.content.[0].phase_name").value("name1")) .andExpect(jsonPath("$.content.[1].phase_name").value("name2")) @@ -170,21 +190,22 @@ void given_search_input_without_sort_should_return_a_page_of_kill_chain_phases_w @DisplayName("Sorting by name desc") @Test - void given_sort_input_should_return_a_page_of_kill_chain_phases_sort_by_name_desc() throws Exception { - SearchPaginationInput searchPaginationInput = PaginationFixture.getDefault() - .textSearch("name") - .sorts(List.of(SortField.builder().property("phase_name").direction("desc").build())) - .build(); - - mvc.perform(post("/api/kill_chain_phases/search") - .contentType(MediaType.APPLICATION_JSON) - .content(asJsonString(searchPaginationInput))) + void given_sort_input_should_return_a_page_of_kill_chain_phases_sort_by_name_desc() + throws Exception { + SearchPaginationInput searchPaginationInput = + PaginationFixture.getDefault() + .textSearch("name") + .sorts(List.of(SortField.builder().property("phase_name").direction("desc").build())) + .build(); + + mvc.perform( + post("/api/kill_chain_phases/search") + .contentType(MediaType.APPLICATION_JSON) + .content(asJsonString(searchPaginationInput))) .andExpect(status().is2xxSuccessful()) .andExpect(jsonPath("$.content.[0].phase_name").value("name3")) .andExpect(jsonPath("$.content.[1].phase_name").value("name2")) .andExpect(jsonPath("$.content.[2].phase_name").value("name1")); } - } - } diff --git a/openbas-api/src/test/java/io/openbas/rest/AtomicTestingApiTest.java b/openbas-api/src/test/java/io/openbas/rest/AtomicTestingApiTest.java index 62355ae20c..aea4b773c4 100644 --- a/openbas-api/src/test/java/io/openbas/rest/AtomicTestingApiTest.java +++ b/openbas-api/src/test/java/io/openbas/rest/AtomicTestingApiTest.java @@ -1,5 +1,11 @@ package io.openbas.rest; +import static io.openbas.injectors.email.EmailContract.EMAIL_DEFAULT; +import static org.junit.jupiter.api.Assertions.*; +import static org.junit.jupiter.api.TestInstance.Lifecycle.PER_CLASS; +import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.*; +import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status; + import com.jayway.jsonpath.JsonPath; import io.openbas.IntegrationTest; import io.openbas.database.model.*; @@ -7,148 +13,148 @@ import io.openbas.database.repository.InjectStatusRepository; import io.openbas.database.repository.InjectorContractRepository; import io.openbas.utils.mockUser.WithMockAdminUser; +import java.time.Instant; +import java.util.List; import org.junit.jupiter.api.*; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.http.MediaType; import org.springframework.test.web.servlet.MockMvc; -import java.time.Instant; -import java.util.List; - -import static io.openbas.injectors.email.EmailContract.EMAIL_DEFAULT; -import static org.junit.jupiter.api.Assertions.*; -import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.*; -import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status; - -import static org.junit.jupiter.api.TestInstance.Lifecycle.PER_CLASS; - @TestInstance(PER_CLASS) @TestMethodOrder(MethodOrderer.OrderAnnotation.class) public class AtomicTestingApiTest extends IntegrationTest { - public static final String ATOMIC_TESTINGS_URI = "/api/atomic-testings"; - - static Inject INJECT_WITH_PAYLOAD; - static Inject INJECT_WITHOUT_PAYLOAD; - static InjectStatus INJECT_STATUS; - static String NEW_INJECT_ID; + public static final String ATOMIC_TESTINGS_URI = "/api/atomic-testings"; - @Autowired - private MockMvc mvc; - @Autowired - private InjectRepository injectRepository; - @Autowired - private InjectorContractRepository injectorContractRepository; - @Autowired - private InjectStatusRepository injectStatusRepository; + static Inject INJECT_WITH_PAYLOAD; + static Inject INJECT_WITHOUT_PAYLOAD; + static InjectStatus INJECT_STATUS; + static String NEW_INJECT_ID; - @BeforeAll - void beforeAll() { - Inject injectToCreate1 = new Inject(); - injectToCreate1.setTitle("Inject without payload"); - injectToCreate1.setCreatedAt(Instant.now()); - injectToCreate1.setUpdatedAt(Instant.now()); - injectToCreate1.setDependsDuration(0L); - injectToCreate1.setEnabled(true); - injectToCreate1.setInjectorContract(injectorContractRepository.findById(EMAIL_DEFAULT).orElseThrow()); - INJECT_WITHOUT_PAYLOAD = injectRepository.save(injectToCreate1); + @Autowired private MockMvc mvc; + @Autowired private InjectRepository injectRepository; + @Autowired private InjectorContractRepository injectorContractRepository; + @Autowired private InjectStatusRepository injectStatusRepository; - Inject injectToCreate2 = new Inject(); - injectToCreate2.setTitle("Inject with payload"); - injectToCreate2.setCreatedAt(Instant.now()); - injectToCreate2.setUpdatedAt(Instant.now()); - injectToCreate2.setDependsDuration(0L); - injectToCreate2.setEnabled(true); - injectToCreate2.setInjectorContract(injectorContractRepository.findById(EMAIL_DEFAULT).orElseThrow()); - INJECT_WITH_PAYLOAD = injectRepository.save(injectToCreate2); - InjectStatus injectStatus = new InjectStatus(); - injectStatus.setInject(injectToCreate2); - injectStatus.setTrackingSentDate(Instant.now()); - injectStatus.setName(ExecutionStatus.SUCCESS); - injectStatus.setCommandsLines(new InjectStatusCommandLine(List.of("cmd"), List.of("clean cmd"), "id1234567")); - INJECT_STATUS = injectStatusRepository.save(injectStatus); - } + @BeforeAll + void beforeAll() { + Inject injectToCreate1 = new Inject(); + injectToCreate1.setTitle("Inject without payload"); + injectToCreate1.setCreatedAt(Instant.now()); + injectToCreate1.setUpdatedAt(Instant.now()); + injectToCreate1.setDependsDuration(0L); + injectToCreate1.setEnabled(true); + injectToCreate1.setInjectorContract( + injectorContractRepository.findById(EMAIL_DEFAULT).orElseThrow()); + INJECT_WITHOUT_PAYLOAD = injectRepository.save(injectToCreate1); - @DisplayName("Find an atomic testing without payload") - @Test - @WithMockAdminUser - @Order(1) - void findAnAtomicTestingTestWithoutPayload() throws Exception { - String response = mvc.perform(get(ATOMIC_TESTINGS_URI + "/" + INJECT_WITHOUT_PAYLOAD.getId()) - .accept(MediaType.APPLICATION_JSON)) - .andExpect(status().is2xxSuccessful()) - .andReturn() - .getResponse() - .getContentAsString(); - // -- ASSERT -- - assertNotNull(response); - assertEquals(INJECT_WITHOUT_PAYLOAD.getId(), JsonPath.read(response, "$.inject_id")); - assertNull(JsonPath.read(response, "$.inject_commands_lines")); - } + Inject injectToCreate2 = new Inject(); + injectToCreate2.setTitle("Inject with payload"); + injectToCreate2.setCreatedAt(Instant.now()); + injectToCreate2.setUpdatedAt(Instant.now()); + injectToCreate2.setDependsDuration(0L); + injectToCreate2.setEnabled(true); + injectToCreate2.setInjectorContract( + injectorContractRepository.findById(EMAIL_DEFAULT).orElseThrow()); + INJECT_WITH_PAYLOAD = injectRepository.save(injectToCreate2); + InjectStatus injectStatus = new InjectStatus(); + injectStatus.setInject(injectToCreate2); + injectStatus.setTrackingSentDate(Instant.now()); + injectStatus.setName(ExecutionStatus.SUCCESS); + injectStatus.setCommandsLines( + new InjectStatusCommandLine(List.of("cmd"), List.of("clean cmd"), "id1234567")); + INJECT_STATUS = injectStatusRepository.save(injectStatus); + } - @DisplayName("Find an atomic testing with payload") - @Test - @WithMockAdminUser - @Order(2) - void findAnAtomicTestingTestWithPayload() throws Exception { - String response = mvc.perform(get(ATOMIC_TESTINGS_URI + "/" + INJECT_WITH_PAYLOAD.getId()) - .accept(MediaType.APPLICATION_JSON)) - .andExpect(status().is2xxSuccessful()) - .andReturn() - .getResponse() - .getContentAsString(); - // -- ASSERT -- - assertNotNull(response); - assertEquals(INJECT_WITH_PAYLOAD.getId(), JsonPath.read(response, "$.inject_id")); - assertNotNull(JsonPath.read(response, "$.inject_commands_lines")); - } + @DisplayName("Find an atomic testing without payload") + @Test + @WithMockAdminUser + @Order(1) + void findAnAtomicTestingTestWithoutPayload() throws Exception { + String response = + mvc.perform( + get(ATOMIC_TESTINGS_URI + "/" + INJECT_WITHOUT_PAYLOAD.getId()) + .accept(MediaType.APPLICATION_JSON)) + .andExpect(status().is2xxSuccessful()) + .andReturn() + .getResponse() + .getContentAsString(); + // -- ASSERT -- + assertNotNull(response); + assertEquals(INJECT_WITHOUT_PAYLOAD.getId(), JsonPath.read(response, "$.inject_id")); + assertNull(JsonPath.read(response, "$.inject_commands_lines")); + } - @DisplayName("Duplicate and delete an atomic testing") - @Test - @WithMockAdminUser - @Order(3) - void duplicateAndDeleteAtomicTestingTest() throws Exception { - // Duplicate - String response = mvc.perform(post(ATOMIC_TESTINGS_URI + "/" + INJECT_WITHOUT_PAYLOAD.getId()) - .contentType(MediaType.APPLICATION_JSON) - .accept(MediaType.APPLICATION_JSON)) - .andExpect(status().is2xxSuccessful()) - .andReturn() - .getResponse() - .getContentAsString(); - assertNotNull(response); - // Assert duplicate - NEW_INJECT_ID = JsonPath.read(response, "$.inject_id"); - response = mvc.perform(get(ATOMIC_TESTINGS_URI + "/" + NEW_INJECT_ID) - .accept(MediaType.APPLICATION_JSON)) - .andExpect(status().is2xxSuccessful()) - .andReturn() - .getResponse() - .getContentAsString(); - assertEquals(NEW_INJECT_ID, JsonPath.read(response, "$.inject_id")); - // Delete - response = mvc.perform(delete(ATOMIC_TESTINGS_URI + "/" + NEW_INJECT_ID) - .accept(MediaType.APPLICATION_JSON)) - .andExpect(status().is2xxSuccessful()) - .andReturn() - .getResponse() - .getContentAsString(); - assertNotNull(response); - // Assert delete - response = mvc.perform(get(ATOMIC_TESTINGS_URI + "/" + NEW_INJECT_ID) - .accept(MediaType.APPLICATION_JSON)) - .andExpect(status().is4xxClientError()) - .andReturn() - .getResponse() - .getContentAsString(); - assertNotNull(response); - } + @DisplayName("Find an atomic testing with payload") + @Test + @WithMockAdminUser + @Order(2) + void findAnAtomicTestingTestWithPayload() throws Exception { + String response = + mvc.perform( + get(ATOMIC_TESTINGS_URI + "/" + INJECT_WITH_PAYLOAD.getId()) + .accept(MediaType.APPLICATION_JSON)) + .andExpect(status().is2xxSuccessful()) + .andReturn() + .getResponse() + .getContentAsString(); + // -- ASSERT -- + assertNotNull(response); + assertEquals(INJECT_WITH_PAYLOAD.getId(), JsonPath.read(response, "$.inject_id")); + assertNotNull(JsonPath.read(response, "$.inject_commands_lines")); + } - @AfterAll - void afterAll() { - injectStatusRepository.delete(INJECT_STATUS); - injectRepository.delete(INJECT_WITH_PAYLOAD); - injectRepository.delete(INJECT_WITHOUT_PAYLOAD); - } + @DisplayName("Duplicate and delete an atomic testing") + @Test + @WithMockAdminUser + @Order(3) + void duplicateAndDeleteAtomicTestingTest() throws Exception { + // Duplicate + String response = + mvc.perform( + post(ATOMIC_TESTINGS_URI + "/" + INJECT_WITHOUT_PAYLOAD.getId()) + .contentType(MediaType.APPLICATION_JSON) + .accept(MediaType.APPLICATION_JSON)) + .andExpect(status().is2xxSuccessful()) + .andReturn() + .getResponse() + .getContentAsString(); + assertNotNull(response); + // Assert duplicate + NEW_INJECT_ID = JsonPath.read(response, "$.inject_id"); + response = + mvc.perform( + get(ATOMIC_TESTINGS_URI + "/" + NEW_INJECT_ID).accept(MediaType.APPLICATION_JSON)) + .andExpect(status().is2xxSuccessful()) + .andReturn() + .getResponse() + .getContentAsString(); + assertEquals(NEW_INJECT_ID, JsonPath.read(response, "$.inject_id")); + // Delete + response = + mvc.perform( + delete(ATOMIC_TESTINGS_URI + "/" + NEW_INJECT_ID) + .accept(MediaType.APPLICATION_JSON)) + .andExpect(status().is2xxSuccessful()) + .andReturn() + .getResponse() + .getContentAsString(); + assertNotNull(response); + // Assert delete + response = + mvc.perform( + get(ATOMIC_TESTINGS_URI + "/" + NEW_INJECT_ID).accept(MediaType.APPLICATION_JSON)) + .andExpect(status().is4xxClientError()) + .andReturn() + .getResponse() + .getContentAsString(); + assertNotNull(response); + } + @AfterAll + void afterAll() { + injectStatusRepository.delete(INJECT_STATUS); + injectRepository.delete(INJECT_WITH_PAYLOAD); + injectRepository.delete(INJECT_WITHOUT_PAYLOAD); + } } diff --git a/openbas-api/src/test/java/io/openbas/rest/ChallengeApiTest.java b/openbas-api/src/test/java/io/openbas/rest/ChallengeApiTest.java index f0548eaa8c..382c689d7b 100644 --- a/openbas-api/src/test/java/io/openbas/rest/ChallengeApiTest.java +++ b/openbas-api/src/test/java/io/openbas/rest/ChallengeApiTest.java @@ -1,5 +1,13 @@ package io.openbas.rest; +import static io.openbas.injectors.challenge.ChallengeContract.CHALLENGE_PUBLISH; +import static io.openbas.rest.scenario.ScenarioApi.SCENARIO_URI; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertNotNull; +import static org.junit.jupiter.api.TestInstance.Lifecycle.PER_CLASS; +import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get; +import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status; + import com.fasterxml.jackson.databind.ObjectMapper; import com.jayway.jsonpath.JsonPath; import io.openbas.database.model.Challenge; @@ -13,6 +21,7 @@ import io.openbas.service.ScenarioService; import io.openbas.utils.mockUser.WithMockObserverUser; import jakarta.annotation.Resource; +import java.util.List; import org.junit.jupiter.api.*; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.boot.test.autoconfigure.web.servlet.AutoConfigureMockMvc; @@ -20,37 +29,20 @@ import org.springframework.http.MediaType; import org.springframework.test.web.servlet.MockMvc; -import java.util.List; - -import static io.openbas.injectors.challenge.ChallengeContract.CHALLENGE_PUBLISH; -import static io.openbas.rest.scenario.ScenarioApi.SCENARIO_URI; -import static org.junit.jupiter.api.Assertions.assertEquals; -import static org.junit.jupiter.api.Assertions.assertNotNull; -import static org.junit.jupiter.api.TestInstance.Lifecycle.PER_CLASS; -import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get; -import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status; - @SpringBootTest @AutoConfigureMockMvc @TestMethodOrder(MethodOrderer.OrderAnnotation.class) @TestInstance(PER_CLASS) class ChallengeApiTest { - @Autowired - private MockMvc mvc; + @Autowired private MockMvc mvc; - @Autowired - private ScenarioRepository scenarioRepository; - @Autowired - private ScenarioService scenarioService; - @Autowired - private InjectRepository injectRepository; - @Autowired - private ChallengeRepository challengeRepository; - @Autowired - private InjectorContractRepository injectorContractRepository; - @Resource - private ObjectMapper objectMapper; + @Autowired private ScenarioRepository scenarioRepository; + @Autowired private ScenarioService scenarioService; + @Autowired private InjectRepository injectRepository; + @Autowired private ChallengeRepository challengeRepository; + @Autowired private InjectorContractRepository injectorContractRepository; + @Resource private ObjectMapper objectMapper; static String SCENARIO_ID; static String CHALLENGE_ID; @@ -85,7 +77,8 @@ void retrieveChallengesVariableForScenarioTest() throws Exception { content.setChallenges(List.of(challenge.getId())); Inject inject = new Inject(); inject.setTitle("Test inject"); - inject.setInjectorContract(this.injectorContractRepository.findById(CHALLENGE_PUBLISH).orElseThrow()); + inject.setInjectorContract( + this.injectorContractRepository.findById(CHALLENGE_PUBLISH).orElseThrow()); inject.setContent(this.objectMapper.valueToTree(content)); inject.setDependsDuration(0L); inject.setScenario(scenario); @@ -93,17 +86,18 @@ void retrieveChallengesVariableForScenarioTest() throws Exception { INJECT_ID = inject.getId(); // -- EXECUTE -- - String response = this.mvc - .perform(get(SCENARIO_URI + "/" + SCENARIO_ID + "/challenges") - .accept(MediaType.APPLICATION_JSON)) - .andExpect(status().is2xxSuccessful()) - .andReturn() - .getResponse() - .getContentAsString(); + String response = + this.mvc + .perform( + get(SCENARIO_URI + "/" + SCENARIO_ID + "/challenges") + .accept(MediaType.APPLICATION_JSON)) + .andExpect(status().is2xxSuccessful()) + .andReturn() + .getResponse() + .getContentAsString(); // -- ASSERT -- assertNotNull(response); assertEquals(challengeName, JsonPath.read(response, "$[0].challenge_name")); } - } diff --git a/openbas-api/src/test/java/io/openbas/rest/ChannelApiTest.java b/openbas-api/src/test/java/io/openbas/rest/ChannelApiTest.java index 263ff3bc29..5f58f4a0a8 100644 --- a/openbas-api/src/test/java/io/openbas/rest/ChannelApiTest.java +++ b/openbas-api/src/test/java/io/openbas/rest/ChannelApiTest.java @@ -1,5 +1,13 @@ package io.openbas.rest; +import static io.openbas.rest.scenario.ScenarioApi.SCENARIO_URI; +import static io.openbas.utils.JsonUtils.asJsonString; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertNotNull; +import static org.junit.jupiter.api.TestInstance.Lifecycle.PER_CLASS; +import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.*; +import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status; + import com.jayway.jsonpath.JsonPath; import io.openbas.database.model.Channel; import io.openbas.database.model.Scenario; @@ -8,8 +16,8 @@ import io.openbas.database.repository.ScenarioRepository; import io.openbas.rest.channel.form.ArticleCreateInput; import io.openbas.rest.channel.form.ArticleUpdateInput; -import io.openbas.utils.mockUser.WithMockPlannerUser; import io.openbas.service.ScenarioService; +import io.openbas.utils.mockUser.WithMockPlannerUser; import org.junit.jupiter.api.*; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.boot.test.autoconfigure.web.servlet.AutoConfigureMockMvc; @@ -17,31 +25,18 @@ import org.springframework.http.MediaType; import org.springframework.test.web.servlet.MockMvc; -import static io.openbas.rest.scenario.ScenarioApi.SCENARIO_URI; -import static io.openbas.utils.JsonUtils.asJsonString; -import static org.junit.jupiter.api.Assertions.assertEquals; -import static org.junit.jupiter.api.Assertions.assertNotNull; -import static org.junit.jupiter.api.TestInstance.Lifecycle.PER_CLASS; -import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.*; -import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status; - @SpringBootTest @AutoConfigureMockMvc @TestMethodOrder(MethodOrderer.OrderAnnotation.class) @TestInstance(PER_CLASS) class ChannelApiTest { - @Autowired - private MockMvc mvc; + @Autowired private MockMvc mvc; - @Autowired - private ScenarioService scenarioService; - @Autowired - private ScenarioRepository scenarioRepository; - @Autowired - private ChannelRepository channelRepository; - @Autowired - private ArticleRepository articleRepository; + @Autowired private ScenarioService scenarioService; + @Autowired private ScenarioRepository scenarioRepository; + @Autowired private ChannelRepository channelRepository; + @Autowired private ArticleRepository articleRepository; static String SCENARIO_ID; static String CHANNEL_ID; @@ -78,15 +73,17 @@ void createArticleForScenarioTest() throws Exception { articleCreateInput.setChannelId(CHANNEL_ID); // -- EXECUTE -- - String response = this.mvc - .perform(post(SCENARIO_URI + "/" + SCENARIO_ID + "/articles") - .content(asJsonString(articleCreateInput)) - .contentType(MediaType.APPLICATION_JSON) - .accept(MediaType.APPLICATION_JSON)) - .andExpect(status().is2xxSuccessful()) - .andReturn() - .getResponse() - .getContentAsString(); + String response = + this.mvc + .perform( + post(SCENARIO_URI + "/" + SCENARIO_ID + "/articles") + .content(asJsonString(articleCreateInput)) + .contentType(MediaType.APPLICATION_JSON) + .accept(MediaType.APPLICATION_JSON)) + .andExpect(status().is2xxSuccessful()) + .andReturn() + .getResponse() + .getContentAsString(); // -- ASSERT -- assertNotNull(response); @@ -100,13 +97,15 @@ void createArticleForScenarioTest() throws Exception { @WithMockPlannerUser void retrieveArticlesForScenarioTest() throws Exception { // -- EXECUTE -- - String response = this.mvc - .perform(get(SCENARIO_URI + "/" + SCENARIO_ID + "/articles") - .accept(MediaType.APPLICATION_JSON)) - .andExpect(status().is2xxSuccessful()) - .andReturn() - .getResponse() - .getContentAsString(); + String response = + this.mvc + .perform( + get(SCENARIO_URI + "/" + SCENARIO_ID + "/articles") + .accept(MediaType.APPLICATION_JSON)) + .andExpect(status().is2xxSuccessful()) + .andReturn() + .getResponse() + .getContentAsString(); // -- ASSERT -- assertNotNull(response); @@ -124,15 +123,17 @@ void updateArticleForScenarioTest() throws Exception { articleUpdateInput.setChannelId(CHANNEL_ID); // -- EXECUTE -- - String response = this.mvc - .perform(put(SCENARIO_URI + "/" + SCENARIO_ID + "/articles/" + ARTICLE_ID) - .content(asJsonString(articleUpdateInput)) - .contentType(MediaType.APPLICATION_JSON) - .accept(MediaType.APPLICATION_JSON)) - .andExpect(status().is2xxSuccessful()) - .andReturn() - .getResponse() - .getContentAsString(); + String response = + this.mvc + .perform( + put(SCENARIO_URI + "/" + SCENARIO_ID + "/articles/" + ARTICLE_ID) + .content(asJsonString(articleUpdateInput)) + .contentType(MediaType.APPLICATION_JSON) + .accept(MediaType.APPLICATION_JSON)) + .andExpect(status().is2xxSuccessful()) + .andReturn() + .getResponse() + .getContentAsString(); // -- ASSERT -- assertNotNull(response); @@ -145,8 +146,8 @@ void updateArticleForScenarioTest() throws Exception { @WithMockPlannerUser void deleteArticleForScenarioTest() throws Exception { // -- EXECUTE 1 ASSERT -- - this.mvc.perform(delete(SCENARIO_URI + "/" + SCENARIO_ID + "/articles/" + ARTICLE_ID)) + this.mvc + .perform(delete(SCENARIO_URI + "/" + SCENARIO_ID + "/articles/" + ARTICLE_ID)) .andExpect(status().is2xxSuccessful()); } - } diff --git a/openbas-api/src/test/java/io/openbas/rest/ExerciseApiSearchTest.java b/openbas-api/src/test/java/io/openbas/rest/ExerciseApiSearchTest.java index 9fbe87ad15..5999ad5f95 100644 --- a/openbas-api/src/test/java/io/openbas/rest/ExerciseApiSearchTest.java +++ b/openbas-api/src/test/java/io/openbas/rest/ExerciseApiSearchTest.java @@ -1,5 +1,15 @@ package io.openbas.rest; +import static io.openbas.database.model.ExerciseStatus.SCHEDULED; +import static io.openbas.database.model.Filters.FilterOperator.contains; +import static io.openbas.rest.exercise.ExerciseApi.EXERCISE_URI; +import static io.openbas.utils.JsonUtils.asJsonString; +import static java.lang.String.valueOf; +import static org.junit.jupiter.api.TestInstance.Lifecycle.PER_CLASS; +import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.post; +import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.jsonPath; +import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status; + import io.openbas.IntegrationTest; import io.openbas.database.model.Exercise; import io.openbas.database.repository.ExerciseRepository; @@ -8,32 +18,19 @@ import io.openbas.utils.mockUser.WithMockAdminUser; import io.openbas.utils.pagination.SearchPaginationInput; import io.openbas.utils.pagination.SortField; +import java.util.ArrayList; +import java.util.List; import org.junit.jupiter.api.*; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.http.MediaType; import org.springframework.test.web.servlet.MockMvc; -import java.util.ArrayList; -import java.util.List; - -import static io.openbas.database.model.ExerciseStatus.SCHEDULED; -import static io.openbas.database.model.Filters.FilterOperator.contains; -import static io.openbas.rest.exercise.ExerciseApi.EXERCISE_URI; -import static io.openbas.utils.JsonUtils.asJsonString; -import static java.lang.String.valueOf; -import static org.junit.jupiter.api.TestInstance.Lifecycle.PER_CLASS; -import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.post; -import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.jsonPath; -import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status; - @TestInstance(PER_CLASS) public class ExerciseApiSearchTest extends IntegrationTest { - @Autowired - private MockMvc mvc; + @Autowired private MockMvc mvc; - @Autowired - private ExerciseRepository exerciseRepository; + @Autowired private ExerciseRepository exerciseRepository; private static final List EXERCISE_IDS = new ArrayList<>(); @@ -66,11 +63,13 @@ class SearchingPageOfExercises { @Test @DisplayName("Retrieving first page of exercises by text search") void given_working_search_input_should_return_a_page_of_exercises() throws Exception { - SearchPaginationInput searchPaginationInput = PaginationFixture.getDefault().textSearch("Crisis").build(); + SearchPaginationInput searchPaginationInput = + PaginationFixture.getDefault().textSearch("Crisis").build(); - mvc.perform(post(EXERCISE_URI + "/search") - .contentType(MediaType.APPLICATION_JSON) - .content(asJsonString(searchPaginationInput))) + mvc.perform( + post(EXERCISE_URI + "/search") + .contentType(MediaType.APPLICATION_JSON) + .content(asJsonString(searchPaginationInput))) .andExpect(status().is2xxSuccessful()) .andExpect(jsonPath("$.numberOfElements").value(1)); } @@ -78,11 +77,13 @@ void given_working_search_input_should_return_a_page_of_exercises() throws Excep @Test @DisplayName("Not retrieving first page of exercises by text search") void given_not_working_search_input_should_return_a_page_of_exercises() throws Exception { - SearchPaginationInput searchPaginationInput = PaginationFixture.getDefault().textSearch("wrong").build(); + SearchPaginationInput searchPaginationInput = + PaginationFixture.getDefault().textSearch("wrong").build(); - mvc.perform(post(EXERCISE_URI + "/search") - .contentType(MediaType.APPLICATION_JSON) - .content(asJsonString(searchPaginationInput))) + mvc.perform( + post(EXERCISE_URI + "/search") + .contentType(MediaType.APPLICATION_JSON) + .content(asJsonString(searchPaginationInput))) .andExpect(status().is2xxSuccessful()) .andExpect(jsonPath("$.numberOfElements").value(0)); } @@ -94,14 +95,17 @@ class SortingPageOfExercises { @Test @DisplayName("Sorting page of exercises by name") - void given_sorting_input_by_name_should_return_a_page_of_exercises_sort_by_name() throws Exception { - SearchPaginationInput searchPaginationInput = PaginationFixture.getDefault() - .sorts(List.of(SortField.builder().property("exercise_name").build())) - .build(); - - mvc.perform(post(EXERCISE_URI + "/search") - .contentType(MediaType.APPLICATION_JSON) - .content(asJsonString(searchPaginationInput))) + void given_sorting_input_by_name_should_return_a_page_of_exercises_sort_by_name() + throws Exception { + SearchPaginationInput searchPaginationInput = + PaginationFixture.getDefault() + .sorts(List.of(SortField.builder().property("exercise_name").build())) + .build(); + + mvc.perform( + post(EXERCISE_URI + "/search") + .contentType(MediaType.APPLICATION_JSON) + .content(asJsonString(searchPaginationInput))) .andExpect(status().is2xxSuccessful()) .andExpect(jsonPath("$.content.[0].exercise_name").value("Crisis exercise")) .andExpect(jsonPath("$.content.[1].exercise_name").value("Incident response exercise")); @@ -109,14 +113,22 @@ void given_sorting_input_by_name_should_return_a_page_of_exercises_sort_by_name( @Test @DisplayName("Sorting page of exercises by start date") - void given_sorting_input_by_start_date_should_return_a_page_of_exercises_sort_by_start_date() throws Exception { - SearchPaginationInput searchPaginationInput = PaginationFixture.getDefault() - .sorts(List.of(SortField.builder().property("exercise_start_date").direction("desc").build())) - .build(); - - mvc.perform(post(EXERCISE_URI + "/search") - .contentType(MediaType.APPLICATION_JSON) - .content(asJsonString(searchPaginationInput))) + void given_sorting_input_by_start_date_should_return_a_page_of_exercises_sort_by_start_date() + throws Exception { + SearchPaginationInput searchPaginationInput = + PaginationFixture.getDefault() + .sorts( + List.of( + SortField.builder() + .property("exercise_start_date") + .direction("desc") + .build())) + .build(); + + mvc.perform( + post(EXERCISE_URI + "/search") + .contentType(MediaType.APPLICATION_JSON) + .content(asJsonString(searchPaginationInput))) .andExpect(status().is2xxSuccessful()) .andExpect(jsonPath("$.content.[1].exercise_name").value("Incident response exercise")) .andExpect(jsonPath("$.content.[0].exercise_name").value("Crisis exercise")); @@ -129,28 +141,30 @@ class FilteringPageOfExercises { @Test @DisplayName("Filtering page of exercises by name") - void given_filter_input_by_name_should_return_a_page_of_exercises_filter_by_name() throws Exception { - SearchPaginationInput searchPaginationInput = PaginationFixture.simpleFilter( - "exercise_name", "Crisis", contains - ); - - mvc.perform(post(EXERCISE_URI + "/search") - .contentType(MediaType.APPLICATION_JSON) - .content(asJsonString(searchPaginationInput))) + void given_filter_input_by_name_should_return_a_page_of_exercises_filter_by_name() + throws Exception { + SearchPaginationInput searchPaginationInput = + PaginationFixture.simpleFilter("exercise_name", "Crisis", contains); + + mvc.perform( + post(EXERCISE_URI + "/search") + .contentType(MediaType.APPLICATION_JSON) + .content(asJsonString(searchPaginationInput))) .andExpect(status().is2xxSuccessful()) .andExpect(jsonPath("$.numberOfElements").value(1)); } @Test @DisplayName("Filtering page of exercises by status") - void given_filter_input_by_sttaus_should_return_a_page_of_exercises_filter_by_status() throws Exception { - SearchPaginationInput searchPaginationInput = PaginationFixture.simpleFilter( - "exercise_status", valueOf(SCHEDULED), contains - ); - - mvc.perform(post(EXERCISE_URI + "/search") - .contentType(MediaType.APPLICATION_JSON) - .content(asJsonString(searchPaginationInput))) + void given_filter_input_by_sttaus_should_return_a_page_of_exercises_filter_by_status() + throws Exception { + SearchPaginationInput searchPaginationInput = + PaginationFixture.simpleFilter("exercise_status", valueOf(SCHEDULED), contains); + + mvc.perform( + post(EXERCISE_URI + "/search") + .contentType(MediaType.APPLICATION_JSON) + .content(asJsonString(searchPaginationInput))) .andExpect(status().is2xxSuccessful()) .andExpect(jsonPath("$.numberOfElements").value(2)); } diff --git a/openbas-api/src/test/java/io/openbas/rest/InjectApiTest.java b/openbas-api/src/test/java/io/openbas/rest/InjectApiTest.java index 03e5a3ddae..1a2d015f5b 100644 --- a/openbas-api/src/test/java/io/openbas/rest/InjectApiTest.java +++ b/openbas-api/src/test/java/io/openbas/rest/InjectApiTest.java @@ -1,9 +1,19 @@ package io.openbas.rest; +import static io.openbas.database.model.ExerciseStatus.RUNNING; +import static io.openbas.injectors.email.EmailContract.EMAIL_DEFAULT; +import static io.openbas.rest.exercise.ExerciseApi.EXERCISE_URI; +import static io.openbas.rest.scenario.ScenarioApi.SCENARIO_URI; +import static io.openbas.utils.JsonUtils.asJsonString; +import static org.junit.jupiter.api.Assertions.*; +import static org.junit.jupiter.api.TestInstance.Lifecycle.PER_CLASS; +import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.*; +import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status; + import com.jayway.jsonpath.JsonPath; import io.openbas.IntegrationTest; -import io.openbas.database.model.InjectorContract; import io.openbas.database.model.*; +import io.openbas.database.model.InjectorContract; import io.openbas.database.repository.*; import io.openbas.rest.exercise.ExerciseService; import io.openbas.rest.inject.form.InjectInput; @@ -11,24 +21,13 @@ import io.openbas.utils.fixtures.InjectExpectationFixture; import io.openbas.utils.mockUser.WithMockObserverUser; import io.openbas.utils.mockUser.WithMockPlannerUser; +import java.time.Instant; +import java.util.List; import org.junit.jupiter.api.*; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.http.MediaType; import org.springframework.test.web.servlet.MockMvc; -import java.time.Instant; -import java.util.List; - -import static io.openbas.database.model.ExerciseStatus.RUNNING; -import static io.openbas.injectors.email.EmailContract.EMAIL_DEFAULT; -import static io.openbas.rest.exercise.ExerciseApi.EXERCISE_URI; -import static io.openbas.rest.scenario.ScenarioApi.SCENARIO_URI; -import static io.openbas.utils.JsonUtils.asJsonString; -import static org.junit.jupiter.api.Assertions.*; -import static org.junit.jupiter.api.TestInstance.Lifecycle.PER_CLASS; -import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.*; -import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status; - @TestMethodOrder(MethodOrderer.OrderAnnotation.class) @TestInstance(PER_CLASS) class InjectApiTest extends IntegrationTest { @@ -40,28 +39,17 @@ class InjectApiTest extends IntegrationTest { static Team TEAM; static String SCENARIO_INJECT_ID; - @Autowired - private MockMvc mvc; - @Autowired - private ScenarioService scenarioService; - @Autowired - private ExerciseService exerciseService; - @Autowired - private ExerciseRepository exerciseRepository; - @Autowired - private ScenarioRepository scenarioRepository; - @Autowired - private InjectRepository injectRepository; - @Autowired - private DocumentRepository documentRepository; - @Autowired - private CommunicationRepository communicationRepository; - @Autowired - private InjectExpectationRepository injectExpectationRepository; - @Autowired - private TeamRepository teamRepository; - @Autowired - private InjectorContractRepository injectorContractRepository; + @Autowired private MockMvc mvc; + @Autowired private ScenarioService scenarioService; + @Autowired private ExerciseService exerciseService; + @Autowired private ExerciseRepository exerciseRepository; + @Autowired private ScenarioRepository scenarioRepository; + @Autowired private InjectRepository injectRepository; + @Autowired private DocumentRepository documentRepository; + @Autowired private CommunicationRepository communicationRepository; + @Autowired private InjectExpectationRepository injectExpectationRepository; + @Autowired private TeamRepository teamRepository; + @Autowired private InjectorContractRepository injectorContractRepository; @BeforeAll void beforeAll() { @@ -115,26 +103,26 @@ void addInjectForScenarioTest() throws Exception { input.setDependsDuration(0L); // -- EXECUTE -- - String response = mvc - .perform(post(SCENARIO_URI + "/" + SCENARIO.getId() + "/injects") - .content(asJsonString(input)) - .contentType(MediaType.APPLICATION_JSON) - .accept(MediaType.APPLICATION_JSON)) - .andExpect(status().is2xxSuccessful()) - .andReturn() - .getResponse() - .getContentAsString(); + String response = + mvc.perform( + post(SCENARIO_URI + "/" + SCENARIO.getId() + "/injects") + .content(asJsonString(input)) + .contentType(MediaType.APPLICATION_JSON) + .accept(MediaType.APPLICATION_JSON)) + .andExpect(status().is2xxSuccessful()) + .andReturn() + .getResponse() + .getContentAsString(); // -- ASSERT -- assertNotNull(response); SCENARIO_INJECT_ID = JsonPath.read(response, "$.inject_id"); - response = mvc - .perform(get(SCENARIO_URI + "/" + SCENARIO.getId()) - .accept(MediaType.APPLICATION_JSON)) - .andExpect(status().is2xxSuccessful()) - .andReturn() - .getResponse() - .getContentAsString(); + response = + mvc.perform(get(SCENARIO_URI + "/" + SCENARIO.getId()).accept(MediaType.APPLICATION_JSON)) + .andExpect(status().is2xxSuccessful()) + .andReturn() + .getResponse() + .getContentAsString(); assertEquals(SCENARIO_INJECT_ID, JsonPath.read(response, "$.scenario_injects[0]")); } @@ -144,13 +132,14 @@ void addInjectForScenarioTest() throws Exception { @WithMockObserverUser void retrieveInjectsForScenarioTest() throws Exception { // -- EXECUTE -- - String response = mvc - .perform(get(SCENARIO_URI + "/" + SCENARIO.getId() + "/injects") - .accept(MediaType.APPLICATION_JSON)) - .andExpect(status().is2xxSuccessful()) - .andReturn() - .getResponse() - .getContentAsString(); + String response = + mvc.perform( + get(SCENARIO_URI + "/" + SCENARIO.getId() + "/injects") + .accept(MediaType.APPLICATION_JSON)) + .andExpect(status().is2xxSuccessful()) + .andReturn() + .getResponse() + .getContentAsString(); // -- ASSERT -- assertNotNull(response); @@ -163,13 +152,14 @@ void retrieveInjectsForScenarioTest() throws Exception { @WithMockObserverUser void retrieveInjectForScenarioTest() throws Exception { // -- EXECUTE -- - String response = mvc - .perform(get(SCENARIO_URI + "/" + SCENARIO.getId() + "/injects/" + SCENARIO_INJECT_ID) - .accept(MediaType.APPLICATION_JSON)) - .andExpect(status().is2xxSuccessful()) - .andReturn() - .getResponse() - .getContentAsString(); + String response = + mvc.perform( + get(SCENARIO_URI + "/" + SCENARIO.getId() + "/injects/" + SCENARIO_INJECT_ID) + .accept(MediaType.APPLICATION_JSON)) + .andExpect(status().is2xxSuccessful()) + .andReturn() + .getResponse() + .getContentAsString(); // -- ASSERT -- assertNotNull(response); @@ -186,19 +176,21 @@ void updateInjectForScenarioTest() throws Exception { InjectInput input = new InjectInput(); String injectTitle = "A new title"; input.setTitle(injectTitle); - input.setInjectorContract(inject.getInjectorContract().map(InjectorContract::getId).orElse(null)); + input.setInjectorContract( + inject.getInjectorContract().map(InjectorContract::getId).orElse(null)); input.setDependsDuration(inject.getDependsDuration()); // -- EXECUTE -- - String response = mvc - .perform(put(SCENARIO_URI + "/" + SCENARIO.getId() + "/injects/" + SCENARIO_INJECT_ID) - .content(asJsonString(input)) - .contentType(MediaType.APPLICATION_JSON) - .accept(MediaType.APPLICATION_JSON)) - .andExpect(status().is2xxSuccessful()) - .andReturn() - .getResponse() - .getContentAsString(); + String response = + mvc.perform( + put(SCENARIO_URI + "/" + SCENARIO.getId() + "/injects/" + SCENARIO_INJECT_ID) + .content(asJsonString(input)) + .contentType(MediaType.APPLICATION_JSON) + .accept(MediaType.APPLICATION_JSON)) + .andExpect(status().is2xxSuccessful()) + .andReturn() + .getResponse() + .getContentAsString(); // -- ASSERT -- assertNotNull(response); @@ -229,7 +221,8 @@ void deleteInjectsForScenarioTest() throws Exception { injectForScenario1.setCreatedAt(Instant.now()); injectForScenario1.setUpdatedAt(Instant.now()); injectForScenario1.setDependsDuration(5L); - injectForScenario1.setInjectorContract(injectorContractRepository.findById(EMAIL_DEFAULT).orElseThrow()); + injectForScenario1.setInjectorContract( + injectorContractRepository.findById(EMAIL_DEFAULT).orElseThrow()); injectForScenario1.setScenario(SCENARIO); Inject createdInject = injectRepository.save(injectForScenario1); @@ -238,28 +231,46 @@ void deleteInjectsForScenarioTest() throws Exception { injectDocument4.setDocument(DOCUMENT2); createdInject.setDocuments(List.of(injectDocument4)); - injectExpectationRepository.save(InjectExpectationFixture.createArticleInjectExpectation(TEAM, createdInject)); + injectExpectationRepository.save( + InjectExpectationFixture.createArticleInjectExpectation(TEAM, createdInject)); // -- ASSERT -- - assertTrue(injectRepository.existsById(createdInject.getId()), "The inject should exist from the database"); - assertFalse(injectRepository.findByScenarioId(SCENARIO.getId()).isEmpty(), + assertTrue( + injectRepository.existsById(createdInject.getId()), + "The inject should exist from the database"); + assertFalse( + injectRepository.findByScenarioId(SCENARIO.getId()).isEmpty(), "There should be injects for the scenario in the database"); - assertFalse(injectExpectationRepository.findAllByInjectAndTeam(createdInject.getId(), TEAM.getId()).isEmpty(), + assertFalse( + injectExpectationRepository + .findAllByInjectAndTeam(createdInject.getId(), TEAM.getId()) + .isEmpty(), "There should be expectations for the scenario in the database"); // -- EXECUTE -- - mvc.perform(delete(SCENARIO_URI + "/" + SCENARIO.getId() + "/injects") - .content(asJsonString(List.of(createdInject.getId()))) - .contentType(MediaType.APPLICATION_JSON)) + mvc.perform( + delete(SCENARIO_URI + "/" + SCENARIO.getId() + "/injects") + .content(asJsonString(List.of(createdInject.getId()))) + .contentType(MediaType.APPLICATION_JSON)) .andExpect(status().is2xxSuccessful()); // -- ASSERT -- - assertFalse(injectRepository.existsById(createdInject.getId()), "The inject should be deleted from the database"); - assertTrue(scenarioRepository.existsById(SCENARIO.getId()), "The scenario should still exist in the database"); - assertTrue(injectRepository.findByScenarioId(SCENARIO.getId()).isEmpty(), + assertFalse( + injectRepository.existsById(createdInject.getId()), + "The inject should be deleted from the database"); + assertTrue( + scenarioRepository.existsById(SCENARIO.getId()), + "The scenario should still exist in the database"); + assertTrue( + injectRepository.findByScenarioId(SCENARIO.getId()).isEmpty(), "There should be no injects for the scenario in the database"); - assertTrue(documentRepository.existsById(DOCUMENT2.getId()), "The document should still exist in the database"); - assertTrue(injectExpectationRepository.findAllByInjectAndTeam(createdInject.getId(), TEAM.getId()).isEmpty(), + assertTrue( + documentRepository.existsById(DOCUMENT2.getId()), + "The document should still exist in the database"); + assertTrue( + injectExpectationRepository + .findAllByInjectAndTeam(createdInject.getId(), TEAM.getId()) + .isEmpty(), "There should be no expectations related to the inject in the database"); } @@ -317,35 +328,62 @@ void deleteInjectsForExerciseTest() throws Exception { communication.setReceivedAt(Instant.now()); Communication createdCommunication = communicationRepository.save(communication); - injectExpectationRepository.save(InjectExpectationFixture.createPreventionInjectExpectation(TEAM, createdInject1)); - injectExpectationRepository.save(InjectExpectationFixture.createDetectionInjectExpectation(TEAM, createdInject1)); - injectExpectationRepository.save(InjectExpectationFixture.createManualInjectExpectation(TEAM, createdInject2)); + injectExpectationRepository.save( + InjectExpectationFixture.createPreventionInjectExpectation(TEAM, createdInject1)); + injectExpectationRepository.save( + InjectExpectationFixture.createDetectionInjectExpectation(TEAM, createdInject1)); + injectExpectationRepository.save( + InjectExpectationFixture.createManualInjectExpectation(TEAM, createdInject2)); // -- ASSERT -- - assertTrue(injectRepository.existsById(createdInject1.getId()), "The inject should exist from the database"); - assertFalse(injectRepository.findByExerciseId(EXERCISE.getId()).isEmpty(), + assertTrue( + injectRepository.existsById(createdInject1.getId()), + "The inject should exist from the database"); + assertFalse( + injectRepository.findByExerciseId(EXERCISE.getId()).isEmpty(), "There should be injects for the exercise in the database"); assertEquals(1, communicationRepository.findByInjectId(createdInject1.getId()).size()); - assertEquals(2, injectExpectationRepository.findAllByInjectAndTeam(createdInject1.getId(), TEAM.getId()).size()); - assertEquals(1, injectExpectationRepository.findAllByInjectAndTeam(createdInject2.getId(), TEAM.getId()).size()); + assertEquals( + 2, + injectExpectationRepository + .findAllByInjectAndTeam(createdInject1.getId(), TEAM.getId()) + .size()); + assertEquals( + 1, + injectExpectationRepository + .findAllByInjectAndTeam(createdInject2.getId(), TEAM.getId()) + .size()); // -- EXECUTE -- - mvc.perform(delete(EXERCISE_URI + "/" + EXERCISE.getId() + "/injects") - .content(asJsonString(List.of(createdInject1.getId(), createdInject2.getId()))) - .contentType(MediaType.APPLICATION_JSON)) + mvc.perform( + delete(EXERCISE_URI + "/" + EXERCISE.getId() + "/injects") + .content(asJsonString(List.of(createdInject1.getId(), createdInject2.getId()))) + .contentType(MediaType.APPLICATION_JSON)) .andExpect(status().is2xxSuccessful()); // -- ASSERT -- - assertFalse(injectRepository.existsById(createdInject1.getId()), "The inject should be deleted from the database"); - assertFalse(injectRepository.existsById(createdInject2.getId()), "The inject should be deleted from the database"); - assertTrue(exerciseRepository.existsById(EXERCISE.getId()), "The exercise should still exist in the database"); - assertTrue(injectRepository.findByExerciseId(EXERCISE.getId()).isEmpty(), + assertFalse( + injectRepository.existsById(createdInject1.getId()), + "The inject should be deleted from the database"); + assertFalse( + injectRepository.existsById(createdInject2.getId()), + "The inject should be deleted from the database"); + assertTrue( + exerciseRepository.existsById(EXERCISE.getId()), + "The exercise should still exist in the database"); + assertTrue( + injectRepository.findByExerciseId(EXERCISE.getId()).isEmpty(), "There should be no injects for the exercise in the database"); - assertTrue(documentRepository.existsById(DOCUMENT1.getId()), "The document should still exist in the database"); - assertFalse(communicationRepository.existsById(createdCommunication.getId()), + assertTrue( + documentRepository.existsById(DOCUMENT1.getId()), + "The document should still exist in the database"); + assertFalse( + communicationRepository.existsById(createdCommunication.getId()), "The communication should be deleted from the database"); - assertTrue(injectExpectationRepository.findAllByInjectAndTeam(createdInject1.getId(), TEAM.getId()).isEmpty(), + assertTrue( + injectExpectationRepository + .findAllByInjectAndTeam(createdInject1.getId(), TEAM.getId()) + .isEmpty(), "There should be no expectations related to the inject in the database"); } } - diff --git a/openbas-api/src/test/java/io/openbas/rest/MapperApiTest.java b/openbas-api/src/test/java/io/openbas/rest/MapperApiTest.java index d520074774..f54e703369 100644 --- a/openbas-api/src/test/java/io/openbas/rest/MapperApiTest.java +++ b/openbas-api/src/test/java/io/openbas/rest/MapperApiTest.java @@ -1,5 +1,12 @@ package io.openbas.rest; +import static io.openbas.utils.JsonUtils.asJsonString; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertNotNull; +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.Mockito.*; +import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status; + import com.fasterxml.jackson.databind.ObjectMapper; import com.jayway.jsonpath.JsonPath; import io.openbas.database.model.ImportMapper; @@ -13,6 +20,13 @@ import io.openbas.service.MapperService; import io.openbas.utils.fixtures.PaginationFixture; import io.openbas.utils.mockMapper.MockMapperUtils; +import java.io.File; +import java.io.FileInputStream; +import java.io.InputStream; +import java.lang.reflect.Field; +import java.util.List; +import java.util.Optional; +import java.util.UUID; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.DisplayName; import org.junit.jupiter.api.Test; @@ -31,39 +45,20 @@ import org.springframework.test.web.servlet.setup.MockMvcBuilders; import org.springframework.util.ResourceUtils; -import java.io.File; -import java.io.FileInputStream; -import java.io.InputStream; -import java.lang.reflect.Field; -import java.util.List; -import java.util.Optional; -import java.util.UUID; - -import static io.openbas.utils.JsonUtils.asJsonString; -import static org.junit.jupiter.api.Assertions.assertEquals; -import static org.junit.jupiter.api.Assertions.assertNotNull; -import static org.mockito.ArgumentMatchers.any; -import static org.mockito.Mockito.*; -import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status; - @SpringBootTest @ExtendWith(MockitoExtension.class) public class MapperApiTest { private MockMvc mvc; - @Mock - private ImportMapperRepository importMapperRepository; + @Mock private ImportMapperRepository importMapperRepository; - @Mock - private MapperService mapperService; - @Mock - private InjectService injectService; + @Mock private MapperService mapperService; + @Mock private InjectService injectService; private MapperApi mapperApi; - @Autowired - private ObjectMapper objectMapper; + @Autowired private ObjectMapper objectMapper; @BeforeEach void before() throws IllegalAccessException, NoSuchFieldException { @@ -74,8 +69,7 @@ void before() throws IllegalAccessException, NoSuchFieldException { sessionContextField.setAccessible(true); sessionContextField.set(mapperApi, objectMapper); - mvc = MockMvcBuilders.standaloneSetup(mapperApi) - .build(); + mvc = MockMvcBuilders.standaloneSetup(mapperApi).build(); } // -- SCENARIOS -- @@ -89,10 +83,12 @@ void searchMappers() throws Exception { PageImpl page = new PageImpl<>(importMappers, pageable, importMappers.size()); when(importMapperRepository.findAll(any(), any())).thenReturn(page); // -- EXECUTE -- - String response = this.mvc - .perform(MockMvcRequestBuilders.post("/api/mappers/search") - .contentType(MediaType.APPLICATION_JSON) - .content(asJsonString(PaginationFixture.getDefault().textSearch("").build()))) + String response = + this.mvc + .perform( + MockMvcRequestBuilders.post("/api/mappers/search") + .contentType(MediaType.APPLICATION_JSON) + .content(asJsonString(PaginationFixture.getDefault().textSearch("").build()))) .andExpect(status().is2xxSuccessful()) .andReturn() .getResponse() @@ -100,7 +96,8 @@ void searchMappers() throws Exception { // -- ASSERT -- assertNotNull(response); - assertEquals(JsonPath.read(response, "$.content[0].import_mapper_id"), importMappers.get(0).getId()); + assertEquals( + JsonPath.read(response, "$.content[0].import_mapper_id"), importMappers.get(0).getId()); } @DisplayName("Test search of a specific mapper") @@ -110,8 +107,10 @@ void searchSpecificMapper() throws Exception { ImportMapper importMapper = MockMapperUtils.createImportMapper(); when(importMapperRepository.findById(any())).thenReturn(Optional.of(importMapper)); // -- EXECUTE -- - String response = this.mvc - .perform(MockMvcRequestBuilders.get("/api/mappers/" + importMapper.getId()) + String response = + this.mvc + .perform( + MockMvcRequestBuilders.get("/api/mappers/" + importMapper.getId()) .contentType(MediaType.APPLICATION_JSON)) .andExpect(status().is2xxSuccessful()) .andReturn() @@ -133,8 +132,10 @@ void createMapper() throws Exception { importMapperInput.setInjectTypeColumn("B"); when(mapperService.createAndSaveImportMapper(any())).thenReturn(importMapper); // -- EXECUTE -- - String response = this.mvc - .perform(MockMvcRequestBuilders.post("/api/mappers/") + String response = + this.mvc + .perform( + MockMvcRequestBuilders.post("/api/mappers/") .contentType(MediaType.APPLICATION_JSON) .content(asJsonString(importMapperInput))) .andExpect(status().is2xxSuccessful()) @@ -156,8 +157,10 @@ void duplicateMapper() throws Exception { when(mapperService.getDuplicateImportMapper(any())).thenReturn(importMapperDuplicated); // -- EXECUTE -- - String response = this.mvc - .perform(MockMvcRequestBuilders.post("/api/mappers/"+ importMapper.getId()) + String response = + this.mvc + .perform( + MockMvcRequestBuilders.post("/api/mappers/" + importMapper.getId()) .contentType(MediaType.APPLICATION_JSON) .content(asJsonString(importMapper))) .andExpect(status().is2xxSuccessful()) @@ -177,10 +180,11 @@ void deleteSpecificMapper() throws Exception { ImportMapper importMapper = MockMapperUtils.createImportMapper(); // -- EXECUTE -- this.mvc - .perform(MockMvcRequestBuilders.delete("/api/mappers/" + importMapper.getId()) - .contentType(MediaType.APPLICATION_JSON) - .content(asJsonString(PaginationFixture.getDefault().textSearch("").build()))) - .andExpect(status().is2xxSuccessful()); + .perform( + MockMvcRequestBuilders.delete("/api/mappers/" + importMapper.getId()) + .contentType(MediaType.APPLICATION_JSON) + .content(asJsonString(PaginationFixture.getDefault().textSearch("").build()))) + .andExpect(status().is2xxSuccessful()); verify(importMapperRepository, times(1)).deleteById(any()); } @@ -195,8 +199,10 @@ void updateSpecificMapper() throws Exception { importMapperInput.setInjectTypeColumn("B"); when(mapperService.updateImportMapper(any(), any())).thenReturn(importMapper); // -- EXECUTE -- - String response = this.mvc - .perform(MockMvcRequestBuilders.put("/api/mappers/" + importMapper.getId()) + String response = + this.mvc + .perform( + MockMvcRequestBuilders.put("/api/mappers/" + importMapper.getId()) .contentType(MediaType.APPLICATION_JSON) .content(asJsonString(importMapperInput))) .andExpect(status().is2xxSuccessful()) @@ -209,8 +215,6 @@ void updateSpecificMapper() throws Exception { assertEquals(JsonPath.read(response, "$.import_mapper_id"), importMapper.getId()); } - - @DisplayName("Test store xls") @Test void testStoreXls() throws Exception { @@ -219,15 +223,13 @@ void testStoreXls() throws Exception { File testFile = ResourceUtils.getFile("classpath:xls-test-files/test_file_1.xlsx"); InputStream in = new FileInputStream(testFile); - MockMultipartFile xlsFile = new MockMultipartFile("file", - "my-awesome-file.xls", - "application/xlsx", - in.readAllBytes()); + MockMultipartFile xlsFile = + new MockMultipartFile("file", "my-awesome-file.xls", "application/xlsx", in.readAllBytes()); // -- EXECUTE -- - String response = this.mvc - .perform(MockMvcRequestBuilders.multipart("/api/mappers/store") - .file(xlsFile)) + String response = + this.mvc + .perform(MockMvcRequestBuilders.multipart("/api/mappers/store").file(xlsFile)) .andExpect(status().is2xxSuccessful()) .andReturn() .getResponse() @@ -237,8 +239,6 @@ void testStoreXls() throws Exception { assertNotNull(response); } - - @DisplayName("Test testing an import xls") @Test void testTestingXls() throws Exception { @@ -251,12 +251,17 @@ void testTestingXls() throws Exception { injectsImportInput.getImportMapper().setName("TEST"); - when(injectService.importInjectIntoScenarioFromXLS(any(), any(), any(), any(), anyInt(), anyBoolean())).thenReturn(new ImportTestSummary()); + when(injectService.importInjectIntoScenarioFromXLS( + any(), any(), any(), any(), anyInt(), anyBoolean())) + .thenReturn(new ImportTestSummary()); when(mapperService.createImportMapper(any())).thenReturn(importMapper); // -- EXECUTE -- - String response = this.mvc - .perform(MockMvcRequestBuilders.post("/api/mappers/store/{importId}", UUID.randomUUID().toString()) + String response = + this.mvc + .perform( + MockMvcRequestBuilders.post( + "/api/mappers/store/{importId}", UUID.randomUUID().toString()) .contentType(MediaType.APPLICATION_JSON) .content(asJsonString(injectsImportInput))) .andExpect(status().is2xxSuccessful()) @@ -267,5 +272,4 @@ void testTestingXls() throws Exception { // -- ASSERT -- assertNotNull(response); } - } diff --git a/openbas-api/src/test/java/io/openbas/rest/PayloadApiSearchTest.java b/openbas-api/src/test/java/io/openbas/rest/PayloadApiSearchTest.java index 0f668fd7ab..d2d0afa7a2 100644 --- a/openbas-api/src/test/java/io/openbas/rest/PayloadApiSearchTest.java +++ b/openbas-api/src/test/java/io/openbas/rest/PayloadApiSearchTest.java @@ -1,20 +1,5 @@ package io.openbas.rest; -import io.openbas.IntegrationTest; -import io.openbas.database.model.Payload; -import io.openbas.database.repository.PayloadRepository; -import io.openbas.utils.fixtures.PaginationFixture; -import io.openbas.utils.mockUser.WithMockAdminUser; -import io.openbas.utils.pagination.SearchPaginationInput; -import io.openbas.utils.pagination.SortField; -import org.junit.jupiter.api.*; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.http.MediaType; -import org.springframework.test.web.servlet.MockMvc; - -import java.util.ArrayList; -import java.util.List; - import static io.openbas.database.model.Endpoint.PLATFORM_ARCH.arm64; import static io.openbas.database.model.Endpoint.PLATFORM_TYPE.Linux; import static io.openbas.database.model.Filters.FilterOperator.contains; @@ -28,14 +13,26 @@ import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.jsonPath; import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status; +import io.openbas.IntegrationTest; +import io.openbas.database.model.Payload; +import io.openbas.database.repository.PayloadRepository; +import io.openbas.utils.fixtures.PaginationFixture; +import io.openbas.utils.mockUser.WithMockAdminUser; +import io.openbas.utils.pagination.SearchPaginationInput; +import io.openbas.utils.pagination.SortField; +import java.util.ArrayList; +import java.util.List; +import org.junit.jupiter.api.*; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.http.MediaType; +import org.springframework.test.web.servlet.MockMvc; + @TestInstance(PER_CLASS) public class PayloadApiSearchTest extends IntegrationTest { - @Autowired - private MockMvc mvc; + @Autowired private MockMvc mvc; - @Autowired - private PayloadRepository payloadRepository; + @Autowired private PayloadRepository payloadRepository; private static final List PAYLOAD_COMMAND_IDS = new ArrayList<>(); @@ -72,11 +69,13 @@ class SearchingPageOfPayloads { @Test @DisplayName("Retrieving first page of payloads by textsearch") void given_working_search_input_should_return_a_page_of_payloads() throws Exception { - SearchPaginationInput searchPaginationInput = PaginationFixture.getDefault().textSearch("command").build(); + SearchPaginationInput searchPaginationInput = + PaginationFixture.getDefault().textSearch("command").build(); - mvc.perform(post(PAYLOAD_URI + "/search") - .contentType(MediaType.APPLICATION_JSON) - .content(asJsonString(searchPaginationInput))) + mvc.perform( + post(PAYLOAD_URI + "/search") + .contentType(MediaType.APPLICATION_JSON) + .content(asJsonString(searchPaginationInput))) .andExpect(status().is2xxSuccessful()) .andExpect(jsonPath("$.numberOfElements").value(1)); } @@ -84,11 +83,13 @@ void given_working_search_input_should_return_a_page_of_payloads() throws Except @Test @DisplayName("Not retrieving first page of payloads by textsearch") void given_not_working_search_input_should_return_a_page_of_payloads() throws Exception { - SearchPaginationInput searchPaginationInput = PaginationFixture.getDefault().textSearch("wrong").build(); + SearchPaginationInput searchPaginationInput = + PaginationFixture.getDefault().textSearch("wrong").build(); - mvc.perform(post(PAYLOAD_URI + "/search") - .contentType(MediaType.APPLICATION_JSON) - .content(asJsonString(searchPaginationInput))) + mvc.perform( + post(PAYLOAD_URI + "/search") + .contentType(MediaType.APPLICATION_JSON) + .content(asJsonString(searchPaginationInput))) .andExpect(status().is2xxSuccessful()) .andExpect(jsonPath("$.numberOfElements").value(0)); } @@ -100,14 +101,17 @@ class SortingPageOfPayloads { @Test @DisplayName("Sorting page of payloads by name") - void given_sorting_input_by_name_should_return_a_page_of_payloads_sort_by_name() throws Exception { - SearchPaginationInput searchPaginationInput = PaginationFixture.getDefault() - .sorts(List.of(SortField.builder().property("payload_name").build())) - .build(); - - mvc.perform(post(PAYLOAD_URI + "/search") - .contentType(MediaType.APPLICATION_JSON) - .content(asJsonString(searchPaginationInput))) + void given_sorting_input_by_name_should_return_a_page_of_payloads_sort_by_name() + throws Exception { + SearchPaginationInput searchPaginationInput = + PaginationFixture.getDefault() + .sorts(List.of(SortField.builder().property("payload_name").build())) + .build(); + + mvc.perform( + post(PAYLOAD_URI + "/search") + .contentType(MediaType.APPLICATION_JSON) + .content(asJsonString(searchPaginationInput))) .andExpect(status().is2xxSuccessful()) .andExpect(jsonPath("$.content.[0].payload_name").value("command payload")) .andExpect(jsonPath("$.content.[1].payload_name").value("dns resolution payload")); @@ -117,13 +121,20 @@ void given_sorting_input_by_name_should_return_a_page_of_payloads_sort_by_name() @DisplayName("Sorting page of payloads by platforms") void given_sorting_input_by_updated_at_should_return_a_page_of_payloads_sort_by_updated_at() throws Exception { - SearchPaginationInput searchPaginationInput = PaginationFixture.getDefault() - .sorts(List.of(SortField.builder().property("payload_updated_at").direction("desc").build())) - .build(); - - mvc.perform(post(PAYLOAD_URI + "/search") - .contentType(MediaType.APPLICATION_JSON) - .content(asJsonString(searchPaginationInput))) + SearchPaginationInput searchPaginationInput = + PaginationFixture.getDefault() + .sorts( + List.of( + SortField.builder() + .property("payload_updated_at") + .direction("desc") + .build())) + .build(); + + mvc.perform( + post(PAYLOAD_URI + "/search") + .contentType(MediaType.APPLICATION_JSON) + .content(asJsonString(searchPaginationInput))) .andExpect(status().is2xxSuccessful()) .andExpect(jsonPath("$.content.[0].payload_name").value("executable payload")) .andExpect(jsonPath("$.content.[1].payload_name").value("dns resolution payload")) @@ -137,62 +148,64 @@ class FilteringPageOfPayloads { @Test @DisplayName("Filtering page of payloads by name") - void given_filter_input_by_name_should_return_a_page_of_payloads_filter_by_name() throws Exception { - SearchPaginationInput searchPaginationInput = PaginationFixture.simpleFilter( - "payload_name", "command", contains - ); - - mvc.perform(post(PAYLOAD_URI + "/search") - .contentType(MediaType.APPLICATION_JSON) - .content(asJsonString(searchPaginationInput))) + void given_filter_input_by_name_should_return_a_page_of_payloads_filter_by_name() + throws Exception { + SearchPaginationInput searchPaginationInput = + PaginationFixture.simpleFilter("payload_name", "command", contains); + + mvc.perform( + post(PAYLOAD_URI + "/search") + .contentType(MediaType.APPLICATION_JSON) + .content(asJsonString(searchPaginationInput))) .andExpect(status().is2xxSuccessful()) .andExpect(jsonPath("$.numberOfElements").value(1)); } @Test @DisplayName("Filtering page of payloads by platforms") - void given_filter_input_by_platforms_should_return_a_page_of_payloads_filter_by_platforms() throws Exception { - SearchPaginationInput searchPaginationInput = PaginationFixture.simpleFilter( - "payload_platforms", valueOf(Linux), contains - ); - - mvc.perform(post(PAYLOAD_URI + "/search") - .contentType(MediaType.APPLICATION_JSON) - .content(asJsonString(searchPaginationInput))) + void given_filter_input_by_platforms_should_return_a_page_of_payloads_filter_by_platforms() + throws Exception { + SearchPaginationInput searchPaginationInput = + PaginationFixture.simpleFilter("payload_platforms", valueOf(Linux), contains); + + mvc.perform( + post(PAYLOAD_URI + "/search") + .contentType(MediaType.APPLICATION_JSON) + .content(asJsonString(searchPaginationInput))) .andExpect(status().is2xxSuccessful()) .andExpect(jsonPath("$.numberOfElements").value(1)); } @Test @DisplayName("Filtering page of payloads by source") - void given_filter_input_by_source_should_return_a_page_of_payloads_filter_by_source() throws Exception { - SearchPaginationInput searchPaginationInput = PaginationFixture.simpleFilter( - "payload_source", valueOf(MANUAL), contains - ); - - mvc.perform(post(PAYLOAD_URI + "/search") - .contentType(MediaType.APPLICATION_JSON) - .content(asJsonString(searchPaginationInput))) + void given_filter_input_by_source_should_return_a_page_of_payloads_filter_by_source() + throws Exception { + SearchPaginationInput searchPaginationInput = + PaginationFixture.simpleFilter("payload_source", valueOf(MANUAL), contains); + + mvc.perform( + post(PAYLOAD_URI + "/search") + .contentType(MediaType.APPLICATION_JSON) + .content(asJsonString(searchPaginationInput))) .andExpect(status().is2xxSuccessful()) .andExpect(jsonPath("$.numberOfElements").value(3)); } @Test @DisplayName("Filtering page of payloads by architecture") - void given_filter_input_by_arch_should_return_a_page_of_executable_payloads_filtered_by_architecture() throws Exception { - SearchPaginationInput searchPaginationInput = PaginationFixture.simpleFilter( - "executable_arch", valueOf(arm64), contains - ); - - mvc.perform(post(PAYLOAD_URI + "/search") - .contentType(MediaType.APPLICATION_JSON) - .content(asJsonString(searchPaginationInput))) + void + given_filter_input_by_arch_should_return_a_page_of_executable_payloads_filtered_by_architecture() + throws Exception { + SearchPaginationInput searchPaginationInput = + PaginationFixture.simpleFilter("executable_arch", valueOf(arm64), contains); + + mvc.perform( + post(PAYLOAD_URI + "/search") + .contentType(MediaType.APPLICATION_JSON) + .content(asJsonString(searchPaginationInput))) .andExpect(status().is2xxSuccessful()) .andExpect(jsonPath("$.numberOfElements").value(1)); } - } - } - } diff --git a/openbas-api/src/test/java/io/openbas/rest/PayloadApiTest.java b/openbas-api/src/test/java/io/openbas/rest/PayloadApiTest.java index 0ea6927e30..a263d3dfa3 100644 --- a/openbas-api/src/test/java/io/openbas/rest/PayloadApiTest.java +++ b/openbas-api/src/test/java/io/openbas/rest/PayloadApiTest.java @@ -1,5 +1,12 @@ package io.openbas.rest; +import static io.openbas.utils.JsonUtils.asJsonString; +import static org.junit.jupiter.api.TestInstance.Lifecycle.PER_CLASS; +import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.post; +import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.put; +import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.jsonPath; +import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status; + import com.jayway.jsonpath.JsonPath; import io.openbas.IntegrationTest; import io.openbas.database.model.Document; @@ -10,89 +17,77 @@ import io.openbas.rest.payload.form.PayloadCreateInput; import io.openbas.rest.payload.form.PayloadUpdateInput; import io.openbas.utils.mockUser.WithMockAdminUser; +import java.util.Collections; +import java.util.List; import org.junit.jupiter.api.*; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.http.MediaType; import org.springframework.test.web.servlet.MockMvc; -import java.util.Collections; -import java.util.List; - -import static io.openbas.utils.JsonUtils.asJsonString; -import static org.junit.jupiter.api.TestInstance.Lifecycle.PER_CLASS; -import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.post; -import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.put; -import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.jsonPath; -import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status; - @TestInstance(PER_CLASS) public class PayloadApiTest extends IntegrationTest { - private static final String PAYLOAD_URI = "/api/payloads"; - private static Document EXECUTABLE_FILE; - - @Autowired - private MockMvc mvc; - @Autowired - private DocumentRepository documentRepository; - @Autowired - private PayloadRepository payloadRepository; - - @BeforeAll - void beforeAll() { - Document executableFile = new Document(); - executableFile.setName("Executable file"); - executableFile.setType("text/x-sh"); - EXECUTABLE_FILE = documentRepository.save(executableFile); - } - - @AfterAll - void afterAll() { - this.documentRepository.deleteAll(List.of(EXECUTABLE_FILE)); - this.payloadRepository.deleteAll(); - } - - @Test - @DisplayName("Create Executable Payload") - @WithMockAdminUser - void createExecutablePayload() throws Exception { - PayloadCreateInput input = getExecutablePayloadCreateInput(); - - mvc.perform(post(PAYLOAD_URI) - .contentType(MediaType.APPLICATION_JSON) - .content(asJsonString(input))) - .andExpect(status().is2xxSuccessful()) - .andExpect(jsonPath("$.payload_name").value("My Executable Payload")) - .andExpect(jsonPath("$.payload_description").value("Executable description")) - .andExpect(jsonPath("$.payload_source").value("MANUAL")) - .andExpect(jsonPath("$.payload_status").value("VERIFIED")) - .andExpect(jsonPath("$.payload_platforms.[0]").value("Linux")) - .andExpect(jsonPath("$.executable_arch").value("x86_64")); - } - - @Test - @DisplayName("Creating an Executable Payload without Arch should fail") - @WithMockAdminUser - void createExecutablePayloadWithoutArch() throws Exception { - PayloadCreateInput input = getExecutablePayloadCreateInput(); - input.setExecutableArch(null); - - mvc.perform(post(PAYLOAD_URI) - .contentType(MediaType.APPLICATION_JSON) - .content(asJsonString(input))) - .andExpect(status().isBadRequest()); - } - - - @Test - @DisplayName("Update Executable Payload") - @WithMockAdminUser - void updateExecutablePayload() throws Exception { - PayloadCreateInput createInput = getExecutablePayloadCreateInput(); - - String response = mvc.perform(post(PAYLOAD_URI) - .contentType(MediaType.APPLICATION_JSON) - .content(asJsonString(createInput))) + private static final String PAYLOAD_URI = "/api/payloads"; + private static Document EXECUTABLE_FILE; + + @Autowired private MockMvc mvc; + @Autowired private DocumentRepository documentRepository; + @Autowired private PayloadRepository payloadRepository; + + @BeforeAll + void beforeAll() { + Document executableFile = new Document(); + executableFile.setName("Executable file"); + executableFile.setType("text/x-sh"); + EXECUTABLE_FILE = documentRepository.save(executableFile); + } + + @AfterAll + void afterAll() { + this.documentRepository.deleteAll(List.of(EXECUTABLE_FILE)); + this.payloadRepository.deleteAll(); + } + + @Test + @DisplayName("Create Executable Payload") + @WithMockAdminUser + void createExecutablePayload() throws Exception { + PayloadCreateInput input = getExecutablePayloadCreateInput(); + + mvc.perform( + post(PAYLOAD_URI).contentType(MediaType.APPLICATION_JSON).content(asJsonString(input))) + .andExpect(status().is2xxSuccessful()) + .andExpect(jsonPath("$.payload_name").value("My Executable Payload")) + .andExpect(jsonPath("$.payload_description").value("Executable description")) + .andExpect(jsonPath("$.payload_source").value("MANUAL")) + .andExpect(jsonPath("$.payload_status").value("VERIFIED")) + .andExpect(jsonPath("$.payload_platforms.[0]").value("Linux")) + .andExpect(jsonPath("$.executable_arch").value("x86_64")); + } + + @Test + @DisplayName("Creating an Executable Payload without Arch should fail") + @WithMockAdminUser + void createExecutablePayloadWithoutArch() throws Exception { + PayloadCreateInput input = getExecutablePayloadCreateInput(); + input.setExecutableArch(null); + + mvc.perform( + post(PAYLOAD_URI).contentType(MediaType.APPLICATION_JSON).content(asJsonString(input))) + .andExpect(status().isBadRequest()); + } + + @Test + @DisplayName("Update Executable Payload") + @WithMockAdminUser + void updateExecutablePayload() throws Exception { + PayloadCreateInput createInput = getExecutablePayloadCreateInput(); + + String response = + mvc.perform( + post(PAYLOAD_URI) + .contentType(MediaType.APPLICATION_JSON) + .content(asJsonString(createInput))) .andExpect(status().is2xxSuccessful()) .andExpect(jsonPath("$.payload_name").value("My Executable Payload")) .andExpect(jsonPath("$.payload_platforms.[0]").value("Linux")) @@ -101,62 +96,66 @@ void updateExecutablePayload() throws Exception { .getResponse() .getContentAsString(); - var payloadId = JsonPath.read(response, "$.payload_id"); + var payloadId = JsonPath.read(response, "$.payload_id"); - PayloadUpdateInput updateInput = new PayloadUpdateInput(); - updateInput.setName("My Updated Executable Payload"); - updateInput.setPlatforms(new Endpoint.PLATFORM_TYPE[]{Endpoint.PLATFORM_TYPE.MacOS}); - updateInput.setExecutableArch(Endpoint.PLATFORM_ARCH.arm64); - updateInput.setExecutableFile(EXECUTABLE_FILE.getId()); + PayloadUpdateInput updateInput = new PayloadUpdateInput(); + updateInput.setName("My Updated Executable Payload"); + updateInput.setPlatforms(new Endpoint.PLATFORM_TYPE[] {Endpoint.PLATFORM_TYPE.MacOS}); + updateInput.setExecutableArch(Endpoint.PLATFORM_ARCH.arm64); + updateInput.setExecutableFile(EXECUTABLE_FILE.getId()); - mvc.perform(put(PAYLOAD_URI + "/" + payloadId) + mvc.perform( + put(PAYLOAD_URI + "/" + payloadId) .contentType(MediaType.APPLICATION_JSON) .content(asJsonString(updateInput))) - .andExpect(status().is2xxSuccessful()) - .andExpect(jsonPath("$.payload_name").value("My Updated Executable Payload")) - .andExpect(jsonPath("$.payload_platforms.[0]").value("MacOS")) - .andExpect(jsonPath("$.executable_arch").value("arm64")); - } - - @Test - @DisplayName("Updating an Executable Payload without arch should fail") - @WithMockAdminUser - void updateExecutablePayloadWithoutArch() throws Exception { - PayloadCreateInput createInput = getExecutablePayloadCreateInput(); - - String response = mvc.perform(post(PAYLOAD_URI) - .contentType(MediaType.APPLICATION_JSON) - .content(asJsonString(createInput))) + .andExpect(status().is2xxSuccessful()) + .andExpect(jsonPath("$.payload_name").value("My Updated Executable Payload")) + .andExpect(jsonPath("$.payload_platforms.[0]").value("MacOS")) + .andExpect(jsonPath("$.executable_arch").value("arm64")); + } + + @Test + @DisplayName("Updating an Executable Payload without arch should fail") + @WithMockAdminUser + void updateExecutablePayloadWithoutArch() throws Exception { + PayloadCreateInput createInput = getExecutablePayloadCreateInput(); + + String response = + mvc.perform( + post(PAYLOAD_URI) + .contentType(MediaType.APPLICATION_JSON) + .content(asJsonString(createInput))) .andExpect(status().is2xxSuccessful()) .andReturn() .getResponse() .getContentAsString(); - var payloadId = JsonPath.read(response, "$.payload_id"); + var payloadId = JsonPath.read(response, "$.payload_id"); - PayloadUpdateInput updateInput = new PayloadUpdateInput(); - updateInput.setName("My Updated Executable Payload"); - updateInput.setPlatforms(new Endpoint.PLATFORM_TYPE[]{Endpoint.PLATFORM_TYPE.MacOS}); - updateInput.setExecutableFile(EXECUTABLE_FILE.getId()); + PayloadUpdateInput updateInput = new PayloadUpdateInput(); + updateInput.setName("My Updated Executable Payload"); + updateInput.setPlatforms(new Endpoint.PLATFORM_TYPE[] {Endpoint.PLATFORM_TYPE.MacOS}); + updateInput.setExecutableFile(EXECUTABLE_FILE.getId()); - mvc.perform(put(PAYLOAD_URI + "/" + payloadId) + mvc.perform( + put(PAYLOAD_URI + "/" + payloadId) .contentType(MediaType.APPLICATION_JSON) .content(asJsonString(updateInput))) - .andExpect(status().isBadRequest()); - } - - private PayloadCreateInput getExecutablePayloadCreateInput() { - PayloadCreateInput input = new PayloadCreateInput(); - input.setType("Executable"); - input.setName("My Executable Payload"); - input.setDescription("Executable description"); - input.setSource(Payload.PAYLOAD_SOURCE.MANUAL); - input.setStatus(Payload.PAYLOAD_STATUS.VERIFIED); - input.setPlatforms(new Endpoint.PLATFORM_TYPE[]{Endpoint.PLATFORM_TYPE.Linux}); - input.setAttackPatternsIds(Collections.emptyList()); - input.setTagIds(Collections.emptyList()); - input.setExecutableFile(EXECUTABLE_FILE.getId()); - input.setExecutableArch(Endpoint.PLATFORM_ARCH.x86_64); - return input; - } + .andExpect(status().isBadRequest()); + } + + private PayloadCreateInput getExecutablePayloadCreateInput() { + PayloadCreateInput input = new PayloadCreateInput(); + input.setType("Executable"); + input.setName("My Executable Payload"); + input.setDescription("Executable description"); + input.setSource(Payload.PAYLOAD_SOURCE.MANUAL); + input.setStatus(Payload.PAYLOAD_STATUS.VERIFIED); + input.setPlatforms(new Endpoint.PLATFORM_TYPE[] {Endpoint.PLATFORM_TYPE.Linux}); + input.setAttackPatternsIds(Collections.emptyList()); + input.setTagIds(Collections.emptyList()); + input.setExecutableFile(EXECUTABLE_FILE.getId()); + input.setExecutableArch(Endpoint.PLATFORM_ARCH.x86_64); + return input; + } } diff --git a/openbas-api/src/test/java/io/openbas/rest/ReportApiTest.java b/openbas-api/src/test/java/io/openbas/rest/ReportApiTest.java index 7cc1044a83..32a9da306c 100644 --- a/openbas-api/src/test/java/io/openbas/rest/ReportApiTest.java +++ b/openbas-api/src/test/java/io/openbas/rest/ReportApiTest.java @@ -1,5 +1,13 @@ package io.openbas.rest; +import static io.openbas.utils.JsonUtils.asJsonString; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertNotNull; +import static org.junit.jupiter.api.TestInstance.Lifecycle.PER_CLASS; +import static org.mockito.ArgumentMatchers.*; +import static org.mockito.Mockito.*; +import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status; + import com.fasterxml.jackson.databind.ObjectMapper; import com.jayway.jsonpath.JsonPath; import io.openbas.database.model.*; @@ -12,6 +20,9 @@ import io.openbas.service.ReportService; import io.openbas.utils.fixtures.PaginationFixture; import io.openbas.utils.mockUser.WithMockPlannerUser; +import java.lang.reflect.Field; +import java.util.List; +import java.util.UUID; import org.junit.jupiter.api.*; import org.mockito.Mock; import org.springframework.beans.factory.annotation.Autowired; @@ -22,189 +33,184 @@ import org.springframework.test.web.servlet.request.MockMvcRequestBuilders; import org.springframework.test.web.servlet.setup.MockMvcBuilders; -import java.lang.reflect.Field; -import java.util.ArrayList; -import java.util.List; -import java.util.UUID; - -import static io.openbas.utils.JsonUtils.asJsonString; -import static org.junit.jupiter.api.Assertions.assertEquals; -import static org.junit.jupiter.api.Assertions.assertNotNull; -import static org.junit.jupiter.api.TestInstance.Lifecycle.PER_CLASS; -import static org.mockito.ArgumentMatchers.*; -import static org.mockito.Mockito.*; -import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status; - @SpringBootTest @AutoConfigureMockMvc @TestMethodOrder(MethodOrderer.OrderAnnotation.class) @TestInstance(PER_CLASS) public class ReportApiTest { - private MockMvc mvc; - - @Mock - private ReportService reportService; - @Mock - private ExerciseService exerciseService; - @Mock - private InjectService injectService; - - @Autowired - private ObjectMapper objectMapper; - - private Exercise exercise; - private Report report; - private ReportInput reportInput; - - @BeforeEach - void before() throws IllegalAccessException, NoSuchFieldException { - ReportApi reportApi = new ReportApi(exerciseService, reportService, injectService); - Field sessionContextField = MapperApi.class.getSuperclass().getDeclaredField("mapper"); - sessionContextField.setAccessible(true); - sessionContextField.set(reportApi, objectMapper); - mvc = MockMvcBuilders.standaloneSetup(reportApi) - .build(); - - exercise = new Exercise(); - exercise.setName("Exercise name"); - exercise.setId("exercise123"); - report = new Report(); - report.setId(UUID.randomUUID().toString()); - reportInput = new ReportInput(); - reportInput.setName("Report name"); + private MockMvc mvc; + + @Mock private ReportService reportService; + @Mock private ExerciseService exerciseService; + @Mock private InjectService injectService; + + @Autowired private ObjectMapper objectMapper; + + private Exercise exercise; + private Report report; + private ReportInput reportInput; + + @BeforeEach + void before() throws IllegalAccessException, NoSuchFieldException { + ReportApi reportApi = new ReportApi(exerciseService, reportService, injectService); + Field sessionContextField = MapperApi.class.getSuperclass().getDeclaredField("mapper"); + sessionContextField.setAccessible(true); + sessionContextField.set(reportApi, objectMapper); + mvc = MockMvcBuilders.standaloneSetup(reportApi).build(); + + exercise = new Exercise(); + exercise.setName("Exercise name"); + exercise.setId("exercise123"); + report = new Report(); + report.setId(UUID.randomUUID().toString()); + reportInput = new ReportInput(); + reportInput.setName("Report name"); + } + + @Nested + @WithMockPlannerUser + @DisplayName("Reports for exercise") + class ReportsForExercise { + @DisplayName("Create report") + @Test + void createReportForExercise() throws Exception { + // -- PREPARE -- + when(exerciseService.exercise(anyString())).thenReturn(exercise); + when(reportService.updateReport(any(Report.class), any(ReportInput.class))) + .thenReturn(report); + + // -- EXECUTE -- + String response = + mvc.perform( + MockMvcRequestBuilders.post("/api/exercises/" + exercise.getId() + "/reports") + .content(asJsonString(reportInput)) + .contentType(MediaType.APPLICATION_JSON) + .accept(MediaType.APPLICATION_JSON)) + .andExpect(status().is2xxSuccessful()) + .andReturn() + .getResponse() + .getContentAsString(); + + // -- ASSERT -- + verify(exerciseService).exercise(exercise.getId()); + assertNotNull(response); + assertEquals(JsonPath.read(response, "$.report_id"), report.getId()); + } + + @DisplayName("Retrieve reports") + @Test + void retrieveReportForExercise() throws Exception { + // PREPARE + List reports = List.of(report); + when(reportService.reportsFromExercise(anyString())).thenReturn(reports); + + // -- EXECUTE -- + String response = + mvc.perform( + MockMvcRequestBuilders.get("/api/exercises/fakeExercisesId123/reports") + .contentType(MediaType.APPLICATION_JSON)) + .andExpect(status().is2xxSuccessful()) + .andReturn() + .getResponse() + .getContentAsString(); + + // -- ASSERT -- + verify(reportService).reportsFromExercise("fakeExercisesId123"); + assertNotNull(response); + assertEquals(JsonPath.read(response, "$[0].report_id"), report.getId()); + } + + @DisplayName("Update Report") + @Test + void updateReportForExercise() throws Exception { + // -- PREPARE -- + report.setExercise(exercise); + when(reportService.report(any())).thenReturn(report); + when(reportService.updateReport(any(Report.class), any(ReportInput.class))) + .thenReturn(report); + + // -- EXECUTE -- + String response = + mvc.perform( + MockMvcRequestBuilders.put( + "/api/exercises/" + exercise.getId() + "/reports/" + report.getId()) + .content(asJsonString(reportInput)) + .contentType(MediaType.APPLICATION_JSON) + .accept(MediaType.APPLICATION_JSON)) + .andExpect(status().is2xxSuccessful()) + .andReturn() + .getResponse() + .getContentAsString(); + + // -- ASSERT -- + report.setName("fake"); + verify(reportService).report(UUID.fromString(report.getId())); + verify(reportService).updateReport(report, reportInput); + assertNotNull(response); + assertEquals(JsonPath.read(response, "$.report_id"), report.getId()); + } + + @DisplayName("Update report inject comment") + @Test + void updateReportInjectCommentTest() throws Exception { + // -- PREPARE -- + Inject inject = new Inject(); + inject.setTitle("Test inject"); + inject.setId(UUID.randomUUID().toString()); + inject.setExercise(exercise); + report.setExercise(exercise); + ReportInjectCommentInput injectCommentInput = new ReportInjectCommentInput(); + injectCommentInput.setInjectId(inject.getId()); + injectCommentInput.setComment("Comment test"); + + when(reportService.report(any())).thenReturn(report); + when(injectService.inject(any())).thenReturn(inject); + when(reportService.updateReportInjectComment( + any(Report.class), any(Inject.class), any(ReportInjectCommentInput.class))) + .thenReturn(null); + + // -- EXECUTE -- + String response = + mvc.perform( + MockMvcRequestBuilders.put( + "/api/exercises/" + + exercise.getId() + + "/reports/" + + report.getId() + + "/inject-comments") + .content(asJsonString(injectCommentInput)) + .contentType(MediaType.APPLICATION_JSON) + .accept(MediaType.APPLICATION_JSON)) + .andExpect(status().is2xxSuccessful()) + .andReturn() + .getResponse() + .getContentAsString(); + + // -- ASSERT -- + verify(reportService).report(UUID.fromString(report.getId())); + verify(injectService).inject(inject.getId()); + verify(reportService).updateReportInjectComment(report, inject, injectCommentInput); + assertNotNull(response); } - @Nested - @WithMockPlannerUser - @DisplayName("Reports for exercise") - class ReportsForExercise { - @DisplayName("Create report") - @Test - void createReportForExercise() throws Exception { - // -- PREPARE -- - when(exerciseService.exercise(anyString())).thenReturn(exercise); - when(reportService.updateReport(any(Report.class), any(ReportInput.class))) - .thenReturn(report); - - // -- EXECUTE -- - String response = mvc - .perform(MockMvcRequestBuilders.post("/api/exercises/"+exercise.getId()+"/reports") - .content(asJsonString(reportInput)) - .contentType(MediaType.APPLICATION_JSON) - .accept(MediaType.APPLICATION_JSON)) - .andExpect(status().is2xxSuccessful()) - .andReturn() - .getResponse() - .getContentAsString(); - - // -- ASSERT -- - verify(exerciseService).exercise(exercise.getId()); - assertNotNull(response); - assertEquals(JsonPath.read(response, "$.report_id"), report.getId()); - } - - @DisplayName("Retrieve reports") - @Test - void retrieveReportForExercise() throws Exception { - // PREPARE - List reports = List.of(report); - when(reportService.reportsFromExercise(anyString())).thenReturn(reports); - - // -- EXECUTE -- - String response = mvc - .perform(MockMvcRequestBuilders.get( "/api/exercises/fakeExercisesId123/reports") - .contentType(MediaType.APPLICATION_JSON)) - .andExpect(status().is2xxSuccessful()) - .andReturn() - .getResponse() - .getContentAsString(); - - // -- ASSERT -- - verify(reportService).reportsFromExercise("fakeExercisesId123"); - assertNotNull(response); - assertEquals(JsonPath.read(response, "$[0].report_id"), report.getId()); - } - - @DisplayName("Update Report") - @Test - void updateReportForExercise() throws Exception { - // -- PREPARE -- - report.setExercise(exercise); - when(reportService.report(any())).thenReturn(report); - when(reportService.updateReport(any(Report.class), any(ReportInput.class))) - .thenReturn(report); - - // -- EXECUTE -- - String response = mvc - .perform(MockMvcRequestBuilders.put("/api/exercises/"+ exercise.getId() +"/reports/"+ report.getId()) - .content(asJsonString(reportInput)) - .contentType(MediaType.APPLICATION_JSON) - .accept(MediaType.APPLICATION_JSON)) - .andExpect(status().is2xxSuccessful()) - .andReturn() - .getResponse() - .getContentAsString(); - - // -- ASSERT -- - report.setName("fake"); - verify(reportService).report(UUID.fromString(report.getId())); - verify(reportService).updateReport(report, reportInput); - assertNotNull(response); - assertEquals(JsonPath.read(response, "$.report_id"), report.getId()); - } - - @DisplayName("Update report inject comment") - @Test - void updateReportInjectCommentTest() throws Exception { - // -- PREPARE -- - Inject inject = new Inject(); - inject.setTitle("Test inject"); - inject.setId(UUID.randomUUID().toString()); - inject.setExercise(exercise); - report.setExercise(exercise); - ReportInjectCommentInput injectCommentInput = new ReportInjectCommentInput(); - injectCommentInput.setInjectId(inject.getId()); - injectCommentInput.setComment("Comment test"); - - when(reportService.report(any())).thenReturn(report); - when(injectService.inject(any())).thenReturn(inject); - when(reportService.updateReportInjectComment(any(Report.class), any(Inject.class), any(ReportInjectCommentInput.class))) - .thenReturn(null); - - // -- EXECUTE -- - String response = mvc - .perform(MockMvcRequestBuilders.put("/api/exercises/"+ exercise.getId() +"/reports/"+ report.getId()+"/inject-comments") - .content(asJsonString(injectCommentInput)) - .contentType(MediaType.APPLICATION_JSON) - .accept(MediaType.APPLICATION_JSON)) - .andExpect(status().is2xxSuccessful()) - .andReturn() - .getResponse() - .getContentAsString(); - - // -- ASSERT -- - verify(reportService).report(UUID.fromString(report.getId())); - verify(injectService).inject(inject.getId()); - verify(reportService).updateReportInjectComment(report, inject, injectCommentInput); - assertNotNull(response); - } - - @DisplayName("Delete Report") - @Test - void deleteReportForExercise() throws Exception { - // -- PREPARE -- - report.setExercise(exercise); - when(reportService.report(any())).thenReturn(report); - - // -- EXECUTE -- - mvc.perform(MockMvcRequestBuilders.delete("/api/exercises/" + exercise.getId() +"/reports/"+ report.getId()) - .contentType(MediaType.APPLICATION_JSON) - .content(asJsonString(PaginationFixture.getDefault().textSearch("").build()))) - .andExpect(status().is2xxSuccessful()); - - // -- ASSERT -- - verify(reportService, times(1)).deleteReport(UUID.fromString(report.getId())); - } + @DisplayName("Delete Report") + @Test + void deleteReportForExercise() throws Exception { + // -- PREPARE -- + report.setExercise(exercise); + when(reportService.report(any())).thenReturn(report); + + // -- EXECUTE -- + mvc.perform( + MockMvcRequestBuilders.delete( + "/api/exercises/" + exercise.getId() + "/reports/" + report.getId()) + .contentType(MediaType.APPLICATION_JSON) + .content(asJsonString(PaginationFixture.getDefault().textSearch("").build()))) + .andExpect(status().is2xxSuccessful()); + + // -- ASSERT -- + verify(reportService, times(1)).deleteReport(UUID.fromString(report.getId())); } + } } diff --git a/openbas-api/src/test/java/io/openbas/rest/ScenarioInjectApiSearchTest.java b/openbas-api/src/test/java/io/openbas/rest/ScenarioInjectApiSearchTest.java index b9ff610782..a38cafd078 100644 --- a/openbas-api/src/test/java/io/openbas/rest/ScenarioInjectApiSearchTest.java +++ b/openbas-api/src/test/java/io/openbas/rest/ScenarioInjectApiSearchTest.java @@ -1,5 +1,16 @@ package io.openbas.rest; +import static io.openbas.database.model.Filters.FilterOperator.contains; +import static io.openbas.injectors.email.EmailContract.EMAIL_DEFAULT; +import static io.openbas.rest.scenario.ScenarioApi.SCENARIO_URI; +import static io.openbas.utils.JsonUtils.asJsonString; +import static io.openbas.utils.fixtures.InjectFixture.getInjectForEmailContract; +import static io.openbas.utils.fixtures.ScenarioFixture.createDefaultCrisisScenario; +import static org.junit.jupiter.api.TestInstance.Lifecycle.PER_CLASS; +import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.post; +import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.jsonPath; +import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status; + import io.openbas.IntegrationTest; import io.openbas.database.model.Inject; import io.openbas.database.model.InjectorContract; @@ -11,37 +22,21 @@ import io.openbas.utils.mockUser.WithMockAdminUser; import io.openbas.utils.pagination.SearchPaginationInput; import io.openbas.utils.pagination.SortField; +import java.util.ArrayList; +import java.util.List; import org.junit.jupiter.api.*; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.http.MediaType; import org.springframework.test.web.servlet.MockMvc; -import java.util.ArrayList; -import java.util.List; - -import static io.openbas.database.model.Filters.FilterOperator.contains; -import static io.openbas.injectors.email.EmailContract.EMAIL_DEFAULT; -import static io.openbas.rest.scenario.ScenarioApi.SCENARIO_URI; -import static io.openbas.utils.JsonUtils.asJsonString; -import static io.openbas.utils.fixtures.InjectFixture.getInjectForEmailContract; -import static io.openbas.utils.fixtures.ScenarioFixture.createDefaultCrisisScenario; -import static org.junit.jupiter.api.TestInstance.Lifecycle.PER_CLASS; -import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.post; -import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.jsonPath; -import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status; - @TestInstance(PER_CLASS) public class ScenarioInjectApiSearchTest extends IntegrationTest { - @Autowired - private MockMvc mvc; + @Autowired private MockMvc mvc; - @Autowired - private InjectRepository injectRepository; - @Autowired - private InjectorContractRepository injectorContractRepository; - @Autowired - private ScenarioRepository scenarioRepository; + @Autowired private InjectRepository injectRepository; + @Autowired private InjectorContractRepository injectorContractRepository; + @Autowired private ScenarioRepository scenarioRepository; private static final List INJECT_IDS = new ArrayList<>(); private static String SCENARIO_ID; @@ -49,7 +44,8 @@ public class ScenarioInjectApiSearchTest extends IntegrationTest { @BeforeAll void beforeAll() { - InjectorContract injectorContract = this.injectorContractRepository.findById(EMAIL_DEFAULT).orElseThrow(); + InjectorContract injectorContract = + this.injectorContractRepository.findById(EMAIL_DEFAULT).orElseThrow(); EMAIL_INJECTOR_CONTRACT_ID = injectorContract.getInjector().getId(); Scenario scenario = createDefaultCrisisScenario(); @@ -89,11 +85,13 @@ class SearchingPageOfInjects { @Test @DisplayName("Retrieving first page of injects by textsearch") void given_working_search_input_should_return_a_page_of_injects() throws Exception { - SearchPaginationInput searchPaginationInput = PaginationFixture.getDefault().textSearch("default").build(); + SearchPaginationInput searchPaginationInput = + PaginationFixture.getDefault().textSearch("default").build(); - mvc.perform(post(SCENARIO_URI + "/" + SCENARIO_ID + "/injects/simple") - .contentType(MediaType.APPLICATION_JSON) - .content(asJsonString(searchPaginationInput))) + mvc.perform( + post(SCENARIO_URI + "/" + SCENARIO_ID + "/injects/simple") + .contentType(MediaType.APPLICATION_JSON) + .content(asJsonString(searchPaginationInput))) .andExpect(status().is2xxSuccessful()) .andExpect(jsonPath("$.numberOfElements").value(1)); } @@ -101,11 +99,13 @@ void given_working_search_input_should_return_a_page_of_injects() throws Excepti @Test @DisplayName("Not retrieving first page of injects by textsearch") void given_not_working_search_input_should_return_a_page_of_injects() throws Exception { - SearchPaginationInput searchPaginationInput = PaginationFixture.getDefault().textSearch("wrong").build(); + SearchPaginationInput searchPaginationInput = + PaginationFixture.getDefault().textSearch("wrong").build(); - mvc.perform(post(SCENARIO_URI + "/" + SCENARIO_ID + "/injects/simple") - .contentType(MediaType.APPLICATION_JSON) - .content(asJsonString(searchPaginationInput))) + mvc.perform( + post(SCENARIO_URI + "/" + SCENARIO_ID + "/injects/simple") + .contentType(MediaType.APPLICATION_JSON) + .content(asJsonString(searchPaginationInput))) .andExpect(status().is2xxSuccessful()) .andExpect(jsonPath("$.numberOfElements").value(0)); } @@ -117,14 +117,17 @@ class SortingPageOfInjects { @Test @DisplayName("Sorting page of injects by name") - void given_sorting_input_by_name_should_return_a_page_of_injects_sort_by_name() throws Exception { - SearchPaginationInput searchPaginationInput = PaginationFixture.getDefault() - .sorts(List.of(SortField.builder().property("inject_title").build())) - .build(); - - mvc.perform(post(SCENARIO_URI + "/" + SCENARIO_ID + "/injects/simple") - .contentType(MediaType.APPLICATION_JSON) - .content(asJsonString(searchPaginationInput))) + void given_sorting_input_by_name_should_return_a_page_of_injects_sort_by_name() + throws Exception { + SearchPaginationInput searchPaginationInput = + PaginationFixture.getDefault() + .sorts(List.of(SortField.builder().property("inject_title").build())) + .build(); + + mvc.perform( + post(SCENARIO_URI + "/" + SCENARIO_ID + "/injects/simple") + .contentType(MediaType.APPLICATION_JSON) + .content(asJsonString(searchPaginationInput))) .andExpect(status().is2xxSuccessful()) .andExpect(jsonPath("$.content.[0].inject_title").value("Inject default email")) .andExpect(jsonPath("$.content.[1].inject_title").value("Inject global email")); @@ -134,13 +137,20 @@ void given_sorting_input_by_name_should_return_a_page_of_injects_sort_by_name() @DisplayName("Sorting page of injects by updated at") void given_sorting_input_by_updated_at_should_return_a_page_of_injects_sort_by_updated_at() throws Exception { - SearchPaginationInput searchPaginationInput = PaginationFixture.getDefault() - .sorts(List.of(SortField.builder().property("inject_depends_duration").direction("asc").build())) - .build(); - - mvc.perform(post(SCENARIO_URI + "/" + SCENARIO_ID + "/injects/simple") - .contentType(MediaType.APPLICATION_JSON) - .content(asJsonString(searchPaginationInput))) + SearchPaginationInput searchPaginationInput = + PaginationFixture.getDefault() + .sorts( + List.of( + SortField.builder() + .property("inject_depends_duration") + .direction("asc") + .build())) + .build(); + + mvc.perform( + post(SCENARIO_URI + "/" + SCENARIO_ID + "/injects/simple") + .contentType(MediaType.APPLICATION_JSON) + .content(asJsonString(searchPaginationInput))) .andExpect(status().is2xxSuccessful()) .andExpect(jsonPath("$.content.[0].inject_title").value("Inject global email")) .andExpect(jsonPath("$.content.[1].inject_title").value("Inject default email")); @@ -153,33 +163,35 @@ class FilteringPageOfInjects { @Test @DisplayName("Filtering page of injects by name") - void given_filter_input_by_name_should_return_a_page_of_injects_filter_by_name() throws Exception { - SearchPaginationInput searchPaginationInput = PaginationFixture.simpleFilter( - "inject_title", "email", contains - ); - - mvc.perform(post(SCENARIO_URI + "/" + SCENARIO_ID + "/injects/simple") - .contentType(MediaType.APPLICATION_JSON) - .content(asJsonString(searchPaginationInput))) + void given_filter_input_by_name_should_return_a_page_of_injects_filter_by_name() + throws Exception { + SearchPaginationInput searchPaginationInput = + PaginationFixture.simpleFilter("inject_title", "email", contains); + + mvc.perform( + post(SCENARIO_URI + "/" + SCENARIO_ID + "/injects/simple") + .contentType(MediaType.APPLICATION_JSON) + .content(asJsonString(searchPaginationInput))) .andExpect(status().is2xxSuccessful()) .andExpect(jsonPath("$.numberOfElements").value(2)); } @Test @DisplayName("Filtering page of injects by injector contract") - void given_filter_input_by_injector_contract_should_return_a_page_of_injects_filter_by_injector_contract() throws Exception { - SearchPaginationInput searchPaginationInput = PaginationFixture.simpleFilter( - "inject_injector_contract", EMAIL_INJECTOR_CONTRACT_ID, contains - ); - - mvc.perform(post(SCENARIO_URI + "/" + SCENARIO_ID + "/injects/simple") - .contentType(MediaType.APPLICATION_JSON) - .content(asJsonString(searchPaginationInput))) + void + given_filter_input_by_injector_contract_should_return_a_page_of_injects_filter_by_injector_contract() + throws Exception { + SearchPaginationInput searchPaginationInput = + PaginationFixture.simpleFilter( + "inject_injector_contract", EMAIL_INJECTOR_CONTRACT_ID, contains); + + mvc.perform( + post(SCENARIO_URI + "/" + SCENARIO_ID + "/injects/simple") + .contentType(MediaType.APPLICATION_JSON) + .content(asJsonString(searchPaginationInput))) .andExpect(status().is2xxSuccessful()) .andExpect(jsonPath("$.numberOfElements").value(2)); } } - } - } diff --git a/openbas-api/src/test/java/io/openbas/rest/TeamApiTest.java b/openbas-api/src/test/java/io/openbas/rest/TeamApiTest.java index 311f3f1024..c20d526ef4 100644 --- a/openbas-api/src/test/java/io/openbas/rest/TeamApiTest.java +++ b/openbas-api/src/test/java/io/openbas/rest/TeamApiTest.java @@ -1,5 +1,14 @@ package io.openbas.rest; +import static io.openbas.rest.scenario.ScenarioApi.SCENARIO_URI; +import static io.openbas.utils.JsonUtils.asJsonString; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertNotNull; +import static org.junit.jupiter.api.TestInstance.Lifecycle.PER_CLASS; +import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get; +import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.put; +import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status; + import com.jayway.jsonpath.JsonPath; import io.openbas.database.model.Scenario; import io.openbas.database.model.Team; @@ -9,9 +18,11 @@ import io.openbas.database.repository.UserRepository; import io.openbas.rest.exercise.form.ScenarioTeamPlayersEnableInput; import io.openbas.rest.scenario.form.ScenarioUpdateTeamsInput; +import io.openbas.service.ScenarioService; import io.openbas.utils.mockUser.WithMockObserverUser; import io.openbas.utils.mockUser.WithMockPlannerUser; -import io.openbas.service.ScenarioService; +import java.util.ArrayList; +import java.util.List; import org.junit.jupiter.api.*; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.boot.test.autoconfigure.web.servlet.AutoConfigureMockMvc; @@ -19,35 +30,18 @@ import org.springframework.http.MediaType; import org.springframework.test.web.servlet.MockMvc; -import java.util.ArrayList; -import java.util.List; - -import static io.openbas.rest.scenario.ScenarioApi.SCENARIO_URI; -import static io.openbas.utils.JsonUtils.asJsonString; -import static org.junit.jupiter.api.Assertions.assertEquals; -import static org.junit.jupiter.api.Assertions.assertNotNull; -import static org.junit.jupiter.api.TestInstance.Lifecycle.PER_CLASS; -import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get; -import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.put; -import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status; - @SpringBootTest @AutoConfigureMockMvc @TestMethodOrder(MethodOrderer.OrderAnnotation.class) @TestInstance(PER_CLASS) public class TeamApiTest { - @Autowired - private MockMvc mvc; + @Autowired private MockMvc mvc; - @Autowired - private ScenarioService scenarioService; - @Autowired - private ScenarioRepository scenarioRepository; - @Autowired - private TeamRepository teamRepository; - @Autowired - private UserRepository userRepository; + @Autowired private ScenarioService scenarioService; + @Autowired private ScenarioRepository scenarioRepository; + @Autowired private TeamRepository teamRepository; + @Autowired private UserRepository userRepository; static String SCENARIO_ID; static String TEAM_ID; @@ -82,25 +76,27 @@ void addTeamOnScenarioTest() throws Exception { input.setTeamIds(List.of(TEAM_ID)); // -- EXECUTE -- - String response = this.mvc - .perform(put(SCENARIO_URI + "/" + SCENARIO_ID + "/teams/add") - .content(asJsonString(input)) - .contentType(MediaType.APPLICATION_JSON) - .accept(MediaType.APPLICATION_JSON)) - .andExpect(status().is2xxSuccessful()) - .andReturn() - .getResponse() - .getContentAsString(); + String response = + this.mvc + .perform( + put(SCENARIO_URI + "/" + SCENARIO_ID + "/teams/add") + .content(asJsonString(input)) + .contentType(MediaType.APPLICATION_JSON) + .accept(MediaType.APPLICATION_JSON)) + .andExpect(status().is2xxSuccessful()) + .andReturn() + .getResponse() + .getContentAsString(); // -- ASSERT -- assertNotNull(response); - response = this.mvc - .perform(get(SCENARIO_URI + "/" + SCENARIO_ID) - .accept(MediaType.APPLICATION_JSON)) - .andExpect(status().is2xxSuccessful()) - .andReturn() - .getResponse() - .getContentAsString(); + response = + this.mvc + .perform(get(SCENARIO_URI + "/" + SCENARIO_ID).accept(MediaType.APPLICATION_JSON)) + .andExpect(status().is2xxSuccessful()) + .andReturn() + .getResponse() + .getContentAsString(); assertEquals(TEAM_ID, JsonPath.read(response, "$.scenario_teams[0]")); } @@ -110,13 +106,14 @@ void addTeamOnScenarioTest() throws Exception { @WithMockObserverUser void retrieveTeamsOnScenarioTest() throws Exception { // -- EXECUTE -- - String response = this.mvc - .perform(get(SCENARIO_URI + "/" + SCENARIO_ID + "/teams") - .accept(MediaType.APPLICATION_JSON)) - .andExpect(status().is2xxSuccessful()) - .andReturn() - .getResponse() - .getContentAsString(); + String response = + this.mvc + .perform( + get(SCENARIO_URI + "/" + SCENARIO_ID + "/teams").accept(MediaType.APPLICATION_JSON)) + .andExpect(status().is2xxSuccessful()) + .andReturn() + .getResponse() + .getContentAsString(); // -- ASSERT -- assertNotNull(response); @@ -137,25 +134,27 @@ void addPlayerOnTeamOnScenarioTest() throws Exception { input.setPlayersIds(List.of(USER_ID)); // -- EXECUTE -- - String response = this.mvc - .perform(put(SCENARIO_URI + "/" + SCENARIO_ID + "/teams/" + TEAM_ID + "/players/add") - .content(asJsonString(input)) - .contentType(MediaType.APPLICATION_JSON) - .accept(MediaType.APPLICATION_JSON)) - .andExpect(status().is2xxSuccessful()) - .andReturn() - .getResponse() - .getContentAsString(); + String response = + this.mvc + .perform( + put(SCENARIO_URI + "/" + SCENARIO_ID + "/teams/" + TEAM_ID + "/players/add") + .content(asJsonString(input)) + .contentType(MediaType.APPLICATION_JSON) + .accept(MediaType.APPLICATION_JSON)) + .andExpect(status().is2xxSuccessful()) + .andReturn() + .getResponse() + .getContentAsString(); // -- ASSERT -- assertNotNull(response); - response = this.mvc - .perform(get(SCENARIO_URI + "/" + SCENARIO_ID) - .accept(MediaType.APPLICATION_JSON)) - .andExpect(status().is2xxSuccessful()) - .andReturn() - .getResponse() - .getContentAsString(); + response = + this.mvc + .perform(get(SCENARIO_URI + "/" + SCENARIO_ID).accept(MediaType.APPLICATION_JSON)) + .andExpect(status().is2xxSuccessful()) + .andReturn() + .getResponse() + .getContentAsString(); assertEquals(USER_ID, JsonPath.read(response, "$.scenario_teams_users[0].user_id")); } @@ -169,25 +168,27 @@ void removePlayerOnTeamOnScenarioTest() throws Exception { input.setPlayersIds(List.of(USER_ID)); // -- EXECUTE -- - String response = this.mvc - .perform(put(SCENARIO_URI + "/" + SCENARIO_ID + "/teams/" + TEAM_ID + "/players/remove") - .content(asJsonString(input)) - .contentType(MediaType.APPLICATION_JSON) - .accept(MediaType.APPLICATION_JSON)) - .andExpect(status().is2xxSuccessful()) - .andReturn() - .getResponse() - .getContentAsString(); + String response = + this.mvc + .perform( + put(SCENARIO_URI + "/" + SCENARIO_ID + "/teams/" + TEAM_ID + "/players/remove") + .content(asJsonString(input)) + .contentType(MediaType.APPLICATION_JSON) + .accept(MediaType.APPLICATION_JSON)) + .andExpect(status().is2xxSuccessful()) + .andReturn() + .getResponse() + .getContentAsString(); // -- ASSERT -- assertNotNull(response); - response = this.mvc - .perform(get(SCENARIO_URI + "/" + SCENARIO_ID) - .accept(MediaType.APPLICATION_JSON)) - .andExpect(status().is2xxSuccessful()) - .andReturn() - .getResponse() - .getContentAsString(); + response = + this.mvc + .perform(get(SCENARIO_URI + "/" + SCENARIO_ID).accept(MediaType.APPLICATION_JSON)) + .andExpect(status().is2xxSuccessful()) + .andReturn() + .getResponse() + .getContentAsString(); assertEquals(new ArrayList<>(), JsonPath.read(response, "$.scenario_teams_users")); } @@ -198,30 +199,35 @@ void removePlayerOnTeamOnScenarioTest() throws Exception { void removeTeamOnScenarioTest() throws Exception { // -- PREPARE -- ScenarioUpdateTeamsInput input = new ScenarioUpdateTeamsInput(); - input.setTeamIds(new ArrayList<>() {{ - add(TEAM_ID); - }}); + input.setTeamIds( + new ArrayList<>() { + { + add(TEAM_ID); + } + }); // -- EXECUTE -- - String response = this.mvc - .perform(put(SCENARIO_URI + "/" + SCENARIO_ID + "/teams/remove") - .content(asJsonString(input)) - .contentType(MediaType.APPLICATION_JSON) - .accept(MediaType.APPLICATION_JSON)) - .andExpect(status().is2xxSuccessful()) - .andReturn() - .getResponse() - .getContentAsString(); + String response = + this.mvc + .perform( + put(SCENARIO_URI + "/" + SCENARIO_ID + "/teams/remove") + .content(asJsonString(input)) + .contentType(MediaType.APPLICATION_JSON) + .accept(MediaType.APPLICATION_JSON)) + .andExpect(status().is2xxSuccessful()) + .andReturn() + .getResponse() + .getContentAsString(); // -- ASSERT -- assertNotNull(response); - response = this.mvc - .perform(get(SCENARIO_URI + "/" + SCENARIO_ID) - .accept(MediaType.APPLICATION_JSON)) - .andExpect(status().is2xxSuccessful()) - .andReturn() - .getResponse() - .getContentAsString(); + response = + this.mvc + .perform(get(SCENARIO_URI + "/" + SCENARIO_ID).accept(MediaType.APPLICATION_JSON)) + .andExpect(status().is2xxSuccessful()) + .andReturn() + .getResponse() + .getContentAsString(); assertEquals(new ArrayList<>(), JsonPath.read(response, "$.scenario_teams")); } } diff --git a/openbas-api/src/test/java/io/openbas/rest/UserApiTest.java b/openbas-api/src/test/java/io/openbas/rest/UserApiTest.java index 43f47db5d3..ca72797b60 100644 --- a/openbas-api/src/test/java/io/openbas/rest/UserApiTest.java +++ b/openbas-api/src/test/java/io/openbas/rest/UserApiTest.java @@ -1,5 +1,12 @@ package io.openbas.rest; +import static io.openbas.utils.JsonUtils.asJsonString; +import static io.openbas.utils.fixtures.UserFixture.EMAIL; +import static org.junit.jupiter.api.TestInstance.Lifecycle.PER_CLASS; +import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.post; +import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.jsonPath; +import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status; + import io.openbas.IntegrationTest; import io.openbas.database.model.User; import io.openbas.database.repository.UserRepository; @@ -12,132 +19,128 @@ import org.springframework.security.test.context.support.WithMockUser; import org.springframework.test.web.servlet.MockMvc; -import static io.openbas.utils.JsonUtils.asJsonString; -import static io.openbas.utils.fixtures.UserFixture.EMAIL; -import static org.junit.jupiter.api.TestInstance.Lifecycle.PER_CLASS; -import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.post; -import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.jsonPath; -import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status; - @TestInstance(PER_CLASS) class UserApiTest extends IntegrationTest { - private User savedUser; - - @Autowired - private MockMvc mvc; - - @Autowired - private UserRepository userRepository; - - @BeforeAll - public void setup() { - // Create user - User user = new User(); - user.setEmail(EMAIL); - user.setPassword(UserFixture.ENCODED_PASSWORD); - if (this.userRepository.findByEmailIgnoreCase(EMAIL).isEmpty()) { - savedUser = this.userRepository.save(user); - } else { - savedUser = this.userRepository.findByEmailIgnoreCase(EMAIL).get(); - } - } + private User savedUser; + @Autowired private MockMvc mvc; - @AfterAll - public void teardown() { - this.userRepository.deleteById(savedUser.getId()); - } + @Autowired private UserRepository userRepository; - @Nested - @DisplayName("Logging in") - class LoggingIn { - @Nested - @DisplayName("Logging in by email") - class LoggingInByEmail { - @DisplayName("Retrieve user by email in lowercase succeed") - @Test - @WithMockUser - void given_known_login_user_input_should_return_user() throws Exception { - LoginUserInput loginUserInput = UserFixture.getLoginUserInput(); - - mvc.perform(post("/api/login") - .contentType(MediaType.APPLICATION_JSON) - .content(asJsonString(loginUserInput))) - .andExpect(status().is2xxSuccessful()) - .andExpect(jsonPath("user_email").value(EMAIL)); - - } - - @DisplayName("Retrieve user by email failed") - @Test - @WithMockUser - void given_unknown_login_user_input_should_throw_AccessDeniedException() throws Exception { - LoginUserInput loginUserInput = UserFixture.getDefault().login("unknown@filigran.io").password("dontcare").build(); - - mvc.perform(post("/api/login") - .contentType(MediaType.APPLICATION_JSON) - .content(asJsonString(loginUserInput))) - .andExpect(status().is4xxClientError()); - - } - - @DisplayName("Retrieve user by email in uppercase succeed") - @Test - @WithMockUser - void given_known_login_user_in_uppercase_input_should_return_user() throws Exception { - LoginUserInput loginUserInput = UserFixture.getDefaultWithPwd().login("USER2@filigran.io").build(); - - mvc.perform(post("/api/login") - .contentType(MediaType.APPLICATION_JSON) - .content(asJsonString(loginUserInput))) - .andExpect(status().is2xxSuccessful()) - .andExpect(jsonPath("user_email").value(EMAIL)); - - } - - @DisplayName("Retrieve user by email in alternatingcase succeed") - @Test - @WithMockUser - void given_known_login_user_in_alternatingcase_input_should_return_user() throws Exception { - LoginUserInput loginUserInput = UserFixture.getDefaultWithPwd().login("uSeR2@filigran.io").build(); - - mvc.perform(post("/api/login") - .contentType(MediaType.APPLICATION_JSON) - .content(asJsonString(loginUserInput))) - .andExpect(status().is2xxSuccessful()) - .andExpect(jsonPath("user_email").value(EMAIL)); - } - } + @BeforeAll + public void setup() { + // Create user + User user = new User(); + user.setEmail(EMAIL); + user.setPassword(UserFixture.ENCODED_PASSWORD); + if (this.userRepository.findByEmailIgnoreCase(EMAIL).isEmpty()) { + savedUser = this.userRepository.save(user); + } else { + savedUser = this.userRepository.findByEmailIgnoreCase(EMAIL).get(); } + } + + @AfterAll + public void teardown() { + this.userRepository.deleteById(savedUser.getId()); + } + @Nested + @DisplayName("Logging in") + class LoggingIn { @Nested - @DisplayName("Create user") - class Creating { - @DisplayName("Create existing user by email in lowercase gives a conflict") - @Test - @WithMockUser(roles = {"ADMIN"}) - void given_known_create_user_in_lowercase_input_should_return_conflict() throws Exception { - CreateUserInput input = new CreateUserInput(); - input.setEmail(EMAIL); - - mvc.perform(post("/api/users") + @DisplayName("Logging in by email") + class LoggingInByEmail { + @DisplayName("Retrieve user by email in lowercase succeed") + @Test + @WithMockUser + void given_known_login_user_input_should_return_user() throws Exception { + LoginUserInput loginUserInput = UserFixture.getLoginUserInput(); + + mvc.perform( + post("/api/login") .contentType(MediaType.APPLICATION_JSON) - .content(asJsonString(input))) - .andExpect(status().isConflict()); - } - - @DisplayName("Create existing user by email in uppercase gives a conflict") - @Test - @WithMockUser(roles = {"ADMIN"}) - void given_known_create_user_in_uppercase_input_should_return_conflict() throws Exception { - CreateUserInput input = new CreateUserInput(); - input.setEmail(EMAIL.toUpperCase()); - - mvc.perform(post("/api/users") + .content(asJsonString(loginUserInput))) + .andExpect(status().is2xxSuccessful()) + .andExpect(jsonPath("user_email").value(EMAIL)); + } + + @DisplayName("Retrieve user by email failed") + @Test + @WithMockUser + void given_unknown_login_user_input_should_throw_AccessDeniedException() throws Exception { + LoginUserInput loginUserInput = + UserFixture.getDefault().login("unknown@filigran.io").password("dontcare").build(); + + mvc.perform( + post("/api/login") .contentType(MediaType.APPLICATION_JSON) - .content(asJsonString(input))) - .andExpect(status().isConflict()); - } + .content(asJsonString(loginUserInput))) + .andExpect(status().is4xxClientError()); + } + + @DisplayName("Retrieve user by email in uppercase succeed") + @Test + @WithMockUser + void given_known_login_user_in_uppercase_input_should_return_user() throws Exception { + LoginUserInput loginUserInput = + UserFixture.getDefaultWithPwd().login("USER2@filigran.io").build(); + + mvc.perform( + post("/api/login") + .contentType(MediaType.APPLICATION_JSON) + .content(asJsonString(loginUserInput))) + .andExpect(status().is2xxSuccessful()) + .andExpect(jsonPath("user_email").value(EMAIL)); + } + + @DisplayName("Retrieve user by email in alternatingcase succeed") + @Test + @WithMockUser + void given_known_login_user_in_alternatingcase_input_should_return_user() throws Exception { + LoginUserInput loginUserInput = + UserFixture.getDefaultWithPwd().login("uSeR2@filigran.io").build(); + + mvc.perform( + post("/api/login") + .contentType(MediaType.APPLICATION_JSON) + .content(asJsonString(loginUserInput))) + .andExpect(status().is2xxSuccessful()) + .andExpect(jsonPath("user_email").value(EMAIL)); + } + } + } + + @Nested + @DisplayName("Create user") + class Creating { + @DisplayName("Create existing user by email in lowercase gives a conflict") + @Test + @WithMockUser(roles = {"ADMIN"}) + void given_known_create_user_in_lowercase_input_should_return_conflict() throws Exception { + CreateUserInput input = new CreateUserInput(); + input.setEmail(EMAIL); + + mvc.perform( + post("/api/users") + .contentType(MediaType.APPLICATION_JSON) + .content(asJsonString(input))) + .andExpect(status().isConflict()); + } + + @DisplayName("Create existing user by email in uppercase gives a conflict") + @Test + @WithMockUser(roles = {"ADMIN"}) + void given_known_create_user_in_uppercase_input_should_return_conflict() throws Exception { + CreateUserInput input = new CreateUserInput(); + input.setEmail(EMAIL.toUpperCase()); + + mvc.perform( + post("/api/users") + .contentType(MediaType.APPLICATION_JSON) + .content(asJsonString(input))) + .andExpect(status().isConflict()); } + } } diff --git a/openbas-api/src/test/java/io/openbas/rest/VariableApiTest.java b/openbas-api/src/test/java/io/openbas/rest/VariableApiTest.java index 32d20c442e..5cc8a49187 100644 --- a/openbas-api/src/test/java/io/openbas/rest/VariableApiTest.java +++ b/openbas-api/src/test/java/io/openbas/rest/VariableApiTest.java @@ -1,13 +1,22 @@ package io.openbas.rest; +import static io.openbas.rest.scenario.ScenarioApi.SCENARIO_URI; +import static io.openbas.utils.JsonUtils.asJsonString; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertNotNull; +import static org.junit.jupiter.api.TestInstance.Lifecycle.PER_CLASS; +import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.*; +import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.jsonPath; +import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status; + import com.jayway.jsonpath.JsonPath; import io.openbas.database.model.Scenario; import io.openbas.database.model.Variable; import io.openbas.database.repository.ScenarioRepository; import io.openbas.database.repository.VariableRepository; +import io.openbas.service.ScenarioService; import io.openbas.utils.mockUser.WithMockObserverUser; import io.openbas.utils.mockUser.WithMockPlannerUser; -import io.openbas.service.ScenarioService; import org.junit.jupiter.api.*; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.boot.test.autoconfigure.web.servlet.AutoConfigureMockMvc; @@ -15,30 +24,17 @@ import org.springframework.http.MediaType; import org.springframework.test.web.servlet.MockMvc; -import static io.openbas.rest.scenario.ScenarioApi.SCENARIO_URI; -import static io.openbas.utils.JsonUtils.asJsonString; -import static org.junit.jupiter.api.Assertions.assertEquals; -import static org.junit.jupiter.api.Assertions.assertNotNull; -import static org.junit.jupiter.api.TestInstance.Lifecycle.PER_CLASS; -import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.*; -import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.jsonPath; -import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status; - @SpringBootTest @AutoConfigureMockMvc @TestMethodOrder(MethodOrderer.OrderAnnotation.class) @TestInstance(PER_CLASS) public class VariableApiTest { - @Autowired - private MockMvc mvc; + @Autowired private MockMvc mvc; - @Autowired - private ScenarioService scenarioService; - @Autowired - private ScenarioRepository scenarioRepository; - @Autowired - private VariableRepository variableRepository; + @Autowired private ScenarioService scenarioService; + @Autowired private ScenarioRepository scenarioRepository; + @Autowired private VariableRepository variableRepository; static String VARIABLE_ID; static String SCENARIO_ID; @@ -65,10 +61,11 @@ void createVariableForScenarioTest() throws Exception { // -- EXECUTE & ASSERT -- this.mvc - .perform(post(SCENARIO_URI + "/" + SCENARIO_ID + "/variables") - .content(asJsonString(variable)) - .contentType(MediaType.APPLICATION_JSON) - .accept(MediaType.APPLICATION_JSON)) + .perform( + post(SCENARIO_URI + "/" + SCENARIO_ID + "/variables") + .content(asJsonString(variable)) + .contentType(MediaType.APPLICATION_JSON) + .accept(MediaType.APPLICATION_JSON)) .andExpect(status().is4xxClientError()); // -- PREPARE -- @@ -77,16 +74,18 @@ void createVariableForScenarioTest() throws Exception { variable.setScenario(scenario); // -- EXECUTE -- - String response = this.mvc - .perform(post(SCENARIO_URI + "/" + SCENARIO_ID + "/variables") - .content(asJsonString(variable)) - .contentType(MediaType.APPLICATION_JSON) - .accept(MediaType.APPLICATION_JSON)) - .andExpect(status().is2xxSuccessful()) - .andExpect(jsonPath("$.variable_key").value(variableKey)) - .andReturn() - .getResponse() - .getContentAsString(); + String response = + this.mvc + .perform( + post(SCENARIO_URI + "/" + SCENARIO_ID + "/variables") + .content(asJsonString(variable)) + .contentType(MediaType.APPLICATION_JSON) + .accept(MediaType.APPLICATION_JSON)) + .andExpect(status().is2xxSuccessful()) + .andExpect(jsonPath("$.variable_key").value(variableKey)) + .andReturn() + .getResponse() + .getContentAsString(); // -- ASSERT -- assertNotNull(response); @@ -99,13 +98,15 @@ void createVariableForScenarioTest() throws Exception { @WithMockObserverUser void retrieveVariableForScenarioTest() throws Exception { // -- EXECUTE -- - String response = this.mvc - .perform(get(SCENARIO_URI + "/" + SCENARIO_ID + "/variables") - .accept(MediaType.APPLICATION_JSON)) - .andExpect(status().is2xxSuccessful()) - .andReturn() - .getResponse() - .getContentAsString(); + String response = + this.mvc + .perform( + get(SCENARIO_URI + "/" + SCENARIO_ID + "/variables") + .accept(MediaType.APPLICATION_JSON)) + .andExpect(status().is2xxSuccessful()) + .andReturn() + .getResponse() + .getContentAsString(); // -- ASSERT -- assertNotNull(response); @@ -117,13 +118,15 @@ void retrieveVariableForScenarioTest() throws Exception { @WithMockPlannerUser void updateVariableForScenarioTest() throws Exception { // -- PREPARE -- - String response = this.mvc - .perform(get(SCENARIO_URI + "/" + SCENARIO_ID + "/variables") - .accept(MediaType.APPLICATION_JSON)) - .andExpect(status().is2xxSuccessful()) - .andReturn() - .getResponse() - .getContentAsString(); + String response = + this.mvc + .perform( + get(SCENARIO_URI + "/" + SCENARIO_ID + "/variables") + .accept(MediaType.APPLICATION_JSON)) + .andExpect(status().is2xxSuccessful()) + .andReturn() + .getResponse() + .getContentAsString(); Variable variable = new Variable(); String variableValue = "variable-value"; @@ -131,15 +134,17 @@ void updateVariableForScenarioTest() throws Exception { variable.setValue("variable-value"); // -- EXECUTE -- - response = this.mvc - .perform(put(SCENARIO_URI + "/" + SCENARIO_ID + "/variables/" + VARIABLE_ID) - .content(asJsonString(variable)) - .contentType(MediaType.APPLICATION_JSON) - .accept(MediaType.APPLICATION_JSON)) - .andExpect(status().is2xxSuccessful()) - .andReturn() - .getResponse() - .getContentAsString(); + response = + this.mvc + .perform( + put(SCENARIO_URI + "/" + SCENARIO_ID + "/variables/" + VARIABLE_ID) + .content(asJsonString(variable)) + .contentType(MediaType.APPLICATION_JSON) + .accept(MediaType.APPLICATION_JSON)) + .andExpect(status().is2xxSuccessful()) + .andReturn() + .getResponse() + .getContentAsString(); // -- ASSERT -- assertNotNull(response); @@ -152,8 +157,8 @@ void updateVariableForScenarioTest() throws Exception { @WithMockPlannerUser void deleteVariableForScenarioTest() throws Exception { // -- EXECUTE 1 ASSERT -- - this.mvc.perform(delete(SCENARIO_URI + "/" + SCENARIO_ID + "/variables/" + VARIABLE_ID)) + this.mvc + .perform(delete(SCENARIO_URI + "/" + SCENARIO_ID + "/variables/" + VARIABLE_ID)) .andExpect(status().is2xxSuccessful()); } - } diff --git a/openbas-api/src/test/java/io/openbas/rest/asset_group/AssetGroupApiSearchTest.java b/openbas-api/src/test/java/io/openbas/rest/asset_group/AssetGroupApiSearchTest.java index c316306816..fabb27cf07 100644 --- a/openbas-api/src/test/java/io/openbas/rest/asset_group/AssetGroupApiSearchTest.java +++ b/openbas-api/src/test/java/io/openbas/rest/asset_group/AssetGroupApiSearchTest.java @@ -1,5 +1,15 @@ package io.openbas.rest.asset_group; +import static io.openbas.database.model.Filters.FilterOperator.contains; +import static io.openbas.database.model.Filters.FilterOperator.not_contains; +import static io.openbas.rest.asset_group.AssetGroupApi.ASSET_GROUP_URI; +import static io.openbas.utils.JsonUtils.asJsonString; +import static java.lang.String.valueOf; +import static org.junit.jupiter.api.TestInstance.Lifecycle.PER_CLASS; +import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.post; +import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.jsonPath; +import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status; + import io.openbas.IntegrationTest; import io.openbas.database.model.AssetGroup; import io.openbas.database.repository.AssetGroupRepository; @@ -8,32 +18,19 @@ import io.openbas.utils.mockUser.WithMockAdminUser; import io.openbas.utils.pagination.SearchPaginationInput; import io.openbas.utils.pagination.SortField; +import java.util.ArrayList; +import java.util.List; import org.junit.jupiter.api.*; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.http.MediaType; import org.springframework.test.web.servlet.MockMvc; -import java.util.ArrayList; -import java.util.List; - -import static io.openbas.database.model.Filters.FilterOperator.contains; -import static io.openbas.database.model.Filters.FilterOperator.not_contains; -import static io.openbas.rest.asset_group.AssetGroupApi.ASSET_GROUP_URI; -import static io.openbas.utils.JsonUtils.asJsonString; -import static java.lang.String.valueOf; -import static org.junit.jupiter.api.TestInstance.Lifecycle.PER_CLASS; -import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.post; -import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.jsonPath; -import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status; - @TestInstance(PER_CLASS) public class AssetGroupApiSearchTest extends IntegrationTest { - @Autowired - private MockMvc mvc; + @Autowired private MockMvc mvc; - @Autowired - private AssetGroupRepository assetGroupRepository; + @Autowired private AssetGroupRepository assetGroupRepository; private static final List ASSET_GROUP_IDS = new ArrayList<>(); @@ -66,11 +63,13 @@ class SearchingPageOfAssetGroups { @Test @DisplayName("Retrieving first page of asset groups by text search") void given_working_search_input_should_return_a_page_of_asset_groups() throws Exception { - SearchPaginationInput searchPaginationInput = PaginationFixture.getDefault().textSearch("Asset Group").build(); + SearchPaginationInput searchPaginationInput = + PaginationFixture.getDefault().textSearch("Asset Group").build(); - mvc.perform(post(ASSET_GROUP_URI + "/search") - .contentType(MediaType.APPLICATION_JSON) - .content(asJsonString(searchPaginationInput))) + mvc.perform( + post(ASSET_GROUP_URI + "/search") + .contentType(MediaType.APPLICATION_JSON) + .content(asJsonString(searchPaginationInput))) .andExpect(status().is2xxSuccessful()) .andExpect(jsonPath("$.numberOfElements").value(2)); } @@ -78,11 +77,13 @@ void given_working_search_input_should_return_a_page_of_asset_groups() throws Ex @Test @DisplayName("Not retrieving first page of asset groups by text search") void given_not_working_search_input_should_return_a_page_of_asset_groups() throws Exception { - SearchPaginationInput searchPaginationInput = PaginationFixture.getDefault().textSearch("wrong").build(); + SearchPaginationInput searchPaginationInput = + PaginationFixture.getDefault().textSearch("wrong").build(); - mvc.perform(post(ASSET_GROUP_URI + "/search") - .contentType(MediaType.APPLICATION_JSON) - .content(asJsonString(searchPaginationInput))) + mvc.perform( + post(ASSET_GROUP_URI + "/search") + .contentType(MediaType.APPLICATION_JSON) + .content(asJsonString(searchPaginationInput))) .andExpect(status().is2xxSuccessful()) .andExpect(jsonPath("$.numberOfElements").value(0)); } @@ -94,14 +95,17 @@ class SortingPageOfAssetGroups { @Test @DisplayName("Sorting page of asset groups by name asc") - void given_sorting_input_by_name_should_return_a_page_of_asset_groups_sort_by_name_asc() throws Exception { - SearchPaginationInput searchPaginationInput = PaginationFixture.getDefault() - .sorts(List.of(SortField.builder().property("asset_group_name").build())) - .build(); - - mvc.perform(post(ASSET_GROUP_URI + "/search") - .contentType(MediaType.APPLICATION_JSON) - .content(asJsonString(searchPaginationInput))) + void given_sorting_input_by_name_should_return_a_page_of_asset_groups_sort_by_name_asc() + throws Exception { + SearchPaginationInput searchPaginationInput = + PaginationFixture.getDefault() + .sorts(List.of(SortField.builder().property("asset_group_name").build())) + .build(); + + mvc.perform( + post(ASSET_GROUP_URI + "/search") + .contentType(MediaType.APPLICATION_JSON) + .content(asJsonString(searchPaginationInput))) .andExpect(status().is2xxSuccessful()) .andExpect(jsonPath("$.content.[0].asset_group_name").value("Asset Group 1")) .andExpect(jsonPath("$.content.[1].asset_group_name").value("Asset Group 2")); @@ -109,14 +113,19 @@ void given_sorting_input_by_name_should_return_a_page_of_asset_groups_sort_by_na @Test @DisplayName("Sorting page of asset groups by name desc") - void given_sorting_input_by_name_should_return_a_page_of_asset_groups_sort_by_name_desc() throws Exception { - SearchPaginationInput searchPaginationInput = PaginationFixture.getDefault() - .sorts(List.of(SortField.builder().property("asset_group_name").direction("desc").build())) - .build(); - - mvc.perform(post(ASSET_GROUP_URI + "/search") - .contentType(MediaType.APPLICATION_JSON) - .content(asJsonString(searchPaginationInput))) + void given_sorting_input_by_name_should_return_a_page_of_asset_groups_sort_by_name_desc() + throws Exception { + SearchPaginationInput searchPaginationInput = + PaginationFixture.getDefault() + .sorts( + List.of( + SortField.builder().property("asset_group_name").direction("desc").build())) + .build(); + + mvc.perform( + post(ASSET_GROUP_URI + "/search") + .contentType(MediaType.APPLICATION_JSON) + .content(asJsonString(searchPaginationInput))) .andExpect(status().is2xxSuccessful()) .andExpect(jsonPath("$.content.[0].asset_group_name").value("Asset Group 2")) .andExpect(jsonPath("$.content.[1].asset_group_name").value("Asset Group 1")); @@ -129,28 +138,31 @@ class FilteringPageOfAssetGroups { @Test @DisplayName("Filtering page of asset groups by name") - void given_filter_input_by_name_should_return_a_page_of_asset_groups_filter_by_name() throws Exception { - SearchPaginationInput searchPaginationInput = PaginationFixture.simpleFilter( - "asset_group_name", "Group", contains - ); - - mvc.perform(post(ASSET_GROUP_URI + "/search") - .contentType(MediaType.APPLICATION_JSON) - .content(asJsonString(searchPaginationInput))) + void given_filter_input_by_name_should_return_a_page_of_asset_groups_filter_by_name() + throws Exception { + SearchPaginationInput searchPaginationInput = + PaginationFixture.simpleFilter("asset_group_name", "Group", contains); + + mvc.perform( + post(ASSET_GROUP_URI + "/search") + .contentType(MediaType.APPLICATION_JSON) + .content(asJsonString(searchPaginationInput))) .andExpect(status().is2xxSuccessful()) .andExpect(jsonPath("$.numberOfElements").value(2)); } @Test @DisplayName("Filtering page of asset groups by description") - void given_filter_input_by_sttaus_should_return_a_page_of_asset_groups_filter_by_description() throws Exception { - SearchPaginationInput searchPaginationInput = PaginationFixture.simpleFilter( - "asset_group_description", valueOf("wrong"), not_contains - ); - - mvc.perform(post(ASSET_GROUP_URI + "/search") - .contentType(MediaType.APPLICATION_JSON) - .content(asJsonString(searchPaginationInput))) + void given_filter_input_by_sttaus_should_return_a_page_of_asset_groups_filter_by_description() + throws Exception { + SearchPaginationInput searchPaginationInput = + PaginationFixture.simpleFilter( + "asset_group_description", valueOf("wrong"), not_contains); + + mvc.perform( + post(ASSET_GROUP_URI + "/search") + .contentType(MediaType.APPLICATION_JSON) + .content(asJsonString(searchPaginationInput))) .andExpect(status().is2xxSuccessful()) .andExpect(jsonPath("$.numberOfElements").value(2)); } diff --git a/openbas-api/src/test/java/io/openbas/rest/scenario/ScenarioApiSearchTest.java b/openbas-api/src/test/java/io/openbas/rest/scenario/ScenarioApiSearchTest.java index cb46e86e0f..e28a32b6e7 100644 --- a/openbas-api/src/test/java/io/openbas/rest/scenario/ScenarioApiSearchTest.java +++ b/openbas-api/src/test/java/io/openbas/rest/scenario/ScenarioApiSearchTest.java @@ -1,5 +1,15 @@ package io.openbas.rest.scenario; +import static io.openbas.database.model.Filters.FilterOperator.contains; +import static io.openbas.database.model.Scenario.SEVERITY.critical; +import static io.openbas.rest.scenario.ScenarioApi.SCENARIO_URI; +import static io.openbas.utils.JsonUtils.asJsonString; +import static java.lang.String.valueOf; +import static org.junit.jupiter.api.TestInstance.Lifecycle.PER_CLASS; +import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.post; +import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.jsonPath; +import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status; + import io.openbas.IntegrationTest; import io.openbas.database.model.Scenario; import io.openbas.database.repository.ScenarioRepository; @@ -8,32 +18,19 @@ import io.openbas.utils.mockUser.WithMockAdminUser; import io.openbas.utils.pagination.SearchPaginationInput; import io.openbas.utils.pagination.SortField; +import java.util.ArrayList; +import java.util.List; import org.junit.jupiter.api.*; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.http.MediaType; import org.springframework.test.web.servlet.MockMvc; -import java.util.ArrayList; -import java.util.List; - -import static io.openbas.database.model.Filters.FilterOperator.contains; -import static io.openbas.database.model.Scenario.SEVERITY.critical; -import static io.openbas.rest.scenario.ScenarioApi.SCENARIO_URI; -import static io.openbas.utils.JsonUtils.asJsonString; -import static java.lang.String.valueOf; -import static org.junit.jupiter.api.TestInstance.Lifecycle.PER_CLASS; -import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.post; -import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.jsonPath; -import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status; - @TestInstance(PER_CLASS) public class ScenarioApiSearchTest extends IntegrationTest { - @Autowired - private MockMvc mvc; + @Autowired private MockMvc mvc; - @Autowired - private ScenarioRepository scenarioRepository; + @Autowired private ScenarioRepository scenarioRepository; private static final List SCENARIO_IDS = new ArrayList<>(); @@ -66,11 +63,13 @@ class SearchingPageOfScenarios { @Test @DisplayName("Retrieving first page of scenarios by textsearch") void given_working_search_input_should_return_a_page_of_scenarios() throws Exception { - SearchPaginationInput searchPaginationInput = PaginationFixture.getDefault().textSearch("Crisis").build(); + SearchPaginationInput searchPaginationInput = + PaginationFixture.getDefault().textSearch("Crisis").build(); - mvc.perform(post(SCENARIO_URI + "/search") - .contentType(MediaType.APPLICATION_JSON) - .content(asJsonString(searchPaginationInput))) + mvc.perform( + post(SCENARIO_URI + "/search") + .contentType(MediaType.APPLICATION_JSON) + .content(asJsonString(searchPaginationInput))) .andExpect(status().is2xxSuccessful()) .andExpect(jsonPath("$.numberOfElements").value(1)); } @@ -78,11 +77,13 @@ void given_working_search_input_should_return_a_page_of_scenarios() throws Excep @Test @DisplayName("Not retrieving first page of scenario by textsearch") void given_not_working_search_input_should_return_a_page_of_scenarios() throws Exception { - SearchPaginationInput searchPaginationInput = PaginationFixture.getDefault().textSearch("wrong").build(); + SearchPaginationInput searchPaginationInput = + PaginationFixture.getDefault().textSearch("wrong").build(); - mvc.perform(post(SCENARIO_URI + "/search") - .contentType(MediaType.APPLICATION_JSON) - .content(asJsonString(searchPaginationInput))) + mvc.perform( + post(SCENARIO_URI + "/search") + .contentType(MediaType.APPLICATION_JSON) + .content(asJsonString(searchPaginationInput))) .andExpect(status().is2xxSuccessful()) .andExpect(jsonPath("$.numberOfElements").value(0)); } @@ -94,14 +95,17 @@ class SortingPageOfScenarios { @Test @DisplayName("Sorting page of scenarios by name") - void given_sorting_input_by_name_should_return_a_page_of_scenarios_sort_by_name() throws Exception { - SearchPaginationInput searchPaginationInput = PaginationFixture.getDefault() - .sorts(List.of(SortField.builder().property("scenario_name").build())) - .build(); - - mvc.perform(post(SCENARIO_URI + "/search") - .contentType(MediaType.APPLICATION_JSON) - .content(asJsonString(searchPaginationInput))) + void given_sorting_input_by_name_should_return_a_page_of_scenarios_sort_by_name() + throws Exception { + SearchPaginationInput searchPaginationInput = + PaginationFixture.getDefault() + .sorts(List.of(SortField.builder().property("scenario_name").build())) + .build(); + + mvc.perform( + post(SCENARIO_URI + "/search") + .contentType(MediaType.APPLICATION_JSON) + .content(asJsonString(searchPaginationInput))) .andExpect(status().is2xxSuccessful()) .andExpect(jsonPath("$.content.[0].scenario_name").value("Crisis scenario")) .andExpect(jsonPath("$.content.[1].scenario_name").value("Incident response scenario")); @@ -111,13 +115,20 @@ void given_sorting_input_by_name_should_return_a_page_of_scenarios_sort_by_name( @DisplayName("Sorting page of scenarios by category") void given_sorting_input_by_category_should_return_a_page_of_scenarios_sort_by_category() throws Exception { - SearchPaginationInput searchPaginationInput = PaginationFixture.getDefault() - .sorts(List.of(SortField.builder().property("scenario_category").direction("desc").build())) - .build(); - - mvc.perform(post(SCENARIO_URI + "/search") - .contentType(MediaType.APPLICATION_JSON) - .content(asJsonString(searchPaginationInput))) + SearchPaginationInput searchPaginationInput = + PaginationFixture.getDefault() + .sorts( + List.of( + SortField.builder() + .property("scenario_category") + .direction("desc") + .build())) + .build(); + + mvc.perform( + post(SCENARIO_URI + "/search") + .contentType(MediaType.APPLICATION_JSON) + .content(asJsonString(searchPaginationInput))) .andExpect(status().is2xxSuccessful()) .andExpect(jsonPath("$.content.[0].scenario_name").value("Incident response scenario")) .andExpect(jsonPath("$.content.[1].scenario_name").value("Crisis scenario")); @@ -130,48 +141,48 @@ class FilteringPageOfScenarios { @Test @DisplayName("Filtering page of scenarios by name") - void given_filter_input_by_name_should_return_a_page_of_scenarios_filter_by_name() throws Exception { - SearchPaginationInput searchPaginationInput = PaginationFixture.simpleFilter( - "scenario_name", "Crisis", contains - ); - - mvc.perform(post(SCENARIO_URI + "/search") - .contentType(MediaType.APPLICATION_JSON) - .content(asJsonString(searchPaginationInput))) + void given_filter_input_by_name_should_return_a_page_of_scenarios_filter_by_name() + throws Exception { + SearchPaginationInput searchPaginationInput = + PaginationFixture.simpleFilter("scenario_name", "Crisis", contains); + + mvc.perform( + post(SCENARIO_URI + "/search") + .contentType(MediaType.APPLICATION_JSON) + .content(asJsonString(searchPaginationInput))) .andExpect(status().is2xxSuccessful()) .andExpect(jsonPath("$.numberOfElements").value(1)); } @Test @DisplayName("Filtering page of scenarios by category") - void given_filter_input_by_category_should_return_a_page_of_scenarios_filter_by_category() throws Exception { - SearchPaginationInput searchPaginationInput = PaginationFixture.simpleFilter( - "scenario_category", "incident-response", contains - ); - - mvc.perform(post(SCENARIO_URI + "/search") - .contentType(MediaType.APPLICATION_JSON) - .content(asJsonString(searchPaginationInput))) + void given_filter_input_by_category_should_return_a_page_of_scenarios_filter_by_category() + throws Exception { + SearchPaginationInput searchPaginationInput = + PaginationFixture.simpleFilter("scenario_category", "incident-response", contains); + + mvc.perform( + post(SCENARIO_URI + "/search") + .contentType(MediaType.APPLICATION_JSON) + .content(asJsonString(searchPaginationInput))) .andExpect(status().is2xxSuccessful()) .andExpect(jsonPath("$.numberOfElements").value(1)); } @Test @DisplayName("Filtering page of scenarios by severity") - void given_filter_input_by_severity_should_return_a_page_of_scenarios_filter_by_severity() throws Exception { - SearchPaginationInput searchPaginationInput = PaginationFixture.simpleFilter( - "scenario_severity", valueOf(critical), contains - ); - - mvc.perform(post(SCENARIO_URI + "/search") - .contentType(MediaType.APPLICATION_JSON) - .content(asJsonString(searchPaginationInput))) + void given_filter_input_by_severity_should_return_a_page_of_scenarios_filter_by_severity() + throws Exception { + SearchPaginationInput searchPaginationInput = + PaginationFixture.simpleFilter("scenario_severity", valueOf(critical), contains); + + mvc.perform( + post(SCENARIO_URI + "/search") + .contentType(MediaType.APPLICATION_JSON) + .content(asJsonString(searchPaginationInput))) .andExpect(status().is2xxSuccessful()) .andExpect(jsonPath("$.numberOfElements").value(1)); } - } - } - } diff --git a/openbas-api/src/test/java/io/openbas/rest/scenario/ScenarioApiTest.java b/openbas-api/src/test/java/io/openbas/rest/scenario/ScenarioApiTest.java index f41a7589c0..a4aad0cd64 100644 --- a/openbas-api/src/test/java/io/openbas/rest/scenario/ScenarioApiTest.java +++ b/openbas-api/src/test/java/io/openbas/rest/scenario/ScenarioApiTest.java @@ -1,5 +1,14 @@ package io.openbas.rest.scenario; +import static io.openbas.rest.scenario.ScenarioApi.SCENARIO_URI; +import static io.openbas.utils.JsonUtils.asJsonString; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertNotNull; +import static org.junit.jupiter.api.TestInstance.Lifecycle.PER_CLASS; +import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.*; +import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.jsonPath; +import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status; + import com.jayway.jsonpath.JsonPath; import io.openbas.database.repository.ScenarioRepository; import io.openbas.rest.scenario.form.ScenarioInformationInput; @@ -13,26 +22,15 @@ import org.springframework.http.MediaType; import org.springframework.test.web.servlet.MockMvc; -import static io.openbas.rest.scenario.ScenarioApi.SCENARIO_URI; -import static io.openbas.utils.JsonUtils.asJsonString; -import static org.junit.jupiter.api.Assertions.assertEquals; -import static org.junit.jupiter.api.Assertions.assertNotNull; -import static org.junit.jupiter.api.TestInstance.Lifecycle.PER_CLASS; -import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.*; -import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.jsonPath; -import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status; - @SpringBootTest @AutoConfigureMockMvc @TestMethodOrder(MethodOrderer.OrderAnnotation.class) @TestInstance(PER_CLASS) public class ScenarioApiTest { - @Autowired - private MockMvc mvc; + @Autowired private MockMvc mvc; - @Autowired - private ScenarioRepository scenarioRepository; + @Autowired private ScenarioRepository scenarioRepository; static String SCENARIO_ID; @@ -51,10 +49,11 @@ void createScenarioTest() throws Exception { // -- EXECUTE & ASSERT -- this.mvc - .perform(post(SCENARIO_URI) - .content(asJsonString(scenarioInput)) - .contentType(MediaType.APPLICATION_JSON) - .accept(MediaType.APPLICATION_JSON)) + .perform( + post(SCENARIO_URI) + .content(asJsonString(scenarioInput)) + .contentType(MediaType.APPLICATION_JSON) + .accept(MediaType.APPLICATION_JSON)) .andExpect(status().is4xxClientError()); // -- PREPARE -- @@ -62,16 +61,18 @@ void createScenarioTest() throws Exception { scenarioInput.setName(name); // -- EXECUTE -- - String response = this.mvc - .perform(post(SCENARIO_URI) - .content(asJsonString(scenarioInput)) - .contentType(MediaType.APPLICATION_JSON) - .accept(MediaType.APPLICATION_JSON)) - .andExpect(status().is2xxSuccessful()) - .andExpect(jsonPath("$.scenario_name").value(name)) - .andReturn() - .getResponse() - .getContentAsString(); + String response = + this.mvc + .perform( + post(SCENARIO_URI) + .content(asJsonString(scenarioInput)) + .contentType(MediaType.APPLICATION_JSON) + .accept(MediaType.APPLICATION_JSON)) + .andExpect(status().is2xxSuccessful()) + .andExpect(jsonPath("$.scenario_name").value(name)) + .andReturn() + .getResponse() + .getContentAsString(); // -- ASSERT -- assertNotNull(response); @@ -84,13 +85,13 @@ void createScenarioTest() throws Exception { @WithMockObserverUser void retrieveScenariosTest() throws Exception { // -- EXECUTE -- - String response = this.mvc - .perform(get(SCENARIO_URI) - .accept(MediaType.APPLICATION_JSON)) - .andExpect(status().is2xxSuccessful()) - .andReturn() - .getResponse() - .getContentAsString(); + String response = + this.mvc + .perform(get(SCENARIO_URI).accept(MediaType.APPLICATION_JSON)) + .andExpect(status().is2xxSuccessful()) + .andReturn() + .getResponse() + .getContentAsString(); // -- ASSERT -- assertNotNull(response); @@ -102,13 +103,13 @@ void retrieveScenariosTest() throws Exception { @WithMockObserverUser void retrieveScenarioTest() throws Exception { // -- EXECUTE -- - String response = this.mvc - .perform(get(SCENARIO_URI + "/" + SCENARIO_ID) - .accept(MediaType.APPLICATION_JSON)) - .andExpect(status().is2xxSuccessful()) - .andReturn() - .getResponse() - .getContentAsString(); + String response = + this.mvc + .perform(get(SCENARIO_URI + "/" + SCENARIO_ID).accept(MediaType.APPLICATION_JSON)) + .andExpect(status().is2xxSuccessful()) + .andReturn() + .getResponse() + .getContentAsString(); // -- ASSERT -- assertNotNull(response); @@ -120,13 +121,13 @@ void retrieveScenarioTest() throws Exception { @WithMockPlannerUser void updateScenarioTest() throws Exception { // -- PREPARE -- - String response = this.mvc - .perform(get(SCENARIO_URI + "/" + SCENARIO_ID) - .accept(MediaType.APPLICATION_JSON)) - .andExpect(status().is2xxSuccessful()) - .andReturn() - .getResponse() - .getContentAsString(); + String response = + this.mvc + .perform(get(SCENARIO_URI + "/" + SCENARIO_ID).accept(MediaType.APPLICATION_JSON)) + .andExpect(status().is2xxSuccessful()) + .andReturn() + .getResponse() + .getContentAsString(); ScenarioInput scenarioInput = new ScenarioInput(); String subtitle = "A subtitle"; @@ -134,15 +135,17 @@ void updateScenarioTest() throws Exception { scenarioInput.setSubtitle(subtitle); // -- EXECUTE -- - response = this.mvc - .perform(put(SCENARIO_URI + "/" + SCENARIO_ID) - .content(asJsonString(scenarioInput)) - .contentType(MediaType.APPLICATION_JSON) - .accept(MediaType.APPLICATION_JSON)) - .andExpect(status().is2xxSuccessful()) - .andReturn() - .getResponse() - .getContentAsString(); + response = + this.mvc + .perform( + put(SCENARIO_URI + "/" + SCENARIO_ID) + .content(asJsonString(scenarioInput)) + .contentType(MediaType.APPLICATION_JSON) + .accept(MediaType.APPLICATION_JSON)) + .andExpect(status().is2xxSuccessful()) + .andReturn() + .getResponse() + .getContentAsString(); // -- ASSERT -- assertNotNull(response); @@ -161,15 +164,17 @@ void updateScenarioInformationTest() throws Exception { scenarioInformationInput.setHeader(header); // -- EXECUTE -- - String response = this.mvc - .perform(put(SCENARIO_URI + "/" + SCENARIO_ID + "/information") - .content(asJsonString(scenarioInformationInput)) - .contentType(MediaType.APPLICATION_JSON) - .accept(MediaType.APPLICATION_JSON)) - .andExpect(status().is2xxSuccessful()) - .andReturn() - .getResponse() - .getContentAsString(); + String response = + this.mvc + .perform( + put(SCENARIO_URI + "/" + SCENARIO_ID + "/information") + .content(asJsonString(scenarioInformationInput)) + .contentType(MediaType.APPLICATION_JSON) + .accept(MediaType.APPLICATION_JSON)) + .andExpect(status().is2xxSuccessful()) + .andReturn() + .getResponse() + .getContentAsString(); // -- ASSERT -- assertNotNull(response); @@ -182,8 +187,8 @@ void updateScenarioInformationTest() throws Exception { @WithMockPlannerUser void deleteScenarioTest() throws Exception { // -- EXECUTE 1 ASSERT -- - this.mvc.perform(delete(SCENARIO_URI + "/" + SCENARIO_ID)) + this.mvc + .perform(delete(SCENARIO_URI + "/" + SCENARIO_ID)) .andExpect(status().is2xxSuccessful()); } - } diff --git a/openbas-api/src/test/java/io/openbas/rest/scenario/ScenarioImportApiTest.java b/openbas-api/src/test/java/io/openbas/rest/scenario/ScenarioImportApiTest.java index dc5a02c726..bd98f71d15 100644 --- a/openbas-api/src/test/java/io/openbas/rest/scenario/ScenarioImportApiTest.java +++ b/openbas-api/src/test/java/io/openbas/rest/scenario/ScenarioImportApiTest.java @@ -1,12 +1,19 @@ package io.openbas.rest.scenario; +import static io.openbas.utils.JsonUtils.asJsonString; +import static org.junit.jupiter.api.Assertions.assertNotNull; +import static org.mockito.ArgumentMatchers.*; +import static org.mockito.Mockito.when; +import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status; + import io.openbas.database.model.ImportMapper; import io.openbas.database.repository.ImportMapperRepository; -import io.openbas.rest.scenario.ScenarioImportApi; import io.openbas.rest.scenario.form.InjectsImportInput; import io.openbas.rest.scenario.response.ImportTestSummary; import io.openbas.service.InjectService; import io.openbas.service.ScenarioService; +import java.util.Optional; +import java.util.UUID; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.DisplayName; import org.junit.jupiter.api.Test; @@ -19,29 +26,17 @@ import org.springframework.test.web.servlet.request.MockMvcRequestBuilders; import org.springframework.test.web.servlet.setup.MockMvcBuilders; -import java.util.Optional; -import java.util.UUID; - -import static io.openbas.utils.JsonUtils.asJsonString; -import static org.junit.jupiter.api.Assertions.assertNotNull; -import static org.mockito.ArgumentMatchers.*; -import static org.mockito.Mockito.when; -import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status; - @SpringBootTest @ExtendWith(MockitoExtension.class) public class ScenarioImportApiTest { private MockMvc mvc; - @Mock - private InjectService injectService; + @Mock private InjectService injectService; - @Mock - private ImportMapperRepository importMapperRepository; + @Mock private ImportMapperRepository importMapperRepository; - @Mock - private ScenarioService scenarioService; + @Mock private ScenarioService scenarioService; private ScenarioImportApi scenarioImportApi; @@ -50,12 +45,12 @@ public class ScenarioImportApiTest { @BeforeEach public void setUp() { // Injecting mocks into the controller - scenarioImportApi = new ScenarioImportApi(injectService, importMapperRepository, scenarioService); + scenarioImportApi = + new ScenarioImportApi(injectService, importMapperRepository, scenarioService); SCENARIO_ID = UUID.randomUUID().toString(); - mvc = MockMvcBuilders.standaloneSetup(scenarioImportApi) - .build(); + mvc = MockMvcBuilders.standaloneSetup(scenarioImportApi).build(); } @DisplayName("Test dry run import xls") @@ -68,11 +63,18 @@ void testDryRunXls() throws Exception { injectsImportInput.setTimezoneOffset(120); when(importMapperRepository.findById(any())).thenReturn(Optional.of(new ImportMapper())); - when(injectService.importInjectIntoScenarioFromXLS(any(), any(), any(), any(), anyInt(), anyBoolean())).thenReturn(new ImportTestSummary()); + when(injectService.importInjectIntoScenarioFromXLS( + any(), any(), any(), any(), anyInt(), anyBoolean())) + .thenReturn(new ImportTestSummary()); // -- EXECUTE -- - String response = this.mvc - .perform(MockMvcRequestBuilders.post("/api/scenarios/{scenarioId}/xls/{importId}/dry", SCENARIO_ID, UUID.randomUUID().toString()) + String response = + this.mvc + .perform( + MockMvcRequestBuilders.post( + "/api/scenarios/{scenarioId}/xls/{importId}/dry", + SCENARIO_ID, + UUID.randomUUID().toString()) .contentType(MediaType.APPLICATION_JSON) .content(asJsonString(injectsImportInput))) .andExpect(status().is2xxSuccessful()) @@ -94,11 +96,18 @@ void testImportXls() throws Exception { injectsImportInput.setTimezoneOffset(120); when(importMapperRepository.findById(any())).thenReturn(Optional.of(new ImportMapper())); - when(injectService.importInjectIntoScenarioFromXLS(any(), any(), any(), any(), anyInt(), anyBoolean())).thenReturn(new ImportTestSummary()); + when(injectService.importInjectIntoScenarioFromXLS( + any(), any(), any(), any(), anyInt(), anyBoolean())) + .thenReturn(new ImportTestSummary()); // -- EXECUTE -- - String response = this.mvc - .perform(MockMvcRequestBuilders.post("/api/scenarios/{scenarioId}/xls/{importId}/import", SCENARIO_ID, UUID.randomUUID().toString()) + String response = + this.mvc + .perform( + MockMvcRequestBuilders.post( + "/api/scenarios/{scenarioId}/xls/{importId}/import", + SCENARIO_ID, + UUID.randomUUID().toString()) .contentType(MediaType.APPLICATION_JSON) .content(asJsonString(injectsImportInput))) .andExpect(status().is2xxSuccessful()) @@ -109,5 +118,4 @@ void testImportXls() throws Exception { // -- ASSERT -- assertNotNull(response); } - } diff --git a/openbas-api/src/test/java/io/openbas/rest/scenario/ScenarioToExerciseServiceTest.java b/openbas-api/src/test/java/io/openbas/rest/scenario/ScenarioToExerciseServiceTest.java index 4134bfa9c4..71b526ea3a 100644 --- a/openbas-api/src/test/java/io/openbas/rest/scenario/ScenarioToExerciseServiceTest.java +++ b/openbas-api/src/test/java/io/openbas/rest/scenario/ScenarioToExerciseServiceTest.java @@ -1,11 +1,26 @@ package io.openbas.rest.scenario; +import static io.openbas.injectors.email.EmailContract.EMAIL_DEFAULT; +import static io.openbas.utils.fixtures.ArticleFixture.ARTICLE_NAME; +import static io.openbas.utils.fixtures.ArticleFixture.getArticle; +import static io.openbas.utils.fixtures.DocumentFixture.getDocumentJpeg; +import static io.openbas.utils.fixtures.InjectFixture.getInjectForEmailContract; +import static io.openbas.utils.fixtures.ObjectiveFixture.OBJECTIVE_NAME; +import static io.openbas.utils.fixtures.ObjectiveFixture.getObjective; +import static io.openbas.utils.fixtures.TagFixture.getTag; +import static io.openbas.utils.fixtures.TeamFixture.getTeam; +import static io.openbas.utils.fixtures.UserFixture.getUser; +import static org.junit.jupiter.api.Assertions.*; + import io.openbas.database.model.*; import io.openbas.database.repository.*; import io.openbas.service.LoadService; import io.openbas.service.ScenarioService; import io.openbas.service.ScenarioToExerciseService; import io.openbas.utils.fixtures.ScenarioFixture; +import java.util.ArrayList; +import java.util.HashSet; +import java.util.List; import org.junit.jupiter.api.AfterAll; import org.junit.jupiter.api.DisplayName; import org.junit.jupiter.api.Test; @@ -13,55 +28,25 @@ import org.springframework.beans.factory.annotation.Autowired; import org.springframework.boot.test.context.SpringBootTest; -import java.util.ArrayList; -import java.util.HashSet; -import java.util.List; - -import static io.openbas.injectors.email.EmailContract.EMAIL_DEFAULT; -import static io.openbas.utils.fixtures.ArticleFixture.ARTICLE_NAME; -import static io.openbas.utils.fixtures.ArticleFixture.getArticle; -import static io.openbas.utils.fixtures.DocumentFixture.getDocumentJpeg; -import static io.openbas.utils.fixtures.InjectFixture.getInjectForEmailContract; -import static io.openbas.utils.fixtures.ObjectiveFixture.OBJECTIVE_NAME; -import static io.openbas.utils.fixtures.ObjectiveFixture.getObjective; -import static io.openbas.utils.fixtures.TagFixture.getTag; -import static io.openbas.utils.fixtures.TeamFixture.getTeam; -import static io.openbas.utils.fixtures.UserFixture.getUser; -import static org.junit.jupiter.api.Assertions.*; - @SpringBootTest @TestInstance(TestInstance.Lifecycle.PER_CLASS) class ScenarioToExerciseServiceTest { - @Autowired - private ScenarioToExerciseService scenarioToExerciseService; - @Autowired - private LoadService loadService; + @Autowired private ScenarioToExerciseService scenarioToExerciseService; + @Autowired private LoadService loadService; - @Autowired - private ScenarioService scenarioService; - @Autowired - private ExerciseRepository exerciseRepository; - @Autowired - private UserRepository userRepository; - @Autowired - private TagRepository tagRepository; - @Autowired - private TeamRepository teamRepository; - @Autowired - private DocumentRepository documentRepository; - @Autowired - private ChannelRepository channelRepository; - @Autowired - private LessonsCategoryRepository lessonsCategoryRepository; - @Autowired - private LessonsQuestionRepository lessonsQuestionRepository; - @Autowired - private InjectRepository injectRepository; - @Autowired - private VariableRepository variableRepository; - @Autowired - private InjectorContractRepository injectorContractRepository; + @Autowired private ScenarioService scenarioService; + @Autowired private ExerciseRepository exerciseRepository; + @Autowired private UserRepository userRepository; + @Autowired private TagRepository tagRepository; + @Autowired private TeamRepository teamRepository; + @Autowired private DocumentRepository documentRepository; + @Autowired private ChannelRepository channelRepository; + @Autowired private LessonsCategoryRepository lessonsCategoryRepository; + @Autowired private LessonsQuestionRepository lessonsQuestionRepository; + @Autowired private InjectRepository injectRepository; + @Autowired private VariableRepository variableRepository; + @Autowired private InjectorContractRepository injectorContractRepository; private static String SCENARIO_ID; private static String EXERCISE_ID; @@ -113,18 +98,24 @@ void scenarioToExerciseTest() { contextualTeam.setContextual(true); Team contextualTeamSaved = this.teamRepository.save(contextualTeam); TEAM_CONTEXTUAL_ID = contextualTeamSaved.getId(); - scenario.setTeams(new ArrayList<>() {{ - add(teamSaved); - add(contextualTeamSaved); - }}); + scenario.setTeams( + new ArrayList<>() { + { + add(teamSaved); + add(contextualTeamSaved); + } + }); // Tag Tag tag = getTag(); Tag tagSaved = this.tagRepository.save(tag); TAG_ID = tagSaved.getId(); - scenario.setTags(new HashSet<>() {{ - add(tagSaved); - }}); + scenario.setTags( + new HashSet<>() { + { + add(tagSaved); + } + }); Scenario scenarioSaved = this.scenarioService.createScenario(scenario); SCENARIO_ID = scenarioSaved.getId(); @@ -143,17 +134,23 @@ void scenarioToExerciseTest() { // Objective Objective objective = getObjective(); objective.setScenario(scenarioSaved); - scenario.setObjectives(new ArrayList<>() {{ - add(objective); - }}); + scenario.setObjectives( + new ArrayList<>() { + { + add(objective); + } + }); // Document Document document = getDocumentJpeg(); Document documentSaved = this.documentRepository.save(document); DOCUMENT_ID = documentSaved.getId(); - scenario.setDocuments(new ArrayList<>() {{ - add(documentSaved); - }}); + scenario.setDocuments( + new ArrayList<>() { + { + add(documentSaved); + } + }); // Article Document documentArticle = new Document(); @@ -167,21 +164,30 @@ void scenarioToExerciseTest() { Channel channelSaved = this.channelRepository.save(channel); CHANNEL_ID = channelSaved.getId(); Article article = getArticle(channelSaved); - article.setDocuments(new ArrayList<>() {{ - add(documentArticleSaved); - }}); - scenarioSaved.setArticles(new ArrayList<>() {{ - add(article); - }}); + article.setDocuments( + new ArrayList<>() { + { + add(documentArticleSaved); + } + }); + scenarioSaved.setArticles( + new ArrayList<>() { + { + add(article); + } + }); // Lessons questions LessonsCategory lessonsCategory = new LessonsCategory(); lessonsCategory.setName("Category"); lessonsCategory.setScenario(scenarioSaved); - lessonsCategory.setTeams(new ArrayList<>() {{ - add(teamSaved); - add(contextualTeamSaved); - }}); + lessonsCategory.setTeams( + new ArrayList<>() { + { + add(teamSaved); + add(contextualTeamSaved); + } + }); LessonsCategory lessonsCategorySaved = this.lessonsCategoryRepository.save(lessonsCategory); LESSON_CATEGORY_ID = lessonsCategorySaved.getId(); LessonsQuestion lessonsQuestion = new LessonsQuestion(); @@ -190,25 +196,39 @@ void scenarioToExerciseTest() { LessonsQuestion lessonsQuestionSaved = this.lessonsQuestionRepository.save(lessonsQuestion); LESSON_QUESTION_ID = lessonsQuestionSaved.getId(); - lessonsCategory.setQuestions(new ArrayList<>() {{ - add(lessonsQuestionSaved); - }}); - scenario.setLessonsCategories(new ArrayList<>() {{ - add(lessonsCategorySaved); - }}); + lessonsCategory.setQuestions( + new ArrayList<>() { + { + add(lessonsQuestionSaved); + } + }); + scenario.setLessonsCategories( + new ArrayList<>() { + { + add(lessonsCategorySaved); + } + }); // Inject - Inject inject = getInjectForEmailContract(this.injectorContractRepository.findById(EMAIL_DEFAULT).orElseThrow()); - inject.setTeams(new ArrayList<>() {{ - add(teamSaved); - add(contextualTeamSaved); - }}); + Inject inject = + getInjectForEmailContract( + this.injectorContractRepository.findById(EMAIL_DEFAULT).orElseThrow()); + inject.setTeams( + new ArrayList<>() { + { + add(teamSaved); + add(contextualTeamSaved); + } + }); inject.setScenario(scenarioSaved); Inject injectSaved = this.injectRepository.save(inject); INJECT_ID = injectSaved.getId(); - scenario.setInjects(new HashSet<>() {{ - add(inject); - }}); + scenario.setInjects( + new HashSet<>() { + { + add(inject); + } + }); // Variables Variable variable = new Variable(); @@ -230,8 +250,10 @@ void scenarioToExerciseTest() { assertEquals(2, (long) exerciseSaved.getGrants().size()); // User & Teams assertEquals(2, (long) exerciseSaved.getTeams().size()); - assertTrue(exerciseSaved.getTeams().stream().anyMatch(t -> teamSaved.getId().equals(t.getId()))); - assertTrue(exerciseSaved.getTeams().stream().anyMatch(t -> Boolean.TRUE.equals(t.getContextual()))); + assertTrue( + exerciseSaved.getTeams().stream().anyMatch(t -> teamSaved.getId().equals(t.getId()))); + assertTrue( + exerciseSaved.getTeams().stream().anyMatch(t -> Boolean.TRUE.equals(t.getContextual()))); // Team Users assertEquals(2, exerciseSaved.getTeamUsers().size()); // Tags @@ -244,15 +266,20 @@ void scenarioToExerciseTest() { // Articles assertEquals(1, exerciseSaved.getArticles().size()); assertEquals(ARTICLE_NAME, exerciseSaved.getArticles().getFirst().getName()); - assertEquals(documentArticleName, exerciseSaved.getArticles().getFirst().getDocuments().getFirst().getName()); + assertEquals( + documentArticleName, + exerciseSaved.getArticles().getFirst().getDocuments().getFirst().getName()); // Lessons questions assertEquals(1, exerciseSaved.getLessonsCategories().size()); LessonsCategory exerciseLessonsCategory = exerciseSaved.getLessonsCategories().getFirst(); assertEquals(1, exerciseLessonsCategory.getQuestions().size()); - assertTrue(exerciseLessonsCategory.getTeams().stream().anyMatch(t -> teamSaved.getId().equals(t.getId()))); - assertTrue(exerciseLessonsCategory.getTeams().stream().anyMatch(t -> Boolean.TRUE.equals(t.getContextual()))); + assertTrue( + exerciseLessonsCategory.getTeams().stream() + .anyMatch(t -> teamSaved.getId().equals(t.getId()))); + assertTrue( + exerciseLessonsCategory.getTeams().stream() + .anyMatch(t -> Boolean.TRUE.equals(t.getContextual()))); // Injects assertEquals(1, exerciseSaved.getInjects().size()); } - } diff --git a/openbas-api/src/test/java/io/openbas/runner/InitAdminCommandLineRunnerTest.java b/openbas-api/src/test/java/io/openbas/runner/InitAdminCommandLineRunnerTest.java index a5004bdad0..e8bfa61a8a 100644 --- a/openbas-api/src/test/java/io/openbas/runner/InitAdminCommandLineRunnerTest.java +++ b/openbas-api/src/test/java/io/openbas/runner/InitAdminCommandLineRunnerTest.java @@ -1,30 +1,27 @@ package io.openbas.runner; +import static io.openbas.database.model.Token.ADMIN_TOKEN_UUID; +import static io.openbas.database.model.User.ADMIN_UUID; +import static org.assertj.core.api.Assertions.assertThat; + import io.openbas.database.model.Token; import io.openbas.database.model.User; import io.openbas.database.repository.TokenRepository; import io.openbas.database.repository.UserRepository; +import java.util.Optional; import org.junit.jupiter.api.DisplayName; import org.junit.jupiter.api.Test; import org.junit.jupiter.api.TestInstance; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.boot.test.context.SpringBootTest; -import java.util.Optional; - -import static io.openbas.database.model.Token.ADMIN_TOKEN_UUID; -import static io.openbas.database.model.User.ADMIN_UUID; -import static org.assertj.core.api.Assertions.assertThat; - @SpringBootTest @TestInstance(TestInstance.Lifecycle.PER_CLASS) public class InitAdminCommandLineRunnerTest { - @Autowired - private UserRepository userRepository; + @Autowired private UserRepository userRepository; - @Autowired - private TokenRepository tokenRepository; + @Autowired private TokenRepository tokenRepository; @DisplayName("Test if admin user is created") @Test @@ -39,5 +36,4 @@ void adminTokenExistTest() { Optional adminToken = this.tokenRepository.findById(ADMIN_TOKEN_UUID); assertThat(adminToken.isPresent()).isEqualTo(true); } - } diff --git a/openbas-api/src/test/java/io/openbas/scheduler/jobs/ScenarioExecutionJobTest.java b/openbas-api/src/test/java/io/openbas/scheduler/jobs/ScenarioExecutionJobTest.java index e350004156..1782cacbc1 100644 --- a/openbas-api/src/test/java/io/openbas/scheduler/jobs/ScenarioExecutionJobTest.java +++ b/openbas-api/src/test/java/io/openbas/scheduler/jobs/ScenarioExecutionJobTest.java @@ -1,38 +1,33 @@ package io.openbas.scheduler.jobs; +import static io.openbas.helper.StreamHelper.fromIterable; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertNotNull; + import io.openbas.database.model.Exercise; import io.openbas.database.model.Scenario; import io.openbas.database.repository.ExerciseRepository; import io.openbas.service.ScenarioService; import io.openbas.utils.fixtures.ScenarioFixture; -import org.junit.jupiter.api.*; -import org.quartz.JobExecutionException; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.boot.test.context.SpringBootTest; - import java.time.Instant; import java.time.ZoneId; import java.time.ZonedDateTime; import java.time.temporal.ChronoUnit; import java.util.List; - -import static io.openbas.helper.StreamHelper.fromIterable; -import static io.openbas.utils.fixtures.ScenarioFixture.getScenario; -import static org.junit.jupiter.api.Assertions.assertEquals; -import static org.junit.jupiter.api.Assertions.assertNotNull; +import org.junit.jupiter.api.*; +import org.quartz.JobExecutionException; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.test.context.SpringBootTest; @SpringBootTest @TestMethodOrder(MethodOrderer.OrderAnnotation.class) @TestInstance(TestInstance.Lifecycle.PER_CLASS) class ScenarioExecutionJobTest { - @Autowired - private ScenarioExecutionJob job; + @Autowired private ScenarioExecutionJob job; - @Autowired - private ScenarioService scenarioService; - @Autowired - private ExerciseRepository exerciseRepository; + @Autowired private ScenarioService scenarioService; + @Autowired private ExerciseRepository exerciseRepository; static String SCENARIO_ID_1; static String SCENARIO_ID_2; @@ -56,7 +51,8 @@ void given_cron_in_one_hour_should_not_create_simulation() throws JobExecutionEx int hourToStart = (zonedDateTime.getHour() + 1) % 24; Scenario scenario = ScenarioFixture.getScenario(); - scenario.setRecurrence("0 " + zonedDateTime.getMinute() + " " + hourToStart + " * * *"); // Every day now + 1 hour + scenario.setRecurrence( + "0 " + zonedDateTime.getMinute() + " " + hourToStart + " * * *"); // Every day now + 1 hour Scenario scenarioSaved = this.scenarioService.createScenario(scenario); SCENARIO_ID_1 = scenarioSaved.getId(); @@ -64,12 +60,11 @@ void given_cron_in_one_hour_should_not_create_simulation() throws JobExecutionEx this.job.execute(null); // -- ASSERT -- - List createdExercises = fromIterable( - this.exerciseRepository.findAll()) - .stream() - .filter(exercise -> exercise.getScenario() != null) - .filter(exercise -> SCENARIO_ID_1.equals(exercise.getScenario().getId())) - .toList(); + List createdExercises = + fromIterable(this.exerciseRepository.findAll()).stream() + .filter(exercise -> exercise.getScenario() != null) + .filter(exercise -> SCENARIO_ID_1.equals(exercise.getScenario().getId())) + .toList(); assertEquals(0, createdExercises.size()); } @@ -82,7 +77,12 @@ void given_cron_in_one_minute_should_create_simulation() throws JobExecutionExce Scenario scenario = ScenarioFixture.getScenario(); int minuteToStart = (zonedDateTime.getMinute() + 1) % 60; - scenario.setRecurrence("0 " + minuteToStart + " " + zonedDateTime.getHour() + " * * *"); // Every day now + 1 minute + scenario.setRecurrence( + "0 " + + minuteToStart + + " " + + zonedDateTime.getHour() + + " * * *"); // Every day now + 1 minute Scenario scenarioSaved = this.scenarioService.createScenario(scenario); SCENARIO_ID_2 = scenarioSaved.getId(); @@ -90,11 +90,11 @@ void given_cron_in_one_minute_should_create_simulation() throws JobExecutionExce this.job.execute(null); // -- ASSERT -- - List createdExercises = fromIterable(this.exerciseRepository.findAll()) - .stream() - .filter(exercise -> exercise.getScenario() != null) - .filter(exercise -> SCENARIO_ID_2.equals(exercise.getScenario().getId())) - .toList(); + List createdExercises = + fromIterable(this.exerciseRepository.findAll()).stream() + .filter(exercise -> exercise.getScenario() != null) + .filter(exercise -> SCENARIO_ID_2.equals(exercise.getScenario().getId())) + .toList(); assertEquals(1, createdExercises.size()); Exercise createdExercise = createdExercises.getFirst(); assertNotNull(createdExercise.getStart()); @@ -110,25 +110,30 @@ void given_cron_in_one_minute_should_not_create_second_simulation() throws JobEx this.job.execute(null); // -- ASSERT -- - List createdExercises = fromIterable( - this.exerciseRepository.findAll()) - .stream() - .filter(exercise -> exercise.getScenario() != null) - .filter(exercise -> SCENARIO_ID_2.equals(exercise.getScenario().getId())) - .toList(); + List createdExercises = + fromIterable(this.exerciseRepository.findAll()).stream() + .filter(exercise -> exercise.getScenario() != null) + .filter(exercise -> SCENARIO_ID_2.equals(exercise.getScenario().getId())) + .toList(); assertEquals(1, createdExercises.size()); } @DisplayName("Not create simulation based on end date before now") @Test @Order(4) - void given_end_date_before_now_should_not_create_second_simulation() throws JobExecutionException { + void given_end_date_before_now_should_not_create_second_simulation() + throws JobExecutionException { // -- PREPARE -- ZonedDateTime zonedDateTime = ZonedDateTime.now(ZoneId.of("UTC")); Scenario scenario = ScenarioFixture.getScenario(); int minuteToStart = (zonedDateTime.getMinute() + 1) % 60; - scenario.setRecurrence("0 " + minuteToStart + " " + zonedDateTime.getHour() + " * * *"); // Every day now + 1 minute + scenario.setRecurrence( + "0 " + + minuteToStart + + " " + + zonedDateTime.getHour() + + " * * *"); // Every day now + 1 minute scenario.setRecurrenceEnd(Instant.now().minus(0, ChronoUnit.DAYS)); Scenario scenarioSaved = this.scenarioService.createScenario(scenario); SCENARIO_ID_3 = scenarioSaved.getId(); @@ -137,12 +142,11 @@ void given_end_date_before_now_should_not_create_second_simulation() throws JobE this.job.execute(null); // -- ASSERT -- - List createdExercises = fromIterable( - this.exerciseRepository.findAll()) - .stream() - .filter(exercise -> exercise.getScenario() != null) - .filter(exercise -> SCENARIO_ID_3.equals(exercise.getScenario().getId())) - .toList(); + List createdExercises = + fromIterable(this.exerciseRepository.findAll()).stream() + .filter(exercise -> exercise.getScenario() != null) + .filter(exercise -> SCENARIO_ID_3.equals(exercise.getScenario().getId())) + .toList(); assertEquals(0, createdExercises.size()); } } diff --git a/openbas-api/src/test/java/io/openbas/service/EmailServiceTest.java b/openbas-api/src/test/java/io/openbas/service/EmailServiceTest.java index 3c94061217..657c31a9ad 100644 --- a/openbas-api/src/test/java/io/openbas/service/EmailServiceTest.java +++ b/openbas-api/src/test/java/io/openbas/service/EmailServiceTest.java @@ -1,11 +1,16 @@ package io.openbas.service; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.mockito.Mockito.*; + import io.openbas.database.model.Execution; import io.openbas.execution.ExecutionContext; import io.openbas.injectors.email.service.EmailService; import io.openbas.utils.fixtures.UserFixture; import jakarta.mail.Session; import jakarta.mail.internet.MimeMessage; +import java.util.Collections; +import java.util.List; import org.junit.jupiter.api.Test; import org.junit.jupiter.api.extension.ExtendWith; import org.mockito.ArgumentCaptor; @@ -14,31 +19,32 @@ import org.mockito.junit.jupiter.MockitoExtension; import org.springframework.mail.javamail.JavaMailSender; -import java.util.Collections; -import java.util.List; - -import static org.junit.jupiter.api.Assertions.assertEquals; -import static org.mockito.Mockito.*; - @ExtendWith(MockitoExtension.class) class EmailServiceTest { - @Mock - private JavaMailSender emailSender; - @InjectMocks - private EmailService emailService; - - @Test - void shouldSetReplyToInHeaderEqualsToFrom() throws Exception { - ArgumentCaptor argument = ArgumentCaptor.forClass(MimeMessage.class); - - Execution execution = new Execution(); - ExecutionContext userContext = new ExecutionContext(UserFixture.getSavedUser(), null); - - when(emailSender.createMimeMessage()).thenReturn(new MimeMessage((Session) null)); - emailService.sendEmail(execution, userContext, "user@openbas.io", List.of("user-reply-to@openbas.io"), null, false, "subject", "message", Collections.emptyList()); - verify(emailSender).send(argument.capture()); - assertEquals("user@openbas.io", argument.getValue().getHeader("From")[0]); - assertEquals("user-reply-to@openbas.io", argument.getValue().getHeader("Reply-To")[0]); - } + @Mock private JavaMailSender emailSender; + @InjectMocks private EmailService emailService; + + @Test + void shouldSetReplyToInHeaderEqualsToFrom() throws Exception { + ArgumentCaptor argument = ArgumentCaptor.forClass(MimeMessage.class); + + Execution execution = new Execution(); + ExecutionContext userContext = new ExecutionContext(UserFixture.getSavedUser(), null); + + when(emailSender.createMimeMessage()).thenReturn(new MimeMessage((Session) null)); + emailService.sendEmail( + execution, + userContext, + "user@openbas.io", + List.of("user-reply-to@openbas.io"), + null, + false, + "subject", + "message", + Collections.emptyList()); + verify(emailSender).send(argument.capture()); + assertEquals("user@openbas.io", argument.getValue().getHeader("From")[0]); + assertEquals("user-reply-to@openbas.io", argument.getValue().getHeader("Reply-To")[0]); + } } diff --git a/openbas-api/src/test/java/io/openbas/service/ExerciseExpectationServiceTest.java b/openbas-api/src/test/java/io/openbas/service/ExerciseExpectationServiceTest.java index ec83dbfe50..88a5fdebe1 100644 --- a/openbas-api/src/test/java/io/openbas/service/ExerciseExpectationServiceTest.java +++ b/openbas-api/src/test/java/io/openbas/service/ExerciseExpectationServiceTest.java @@ -1,5 +1,10 @@ package io.openbas.service; +import static io.openbas.database.model.ExerciseStatus.SCHEDULED; +import static io.openbas.injectors.email.EmailContract.EMAIL_DEFAULT; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertNotNull; + import io.openbas.database.model.Exercise; import io.openbas.database.model.Inject; import io.openbas.database.model.InjectExpectation; @@ -7,41 +12,29 @@ import io.openbas.database.repository.*; import io.openbas.rest.exercise.form.ExpectationUpdateInput; import io.openbas.utils.fixtures.InjectExpectationFixture; +import java.time.Instant; +import java.util.List; import org.junit.jupiter.api.*; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.boot.test.context.SpringBootTest; -import java.time.Instant; -import java.util.List; - -import static io.openbas.database.model.ExerciseStatus.SCHEDULED; -import static io.openbas.database.model.InjectExpectation.EXPECTATION_TYPE.MANUAL; -import static io.openbas.injectors.email.EmailContract.EMAIL_DEFAULT; -import static org.junit.jupiter.api.Assertions.assertEquals; -import static org.junit.jupiter.api.Assertions.assertNotNull; - @SpringBootTest @TestInstance(TestInstance.Lifecycle.PER_CLASS) public class ExerciseExpectationServiceTest { - public static final String EXPECTATION_NAME = "The animation team can validate the audience reaction"; - @Autowired - private ExerciseExpectationService exerciseExpectationService; + public static final String EXPECTATION_NAME = + "The animation team can validate the audience reaction"; + @Autowired private ExerciseExpectationService exerciseExpectationService; - @Autowired - private ExerciseRepository exerciseRepository; + @Autowired private ExerciseRepository exerciseRepository; - @Autowired - private InjectRepository injectRepository; + @Autowired private InjectRepository injectRepository; - @Autowired - private TeamRepository teamRepository; + @Autowired private TeamRepository teamRepository; - @Autowired - private InjectExpectationRepository injectExpectationRepository; + @Autowired private InjectExpectationRepository injectExpectationRepository; - @Autowired - private InjectorContractRepository injectorContractRepository; + @Autowired private InjectorContractRepository injectorContractRepository; static String EXERCISE_ID; @@ -62,7 +55,8 @@ void afterAll() { @DisplayName("Retrieve inject expectations") @Test void retrieveInjectExpectations() { - List expectations = this.exerciseExpectationService.injectExpectations(EXERCISE_ID); + List expectations = + this.exerciseExpectationService.injectExpectations(EXERCISE_ID); assertNotNull(expectations); assertEquals(EXPECTATION_NAME, expectations.getFirst().getName()); @@ -72,14 +66,16 @@ void retrieveInjectExpectations() { @Test void updateInjectExpectation() { // -- PREPARE -- - List expectations = this.exerciseExpectationService.injectExpectations(EXERCISE_ID); + List expectations = + this.exerciseExpectationService.injectExpectations(EXERCISE_ID); assertNotNull(expectations); String id = expectations.getFirst().getId(); // -- EXECUTE -- ExpectationUpdateInput input = new ExpectationUpdateInput(); input.setScore(7.0); - InjectExpectation expectation = this.exerciseExpectationService.updateInjectExpectation(id, input); + InjectExpectation expectation = + this.exerciseExpectationService.updateInjectExpectation(id, input); // -- ASSERT -- assertNotNull(expectation); @@ -105,15 +101,17 @@ private Team getTeam() { private Inject getInject(Exercise exerciseCreated) { Inject inject = new Inject(); inject.setTitle("test"); - inject.setInjectorContract(this.injectorContractRepository.findById(EMAIL_DEFAULT).orElseThrow()); + inject.setInjectorContract( + this.injectorContractRepository.findById(EMAIL_DEFAULT).orElseThrow()); inject.setExercise(exerciseCreated); inject.setDependsDuration(0L); return this.injectRepository.save(inject); } - private void getInjectExpectation(Inject injectCreated, Team teamCreated, Exercise exerciseCreated) { + private void getInjectExpectation( + Inject injectCreated, Team teamCreated, Exercise exerciseCreated) { this.injectExpectationRepository.save( - InjectExpectationFixture.createManualInjectExpectationWithExercise(teamCreated, injectCreated, - exerciseCreated, EXPECTATION_NAME)); + InjectExpectationFixture.createManualInjectExpectationWithExercise( + teamCreated, injectCreated, exerciseCreated, EXPECTATION_NAME)); } } diff --git a/openbas-api/src/test/java/io/openbas/service/ExerciseServiceTest.java b/openbas-api/src/test/java/io/openbas/service/ExerciseServiceTest.java index c4ff3c65a2..1e4cbf47c6 100644 --- a/openbas-api/src/test/java/io/openbas/service/ExerciseServiceTest.java +++ b/openbas-api/src/test/java/io/openbas/service/ExerciseServiceTest.java @@ -1,5 +1,10 @@ package io.openbas.service; +import static io.openbas.utils.fixtures.ExerciseFixture.getExercise; +import static io.openbas.utils.fixtures.TeamFixture.getTeam; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertNotEquals; + import io.openbas.database.model.*; import io.openbas.database.repository.ArticleRepository; import io.openbas.database.repository.ExerciseRepository; @@ -9,6 +14,8 @@ import io.openbas.utils.ExerciseMapper; import io.openbas.utils.ResultUtils; import jakarta.transaction.Transactional; +import java.util.ArrayList; +import java.util.List; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.DisplayName; import org.junit.jupiter.api.Test; @@ -17,70 +24,65 @@ import org.springframework.beans.factory.annotation.Autowired; import org.springframework.boot.test.context.SpringBootTest; -import java.util.ArrayList; -import java.util.List; - -import static io.openbas.utils.fixtures.TeamFixture.getTeam; -import static io.openbas.utils.fixtures.ExerciseFixture.getExercise; -import static org.junit.jupiter.api.Assertions.assertEquals; -import static org.junit.jupiter.api.Assertions.assertNotEquals; - @SpringBootTest public class ExerciseServiceTest { - @Mock - GrantService grantService; - @Mock - InjectDuplicateService injectDuplicateService; - @Mock - VariableService variableService; - @Autowired - private TeamService teamService; + @Mock GrantService grantService; + @Mock InjectDuplicateService injectDuplicateService; + @Mock VariableService variableService; + @Autowired private TeamService teamService; + + @Autowired ExerciseMapper exerciseMapper; + @Autowired ResultUtils resultUtils; + @Autowired private ArticleRepository articleRepository; + @Autowired private ExerciseRepository exerciseRepository; + @Autowired private TeamRepository teamRepository; - @Autowired - ExerciseMapper exerciseMapper; - @Autowired - ResultUtils resultUtils; - @Autowired - private ArticleRepository articleRepository; - @Autowired - private ExerciseRepository exerciseRepository; - @Autowired - private TeamRepository teamRepository; + @InjectMocks private ExerciseService exerciseService; - @InjectMocks - private ExerciseService exerciseService; - @BeforeEach - void setUp() { - exerciseService = new ExerciseService(grantService, injectDuplicateService, - teamService,variableService, exerciseMapper, resultUtils, articleRepository, - exerciseRepository, teamRepository); - } + @BeforeEach + void setUp() { + exerciseService = + new ExerciseService( + grantService, + injectDuplicateService, + teamService, + variableService, + exerciseMapper, + resultUtils, + articleRepository, + exerciseRepository, + teamRepository); + } - @DisplayName("Should create new contextual teams while exercise duplication") - @Test - @Transactional(rollbackOn = Exception.class) - void createNewContextualTeamsWhileExerciseDuplication(){ - // -- PREPARE -- - List exerciseTeams = new ArrayList<>();; - Team contextualTeam = this.teamRepository.save(getTeam(null, "fakeTeamName1", true)); - exerciseTeams.add(contextualTeam); - Team noContextualTeam = this.teamRepository.save(getTeam(null, "fakeTeamName2",false)); - exerciseTeams.add(noContextualTeam); - Exercise exercise = this.exerciseRepository.save(getExercise(exerciseTeams)); + @DisplayName("Should create new contextual teams while exercise duplication") + @Test + @Transactional(rollbackOn = Exception.class) + void createNewContextualTeamsWhileExerciseDuplication() { + // -- PREPARE -- + List exerciseTeams = new ArrayList<>(); + ; + Team contextualTeam = this.teamRepository.save(getTeam(null, "fakeTeamName1", true)); + exerciseTeams.add(contextualTeam); + Team noContextualTeam = this.teamRepository.save(getTeam(null, "fakeTeamName2", false)); + exerciseTeams.add(noContextualTeam); + Exercise exercise = this.exerciseRepository.save(getExercise(exerciseTeams)); - // -- EXECUTE -- - Exercise exerciseDuplicated = exerciseService.getDuplicateExercise(exercise.getId()); + // -- EXECUTE -- + Exercise exerciseDuplicated = exerciseService.getDuplicateExercise(exercise.getId()); - // -- ASSERT -- - assertNotEquals(exercise.getId(), exerciseDuplicated.getId()); - assertEquals(2, exerciseDuplicated.getTeams().size()); - exerciseDuplicated.getTeams().forEach(team -> { - if (team.getContextual()){ + // -- ASSERT -- + assertNotEquals(exercise.getId(), exerciseDuplicated.getId()); + assertEquals(2, exerciseDuplicated.getTeams().size()); + exerciseDuplicated + .getTeams() + .forEach( + team -> { + if (team.getContextual()) { assertNotEquals(contextualTeam.getId(), team.getId()); assertEquals(contextualTeam.getName(), team.getName()); - } else { + } else { assertEquals(noContextualTeam.getId(), team.getId()); - } - }); - } + } + }); + } } diff --git a/openbas-api/src/test/java/io/openbas/service/InjectServiceTest.java b/openbas-api/src/test/java/io/openbas/service/InjectServiceTest.java index 418a245378..2467b48113 100644 --- a/openbas-api/src/test/java/io/openbas/service/InjectServiceTest.java +++ b/openbas-api/src/test/java/io/openbas/service/InjectServiceTest.java @@ -1,5 +1,9 @@ package io.openbas.service; +import static org.junit.jupiter.api.Assertions.*; +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.Mockito.*; + import com.fasterxml.jackson.core.JsonProcessingException; import com.fasterxml.jackson.databind.ObjectMapper; import com.fasterxml.jackson.databind.node.ObjectNode; @@ -14,6 +18,16 @@ import io.openbas.rest.scenario.response.ImportTestSummary; import io.openbas.utils.CustomMockMultipartFile; import jakarta.annotation.Resource; +import java.io.File; +import java.io.FileInputStream; +import java.io.IOException; +import java.io.InputStream; +import java.nio.file.Files; +import java.nio.file.Path; +import java.time.LocalDateTime; +import java.time.Month; +import java.time.ZoneOffset; +import java.util.*; import org.apache.commons.io.FilenameUtils; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.DisplayName; @@ -27,754 +41,800 @@ import org.springframework.mock.web.MockMultipartFile; import org.springframework.util.ResourceUtils; -import java.io.File; -import java.io.FileInputStream; -import java.io.IOException; -import java.io.InputStream; -import java.nio.file.Files; -import java.nio.file.Path; -import java.time.LocalDateTime; -import java.time.Month; -import java.time.ZoneOffset; -import java.util.*; - -import static org.junit.jupiter.api.Assertions.*; -import static org.mockito.ArgumentMatchers.any; -import static org.mockito.Mockito.*; - @ExtendWith(MockitoExtension.class) class InjectServiceTest { - @Mock - InjectRepository injectRepository; - @Mock - InjectDocumentRepository injectDocumentRepository; - @Mock - InjectExpectationRepository injectExpectationRepository; - @Mock - AssetRepository assetRepository; - @Mock - AssetGroupRepository assetGroupRepository; - @Mock - TeamRepository teamRepository; - @Mock - ScenarioTeamUserRepository scenarioTeamUserRepository; - @Mock - ExerciseTeamUserRepository exerciseTeamUserRepository; - @Mock - UserRepository userRepository; - @Mock - ImportMapperRepository importMapperRepository; - @InjectMocks - private InjectService injectService; - - private Scenario mockedScenario; - - private Exercise mockedExercise; - - private ImportMapper mockedImportMapper; - - private InjectsImportInput mockedInjectsImportInput; - @Resource - protected ObjectMapper mapper; - - @BeforeEach - void setUp() { - injectService = new InjectService(injectRepository, injectDocumentRepository, injectExpectationRepository, - assetRepository, assetGroupRepository, scenarioTeamUserRepository, exerciseTeamUserRepository, teamRepository, userRepository); - - mockedScenario = new Scenario(); - mockedExercise = new Exercise(); - mapper = new ObjectMapper(); - } - - @DisplayName("Post and store an XLS file") - @Test - void postAnXLSFile() throws Exception { - // -- PREPARE -- - // Getting a test file - File testFile = ResourceUtils.getFile("classpath:xls-test-files/test_file_1.xlsx"); - - InputStream in = new FileInputStream(testFile); - MockMultipartFile xlsFile = new MockMultipartFile("file", - "my-awesome-file.xls", - "application/xlsx", - in.readAllBytes()); - - ImportPostSummary response = injectService.storeXlsFileForImport(xlsFile); - - // -- ASSERT -- - assertNotNull(response); - try { - UUID.fromString(response.getImportId()); - } catch (Exception ex) { - fail(); - } - assertEquals(1, response.getAvailableSheets().size()); - assertEquals("CHECKLIST", response.getAvailableSheets().get(0)); + @Mock InjectRepository injectRepository; + @Mock InjectDocumentRepository injectDocumentRepository; + @Mock InjectExpectationRepository injectExpectationRepository; + @Mock AssetRepository assetRepository; + @Mock AssetGroupRepository assetGroupRepository; + @Mock TeamRepository teamRepository; + @Mock ScenarioTeamUserRepository scenarioTeamUserRepository; + @Mock ExerciseTeamUserRepository exerciseTeamUserRepository; + @Mock UserRepository userRepository; + @Mock ImportMapperRepository importMapperRepository; + @InjectMocks private InjectService injectService; + + private Scenario mockedScenario; + + private Exercise mockedExercise; + + private ImportMapper mockedImportMapper; + + private InjectsImportInput mockedInjectsImportInput; + @Resource protected ObjectMapper mapper; + + @BeforeEach + void setUp() { + injectService = + new InjectService( + injectRepository, + injectDocumentRepository, + injectExpectationRepository, + assetRepository, + assetGroupRepository, + scenarioTeamUserRepository, + exerciseTeamUserRepository, + teamRepository, + userRepository); + + mockedScenario = new Scenario(); + mockedExercise = new Exercise(); + mapper = new ObjectMapper(); + } + + @DisplayName("Post and store an XLS file") + @Test + void postAnXLSFile() throws Exception { + // -- PREPARE -- + // Getting a test file + File testFile = ResourceUtils.getFile("classpath:xls-test-files/test_file_1.xlsx"); + + InputStream in = new FileInputStream(testFile); + MockMultipartFile xlsFile = + new MockMultipartFile("file", "my-awesome-file.xls", "application/xlsx", in.readAllBytes()); + + ImportPostSummary response = injectService.storeXlsFileForImport(xlsFile); + + // -- ASSERT -- + assertNotNull(response); + try { + UUID.fromString(response.getImportId()); + } catch (Exception ex) { + fail(); } - - @DisplayName("Post and store a corrupted XLS file") - @Test - void postACorruptedXLSFile() throws Exception { - // Getting a test file - File testFile = ResourceUtils.getFile("classpath:xls-test-files/test_file_1.xlsx"); - // -- PREPARE -- - InputStream in = new FileInputStream(testFile); - MockMultipartFile xlsFile = new CustomMockMultipartFile("file", - "my-awesome-file.xls", - "application/xlsx", - in.readAllBytes()); - - // -- EXECUTE -- - try { - injectService.storeXlsFileForImport(xlsFile); - fail(); - } catch(Exception ex) { - assertTrue(ex instanceof BadRequestException); - } + assertEquals(1, response.getAvailableSheets().size()); + assertEquals("CHECKLIST", response.getAvailableSheets().get(0)); + } + + @DisplayName("Post and store a corrupted XLS file") + @Test + void postACorruptedXLSFile() throws Exception { + // Getting a test file + File testFile = ResourceUtils.getFile("classpath:xls-test-files/test_file_1.xlsx"); + // -- PREPARE -- + InputStream in = new FileInputStream(testFile); + MockMultipartFile xlsFile = + new CustomMockMultipartFile( + "file", "my-awesome-file.xls", "application/xlsx", in.readAllBytes()); + + // -- EXECUTE -- + try { + injectService.storeXlsFileForImport(xlsFile); + fail(); + } catch (Exception ex) { + assertTrue(ex instanceof BadRequestException); } - - @DisplayName("Import an XLS file with relative date") - @Test - void testImportXlsRelativeDate() throws IOException { - try (MockedStatic sessionHelper = Mockito.mockStatic(SessionHelper.class)) { - User mockedUser = new User(); - String fileID = UUID.randomUUID().toString(); - File testFile = ResourceUtils.getFile("classpath:xls-test-files/test_file_1.xlsx"); - createTempFile(testFile, fileID); - - mockedImportMapper = createImportMapper(UUID.randomUUID().toString()); - when(userRepository.findById(any())).thenReturn(Optional.of(mockedUser)); - Team team1 = new Team(); - team1.setName("team1"); - Team team2 = new Team(); - team2.setName("team2"); - when(teamRepository.findAll()).thenReturn(List.of(team1)); - when(teamRepository.save(any())).thenReturn(team2); - - mockedScenario.setId(UUID.randomUUID().toString()); - - sessionHelper.when(SessionHelper::currentUser).thenReturn(new OpenBASOAuth2User(mockedUser)); - ImportTestSummary importTestSummary = injectService.importInjectIntoScenarioFromXLS(mockedScenario, - mockedImportMapper, fileID, "CHECKLIST", 120, false); - - verify(teamRepository, times(1)).save(any()); - assertEquals(30 * 24 * 60 * 60, importTestSummary.getInjects().getLast().getDependsDuration()); - - ObjectNode jsonNodeMail = (ObjectNode) mapper.readTree("{\"message\":\"message1\",\"expectations\":[{\"expectation_description\":\"expectation\",\"expectation_name\":\"expectation done\",\"expectation_score\":100.0,\"expectation_type\":\"MANUAL\",\"expectation_expectation_group\":false}]}"); - assertEquals(jsonNodeMail, importTestSummary.getInjects().getFirst().getContent()); - - ObjectNode jsonNodeSms = (ObjectNode) mapper.readTree("{\"subject\":\"subject\",\"body\":\"message2\",\"expectations\":[{\"expectation_description\":\"expectation\",\"expectation_name\":\"expectation done\",\"expectation_score\":100.0,\"expectation_type\":\"MANUAL\",\"expectation_expectation_group\":false}]}"); - assertEquals(jsonNodeSms, importTestSummary.getInjects().getLast().getContent()); - } + } + + @DisplayName("Import an XLS file with relative date") + @Test + void testImportXlsRelativeDate() throws IOException { + try (MockedStatic sessionHelper = Mockito.mockStatic(SessionHelper.class)) { + User mockedUser = new User(); + String fileID = UUID.randomUUID().toString(); + File testFile = ResourceUtils.getFile("classpath:xls-test-files/test_file_1.xlsx"); + createTempFile(testFile, fileID); + + mockedImportMapper = createImportMapper(UUID.randomUUID().toString()); + when(userRepository.findById(any())).thenReturn(Optional.of(mockedUser)); + Team team1 = new Team(); + team1.setName("team1"); + Team team2 = new Team(); + team2.setName("team2"); + when(teamRepository.findAll()).thenReturn(List.of(team1)); + when(teamRepository.save(any())).thenReturn(team2); + + mockedScenario.setId(UUID.randomUUID().toString()); + + sessionHelper.when(SessionHelper::currentUser).thenReturn(new OpenBASOAuth2User(mockedUser)); + ImportTestSummary importTestSummary = + injectService.importInjectIntoScenarioFromXLS( + mockedScenario, mockedImportMapper, fileID, "CHECKLIST", 120, false); + + verify(teamRepository, times(1)).save(any()); + assertEquals( + 30 * 24 * 60 * 60, importTestSummary.getInjects().getLast().getDependsDuration()); + + ObjectNode jsonNodeMail = + (ObjectNode) + mapper.readTree( + "{\"message\":\"message1\",\"expectations\":[{\"expectation_description\":\"expectation\",\"expectation_name\":\"expectation done\",\"expectation_score\":100.0,\"expectation_type\":\"MANUAL\",\"expectation_expectation_group\":false}]}"); + assertEquals(jsonNodeMail, importTestSummary.getInjects().getFirst().getContent()); + + ObjectNode jsonNodeSms = + (ObjectNode) + mapper.readTree( + "{\"subject\":\"subject\",\"body\":\"message2\",\"expectations\":[{\"expectation_description\":\"expectation\",\"expectation_name\":\"expectation done\",\"expectation_score\":100.0,\"expectation_type\":\"MANUAL\",\"expectation_expectation_group\":false}]}"); + assertEquals(jsonNodeSms, importTestSummary.getInjects().getLast().getContent()); } - - @DisplayName("Import a non existing XLS file") - @Test - void testImportXlsBadFile() throws IOException { - try (MockedStatic sessionHelper = Mockito.mockStatic(SessionHelper.class)) { - String fileID = UUID.randomUUID().toString(); - - mockedImportMapper = createImportMapper(UUID.randomUUID().toString()); - try { - injectService.importInjectIntoScenarioFromXLS(mockedScenario, - mockedImportMapper, fileID, "CHECKLIST", 120, true); - fail(); - } catch (Exception ex) { - assertTrue(ex instanceof BadRequestException); - } - } + } + + @DisplayName("Import a non existing XLS file") + @Test + void testImportXlsBadFile() throws IOException { + try (MockedStatic sessionHelper = Mockito.mockStatic(SessionHelper.class)) { + String fileID = UUID.randomUUID().toString(); + + mockedImportMapper = createImportMapper(UUID.randomUUID().toString()); + try { + injectService.importInjectIntoScenarioFromXLS( + mockedScenario, mockedImportMapper, fileID, "CHECKLIST", 120, true); + fail(); + } catch (Exception ex) { + assertTrue(ex instanceof BadRequestException); + } } - - @DisplayName("Import an XLS file and have several matches of importer") - @Test - void testImportXlsSeveralMatches() throws IOException { - try (MockedStatic sessionHelper = Mockito.mockStatic(SessionHelper.class)) { - User mockedUser = new User(); - String fileID = UUID.randomUUID().toString(); - File testFile = ResourceUtils.getFile("classpath:xls-test-files/test_file_1.xlsx"); - createTempFile(testFile, fileID); - - mockedImportMapper = createImportMapper(UUID.randomUUID().toString()); - when(userRepository.findById(any())).thenReturn(Optional.of(mockedUser)); - Team team1 = new Team(); - team1.setName("team1"); - Team team2 = new Team(); - team2.setName("team2"); - when(teamRepository.findAll()).thenReturn(List.of(team1)); - lenient().when(teamRepository.save(any())).thenReturn(team2); - - sessionHelper.when(SessionHelper::currentUser).thenReturn(new OpenBASOAuth2User(mockedUser)); - - InjectImporter injectImporterMailCopy = new InjectImporter(); - injectImporterMailCopy.setId(UUID.randomUUID().toString()); - injectImporterMailCopy.setImportTypeValue(".*mail"); - injectImporterMailCopy.setRuleAttributes(new ArrayList<>()); - injectImporterMailCopy.setInjectorContract(createMailInjectorContract()); - - injectImporterMailCopy.getRuleAttributes().addAll(createRuleAttributeMail()); - mockedImportMapper.getInjectImporters().add(injectImporterMailCopy); - ImportTestSummary importTestSummary = - injectService.importInjectIntoScenarioFromXLS(mockedScenario, - mockedImportMapper, fileID, "CHECKLIST", 120, true); - assertTrue( - importTestSummary.getImportMessage().stream().anyMatch( - importMessage -> importMessage.getMessageLevel().equals(ImportMessage.MessageLevel.WARN) - && importMessage.getErrorCode().equals(ImportMessage.ErrorCode.SEVERAL_MATCHES) - ) - ); - } + } + + @DisplayName("Import an XLS file and have several matches of importer") + @Test + void testImportXlsSeveralMatches() throws IOException { + try (MockedStatic sessionHelper = Mockito.mockStatic(SessionHelper.class)) { + User mockedUser = new User(); + String fileID = UUID.randomUUID().toString(); + File testFile = ResourceUtils.getFile("classpath:xls-test-files/test_file_1.xlsx"); + createTempFile(testFile, fileID); + + mockedImportMapper = createImportMapper(UUID.randomUUID().toString()); + when(userRepository.findById(any())).thenReturn(Optional.of(mockedUser)); + Team team1 = new Team(); + team1.setName("team1"); + Team team2 = new Team(); + team2.setName("team2"); + when(teamRepository.findAll()).thenReturn(List.of(team1)); + lenient().when(teamRepository.save(any())).thenReturn(team2); + + sessionHelper.when(SessionHelper::currentUser).thenReturn(new OpenBASOAuth2User(mockedUser)); + + InjectImporter injectImporterMailCopy = new InjectImporter(); + injectImporterMailCopy.setId(UUID.randomUUID().toString()); + injectImporterMailCopy.setImportTypeValue(".*mail"); + injectImporterMailCopy.setRuleAttributes(new ArrayList<>()); + injectImporterMailCopy.setInjectorContract(createMailInjectorContract()); + + injectImporterMailCopy.getRuleAttributes().addAll(createRuleAttributeMail()); + mockedImportMapper.getInjectImporters().add(injectImporterMailCopy); + ImportTestSummary importTestSummary = + injectService.importInjectIntoScenarioFromXLS( + mockedScenario, mockedImportMapper, fileID, "CHECKLIST", 120, true); + assertTrue( + importTestSummary.getImportMessage().stream() + .anyMatch( + importMessage -> + importMessage.getMessageLevel().equals(ImportMessage.MessageLevel.WARN) + && importMessage + .getErrorCode() + .equals(ImportMessage.ErrorCode.SEVERAL_MATCHES))); } - - @DisplayName("Import an XLS file with absolute date") - @Test - void testImportXlsAbsoluteDate() throws IOException { - try (MockedStatic sessionHelper = Mockito.mockStatic(SessionHelper.class)) { - User mockedUser = new User(); - String fileID = UUID.randomUUID().toString(); - File testFile = ResourceUtils.getFile("classpath:xls-test-files/test_file_2.xlsx"); - createTempFile(testFile, fileID); - - mockedScenario = new Scenario(); - mockedScenario.setId(UUID.randomUUID().toString()); - - mockedImportMapper = createImportMapper(UUID.randomUUID().toString()); - mockedImportMapper.getInjectImporters().forEach(injectImporter -> { - injectImporter.setRuleAttributes(injectImporter.getRuleAttributes().stream() - .map(ruleAttribute -> { - if("trigger_time".equals(ruleAttribute.getName())) { - ruleAttribute.setAdditionalConfig(Map.of("timePattern", "dd/MM/yyyy HH'h'mm")); - } - return ruleAttribute; - }).toList() - ); - }); - when(userRepository.findById(any())).thenReturn(Optional.of(mockedUser)); - Team team1 = new Team(); - team1.setName("team1"); - team1.setUsers(List.of(new User())); - Team team2 = new Team(); - team2.setName("team2"); - team1.setUsers(List.of(new User())); - when(teamRepository.findAll()).thenReturn(List.of(team1)); - when(teamRepository.save(any())).thenReturn(team2); - - when(injectRepository.saveAll(any())).thenReturn(List.of(createNewInject(List.of(team1)), new Inject())); - - sessionHelper.when(SessionHelper::currentUser).thenReturn(new OpenBASOAuth2User(mockedUser)); - ImportTestSummary importTestSummary = - injectService.importInjectIntoScenarioFromXLS(mockedScenario, - mockedImportMapper, fileID, "CHECKLIST", 120, true); - - assertTrue(LocalDateTime.of(2024, Month.JUNE, 26, 0, 0) - .toInstant(ZoneOffset.of("Z")) - .equals(mockedScenario.getRecurrenceStart())); - assertTrue("0 0 7 * * *".equals(mockedScenario.getRecurrence())); - } + } + + @DisplayName("Import an XLS file with absolute date") + @Test + void testImportXlsAbsoluteDate() throws IOException { + try (MockedStatic sessionHelper = Mockito.mockStatic(SessionHelper.class)) { + User mockedUser = new User(); + String fileID = UUID.randomUUID().toString(); + File testFile = ResourceUtils.getFile("classpath:xls-test-files/test_file_2.xlsx"); + createTempFile(testFile, fileID); + + mockedScenario = new Scenario(); + mockedScenario.setId(UUID.randomUUID().toString()); + + mockedImportMapper = createImportMapper(UUID.randomUUID().toString()); + mockedImportMapper + .getInjectImporters() + .forEach( + injectImporter -> { + injectImporter.setRuleAttributes( + injectImporter.getRuleAttributes().stream() + .map( + ruleAttribute -> { + if ("trigger_time".equals(ruleAttribute.getName())) { + ruleAttribute.setAdditionalConfig( + Map.of("timePattern", "dd/MM/yyyy HH'h'mm")); + } + return ruleAttribute; + }) + .toList()); + }); + when(userRepository.findById(any())).thenReturn(Optional.of(mockedUser)); + Team team1 = new Team(); + team1.setName("team1"); + team1.setUsers(List.of(new User())); + Team team2 = new Team(); + team2.setName("team2"); + team1.setUsers(List.of(new User())); + when(teamRepository.findAll()).thenReturn(List.of(team1)); + when(teamRepository.save(any())).thenReturn(team2); + + when(injectRepository.saveAll(any())) + .thenReturn(List.of(createNewInject(List.of(team1)), new Inject())); + + sessionHelper.when(SessionHelper::currentUser).thenReturn(new OpenBASOAuth2User(mockedUser)); + ImportTestSummary importTestSummary = + injectService.importInjectIntoScenarioFromXLS( + mockedScenario, mockedImportMapper, fileID, "CHECKLIST", 120, true); + + assertTrue( + LocalDateTime.of(2024, Month.JUNE, 26, 0, 0) + .toInstant(ZoneOffset.of("Z")) + .equals(mockedScenario.getRecurrenceStart())); + assertTrue("0 0 7 * * *".equals(mockedScenario.getRecurrence())); } - - @DisplayName("Import an XLS file with absolute date") - @Test - void testImportXlsAbsoluteDateWithExistingScenarioTeamUser() throws IOException { - try (MockedStatic sessionHelper = Mockito.mockStatic(SessionHelper.class)) { - User mockedUser = new User(); - String fileID = UUID.randomUUID().toString(); - File testFile = ResourceUtils.getFile("classpath:xls-test-files/test_file_2.xlsx"); - createTempFile(testFile, fileID); - - mockedScenario = new Scenario(); - mockedScenario.setId(UUID.randomUUID().toString()); - - mockedImportMapper = createImportMapper(UUID.randomUUID().toString()); - mockedImportMapper.getInjectImporters().forEach(injectImporter -> { - injectImporter.setRuleAttributes(injectImporter.getRuleAttributes().stream() - .map(ruleAttribute -> { - if("trigger_time".equals(ruleAttribute.getName())) { - ruleAttribute.setAdditionalConfig(Map.of("timePattern", "dd/MM/yyyy HH'h'mm")); - } - return ruleAttribute; - }).toList() - ); - }); - when(userRepository.findById(any())).thenReturn(Optional.of(mockedUser)); - Team team1 = new Team(); - team1.setName("team1"); - team1.setUsers(List.of(new User())); - Team team2 = new Team(); - team2.setName("team2"); - team1.setUsers(List.of(new User())); - when(scenarioTeamUserRepository.findById(any())) - .thenReturn(Optional.of(new ScenarioTeamUser())); - when(teamRepository.findAll()).thenReturn(List.of(team1)); - when(teamRepository.save(any())).thenReturn(team2); - - when(injectRepository.saveAll(any())).thenReturn(List.of(createNewInject(List.of(team1)), new Inject())); - - sessionHelper.when(SessionHelper::currentUser).thenReturn(new OpenBASOAuth2User(mockedUser)); - ImportTestSummary importTestSummary = - injectService.importInjectIntoScenarioFromXLS(mockedScenario, - mockedImportMapper, fileID, "CHECKLIST", 120, true); - - assertTrue(LocalDateTime.of(2024, Month.JUNE, 26, 0, 0) - .toInstant(ZoneOffset.of("Z")) - .equals(mockedScenario.getRecurrenceStart())); - assertTrue("0 0 7 * * *".equals(mockedScenario.getRecurrence())); - } + } + + @DisplayName("Import an XLS file with absolute date") + @Test + void testImportXlsAbsoluteDateWithExistingScenarioTeamUser() throws IOException { + try (MockedStatic sessionHelper = Mockito.mockStatic(SessionHelper.class)) { + User mockedUser = new User(); + String fileID = UUID.randomUUID().toString(); + File testFile = ResourceUtils.getFile("classpath:xls-test-files/test_file_2.xlsx"); + createTempFile(testFile, fileID); + + mockedScenario = new Scenario(); + mockedScenario.setId(UUID.randomUUID().toString()); + + mockedImportMapper = createImportMapper(UUID.randomUUID().toString()); + mockedImportMapper + .getInjectImporters() + .forEach( + injectImporter -> { + injectImporter.setRuleAttributes( + injectImporter.getRuleAttributes().stream() + .map( + ruleAttribute -> { + if ("trigger_time".equals(ruleAttribute.getName())) { + ruleAttribute.setAdditionalConfig( + Map.of("timePattern", "dd/MM/yyyy HH'h'mm")); + } + return ruleAttribute; + }) + .toList()); + }); + when(userRepository.findById(any())).thenReturn(Optional.of(mockedUser)); + Team team1 = new Team(); + team1.setName("team1"); + team1.setUsers(List.of(new User())); + Team team2 = new Team(); + team2.setName("team2"); + team1.setUsers(List.of(new User())); + when(scenarioTeamUserRepository.findById(any())) + .thenReturn(Optional.of(new ScenarioTeamUser())); + when(teamRepository.findAll()).thenReturn(List.of(team1)); + when(teamRepository.save(any())).thenReturn(team2); + + when(injectRepository.saveAll(any())) + .thenReturn(List.of(createNewInject(List.of(team1)), new Inject())); + + sessionHelper.when(SessionHelper::currentUser).thenReturn(new OpenBASOAuth2User(mockedUser)); + ImportTestSummary importTestSummary = + injectService.importInjectIntoScenarioFromXLS( + mockedScenario, mockedImportMapper, fileID, "CHECKLIST", 120, true); + + assertTrue( + LocalDateTime.of(2024, Month.JUNE, 26, 0, 0) + .toInstant(ZoneOffset.of("Z")) + .equals(mockedScenario.getRecurrenceStart())); + assertTrue("0 0 7 * * *".equals(mockedScenario.getRecurrence())); } - - @DisplayName("Import an XLS file with relative and absolute dates") - @Test - void testImportXlsAbsoluteAndRelativeDates() throws IOException { - try (MockedStatic sessionHelper = Mockito.mockStatic(SessionHelper.class)) { - User mockedUser = new User(); - String fileID = UUID.randomUUID().toString(); - File testFile = ResourceUtils.getFile("classpath:xls-test-files/test_file_3.xlsx"); - createTempFile(testFile, fileID); - - mockedScenario = new Scenario(); - mockedScenario.setId(UUID.randomUUID().toString()); - - mockedImportMapper = createImportMapper(UUID.randomUUID().toString()); - mockedImportMapper.getInjectImporters().forEach(injectImporter -> { - injectImporter.setRuleAttributes(injectImporter.getRuleAttributes().stream() - .map(ruleAttribute -> { - if("trigger_time".equals(ruleAttribute.getName())) { - ruleAttribute.setAdditionalConfig(Map.of("timePattern", "dd/MM/yyyy HH'h'mm")); - } - return ruleAttribute; - }).toList() - ); - }); - when(userRepository.findById(any())).thenReturn(Optional.of(mockedUser)); - Team team1 = new Team(); - team1.setName("team1"); - Team team2 = new Team(); - team2.setName("team2"); - when(teamRepository.findAll()).thenReturn(List.of(team1)); - when(teamRepository.save(any())).thenReturn(team2); - - sessionHelper.when(SessionHelper::currentUser).thenReturn(new OpenBASOAuth2User(mockedUser)); - ImportTestSummary importTestSummary = - injectService.importInjectIntoScenarioFromXLS(mockedScenario, - mockedImportMapper, fileID, "CHECKLIST", 120, false); - - List sortedInjects = importTestSummary.getInjects().stream() - .sorted(Comparator.comparing(Inject::getDependsDuration)) - .toList(); - - assertEquals(24 * 60 * 60, sortedInjects.get(1).getDependsDuration()); - assertEquals(24 * 60 * 60 + 5 * 60, sortedInjects.get(2).getDependsDuration()); - assertEquals(2 * 24 * 60 * 60, sortedInjects.get(3).getDependsDuration()); - } + } + + @DisplayName("Import an XLS file with relative and absolute dates") + @Test + void testImportXlsAbsoluteAndRelativeDates() throws IOException { + try (MockedStatic sessionHelper = Mockito.mockStatic(SessionHelper.class)) { + User mockedUser = new User(); + String fileID = UUID.randomUUID().toString(); + File testFile = ResourceUtils.getFile("classpath:xls-test-files/test_file_3.xlsx"); + createTempFile(testFile, fileID); + + mockedScenario = new Scenario(); + mockedScenario.setId(UUID.randomUUID().toString()); + + mockedImportMapper = createImportMapper(UUID.randomUUID().toString()); + mockedImportMapper + .getInjectImporters() + .forEach( + injectImporter -> { + injectImporter.setRuleAttributes( + injectImporter.getRuleAttributes().stream() + .map( + ruleAttribute -> { + if ("trigger_time".equals(ruleAttribute.getName())) { + ruleAttribute.setAdditionalConfig( + Map.of("timePattern", "dd/MM/yyyy HH'h'mm")); + } + return ruleAttribute; + }) + .toList()); + }); + when(userRepository.findById(any())).thenReturn(Optional.of(mockedUser)); + Team team1 = new Team(); + team1.setName("team1"); + Team team2 = new Team(); + team2.setName("team2"); + when(teamRepository.findAll()).thenReturn(List.of(team1)); + when(teamRepository.save(any())).thenReturn(team2); + + sessionHelper.when(SessionHelper::currentUser).thenReturn(new OpenBASOAuth2User(mockedUser)); + ImportTestSummary importTestSummary = + injectService.importInjectIntoScenarioFromXLS( + mockedScenario, mockedImportMapper, fileID, "CHECKLIST", 120, false); + + List sortedInjects = + importTestSummary.getInjects().stream() + .sorted(Comparator.comparing(Inject::getDependsDuration)) + .toList(); + + assertEquals(24 * 60 * 60, sortedInjects.get(1).getDependsDuration()); + assertEquals(24 * 60 * 60 + 5 * 60, sortedInjects.get(2).getDependsDuration()); + assertEquals(2 * 24 * 60 * 60, sortedInjects.get(3).getDependsDuration()); } - - @DisplayName("Import an XLS file with relative dates and absolute hours") - @Test - void testImportXlsRelativeDatesAndAbsoluteHour() throws IOException { - try (MockedStatic sessionHelper = Mockito.mockStatic(SessionHelper.class)) { - User mockedUser = new User(); - String fileID = UUID.randomUUID().toString(); - File testFile = ResourceUtils.getFile("classpath:xls-test-files/test_file_4.xlsx"); - createTempFile(testFile, fileID); - - mockedScenario.setId(UUID.randomUUID().toString()); - mockedScenario.setRecurrenceStart(LocalDateTime.of(2024, Month.JUNE, 26, 0, 0) - .toInstant(ZoneOffset.of("Z"))); - - mockedImportMapper = createImportMapper(UUID.randomUUID().toString()); - mockedImportMapper.getInjectImporters().forEach(injectImporter -> { - injectImporter.setRuleAttributes(injectImporter.getRuleAttributes().stream() - .map(ruleAttribute -> { - if("trigger_time".equals(ruleAttribute.getName())) { + } + + @DisplayName("Import an XLS file with relative dates and absolute hours") + @Test + void testImportXlsRelativeDatesAndAbsoluteHour() throws IOException { + try (MockedStatic sessionHelper = Mockito.mockStatic(SessionHelper.class)) { + User mockedUser = new User(); + String fileID = UUID.randomUUID().toString(); + File testFile = ResourceUtils.getFile("classpath:xls-test-files/test_file_4.xlsx"); + createTempFile(testFile, fileID); + + mockedScenario.setId(UUID.randomUUID().toString()); + mockedScenario.setRecurrenceStart( + LocalDateTime.of(2024, Month.JUNE, 26, 0, 0).toInstant(ZoneOffset.of("Z"))); + + mockedImportMapper = createImportMapper(UUID.randomUUID().toString()); + mockedImportMapper + .getInjectImporters() + .forEach( + injectImporter -> { + injectImporter.setRuleAttributes( + injectImporter.getRuleAttributes().stream() + .map( + ruleAttribute -> { + if ("trigger_time".equals(ruleAttribute.getName())) { ruleAttribute.setAdditionalConfig(Map.of("timePattern", "HH'h'mm")); - } - return ruleAttribute; - }).toList() - ); - }); - when(userRepository.findById(any())).thenReturn(Optional.of(mockedUser)); - Team team1 = new Team(); - team1.setName("team1"); - Team team2 = new Team(); - team2.setName("team2"); - when(teamRepository.findAll()).thenReturn(List.of(team1)); - when(teamRepository.save(any())).thenReturn(team2); - - sessionHelper.when(SessionHelper::currentUser).thenReturn(new OpenBASOAuth2User(mockedUser)); - ImportTestSummary importTestSummary = - injectService.importInjectIntoScenarioFromXLS(mockedScenario, - mockedImportMapper, fileID, "CHECKLIST", 120, false); - - List sortedInjects = importTestSummary.getInjects().stream() - .sorted(Comparator.comparing(Inject::getDependsDuration)) - .toList(); - - assertEquals(24 * 60 * 60, sortedInjects.get(1).getDependsDuration()); - assertEquals(2 * 24 * 60 * 60, sortedInjects.get(2).getDependsDuration()); - assertEquals(4 * 24 * 60 * 60 + 5 * 60, sortedInjects.get(3).getDependsDuration()); - } + } + return ruleAttribute; + }) + .toList()); + }); + when(userRepository.findById(any())).thenReturn(Optional.of(mockedUser)); + Team team1 = new Team(); + team1.setName("team1"); + Team team2 = new Team(); + team2.setName("team2"); + when(teamRepository.findAll()).thenReturn(List.of(team1)); + when(teamRepository.save(any())).thenReturn(team2); + + sessionHelper.when(SessionHelper::currentUser).thenReturn(new OpenBASOAuth2User(mockedUser)); + ImportTestSummary importTestSummary = + injectService.importInjectIntoScenarioFromXLS( + mockedScenario, mockedImportMapper, fileID, "CHECKLIST", 120, false); + + List sortedInjects = + importTestSummary.getInjects().stream() + .sorted(Comparator.comparing(Inject::getDependsDuration)) + .toList(); + + assertEquals(24 * 60 * 60, sortedInjects.get(1).getDependsDuration()); + assertEquals(2 * 24 * 60 * 60, sortedInjects.get(2).getDependsDuration()); + assertEquals(4 * 24 * 60 * 60 + 5 * 60, sortedInjects.get(3).getDependsDuration()); } - - @DisplayName("Critical message when import an XLS file with relative dates " + - "and absolute hours but no date in scenario") - @Test - void testImportXlsRelativeDatesAndAbsoluteHourCriticalMessage() throws IOException { - try (MockedStatic sessionHelper = Mockito.mockStatic(SessionHelper.class)) { - User mockedUser = new User(); - String fileID = UUID.randomUUID().toString(); - File testFile = ResourceUtils.getFile("classpath:xls-test-files/test_file_4.xlsx"); - createTempFile(testFile, fileID); - - mockedScenario = new Scenario(); - mockedScenario.setId(UUID.randomUUID().toString()); - - mockedImportMapper = createImportMapper(UUID.randomUUID().toString()); - mockedImportMapper.getInjectImporters().forEach(injectImporter -> { - injectImporter.setRuleAttributes(injectImporter.getRuleAttributes().stream() - .map(ruleAttribute -> { - if("trigger_time".equals(ruleAttribute.getName())) { + } + + @DisplayName( + "Critical message when import an XLS file with relative dates " + + "and absolute hours but no date in scenario") + @Test + void testImportXlsRelativeDatesAndAbsoluteHourCriticalMessage() throws IOException { + try (MockedStatic sessionHelper = Mockito.mockStatic(SessionHelper.class)) { + User mockedUser = new User(); + String fileID = UUID.randomUUID().toString(); + File testFile = ResourceUtils.getFile("classpath:xls-test-files/test_file_4.xlsx"); + createTempFile(testFile, fileID); + + mockedScenario = new Scenario(); + mockedScenario.setId(UUID.randomUUID().toString()); + + mockedImportMapper = createImportMapper(UUID.randomUUID().toString()); + mockedImportMapper + .getInjectImporters() + .forEach( + injectImporter -> { + injectImporter.setRuleAttributes( + injectImporter.getRuleAttributes().stream() + .map( + ruleAttribute -> { + if ("trigger_time".equals(ruleAttribute.getName())) { ruleAttribute.setAdditionalConfig(Map.of("timePattern", "HH'h'mm")); - } - return ruleAttribute; - }).toList() - ); - }); - when(userRepository.findById(any())).thenReturn(Optional.of(mockedUser)); - Team team1 = new Team(); - team1.setName("team1"); - Team team2 = new Team(); - team2.setName("team2"); - when(teamRepository.findAll()).thenReturn(List.of(team1)); - when(teamRepository.save(any())).thenReturn(team2); - - sessionHelper.when(SessionHelper::currentUser).thenReturn(new OpenBASOAuth2User(mockedUser)); - ImportTestSummary importTestSummary = - injectService.importInjectIntoScenarioFromXLS(mockedScenario, - mockedImportMapper, fileID, "CHECKLIST", 120, true); - - assertTrue(importTestSummary.getImportMessage().stream().anyMatch( - importMessage -> ImportMessage.MessageLevel.CRITICAL.equals(importMessage.getMessageLevel()) - && ImportMessage.ErrorCode.ABSOLUTE_TIME_WITHOUT_START_DATE.equals(importMessage.getErrorCode()) - )); - } + } + return ruleAttribute; + }) + .toList()); + }); + when(userRepository.findById(any())).thenReturn(Optional.of(mockedUser)); + Team team1 = new Team(); + team1.setName("team1"); + Team team2 = new Team(); + team2.setName("team2"); + when(teamRepository.findAll()).thenReturn(List.of(team1)); + when(teamRepository.save(any())).thenReturn(team2); + + sessionHelper.when(SessionHelper::currentUser).thenReturn(new OpenBASOAuth2User(mockedUser)); + ImportTestSummary importTestSummary = + injectService.importInjectIntoScenarioFromXLS( + mockedScenario, mockedImportMapper, fileID, "CHECKLIST", 120, true); + + assertTrue( + importTestSummary.getImportMessage().stream() + .anyMatch( + importMessage -> + ImportMessage.MessageLevel.CRITICAL.equals(importMessage.getMessageLevel()) + && ImportMessage.ErrorCode.ABSOLUTE_TIME_WITHOUT_START_DATE.equals( + importMessage.getErrorCode()))); } - - @DisplayName("Import an XLS file with relative dates, hours and minutes") - @Test - void testImportXlsRelativeDatesHoursAndMinutes() throws IOException { - try (MockedStatic sessionHelper = Mockito.mockStatic(SessionHelper.class)) { - User mockedUser = new User(); - String fileID = UUID.randomUUID().toString(); - File testFile = ResourceUtils.getFile("classpath:xls-test-files/test_file_5.xlsx"); - createTempFile(testFile, fileID); - mockedInjectsImportInput = new InjectsImportInput(); - mockedInjectsImportInput.setImportMapperId(fileID); - mockedInjectsImportInput.setName("CHECKLIST"); - mockedInjectsImportInput.setTimezoneOffset(120); - - mockedScenario = new Scenario(); - - mockedImportMapper = createImportMapper(UUID.randomUUID().toString()); - when(userRepository.findById(any())).thenReturn(Optional.of(mockedUser)); - Team team1 = new Team(); - team1.setName("team1"); - Team team2 = new Team(); - team2.setName("team2"); - when(teamRepository.findAll()).thenReturn(List.of(team1)); - when(teamRepository.save(any())).thenReturn(team2); - - sessionHelper.when(SessionHelper::currentUser).thenReturn(new OpenBASOAuth2User(mockedUser)); - ImportTestSummary importTestSummary = - injectService.importInjectIntoScenarioFromXLS(mockedScenario, - mockedImportMapper, fileID, "CHECKLIST", 120, false); - - List sortedInjects = importTestSummary.getInjects().stream() - .sorted(Comparator.comparing(Inject::getDependsDuration)) - .toList(); - - assertEquals(24 * 60 * 60, sortedInjects.get(1).getDependsDuration()); - assertEquals(((((2 * 24) + 2) * 60) - 5) * 60, sortedInjects.get(2).getDependsDuration()); - assertEquals(4 * 24 * 60 * 60, sortedInjects.get(3).getDependsDuration()); - } + } + + @DisplayName("Import an XLS file with relative dates, hours and minutes") + @Test + void testImportXlsRelativeDatesHoursAndMinutes() throws IOException { + try (MockedStatic sessionHelper = Mockito.mockStatic(SessionHelper.class)) { + User mockedUser = new User(); + String fileID = UUID.randomUUID().toString(); + File testFile = ResourceUtils.getFile("classpath:xls-test-files/test_file_5.xlsx"); + createTempFile(testFile, fileID); + mockedInjectsImportInput = new InjectsImportInput(); + mockedInjectsImportInput.setImportMapperId(fileID); + mockedInjectsImportInput.setName("CHECKLIST"); + mockedInjectsImportInput.setTimezoneOffset(120); + + mockedScenario = new Scenario(); + + mockedImportMapper = createImportMapper(UUID.randomUUID().toString()); + when(userRepository.findById(any())).thenReturn(Optional.of(mockedUser)); + Team team1 = new Team(); + team1.setName("team1"); + Team team2 = new Team(); + team2.setName("team2"); + when(teamRepository.findAll()).thenReturn(List.of(team1)); + when(teamRepository.save(any())).thenReturn(team2); + + sessionHelper.when(SessionHelper::currentUser).thenReturn(new OpenBASOAuth2User(mockedUser)); + ImportTestSummary importTestSummary = + injectService.importInjectIntoScenarioFromXLS( + mockedScenario, mockedImportMapper, fileID, "CHECKLIST", 120, false); + + List sortedInjects = + importTestSummary.getInjects().stream() + .sorted(Comparator.comparing(Inject::getDependsDuration)) + .toList(); + + assertEquals(24 * 60 * 60, sortedInjects.get(1).getDependsDuration()); + assertEquals(((((2 * 24) + 2) * 60) - 5) * 60, sortedInjects.get(2).getDependsDuration()); + assertEquals(4 * 24 * 60 * 60, sortedInjects.get(3).getDependsDuration()); } - - @DisplayName("Import an XLS file with default values") - @Test - void testImportXlsDefaultValue() throws IOException { - try (MockedStatic sessionHelper = Mockito.mockStatic(SessionHelper.class)) { - User mockedUser = new User(); - String fileID = UUID.randomUUID().toString(); - File testFile = ResourceUtils.getFile("classpath:xls-test-files/test_file_5.xlsx"); - createTempFile(testFile, fileID); - - mockedScenario = new Scenario(); - mockedScenario.setId(UUID.randomUUID().toString()); - - mockedImportMapper = createImportMapper(UUID.randomUUID().toString()); - mockedImportMapper.getInjectImporters().forEach(injectImporter -> { - injectImporter.setRuleAttributes(injectImporter.getRuleAttributes().stream() - .map(ruleAttribute -> { - if("title".equals(ruleAttribute.getName()) - || "trigger_time".equals(ruleAttribute.getName())) { + } + + @DisplayName("Import an XLS file with default values") + @Test + void testImportXlsDefaultValue() throws IOException { + try (MockedStatic sessionHelper = Mockito.mockStatic(SessionHelper.class)) { + User mockedUser = new User(); + String fileID = UUID.randomUUID().toString(); + File testFile = ResourceUtils.getFile("classpath:xls-test-files/test_file_5.xlsx"); + createTempFile(testFile, fileID); + + mockedScenario = new Scenario(); + mockedScenario.setId(UUID.randomUUID().toString()); + + mockedImportMapper = createImportMapper(UUID.randomUUID().toString()); + mockedImportMapper + .getInjectImporters() + .forEach( + injectImporter -> { + injectImporter.setRuleAttributes( + injectImporter.getRuleAttributes().stream() + .map( + ruleAttribute -> { + if ("title".equals(ruleAttribute.getName()) + || "trigger_time".equals(ruleAttribute.getName())) { ruleAttribute.setColumns("A"); - } - return ruleAttribute; - }).toList() - ); - }); - when(userRepository.findById(any())).thenReturn(Optional.of(mockedUser)); - Team team1 = new Team(); - team1.setName("team1"); - Team team2 = new Team(); - team2.setName("team2"); - when(teamRepository.findAll()).thenReturn(List.of(team1)); - when(teamRepository.save(any())).thenReturn(team2); - - sessionHelper.when(SessionHelper::currentUser).thenReturn(new OpenBASOAuth2User(mockedUser)); - ImportTestSummary importTestSummary = - injectService.importInjectIntoScenarioFromXLS(mockedScenario, - mockedImportMapper, fileID, "CHECKLIST", 120, false); - - assertSame("title", importTestSummary.getInjects().getFirst().getTitle()); - } - } - - @DisplayName("Import an XLS file in an exercise") - @Test - void testImportXlsWithExercise() throws IOException { - try (MockedStatic sessionHelper = Mockito.mockStatic(SessionHelper.class)) { - User mockedUser = new User(); - String fileID = UUID.randomUUID().toString(); - File testFile = ResourceUtils.getFile("classpath:xls-test-files/test_file_2.xlsx"); - createTempFile(testFile, fileID); - - mockedExercise = new Exercise(); - mockedExercise.setId(UUID.randomUUID().toString()); - - mockedImportMapper = createImportMapper(UUID.randomUUID().toString()); - mockedImportMapper.getInjectImporters().forEach(injectImporter -> { - injectImporter.setRuleAttributes(injectImporter.getRuleAttributes().stream() - .map(ruleAttribute -> { - if("trigger_time".equals(ruleAttribute.getName())) { - ruleAttribute.setAdditionalConfig(Map.of("timePattern", "dd/MM/yyyy HH'h'mm")); - } - return ruleAttribute; - }).toList() - ); - }); - when(userRepository.findById(any())).thenReturn(Optional.of(mockedUser)); - Team team1 = new Team(); - team1.setName("team1"); - team1.setUsers(List.of(new User())); - Team team2 = new Team(); - team2.setName("team2"); - team1.setUsers(List.of(new User())); - when(teamRepository.findAll()).thenReturn(List.of(team1)); - when(teamRepository.save(any())).thenReturn(team2); - - when(injectRepository.saveAll(any())).thenReturn(List.of(createNewInject(List.of(team1)), new Inject())); - - sessionHelper.when(SessionHelper::currentUser).thenReturn(new OpenBASOAuth2User(mockedUser)); - ImportTestSummary importTestSummary = - injectService.importInjectIntoExerciseFromXLS(mockedExercise, - mockedImportMapper, fileID, "CHECKLIST", 120, true); - - assertTrue(LocalDateTime.of(2024, Month.JUNE, 26, 0, 0) - .toInstant(ZoneOffset.of("Z")) - .equals(mockedExercise.getStart().get())); - } - } - - private void createTempFile(File testFile, String fileID) throws IOException { - InputStream in = new FileInputStream(testFile); - MockMultipartFile file = new MockMultipartFile("file", - "my-awesome-file.xls", - "application/xlsx", - in.readAllBytes()); - - // Writing the file in a temp dir - Path tempDir = Files.createDirectory(Path.of(System.getProperty("java.io.tmpdir"), fileID)); - Path tempFile = Files.createTempFile(tempDir, null, "." + FilenameUtils.getExtension(file.getOriginalFilename())); - Files.write(tempFile, file.getBytes()); - - // We're making sure the files are deleted when the test stops - tempDir.toFile().deleteOnExit(); - tempFile.toFile().deleteOnExit(); - } - - private ImportMapper createImportMapper(String id) throws JsonProcessingException { - ImportMapper importMapper = new ImportMapper(); - importMapper.setName("test import mapper"); - importMapper.setId(id); - importMapper.setInjectTypeColumn("B"); - importMapper.setInjectImporters(new ArrayList<>()); - - InjectImporter injectImporterSms = new InjectImporter(); - injectImporterSms.setId(UUID.randomUUID().toString()); - injectImporterSms.setImportTypeValue(".*(sms|SMS).*"); - injectImporterSms.setRuleAttributes(new ArrayList<>()); - injectImporterSms.setInjectorContract(createSmsInjectorContract()); - - injectImporterSms.getRuleAttributes().addAll(createRuleAttributeSms()); - - InjectImporter injectImporterMail = new InjectImporter(); - injectImporterMail.setId(UUID.randomUUID().toString()); - injectImporterMail.setImportTypeValue(".*mail.*"); - injectImporterMail.setRuleAttributes(new ArrayList<>()); - injectImporterMail.setInjectorContract(createMailInjectorContract()); - - injectImporterMail.getRuleAttributes().addAll(createRuleAttributeMail()); - - importMapper.getInjectImporters().add(injectImporterSms); - importMapper.getInjectImporters().add(injectImporterMail); - - return importMapper; - } - - private InjectorContract createSmsInjectorContract() throws JsonProcessingException { - InjectorContract injectorContract = new InjectorContract(); - ObjectNode jsonNode = (ObjectNode) mapper.readTree("{\"config\":{\"type\":\"openbas_ovh_sms\",\"expose\":true,\"label\":{\"en\":\"SMS (OVH)\"},\"color_dark\":\"#9c27b0\",\"color_light\":\"#9c27b0\"},\"label\":{\"en\":\"Send a SMS\",\"fr\":\"Envoyer un SMS\"},\"manual\":false,\"fields\":[{\"key\":\"teams\",\"label\":\"Teams\",\"mandatory\":true,\"readOnly\":false,\"mandatoryGroups\":null,\"linkedFields\":[],\"linkedValues\":[],\"cardinality\":\"n\",\"defaultValue\":[],\"type\":\"team\"},{\"key\":\"message\",\"label\":\"Message\",\"mandatory\":true,\"readOnly\":false,\"mandatoryGroups\":null,\"linkedFields\":[],\"linkedValues\":[],\"defaultValue\":\"\",\"richText\":false,\"type\":\"textarea\"},{\"key\":\"expectations\",\"label\":\"Expectations\",\"mandatory\":false,\"readOnly\":false,\"mandatoryGroups\":null,\"linkedFields\":[],\"linkedValues\":[],\"cardinality\":\"n\",\"defaultValue\":[],\"predefinedExpectations\":[],\"type\":\"expectation\"}],\"variables\":[{\"key\":\"user\",\"label\":\"User that will receive the injection\",\"type\":\"String\",\"cardinality\":\"1\",\"children\":[{\"key\":\"user.id\",\"label\":\"Id of the user in the platform\",\"type\":\"String\",\"cardinality\":\"1\",\"children\":[]},{\"key\":\"user.email\",\"label\":\"Email of the user\",\"type\":\"String\",\"cardinality\":\"1\",\"children\":[]},{\"key\":\"user.firstname\",\"label\":\"Firstname of the user\",\"type\":\"String\",\"cardinality\":\"1\",\"children\":[]},{\"key\":\"user.lastname\",\"label\":\"Lastname of the user\",\"type\":\"String\",\"cardinality\":\"1\",\"children\":[]},{\"key\":\"user.lang\",\"label\":\"Lang of the user\",\"type\":\"String\",\"cardinality\":\"1\",\"children\":[]}]},{\"key\":\"exercise\",\"label\":\"Exercise of the current injection\",\"type\":\"Object\",\"cardinality\":\"1\",\"children\":[{\"key\":\"exercise.id\",\"label\":\"Id of the user in the platform\",\"type\":\"String\",\"cardinality\":\"1\",\"children\":[]},{\"key\":\"exercise.name\",\"label\":\"Name of the exercise\",\"type\":\"String\",\"cardinality\":\"1\",\"children\":[]},{\"key\":\"exercise.description\",\"label\":\"Description of the exercise\",\"type\":\"String\",\"cardinality\":\"1\",\"children\":[]}]},{\"key\":\"teams\",\"label\":\"List of team name for the injection\",\"type\":\"String\",\"cardinality\":\"n\",\"children\":[]},{\"key\":\"player_uri\",\"label\":\"Player interface platform link\",\"type\":\"String\",\"cardinality\":\"1\",\"children\":[]},{\"key\":\"challenges_uri\",\"label\":\"Challenges interface platform link\",\"type\":\"String\",\"cardinality\":\"1\",\"children\":[]},{\"key\":\"scoreboard_uri\",\"label\":\"Scoreboard interface platform link\",\"type\":\"String\",\"cardinality\":\"1\",\"children\":[]},{\"key\":\"lessons_uri\",\"label\":\"Lessons learned interface platform link\",\"type\":\"String\",\"cardinality\":\"1\",\"children\":[]}],\"context\":{},\"contract_id\":\"e9e902bc-b03d-4223-89e1-fca093ac79dd\",\"contract_attack_patterns_external_ids\":[],\"is_atomic_testing\":true,\"needs_executor\":false,\"platforms\":[\"Service\"]}"); - injectorContract.setConvertedContent(jsonNode); - - return injectorContract; - } - - private InjectorContract createMailInjectorContract() throws JsonProcessingException { - InjectorContract injectorContract = new InjectorContract(); - ObjectNode jsonNode = (ObjectNode) mapper.readTree("{\"config\":{\"type\":\"openbas_email\",\"expose\":true,\"label\":{\"en\":\"Email\",\"fr\":\"Email\"},\"color_dark\":\"#cddc39\",\"color_light\":\"#cddc39\"},\"label\":{\"en\":\"Send individual mails\",\"fr\":\"Envoyer des mails individuels\"},\"manual\":false,\"fields\":[{\"key\":\"teams\",\"label\":\"Teams\",\"mandatory\":true,\"readOnly\":false,\"mandatoryGroups\":null,\"linkedFields\":[],\"linkedValues\":[],\"cardinality\":\"n\",\"defaultValue\":[],\"type\":\"team\"},{\"key\":\"subject\",\"label\":\"Subject\",\"mandatory\":true,\"readOnly\":false,\"mandatoryGroups\":null,\"linkedFields\":[],\"linkedValues\":[],\"defaultValue\":\"\",\"type\":\"text\"},{\"key\":\"body\",\"label\":\"Body\",\"mandatory\":true,\"readOnly\":false,\"mandatoryGroups\":null,\"linkedFields\":[],\"linkedValues\":[],\"defaultValue\":\"\",\"richText\":true,\"type\":\"textarea\"},{\"key\":\"encrypted\",\"label\":\"Encrypted\",\"mandatory\":false,\"readOnly\":false,\"mandatoryGroups\":null,\"linkedFields\":[],\"linkedValues\":[],\"defaultValue\":false,\"type\":\"checkbox\"},{\"key\":\"attachments\",\"label\":\"Attachments\",\"mandatory\":false,\"readOnly\":false,\"mandatoryGroups\":null,\"linkedFields\":[],\"linkedValues\":[],\"cardinality\":\"n\",\"defaultValue\":[],\"type\":\"attachment\"},{\"key\":\"expectations\",\"label\":\"Expectations\",\"mandatory\":false,\"readOnly\":false,\"mandatoryGroups\":null,\"linkedFields\":[],\"linkedValues\":[],\"cardinality\":\"n\",\"defaultValue\":[],\"predefinedExpectations\":[],\"type\":\"expectation\"}],\"variables\":[{\"key\":\"document_uri\",\"label\":\"Http user link to upload the document (only for document expectation)\",\"type\":\"String\",\"cardinality\":\"1\",\"children\":[]},{\"key\":\"user\",\"label\":\"User that will receive the injection\",\"type\":\"String\",\"cardinality\":\"1\",\"children\":[{\"key\":\"user.id\",\"label\":\"Id of the user in the platform\",\"type\":\"String\",\"cardinality\":\"1\",\"children\":[]},{\"key\":\"user.email\",\"label\":\"Email of the user\",\"type\":\"String\",\"cardinality\":\"1\",\"children\":[]},{\"key\":\"user.firstname\",\"label\":\"Firstname of the user\",\"type\":\"String\",\"cardinality\":\"1\",\"children\":[]},{\"key\":\"user.lastname\",\"label\":\"Lastname of the user\",\"type\":\"String\",\"cardinality\":\"1\",\"children\":[]},{\"key\":\"user.lang\",\"label\":\"Lang of the user\",\"type\":\"String\",\"cardinality\":\"1\",\"children\":[]}]},{\"key\":\"exercise\",\"label\":\"Exercise of the current injection\",\"type\":\"Object\",\"cardinality\":\"1\",\"children\":[{\"key\":\"exercise.id\",\"label\":\"Id of the user in the platform\",\"type\":\"String\",\"cardinality\":\"1\",\"children\":[]},{\"key\":\"exercise.name\",\"label\":\"Name of the exercise\",\"type\":\"String\",\"cardinality\":\"1\",\"children\":[]},{\"key\":\"exercise.description\",\"label\":\"Description of the exercise\",\"type\":\"String\",\"cardinality\":\"1\",\"children\":[]}]},{\"key\":\"teams\",\"label\":\"List of team name for the injection\",\"type\":\"String\",\"cardinality\":\"n\",\"children\":[]},{\"key\":\"player_uri\",\"label\":\"Player interface platform link\",\"type\":\"String\",\"cardinality\":\"1\",\"children\":[]},{\"key\":\"challenges_uri\",\"label\":\"Challenges interface platform link\",\"type\":\"String\",\"cardinality\":\"1\",\"children\":[]},{\"key\":\"scoreboard_uri\",\"label\":\"Scoreboard interface platform link\",\"type\":\"String\",\"cardinality\":\"1\",\"children\":[]},{\"key\":\"lessons_uri\",\"label\":\"Lessons learned interface platform link\",\"type\":\"String\",\"cardinality\":\"1\",\"children\":[]}],\"context\":{},\"contract_id\":\"138ad8f8-32f8-4a22-8114-aaa12322bd09\",\"contract_attack_patterns_external_ids\":[],\"is_atomic_testing\":true,\"needs_executor\":false,\"platforms\":[\"Service\"]}"); - injectorContract.setConvertedContent(jsonNode); - - return injectorContract; + } + return ruleAttribute; + }) + .toList()); + }); + when(userRepository.findById(any())).thenReturn(Optional.of(mockedUser)); + Team team1 = new Team(); + team1.setName("team1"); + Team team2 = new Team(); + team2.setName("team2"); + when(teamRepository.findAll()).thenReturn(List.of(team1)); + when(teamRepository.save(any())).thenReturn(team2); + + sessionHelper.when(SessionHelper::currentUser).thenReturn(new OpenBASOAuth2User(mockedUser)); + ImportTestSummary importTestSummary = + injectService.importInjectIntoScenarioFromXLS( + mockedScenario, mockedImportMapper, fileID, "CHECKLIST", 120, false); + + assertSame("title", importTestSummary.getInjects().getFirst().getTitle()); } - - private List createRuleAttributeSms() { - List results = new ArrayList<>(); - RuleAttribute ruleAttributeTitle = new RuleAttribute(); - ruleAttributeTitle.setName("title"); - ruleAttributeTitle.setColumns("B"); - ruleAttributeTitle.setDefaultValue("title"); - - RuleAttribute ruleAttributeDescription = new RuleAttribute(); - ruleAttributeDescription.setName("description"); - ruleAttributeDescription.setColumns("G"); - ruleAttributeDescription.setDefaultValue("description"); - - RuleAttribute ruleAttributeTriggerTime = new RuleAttribute(); - ruleAttributeTriggerTime.setName("trigger_time"); - ruleAttributeTriggerTime.setColumns("C"); - ruleAttributeTriggerTime.setDefaultValue("trigger_time"); - ruleAttributeTriggerTime.setAdditionalConfig(Map.of("timePattern", "")); - - RuleAttribute ruleAttributeMessage = new RuleAttribute(); - ruleAttributeMessage.setName("message"); - ruleAttributeMessage.setColumns("F"); - ruleAttributeMessage.setDefaultValue("message"); - - RuleAttribute ruleAttributeTeams = new RuleAttribute(); - ruleAttributeTeams.setName("teams"); - ruleAttributeTeams.setColumns("D"); - ruleAttributeTeams.setDefaultValue("teams"); - - RuleAttribute ruleAttributeExpectationScore = new RuleAttribute(); - ruleAttributeExpectationScore.setName("expectation_score"); - ruleAttributeExpectationScore.setColumns("J"); - ruleAttributeExpectationScore.setDefaultValue("500.0"); - - RuleAttribute ruleAttributeExpectationName = new RuleAttribute(); - ruleAttributeExpectationName.setName("expectation_name"); - ruleAttributeExpectationName.setColumns("I"); - ruleAttributeExpectationName.setDefaultValue("name"); - - RuleAttribute ruleAttributeExpectationDescription = new RuleAttribute(); - ruleAttributeExpectationDescription.setName("expectation_description"); - ruleAttributeExpectationDescription.setColumns("H"); - ruleAttributeExpectationDescription.setDefaultValue("description"); - - results.add(ruleAttributeTitle); - results.add(ruleAttributeDescription); - results.add(ruleAttributeTriggerTime); - results.add(ruleAttributeMessage); - results.add(ruleAttributeTeams); - results.add(ruleAttributeExpectationScore); - results.add(ruleAttributeExpectationName); - results.add(ruleAttributeExpectationDescription); - - return results; - } - - private List createRuleAttributeMail() { - List results = new ArrayList<>(); - RuleAttribute ruleAttributeTitle = new RuleAttribute(); - ruleAttributeTitle.setName("title"); - ruleAttributeTitle.setColumns("B"); - ruleAttributeTitle.setDefaultValue("title"); - - RuleAttribute ruleAttributeDescription = new RuleAttribute(); - ruleAttributeDescription.setName("description"); - ruleAttributeDescription.setColumns("G"); - ruleAttributeDescription.setDefaultValue("description"); - - RuleAttribute ruleAttributeTriggerTime = new RuleAttribute(); - ruleAttributeTriggerTime.setName("trigger_time"); - ruleAttributeTriggerTime.setColumns("C"); - ruleAttributeTriggerTime.setDefaultValue("trigger_time"); - ruleAttributeTriggerTime.setAdditionalConfig(Map.of("timePattern", "")); - - RuleAttribute ruleAttributeMessage = new RuleAttribute(); - ruleAttributeMessage.setName("subject"); - ruleAttributeMessage.setColumns("E"); - ruleAttributeMessage.setDefaultValue("subject"); - - RuleAttribute ruleAttributeSubject = new RuleAttribute(); - ruleAttributeSubject.setName("body"); - ruleAttributeSubject.setColumns("F"); - ruleAttributeSubject.setDefaultValue("body"); - - RuleAttribute ruleAttributeTeams = new RuleAttribute(); - ruleAttributeTeams.setName("teams"); - ruleAttributeTeams.setColumns("D"); - ruleAttributeTeams.setDefaultValue("teams"); - - RuleAttribute ruleAttributeExpectationScore = new RuleAttribute(); - ruleAttributeExpectationScore.setName("expectation_score"); - ruleAttributeExpectationScore.setColumns("J"); - ruleAttributeExpectationScore.setDefaultValue("500.0"); - - RuleAttribute ruleAttributeExpectationName = new RuleAttribute(); - ruleAttributeExpectationName.setName("expectation_name"); - ruleAttributeExpectationName.setColumns("I"); - ruleAttributeExpectationName.setDefaultValue("name"); - - RuleAttribute ruleAttributeExpectationDescription = new RuleAttribute(); - ruleAttributeExpectationDescription.setName("expectation_description"); - ruleAttributeExpectationDescription.setColumns("H"); - ruleAttributeExpectationDescription.setDefaultValue("description"); - - results.add(ruleAttributeTitle); - results.add(ruleAttributeDescription); - results.add(ruleAttributeTriggerTime); - results.add(ruleAttributeMessage); - results.add(ruleAttributeSubject); - results.add(ruleAttributeTeams); - results.add(ruleAttributeExpectationScore); - results.add(ruleAttributeExpectationName); - results.add(ruleAttributeExpectationDescription); - - return results; - } - - private Object deepCopy(Object objectToCopy, Class classToCopy) throws JsonProcessingException { - ObjectMapper objectMapper = new ObjectMapper(); - - return objectMapper - .readValue(objectMapper.writeValueAsString(objectToCopy), classToCopy); - } - - private Inject createNewInject(List teams) { - Inject inject = new Inject(); - inject.setTeams(teams); - inject.setId(UUID.randomUUID().toString()); - return inject; + } + + @DisplayName("Import an XLS file in an exercise") + @Test + void testImportXlsWithExercise() throws IOException { + try (MockedStatic sessionHelper = Mockito.mockStatic(SessionHelper.class)) { + User mockedUser = new User(); + String fileID = UUID.randomUUID().toString(); + File testFile = ResourceUtils.getFile("classpath:xls-test-files/test_file_2.xlsx"); + createTempFile(testFile, fileID); + + mockedExercise = new Exercise(); + mockedExercise.setId(UUID.randomUUID().toString()); + + mockedImportMapper = createImportMapper(UUID.randomUUID().toString()); + mockedImportMapper + .getInjectImporters() + .forEach( + injectImporter -> { + injectImporter.setRuleAttributes( + injectImporter.getRuleAttributes().stream() + .map( + ruleAttribute -> { + if ("trigger_time".equals(ruleAttribute.getName())) { + ruleAttribute.setAdditionalConfig( + Map.of("timePattern", "dd/MM/yyyy HH'h'mm")); + } + return ruleAttribute; + }) + .toList()); + }); + when(userRepository.findById(any())).thenReturn(Optional.of(mockedUser)); + Team team1 = new Team(); + team1.setName("team1"); + team1.setUsers(List.of(new User())); + Team team2 = new Team(); + team2.setName("team2"); + team1.setUsers(List.of(new User())); + when(teamRepository.findAll()).thenReturn(List.of(team1)); + when(teamRepository.save(any())).thenReturn(team2); + + when(injectRepository.saveAll(any())) + .thenReturn(List.of(createNewInject(List.of(team1)), new Inject())); + + sessionHelper.when(SessionHelper::currentUser).thenReturn(new OpenBASOAuth2User(mockedUser)); + ImportTestSummary importTestSummary = + injectService.importInjectIntoExerciseFromXLS( + mockedExercise, mockedImportMapper, fileID, "CHECKLIST", 120, true); + + assertTrue( + LocalDateTime.of(2024, Month.JUNE, 26, 0, 0) + .toInstant(ZoneOffset.of("Z")) + .equals(mockedExercise.getStart().get())); } + } + + private void createTempFile(File testFile, String fileID) throws IOException { + InputStream in = new FileInputStream(testFile); + MockMultipartFile file = + new MockMultipartFile("file", "my-awesome-file.xls", "application/xlsx", in.readAllBytes()); + + // Writing the file in a temp dir + Path tempDir = Files.createDirectory(Path.of(System.getProperty("java.io.tmpdir"), fileID)); + Path tempFile = + Files.createTempFile( + tempDir, null, "." + FilenameUtils.getExtension(file.getOriginalFilename())); + Files.write(tempFile, file.getBytes()); + + // We're making sure the files are deleted when the test stops + tempDir.toFile().deleteOnExit(); + tempFile.toFile().deleteOnExit(); + } + + private ImportMapper createImportMapper(String id) throws JsonProcessingException { + ImportMapper importMapper = new ImportMapper(); + importMapper.setName("test import mapper"); + importMapper.setId(id); + importMapper.setInjectTypeColumn("B"); + importMapper.setInjectImporters(new ArrayList<>()); + + InjectImporter injectImporterSms = new InjectImporter(); + injectImporterSms.setId(UUID.randomUUID().toString()); + injectImporterSms.setImportTypeValue(".*(sms|SMS).*"); + injectImporterSms.setRuleAttributes(new ArrayList<>()); + injectImporterSms.setInjectorContract(createSmsInjectorContract()); + + injectImporterSms.getRuleAttributes().addAll(createRuleAttributeSms()); + + InjectImporter injectImporterMail = new InjectImporter(); + injectImporterMail.setId(UUID.randomUUID().toString()); + injectImporterMail.setImportTypeValue(".*mail.*"); + injectImporterMail.setRuleAttributes(new ArrayList<>()); + injectImporterMail.setInjectorContract(createMailInjectorContract()); + + injectImporterMail.getRuleAttributes().addAll(createRuleAttributeMail()); + + importMapper.getInjectImporters().add(injectImporterSms); + importMapper.getInjectImporters().add(injectImporterMail); + + return importMapper; + } + + private InjectorContract createSmsInjectorContract() throws JsonProcessingException { + InjectorContract injectorContract = new InjectorContract(); + ObjectNode jsonNode = + (ObjectNode) + mapper.readTree( + "{\"config\":{\"type\":\"openbas_ovh_sms\",\"expose\":true,\"label\":{\"en\":\"SMS (OVH)\"},\"color_dark\":\"#9c27b0\",\"color_light\":\"#9c27b0\"},\"label\":{\"en\":\"Send a SMS\",\"fr\":\"Envoyer un SMS\"},\"manual\":false,\"fields\":[{\"key\":\"teams\",\"label\":\"Teams\",\"mandatory\":true,\"readOnly\":false,\"mandatoryGroups\":null,\"linkedFields\":[],\"linkedValues\":[],\"cardinality\":\"n\",\"defaultValue\":[],\"type\":\"team\"},{\"key\":\"message\",\"label\":\"Message\",\"mandatory\":true,\"readOnly\":false,\"mandatoryGroups\":null,\"linkedFields\":[],\"linkedValues\":[],\"defaultValue\":\"\",\"richText\":false,\"type\":\"textarea\"},{\"key\":\"expectations\",\"label\":\"Expectations\",\"mandatory\":false,\"readOnly\":false,\"mandatoryGroups\":null,\"linkedFields\":[],\"linkedValues\":[],\"cardinality\":\"n\",\"defaultValue\":[],\"predefinedExpectations\":[],\"type\":\"expectation\"}],\"variables\":[{\"key\":\"user\",\"label\":\"User that will receive the injection\",\"type\":\"String\",\"cardinality\":\"1\",\"children\":[{\"key\":\"user.id\",\"label\":\"Id of the user in the platform\",\"type\":\"String\",\"cardinality\":\"1\",\"children\":[]},{\"key\":\"user.email\",\"label\":\"Email of the user\",\"type\":\"String\",\"cardinality\":\"1\",\"children\":[]},{\"key\":\"user.firstname\",\"label\":\"Firstname of the user\",\"type\":\"String\",\"cardinality\":\"1\",\"children\":[]},{\"key\":\"user.lastname\",\"label\":\"Lastname of the user\",\"type\":\"String\",\"cardinality\":\"1\",\"children\":[]},{\"key\":\"user.lang\",\"label\":\"Lang of the user\",\"type\":\"String\",\"cardinality\":\"1\",\"children\":[]}]},{\"key\":\"exercise\",\"label\":\"Exercise of the current injection\",\"type\":\"Object\",\"cardinality\":\"1\",\"children\":[{\"key\":\"exercise.id\",\"label\":\"Id of the user in the platform\",\"type\":\"String\",\"cardinality\":\"1\",\"children\":[]},{\"key\":\"exercise.name\",\"label\":\"Name of the exercise\",\"type\":\"String\",\"cardinality\":\"1\",\"children\":[]},{\"key\":\"exercise.description\",\"label\":\"Description of the exercise\",\"type\":\"String\",\"cardinality\":\"1\",\"children\":[]}]},{\"key\":\"teams\",\"label\":\"List of team name for the injection\",\"type\":\"String\",\"cardinality\":\"n\",\"children\":[]},{\"key\":\"player_uri\",\"label\":\"Player interface platform link\",\"type\":\"String\",\"cardinality\":\"1\",\"children\":[]},{\"key\":\"challenges_uri\",\"label\":\"Challenges interface platform link\",\"type\":\"String\",\"cardinality\":\"1\",\"children\":[]},{\"key\":\"scoreboard_uri\",\"label\":\"Scoreboard interface platform link\",\"type\":\"String\",\"cardinality\":\"1\",\"children\":[]},{\"key\":\"lessons_uri\",\"label\":\"Lessons learned interface platform link\",\"type\":\"String\",\"cardinality\":\"1\",\"children\":[]}],\"context\":{},\"contract_id\":\"e9e902bc-b03d-4223-89e1-fca093ac79dd\",\"contract_attack_patterns_external_ids\":[],\"is_atomic_testing\":true,\"needs_executor\":false,\"platforms\":[\"Service\"]}"); + injectorContract.setConvertedContent(jsonNode); + + return injectorContract; + } + + private InjectorContract createMailInjectorContract() throws JsonProcessingException { + InjectorContract injectorContract = new InjectorContract(); + ObjectNode jsonNode = + (ObjectNode) + mapper.readTree( + "{\"config\":{\"type\":\"openbas_email\",\"expose\":true,\"label\":{\"en\":\"Email\",\"fr\":\"Email\"},\"color_dark\":\"#cddc39\",\"color_light\":\"#cddc39\"},\"label\":{\"en\":\"Send individual mails\",\"fr\":\"Envoyer des mails individuels\"},\"manual\":false,\"fields\":[{\"key\":\"teams\",\"label\":\"Teams\",\"mandatory\":true,\"readOnly\":false,\"mandatoryGroups\":null,\"linkedFields\":[],\"linkedValues\":[],\"cardinality\":\"n\",\"defaultValue\":[],\"type\":\"team\"},{\"key\":\"subject\",\"label\":\"Subject\",\"mandatory\":true,\"readOnly\":false,\"mandatoryGroups\":null,\"linkedFields\":[],\"linkedValues\":[],\"defaultValue\":\"\",\"type\":\"text\"},{\"key\":\"body\",\"label\":\"Body\",\"mandatory\":true,\"readOnly\":false,\"mandatoryGroups\":null,\"linkedFields\":[],\"linkedValues\":[],\"defaultValue\":\"\",\"richText\":true,\"type\":\"textarea\"},{\"key\":\"encrypted\",\"label\":\"Encrypted\",\"mandatory\":false,\"readOnly\":false,\"mandatoryGroups\":null,\"linkedFields\":[],\"linkedValues\":[],\"defaultValue\":false,\"type\":\"checkbox\"},{\"key\":\"attachments\",\"label\":\"Attachments\",\"mandatory\":false,\"readOnly\":false,\"mandatoryGroups\":null,\"linkedFields\":[],\"linkedValues\":[],\"cardinality\":\"n\",\"defaultValue\":[],\"type\":\"attachment\"},{\"key\":\"expectations\",\"label\":\"Expectations\",\"mandatory\":false,\"readOnly\":false,\"mandatoryGroups\":null,\"linkedFields\":[],\"linkedValues\":[],\"cardinality\":\"n\",\"defaultValue\":[],\"predefinedExpectations\":[],\"type\":\"expectation\"}],\"variables\":[{\"key\":\"document_uri\",\"label\":\"Http user link to upload the document (only for document expectation)\",\"type\":\"String\",\"cardinality\":\"1\",\"children\":[]},{\"key\":\"user\",\"label\":\"User that will receive the injection\",\"type\":\"String\",\"cardinality\":\"1\",\"children\":[{\"key\":\"user.id\",\"label\":\"Id of the user in the platform\",\"type\":\"String\",\"cardinality\":\"1\",\"children\":[]},{\"key\":\"user.email\",\"label\":\"Email of the user\",\"type\":\"String\",\"cardinality\":\"1\",\"children\":[]},{\"key\":\"user.firstname\",\"label\":\"Firstname of the user\",\"type\":\"String\",\"cardinality\":\"1\",\"children\":[]},{\"key\":\"user.lastname\",\"label\":\"Lastname of the user\",\"type\":\"String\",\"cardinality\":\"1\",\"children\":[]},{\"key\":\"user.lang\",\"label\":\"Lang of the user\",\"type\":\"String\",\"cardinality\":\"1\",\"children\":[]}]},{\"key\":\"exercise\",\"label\":\"Exercise of the current injection\",\"type\":\"Object\",\"cardinality\":\"1\",\"children\":[{\"key\":\"exercise.id\",\"label\":\"Id of the user in the platform\",\"type\":\"String\",\"cardinality\":\"1\",\"children\":[]},{\"key\":\"exercise.name\",\"label\":\"Name of the exercise\",\"type\":\"String\",\"cardinality\":\"1\",\"children\":[]},{\"key\":\"exercise.description\",\"label\":\"Description of the exercise\",\"type\":\"String\",\"cardinality\":\"1\",\"children\":[]}]},{\"key\":\"teams\",\"label\":\"List of team name for the injection\",\"type\":\"String\",\"cardinality\":\"n\",\"children\":[]},{\"key\":\"player_uri\",\"label\":\"Player interface platform link\",\"type\":\"String\",\"cardinality\":\"1\",\"children\":[]},{\"key\":\"challenges_uri\",\"label\":\"Challenges interface platform link\",\"type\":\"String\",\"cardinality\":\"1\",\"children\":[]},{\"key\":\"scoreboard_uri\",\"label\":\"Scoreboard interface platform link\",\"type\":\"String\",\"cardinality\":\"1\",\"children\":[]},{\"key\":\"lessons_uri\",\"label\":\"Lessons learned interface platform link\",\"type\":\"String\",\"cardinality\":\"1\",\"children\":[]}],\"context\":{},\"contract_id\":\"138ad8f8-32f8-4a22-8114-aaa12322bd09\",\"contract_attack_patterns_external_ids\":[],\"is_atomic_testing\":true,\"needs_executor\":false,\"platforms\":[\"Service\"]}"); + injectorContract.setConvertedContent(jsonNode); + + return injectorContract; + } + + private List createRuleAttributeSms() { + List results = new ArrayList<>(); + RuleAttribute ruleAttributeTitle = new RuleAttribute(); + ruleAttributeTitle.setName("title"); + ruleAttributeTitle.setColumns("B"); + ruleAttributeTitle.setDefaultValue("title"); + + RuleAttribute ruleAttributeDescription = new RuleAttribute(); + ruleAttributeDescription.setName("description"); + ruleAttributeDescription.setColumns("G"); + ruleAttributeDescription.setDefaultValue("description"); + + RuleAttribute ruleAttributeTriggerTime = new RuleAttribute(); + ruleAttributeTriggerTime.setName("trigger_time"); + ruleAttributeTriggerTime.setColumns("C"); + ruleAttributeTriggerTime.setDefaultValue("trigger_time"); + ruleAttributeTriggerTime.setAdditionalConfig(Map.of("timePattern", "")); + + RuleAttribute ruleAttributeMessage = new RuleAttribute(); + ruleAttributeMessage.setName("message"); + ruleAttributeMessage.setColumns("F"); + ruleAttributeMessage.setDefaultValue("message"); + + RuleAttribute ruleAttributeTeams = new RuleAttribute(); + ruleAttributeTeams.setName("teams"); + ruleAttributeTeams.setColumns("D"); + ruleAttributeTeams.setDefaultValue("teams"); + + RuleAttribute ruleAttributeExpectationScore = new RuleAttribute(); + ruleAttributeExpectationScore.setName("expectation_score"); + ruleAttributeExpectationScore.setColumns("J"); + ruleAttributeExpectationScore.setDefaultValue("500.0"); + + RuleAttribute ruleAttributeExpectationName = new RuleAttribute(); + ruleAttributeExpectationName.setName("expectation_name"); + ruleAttributeExpectationName.setColumns("I"); + ruleAttributeExpectationName.setDefaultValue("name"); + + RuleAttribute ruleAttributeExpectationDescription = new RuleAttribute(); + ruleAttributeExpectationDescription.setName("expectation_description"); + ruleAttributeExpectationDescription.setColumns("H"); + ruleAttributeExpectationDescription.setDefaultValue("description"); + + results.add(ruleAttributeTitle); + results.add(ruleAttributeDescription); + results.add(ruleAttributeTriggerTime); + results.add(ruleAttributeMessage); + results.add(ruleAttributeTeams); + results.add(ruleAttributeExpectationScore); + results.add(ruleAttributeExpectationName); + results.add(ruleAttributeExpectationDescription); + + return results; + } + + private List createRuleAttributeMail() { + List results = new ArrayList<>(); + RuleAttribute ruleAttributeTitle = new RuleAttribute(); + ruleAttributeTitle.setName("title"); + ruleAttributeTitle.setColumns("B"); + ruleAttributeTitle.setDefaultValue("title"); + + RuleAttribute ruleAttributeDescription = new RuleAttribute(); + ruleAttributeDescription.setName("description"); + ruleAttributeDescription.setColumns("G"); + ruleAttributeDescription.setDefaultValue("description"); + + RuleAttribute ruleAttributeTriggerTime = new RuleAttribute(); + ruleAttributeTriggerTime.setName("trigger_time"); + ruleAttributeTriggerTime.setColumns("C"); + ruleAttributeTriggerTime.setDefaultValue("trigger_time"); + ruleAttributeTriggerTime.setAdditionalConfig(Map.of("timePattern", "")); + + RuleAttribute ruleAttributeMessage = new RuleAttribute(); + ruleAttributeMessage.setName("subject"); + ruleAttributeMessage.setColumns("E"); + ruleAttributeMessage.setDefaultValue("subject"); + + RuleAttribute ruleAttributeSubject = new RuleAttribute(); + ruleAttributeSubject.setName("body"); + ruleAttributeSubject.setColumns("F"); + ruleAttributeSubject.setDefaultValue("body"); + + RuleAttribute ruleAttributeTeams = new RuleAttribute(); + ruleAttributeTeams.setName("teams"); + ruleAttributeTeams.setColumns("D"); + ruleAttributeTeams.setDefaultValue("teams"); + + RuleAttribute ruleAttributeExpectationScore = new RuleAttribute(); + ruleAttributeExpectationScore.setName("expectation_score"); + ruleAttributeExpectationScore.setColumns("J"); + ruleAttributeExpectationScore.setDefaultValue("500.0"); + + RuleAttribute ruleAttributeExpectationName = new RuleAttribute(); + ruleAttributeExpectationName.setName("expectation_name"); + ruleAttributeExpectationName.setColumns("I"); + ruleAttributeExpectationName.setDefaultValue("name"); + + RuleAttribute ruleAttributeExpectationDescription = new RuleAttribute(); + ruleAttributeExpectationDescription.setName("expectation_description"); + ruleAttributeExpectationDescription.setColumns("H"); + ruleAttributeExpectationDescription.setDefaultValue("description"); + + results.add(ruleAttributeTitle); + results.add(ruleAttributeDescription); + results.add(ruleAttributeTriggerTime); + results.add(ruleAttributeMessage); + results.add(ruleAttributeSubject); + results.add(ruleAttributeTeams); + results.add(ruleAttributeExpectationScore); + results.add(ruleAttributeExpectationName); + results.add(ruleAttributeExpectationDescription); + + return results; + } + + private Object deepCopy(Object objectToCopy, Class classToCopy) throws JsonProcessingException { + ObjectMapper objectMapper = new ObjectMapper(); + + return objectMapper.readValue(objectMapper.writeValueAsString(objectToCopy), classToCopy); + } + + private Inject createNewInject(List teams) { + Inject inject = new Inject(); + inject.setTeams(teams); + inject.setId(UUID.randomUUID().toString()); + return inject; + } } diff --git a/openbas-api/src/test/java/io/openbas/service/InjectTestStatusServiceTest.java b/openbas-api/src/test/java/io/openbas/service/InjectTestStatusServiceTest.java index 06e15c0a69..185618d61c 100644 --- a/openbas-api/src/test/java/io/openbas/service/InjectTestStatusServiceTest.java +++ b/openbas-api/src/test/java/io/openbas/service/InjectTestStatusServiceTest.java @@ -1,5 +1,9 @@ package io.openbas.service; +import static io.openbas.injectors.channel.ChannelContract.CHANNEL_PUBLISH; +import static io.openbas.injectors.email.EmailContract.EMAIL_DEFAULT; +import static org.junit.jupiter.api.Assertions.*; + import com.fasterxml.jackson.databind.ObjectMapper; import io.openbas.config.OpenBASOidcUser; import io.openbas.database.model.*; @@ -12,6 +16,8 @@ import io.openbas.utils.fixtures.PaginationFixture; import io.openbas.utils.pagination.SearchPaginationInput; import jakarta.annotation.Resource; +import java.util.Collections; +import java.util.List; import org.junit.jupiter.api.*; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.boot.test.context.SpringBootTest; @@ -20,42 +26,27 @@ import org.springframework.security.core.Authentication; import org.springframework.security.core.context.SecurityContextHolder; - -import java.util.Collections; -import java.util.List; - -import static io.openbas.injectors.channel.ChannelContract.CHANNEL_PUBLISH; -import static io.openbas.injectors.email.EmailContract.EMAIL_DEFAULT; -import static org.junit.jupiter.api.Assertions.*; - @SpringBootTest @TestInstance(TestInstance.Lifecycle.PER_CLASS) public class InjectTestStatusServiceTest { - @Autowired - private InjectRepository injectRepository; + @Autowired private InjectRepository injectRepository; - @Autowired - private ExerciseRepository exerciseRepository; + @Autowired private ExerciseRepository exerciseRepository; - @Autowired - private InjectorContractRepository injectorContractRepository; + @Autowired private InjectorContractRepository injectorContractRepository; - @Autowired - private InjectTestStatusService injectTestStatusService; + @Autowired private InjectTestStatusService injectTestStatusService; - @Autowired - private UserRepository userRepository; + @Autowired private UserRepository userRepository; - @Resource - protected ObjectMapper mapper; + @Resource protected ObjectMapper mapper; private Inject INJECT1; private Inject INJECT2; private Inject INJECT3; private Exercise EXERCISE; - @BeforeAll void beforeAll() { Exercise exercise = new Exercise(); @@ -66,7 +57,8 @@ void beforeAll() { Inject inject = new Inject(); inject.setTitle("test"); - inject.setInjectorContract(this.injectorContractRepository.findById(EMAIL_DEFAULT).orElseThrow()); + inject.setInjectorContract( + this.injectorContractRepository.findById(EMAIL_DEFAULT).orElseThrow()); inject.setExercise(EXERCISE); inject.setDependsDuration(0L); EmailContent content = new EmailContent(); @@ -77,7 +69,8 @@ void beforeAll() { Inject inject2 = new Inject(); inject2.setTitle("test2"); - inject2.setInjectorContract(this.injectorContractRepository.findById(EMAIL_DEFAULT).orElseThrow()); + inject2.setInjectorContract( + this.injectorContractRepository.findById(EMAIL_DEFAULT).orElseThrow()); inject2.setExercise(EXERCISE); inject2.setDependsDuration(0L); EmailContent content2 = new EmailContent(); @@ -88,7 +81,8 @@ void beforeAll() { Inject inject3 = new Inject(); inject3.setTitle("test3"); - inject3.setInjectorContract(this.injectorContractRepository.findById(CHANNEL_PUBLISH).orElseThrow()); + inject3.setInjectorContract( + this.injectorContractRepository.findById(CHANNEL_PUBLISH).orElseThrow()); inject3.setExercise(EXERCISE); inject3.setDependsDuration(0L); ChannelContent content3 = new ChannelContent(); @@ -112,7 +106,8 @@ void testInject() { // Mock the UserDetails with a custom ID User user = this.userRepository.findByEmailIgnoreCase("admin@openbas.io").orElseThrow(); OpenBASOidcUser oidcUser = new OpenBASOidcUser(user); - Authentication auth = new UsernamePasswordAuthenticationToken(oidcUser, "password", Collections.EMPTY_LIST); + Authentication auth = + new UsernamePasswordAuthenticationToken(oidcUser, "password", Collections.EMPTY_LIST); SecurityContextHolder.getContext().setAuthentication(auth); // -- EXECUTE -- @@ -129,24 +124,27 @@ void testNonMailInject() { // Mock the UserDetails with a custom ID User user = this.userRepository.findByEmailIgnoreCase("admin@openbas.io").orElseThrow(); OpenBASOidcUser oidcUser = new OpenBASOidcUser(user); - Authentication auth = new UsernamePasswordAuthenticationToken(oidcUser, "password", Collections.EMPTY_LIST); + Authentication auth = + new UsernamePasswordAuthenticationToken(oidcUser, "password", Collections.EMPTY_LIST); SecurityContextHolder.getContext().setAuthentication(auth); // -- EXECUTE -- - Exception exception = assertThrows(IllegalArgumentException.class, () -> { - injectTestStatusService.testInject(INJECT3.getId()); - }); + Exception exception = + assertThrows( + IllegalArgumentException.class, + () -> { + injectTestStatusService.testInject(INJECT3.getId()); + }); String expectedMessage = "Inject: " + INJECT3.getId() + " is not testable"; String actualMessage = exception.getMessage(); assertTrue(actualMessage.contains(expectedMessage)); // -- CLEAN -- - SearchPaginationInput searchPaginationInput = PaginationFixture.getDefault() - .size(1110) - .build(); - Page tests = injectTestStatusService.findAllInjectTestsByExerciseId(EXERCISE.getId(), - searchPaginationInput); + SearchPaginationInput searchPaginationInput = PaginationFixture.getDefault().size(1110).build(); + Page tests = + injectTestStatusService.findAllInjectTestsByExerciseId( + EXERCISE.getId(), searchPaginationInput); tests.stream().forEach(test -> this.injectTestStatusService.deleteInjectTest(test.getId())); } @@ -156,11 +154,13 @@ void testBulkInject() { // Mock the UserDetails with a custom ID User user = this.userRepository.findByEmailIgnoreCase("admin@openbas.io").orElseThrow(); OpenBASOidcUser oidcUser = new OpenBASOidcUser(user); - Authentication auth = new UsernamePasswordAuthenticationToken(oidcUser, "password", Collections.EMPTY_LIST); + Authentication auth = + new UsernamePasswordAuthenticationToken(oidcUser, "password", Collections.EMPTY_LIST); SecurityContextHolder.getContext().setAuthentication(auth); // -- EXECUTE -- - List tests = injectTestStatusService.bulkTestInjects(List.of(INJECT1.getId(), INJECT2.getId())); + List tests = + injectTestStatusService.bulkTestInjects(List.of(INJECT1.getId(), INJECT2.getId())); assertEquals(2, tests.size()); // -- CLEAN -- @@ -173,24 +173,27 @@ void bulkTestNonMailInject() { // Mock the UserDetails with a custom ID User user = this.userRepository.findByEmailIgnoreCase("admin@openbas.io").orElseThrow(); OpenBASOidcUser oidcUser = new OpenBASOidcUser(user); - Authentication auth = new UsernamePasswordAuthenticationToken(oidcUser, "password", Collections.EMPTY_LIST); + Authentication auth = + new UsernamePasswordAuthenticationToken(oidcUser, "password", Collections.EMPTY_LIST); SecurityContextHolder.getContext().setAuthentication(auth); // -- EXECUTE -- - Exception exception = assertThrows(IllegalArgumentException.class, () -> { - injectTestStatusService.bulkTestInjects(Collections.singletonList(INJECT3.getId())); - }); + Exception exception = + assertThrows( + IllegalArgumentException.class, + () -> { + injectTestStatusService.bulkTestInjects(Collections.singletonList(INJECT3.getId())); + }); String expectedMessage = "No inject ID is testable"; String actualMessage = exception.getMessage(); assertTrue(actualMessage.contains(expectedMessage)); // -- CLEAN -- - SearchPaginationInput searchPaginationInput = PaginationFixture.getDefault() - .size(1110) - .build(); - Page tests = injectTestStatusService.findAllInjectTestsByExerciseId(EXERCISE.getId(), - searchPaginationInput); + SearchPaginationInput searchPaginationInput = PaginationFixture.getDefault().size(1110).build(); + Page tests = + injectTestStatusService.findAllInjectTestsByExerciseId( + EXERCISE.getId(), searchPaginationInput); tests.stream().forEach(test -> this.injectTestStatusService.deleteInjectTest(test.getId())); } @@ -200,19 +203,19 @@ void findAllInjectTestsByExerciseId() { // Mock the UserDetails with a custom ID User user = this.userRepository.findByEmailIgnoreCase("admin@openbas.io").orElseThrow(); OpenBASOidcUser oidcUser = new OpenBASOidcUser(user); - Authentication auth = new UsernamePasswordAuthenticationToken(oidcUser, "password", Collections.EMPTY_LIST); + Authentication auth = + new UsernamePasswordAuthenticationToken(oidcUser, "password", Collections.EMPTY_LIST); SecurityContextHolder.getContext().setAuthentication(auth); // -- PREPARE -- injectTestStatusService.bulkTestInjects(List.of(INJECT1.getId(), INJECT2.getId())); - SearchPaginationInput searchPaginationInput = PaginationFixture.getDefault() - .size(1110) - .build(); + SearchPaginationInput searchPaginationInput = PaginationFixture.getDefault().size(1110).build(); // -- EXECUTE -- - Page tests = injectTestStatusService.findAllInjectTestsByExerciseId(EXERCISE.getId(), - searchPaginationInput); + Page tests = + injectTestStatusService.findAllInjectTestsByExerciseId( + EXERCISE.getId(), searchPaginationInput); assertEquals(2, tests.stream().toList().size()); // -- CLEAN -- @@ -225,7 +228,8 @@ void findTestById() { // Mock the UserDetails with a custom ID User user = this.userRepository.findByEmailIgnoreCase("admin@openbas.io").orElseThrow(); OpenBASOidcUser oidcUser = new OpenBASOidcUser(user); - Authentication auth = new UsernamePasswordAuthenticationToken(oidcUser, "password", Collections.EMPTY_LIST); + Authentication auth = + new UsernamePasswordAuthenticationToken(oidcUser, "password", Collections.EMPTY_LIST); SecurityContextHolder.getContext().setAuthentication(auth); // -- PREPARE -- @@ -245,7 +249,8 @@ void deleteInjectTest() { // Mock the UserDetails with a custom ID User user = this.userRepository.findByEmailIgnoreCase("admin@openbas.io").orElseThrow(); OpenBASOidcUser oidcUser = new OpenBASOidcUser(user); - Authentication auth = new UsernamePasswordAuthenticationToken(oidcUser, "password", Collections.EMPTY_LIST); + Authentication auth = + new UsernamePasswordAuthenticationToken(oidcUser, "password", Collections.EMPTY_LIST); SecurityContextHolder.getContext().setAuthentication(auth); // -- PREPARE -- @@ -254,12 +259,10 @@ void deleteInjectTest() { // --EXECUTE -- injectTestStatusService.deleteInjectTest(test.getId()); - SearchPaginationInput searchPaginationInput = PaginationFixture.getDefault() - .size(1110) - .build(); - Page tests = injectTestStatusService.findAllInjectTestsByExerciseId(EXERCISE.getId(), - searchPaginationInput); + SearchPaginationInput searchPaginationInput = PaginationFixture.getDefault().size(1110).build(); + Page tests = + injectTestStatusService.findAllInjectTestsByExerciseId( + EXERCISE.getId(), searchPaginationInput); assertEquals(0, tests.stream().toList().size()); } - } diff --git a/openbas-api/src/test/java/io/openbas/service/LoadService.java b/openbas-api/src/test/java/io/openbas/service/LoadService.java index 38fbc643b5..94252db68d 100644 --- a/openbas-api/src/test/java/io/openbas/service/LoadService.java +++ b/openbas-api/src/test/java/io/openbas/service/LoadService.java @@ -25,12 +25,14 @@ public Exercise exercise(@NotBlank final String exerciseId) { Hibernate.initialize(exercise.getArticles()); exercise.getArticles().forEach(article -> Hibernate.initialize(article.getDocuments())); Hibernate.initialize(exercise.getLessonsCategories()); - exercise.getLessonsCategories().forEach(lessonsCategory -> { - Hibernate.initialize(lessonsCategory.getQuestions()); - Hibernate.initialize(lessonsCategory.getTeams()); - }); + exercise + .getLessonsCategories() + .forEach( + lessonsCategory -> { + Hibernate.initialize(lessonsCategory.getQuestions()); + Hibernate.initialize(lessonsCategory.getTeams()); + }); Hibernate.initialize(exercise.getInjects()); return exercise; } - } diff --git a/openbas-api/src/test/java/io/openbas/service/MapperServiceExportTest.java b/openbas-api/src/test/java/io/openbas/service/MapperServiceExportTest.java index e130a5823e..1c2a89f565 100644 --- a/openbas-api/src/test/java/io/openbas/service/MapperServiceExportTest.java +++ b/openbas-api/src/test/java/io/openbas/service/MapperServiceExportTest.java @@ -1,24 +1,21 @@ package io.openbas.service; +import static org.junit.jupiter.api.Assertions.assertEquals; + import io.openbas.IntegrationTest; import io.openbas.database.model.ImportMapper; import io.openbas.database.repository.ImportMapperRepository; +import java.util.ArrayList; +import java.util.List; import org.junit.jupiter.api.DisplayName; import org.junit.jupiter.api.Test; import org.springframework.beans.factory.annotation.Autowired; -import java.util.ArrayList; -import java.util.List; - -import static org.junit.jupiter.api.Assertions.assertEquals; - class MapperServiceExportTest extends IntegrationTest { - @Autowired - private ImportMapperRepository importMapperRepository; + @Autowired private ImportMapperRepository importMapperRepository; - @Autowired - private MapperService mapperService; + @Autowired private MapperService mapperService; @DisplayName("Test exporting a mapper") @Test @@ -34,14 +31,15 @@ void exportMapper() throws Exception { String json = this.mapperService.exportMappers(List.of(mapperSaved.getId())); // -- ASSERT -- - assertEquals("[{" - + "\"import_mapper_name\":\"Test Mapper\"," - + "\"import_mapper_inject_type_column\":\"injectType\"," - + "\"import_mapper_inject_importers\":[]" - + "}]", json); + assertEquals( + "[{" + + "\"import_mapper_name\":\"Test Mapper\"," + + "\"import_mapper_inject_type_column\":\"injectType\"," + + "\"import_mapper_inject_importers\":[]" + + "}]", + json); // -- CLEAN -- this.importMapperRepository.delete(mapperSaved); } - } diff --git a/openbas-api/src/test/java/io/openbas/service/MapperServiceTest.java b/openbas-api/src/test/java/io/openbas/service/MapperServiceTest.java index c3b9491055..d84c82e398 100644 --- a/openbas-api/src/test/java/io/openbas/service/MapperServiceTest.java +++ b/openbas-api/src/test/java/io/openbas/service/MapperServiceTest.java @@ -1,11 +1,19 @@ package io.openbas.service; +import static io.openbas.utils.StringUtils.duplicateString; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertNotNull; +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.Mockito.verify; +import static org.mockito.Mockito.when; + import io.openbas.database.model.ImportMapper; import io.openbas.database.model.InjectImporter; import io.openbas.database.repository.ImportMapperRepository; import io.openbas.database.repository.InjectorContractRepository; import io.openbas.rest.mapper.form.*; import io.openbas.utils.mockMapper.MockMapperUtils; +import java.util.Optional; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.DisplayName; import org.junit.jupiter.api.Test; @@ -15,28 +23,15 @@ import org.mockito.junit.jupiter.MockitoExtension; import org.springframework.boot.test.context.SpringBootTest; -import java.util.Optional; - -import static io.openbas.utils.StringUtils.duplicateString; -import static org.junit.jupiter.api.Assertions.assertEquals; -import static org.junit.jupiter.api.Assertions.assertNotNull; -import static org.mockito.ArgumentMatchers.any; -import static org.mockito.Mockito.verify; -import static org.mockito.Mockito.when; - @SpringBootTest @ExtendWith(MockitoExtension.class) public class MapperServiceTest { - @Mock - private ImportMapperRepository importMapperRepository; + @Mock private ImportMapperRepository importMapperRepository; - @Mock - private InjectorContractRepository injectorContractRepository; + @Mock private InjectorContractRepository injectorContractRepository; private MapperService mapperService; - - @BeforeEach void before() { // Injecting mocks into the controller @@ -53,25 +48,33 @@ void createMapper() throws Exception { ImportMapperAddInput importMapperInput = new ImportMapperAddInput(); importMapperInput.setName(importMapper.getName()); importMapperInput.setInjectTypeColumn(importMapper.getInjectTypeColumn()); - importMapperInput.setImporters(importMapper.getInjectImporters().stream().map( - injectImporter -> { - InjectImporterAddInput injectImporterAddInput = new InjectImporterAddInput(); - injectImporterAddInput.setInjectTypeValue(injectImporter.getImportTypeValue()); - injectImporterAddInput.setInjectorContractId(injectImporter.getInjectorContract().getId()); - - injectImporterAddInput.setRuleAttributes(injectImporter.getRuleAttributes().stream().map( - ruleAttribute -> { - RuleAttributeAddInput ruleAttributeAddInput = new RuleAttributeAddInput(); - ruleAttributeAddInput.setName(ruleAttribute.getName()); - ruleAttributeAddInput.setColumns(ruleAttribute.getColumns()); - ruleAttributeAddInput.setDefaultValue(ruleAttribute.getDefaultValue()); - ruleAttributeAddInput.setAdditionalConfig(ruleAttribute.getAdditionalConfig()); - return ruleAttributeAddInput; - } - ).toList()); - return injectImporterAddInput; - } - ).toList()); + importMapperInput.setImporters( + importMapper.getInjectImporters().stream() + .map( + injectImporter -> { + InjectImporterAddInput injectImporterAddInput = new InjectImporterAddInput(); + injectImporterAddInput.setInjectTypeValue(injectImporter.getImportTypeValue()); + injectImporterAddInput.setInjectorContractId( + injectImporter.getInjectorContract().getId()); + + injectImporterAddInput.setRuleAttributes( + injectImporter.getRuleAttributes().stream() + .map( + ruleAttribute -> { + RuleAttributeAddInput ruleAttributeAddInput = + new RuleAttributeAddInput(); + ruleAttributeAddInput.setName(ruleAttribute.getName()); + ruleAttributeAddInput.setColumns(ruleAttribute.getColumns()); + ruleAttributeAddInput.setDefaultValue( + ruleAttribute.getDefaultValue()); + ruleAttributeAddInput.setAdditionalConfig( + ruleAttribute.getAdditionalConfig()); + return ruleAttributeAddInput; + }) + .toList()); + return injectImporterAddInput; + }) + .toList()); when(importMapperRepository.save(any())).thenReturn(importMapper); // -- EXECUTE -- ImportMapper importMapperResponse = mapperService.createAndSaveImportMapper(importMapperInput); @@ -81,39 +84,45 @@ void createMapper() throws Exception { assertEquals(importMapperResponse.getId(), importMapper.getId()); } - @DisplayName("Test duplicate a mapper") - @Test - void duplicateMapper() throws Exception { - // -- PREPARE -- - ImportMapper importMapper = MockMapperUtils.createImportMapper(); - when(importMapperRepository.findById(any())).thenReturn(Optional.of(importMapper)); - ImportMapper importMapperSaved = MockMapperUtils.createImportMapper(); - when(importMapperRepository.save(any(ImportMapper.class))).thenReturn(importMapperSaved); - - // -- EXECUTE -- - ImportMapper response = mapperService.getDuplicateImportMapper(importMapper.getId()); - - // -- ASSERT -- - ArgumentCaptor importMapperCaptor = ArgumentCaptor.forClass(ImportMapper.class); - verify(importMapperRepository).save(importMapperCaptor.capture()); - - ImportMapper capturedImportMapper= importMapperCaptor.getValue(); - // verify importMapper - assertEquals(duplicateString(importMapper.getName()), capturedImportMapper.getName()); - assertEquals(importMapper.getInjectTypeColumn(), capturedImportMapper.getInjectTypeColumn()); - assertEquals(importMapper.getInjectImporters().size(), capturedImportMapper.getInjectImporters().size()); - // verify injectImporter - assertEquals("", capturedImportMapper.getInjectImporters().get(0).getId()); - assertEquals(importMapper.getInjectImporters().get(0).getImportTypeValue(), capturedImportMapper.getInjectImporters().get(0).getImportTypeValue()); - assertEquals(importMapper.getInjectImporters().get(0).getRuleAttributes().size(), - capturedImportMapper.getInjectImporters().get(0).getRuleAttributes().size()); - // verify ruleAttribute - assertEquals("", capturedImportMapper.getInjectImporters().get(0).getRuleAttributes().get(0).getId()); - assertEquals(importMapper.getInjectImporters().get(0).getRuleAttributes().get(0).getName(), - capturedImportMapper.getInjectImporters().get(0).getRuleAttributes().get(0).getName()); - - assertEquals(response.getId(), importMapperSaved.getId()); - } + @DisplayName("Test duplicate a mapper") + @Test + void duplicateMapper() throws Exception { + // -- PREPARE -- + ImportMapper importMapper = MockMapperUtils.createImportMapper(); + when(importMapperRepository.findById(any())).thenReturn(Optional.of(importMapper)); + ImportMapper importMapperSaved = MockMapperUtils.createImportMapper(); + when(importMapperRepository.save(any(ImportMapper.class))).thenReturn(importMapperSaved); + + // -- EXECUTE -- + ImportMapper response = mapperService.getDuplicateImportMapper(importMapper.getId()); + + // -- ASSERT -- + ArgumentCaptor importMapperCaptor = ArgumentCaptor.forClass(ImportMapper.class); + verify(importMapperRepository).save(importMapperCaptor.capture()); + + ImportMapper capturedImportMapper = importMapperCaptor.getValue(); + // verify importMapper + assertEquals(duplicateString(importMapper.getName()), capturedImportMapper.getName()); + assertEquals(importMapper.getInjectTypeColumn(), capturedImportMapper.getInjectTypeColumn()); + assertEquals( + importMapper.getInjectImporters().size(), capturedImportMapper.getInjectImporters().size()); + // verify injectImporter + assertEquals("", capturedImportMapper.getInjectImporters().get(0).getId()); + assertEquals( + importMapper.getInjectImporters().get(0).getImportTypeValue(), + capturedImportMapper.getInjectImporters().get(0).getImportTypeValue()); + assertEquals( + importMapper.getInjectImporters().get(0).getRuleAttributes().size(), + capturedImportMapper.getInjectImporters().get(0).getRuleAttributes().size()); + // verify ruleAttribute + assertEquals( + "", capturedImportMapper.getInjectImporters().get(0).getRuleAttributes().get(0).getId()); + assertEquals( + importMapper.getInjectImporters().get(0).getRuleAttributes().get(0).getName(), + capturedImportMapper.getInjectImporters().get(0).getRuleAttributes().get(0).getName()); + + assertEquals(response.getId(), importMapperSaved.getId()); + } @DisplayName("Test update a specific mapper by using new rule attributes and new inject importer") @Test @@ -123,116 +132,159 @@ void updateSpecificMapperWithNewElements() throws Exception { ImportMapperUpdateInput importMapperInput = new ImportMapperUpdateInput(); importMapperInput.setName(importMapper.getName()); importMapperInput.setInjectTypeColumn(importMapper.getInjectTypeColumn()); - importMapperInput.setImporters(importMapper.getInjectImporters().stream().map( - injectImporter -> { - InjectImporterUpdateInput injectImporterUpdateInput = new InjectImporterUpdateInput(); - injectImporterUpdateInput.setInjectTypeValue(injectImporter.getImportTypeValue()); - injectImporterUpdateInput.setInjectorContractId(injectImporter.getInjectorContract().getId()); - - injectImporterUpdateInput.setRuleAttributes(injectImporter.getRuleAttributes().stream().map( - ruleAttribute -> { - RuleAttributeUpdateInput ruleAttributeUpdateInput = new RuleAttributeUpdateInput(); - ruleAttributeUpdateInput.setName(ruleAttribute.getName()); - ruleAttributeUpdateInput.setColumns(ruleAttribute.getColumns()); - ruleAttributeUpdateInput.setDefaultValue(ruleAttribute.getDefaultValue()); - ruleAttributeUpdateInput.setAdditionalConfig(ruleAttribute.getAdditionalConfig()); - return ruleAttributeUpdateInput; - } - ).toList()); - return injectImporterUpdateInput; - } - ).toList()); + importMapperInput.setImporters( + importMapper.getInjectImporters().stream() + .map( + injectImporter -> { + InjectImporterUpdateInput injectImporterUpdateInput = + new InjectImporterUpdateInput(); + injectImporterUpdateInput.setInjectTypeValue(injectImporter.getImportTypeValue()); + injectImporterUpdateInput.setInjectorContractId( + injectImporter.getInjectorContract().getId()); + + injectImporterUpdateInput.setRuleAttributes( + injectImporter.getRuleAttributes().stream() + .map( + ruleAttribute -> { + RuleAttributeUpdateInput ruleAttributeUpdateInput = + new RuleAttributeUpdateInput(); + ruleAttributeUpdateInput.setName(ruleAttribute.getName()); + ruleAttributeUpdateInput.setColumns(ruleAttribute.getColumns()); + ruleAttributeUpdateInput.setDefaultValue( + ruleAttribute.getDefaultValue()); + ruleAttributeUpdateInput.setAdditionalConfig( + ruleAttribute.getAdditionalConfig()); + return ruleAttributeUpdateInput; + }) + .toList()); + return injectImporterUpdateInput; + }) + .toList()); when(importMapperRepository.findById(any())).thenReturn(Optional.of(importMapper)); when(importMapperRepository.save(any())).thenReturn(importMapper); - when(injectorContractRepository.findAllById(any())).thenReturn(importMapper.getInjectImporters().stream().map(InjectImporter::getInjectorContract).toList()); + when(injectorContractRepository.findAllById(any())) + .thenReturn( + importMapper.getInjectImporters().stream() + .map(InjectImporter::getInjectorContract) + .toList()); // -- EXECUTE -- - ImportMapper response = mapperService.updateImportMapper(importMapper.getId(), importMapperInput); + ImportMapper response = + mapperService.updateImportMapper(importMapper.getId(), importMapperInput); // -- ASSERT -- assertNotNull(response); assertEquals(response.getId(), importMapper.getId()); } - @DisplayName("Test update a specific mapper by creating rule attributes and updating new inject importer") - @Test - void updateSpecificMapperWithUpdatedInjectImporter() throws Exception { - // -- PREPARE -- - ImportMapper importMapper = MockMapperUtils.createImportMapper(); - ImportMapperUpdateInput importMapperInput = new ImportMapperUpdateInput(); - importMapperInput.setName(importMapper.getName()); - importMapperInput.setInjectTypeColumn(importMapper.getInjectTypeColumn()); - importMapperInput.setImporters(importMapper.getInjectImporters().stream().map( + @DisplayName( + "Test update a specific mapper by creating rule attributes and updating new inject importer") + @Test + void updateSpecificMapperWithUpdatedInjectImporter() throws Exception { + // -- PREPARE -- + ImportMapper importMapper = MockMapperUtils.createImportMapper(); + ImportMapperUpdateInput importMapperInput = new ImportMapperUpdateInput(); + importMapperInput.setName(importMapper.getName()); + importMapperInput.setInjectTypeColumn(importMapper.getInjectTypeColumn()); + importMapperInput.setImporters( + importMapper.getInjectImporters().stream() + .map( injectImporter -> { - InjectImporterUpdateInput injectImporterUpdateInput = new InjectImporterUpdateInput(); - injectImporterUpdateInput.setInjectTypeValue(injectImporter.getImportTypeValue()); - injectImporterUpdateInput.setInjectorContractId(injectImporter.getInjectorContract().getId()); - injectImporterUpdateInput.setId(injectImporter.getId()); - - injectImporterUpdateInput.setRuleAttributes(injectImporter.getRuleAttributes().stream().map( - ruleAttribute -> { - RuleAttributeUpdateInput ruleAttributeUpdateInput = new RuleAttributeUpdateInput(); + InjectImporterUpdateInput injectImporterUpdateInput = + new InjectImporterUpdateInput(); + injectImporterUpdateInput.setInjectTypeValue(injectImporter.getImportTypeValue()); + injectImporterUpdateInput.setInjectorContractId( + injectImporter.getInjectorContract().getId()); + injectImporterUpdateInput.setId(injectImporter.getId()); + + injectImporterUpdateInput.setRuleAttributes( + injectImporter.getRuleAttributes().stream() + .map( + ruleAttribute -> { + RuleAttributeUpdateInput ruleAttributeUpdateInput = + new RuleAttributeUpdateInput(); ruleAttributeUpdateInput.setName(ruleAttribute.getName()); ruleAttributeUpdateInput.setColumns(ruleAttribute.getColumns()); - ruleAttributeUpdateInput.setDefaultValue(ruleAttribute.getDefaultValue()); - ruleAttributeUpdateInput.setAdditionalConfig(ruleAttribute.getAdditionalConfig()); + ruleAttributeUpdateInput.setDefaultValue( + ruleAttribute.getDefaultValue()); + ruleAttributeUpdateInput.setAdditionalConfig( + ruleAttribute.getAdditionalConfig()); return ruleAttributeUpdateInput; - } - ).toList()); - return injectImporterUpdateInput; - } - ).toList()); - when(importMapperRepository.findById(any())).thenReturn(Optional.of(importMapper)); - when(importMapperRepository.save(any())).thenReturn(importMapper); - when(injectorContractRepository.findAllById(any())).thenReturn(importMapper.getInjectImporters().stream().map(InjectImporter::getInjectorContract).toList()); - - // -- EXECUTE -- - ImportMapper response = mapperService.updateImportMapper(importMapper.getId(), importMapperInput); - - // -- ASSERT -- - assertNotNull(response); - assertEquals(response.getId(), importMapper.getId()); - } - - @DisplayName("Test update a specific mapper by updating rule attributes and updating inject importer") - @Test - void updateSpecificMapperWithUpdatedElements() throws Exception { - // -- PREPARE -- - ImportMapper importMapper = MockMapperUtils.createImportMapper(); - ImportMapperUpdateInput importMapperInput = new ImportMapperUpdateInput(); - importMapperInput.setName(importMapper.getName()); - importMapperInput.setInjectTypeColumn(importMapper.getInjectTypeColumn()); - importMapperInput.setImporters(importMapper.getInjectImporters().stream().map( + }) + .toList()); + return injectImporterUpdateInput; + }) + .toList()); + when(importMapperRepository.findById(any())).thenReturn(Optional.of(importMapper)); + when(importMapperRepository.save(any())).thenReturn(importMapper); + when(injectorContractRepository.findAllById(any())) + .thenReturn( + importMapper.getInjectImporters().stream() + .map(InjectImporter::getInjectorContract) + .toList()); + + // -- EXECUTE -- + ImportMapper response = + mapperService.updateImportMapper(importMapper.getId(), importMapperInput); + + // -- ASSERT -- + assertNotNull(response); + assertEquals(response.getId(), importMapper.getId()); + } + + @DisplayName( + "Test update a specific mapper by updating rule attributes and updating inject importer") + @Test + void updateSpecificMapperWithUpdatedElements() throws Exception { + // -- PREPARE -- + ImportMapper importMapper = MockMapperUtils.createImportMapper(); + ImportMapperUpdateInput importMapperInput = new ImportMapperUpdateInput(); + importMapperInput.setName(importMapper.getName()); + importMapperInput.setInjectTypeColumn(importMapper.getInjectTypeColumn()); + importMapperInput.setImporters( + importMapper.getInjectImporters().stream() + .map( injectImporter -> { - InjectImporterUpdateInput injectImporterUpdateInput = new InjectImporterUpdateInput(); - injectImporterUpdateInput.setInjectTypeValue(injectImporter.getImportTypeValue()); - injectImporterUpdateInput.setInjectorContractId(injectImporter.getInjectorContract().getId()); - injectImporterUpdateInput.setId(injectImporter.getId()); - - injectImporterUpdateInput.setRuleAttributes(injectImporter.getRuleAttributes().stream().map( - ruleAttribute -> { - RuleAttributeUpdateInput ruleAttributeUpdateInput = new RuleAttributeUpdateInput(); + InjectImporterUpdateInput injectImporterUpdateInput = + new InjectImporterUpdateInput(); + injectImporterUpdateInput.setInjectTypeValue(injectImporter.getImportTypeValue()); + injectImporterUpdateInput.setInjectorContractId( + injectImporter.getInjectorContract().getId()); + injectImporterUpdateInput.setId(injectImporter.getId()); + + injectImporterUpdateInput.setRuleAttributes( + injectImporter.getRuleAttributes().stream() + .map( + ruleAttribute -> { + RuleAttributeUpdateInput ruleAttributeUpdateInput = + new RuleAttributeUpdateInput(); ruleAttributeUpdateInput.setName(ruleAttribute.getName()); ruleAttributeUpdateInput.setColumns(ruleAttribute.getColumns()); - ruleAttributeUpdateInput.setDefaultValue(ruleAttribute.getDefaultValue()); - ruleAttributeUpdateInput.setAdditionalConfig(ruleAttribute.getAdditionalConfig()); + ruleAttributeUpdateInput.setDefaultValue( + ruleAttribute.getDefaultValue()); + ruleAttributeUpdateInput.setAdditionalConfig( + ruleAttribute.getAdditionalConfig()); ruleAttributeUpdateInput.setId(ruleAttribute.getId()); return ruleAttributeUpdateInput; - } - ).toList()); - return injectImporterUpdateInput; - } - ).toList()); - when(importMapperRepository.findById(any())).thenReturn(Optional.of(importMapper)); - when(importMapperRepository.save(any())).thenReturn(importMapper); - when(injectorContractRepository.findAllById(any())).thenReturn(importMapper.getInjectImporters().stream().map(InjectImporter::getInjectorContract).toList()); - - // -- EXECUTE -- - ImportMapper response = mapperService.updateImportMapper(importMapper.getId(), importMapperInput); - - // -- ASSERT -- - assertNotNull(response); - assertEquals(response.getId(), importMapper.getId()); - } + }) + .toList()); + return injectImporterUpdateInput; + }) + .toList()); + when(importMapperRepository.findById(any())).thenReturn(Optional.of(importMapper)); + when(importMapperRepository.save(any())).thenReturn(importMapper); + when(injectorContractRepository.findAllById(any())) + .thenReturn( + importMapper.getInjectImporters().stream() + .map(InjectImporter::getInjectorContract) + .toList()); + + // -- EXECUTE -- + ImportMapper response = + mapperService.updateImportMapper(importMapper.getId(), importMapperInput); + // -- ASSERT -- + assertNotNull(response); + assertEquals(response.getId(), importMapper.getId()); + } } diff --git a/openbas-api/src/test/java/io/openbas/service/ReportServiceTest.java b/openbas-api/src/test/java/io/openbas/service/ReportServiceTest.java index ce618e5a31..d72787cc33 100644 --- a/openbas-api/src/test/java/io/openbas/service/ReportServiceTest.java +++ b/openbas-api/src/test/java/io/openbas/service/ReportServiceTest.java @@ -1,12 +1,18 @@ package io.openbas.service; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.mockito.ArgumentMatchers.*; +import static org.mockito.Mockito.verify; +import static org.mockito.Mockito.when; + import io.openbas.database.model.*; import io.openbas.database.repository.ReportRepository; import io.openbas.rest.report.form.ReportInformationInput; import io.openbas.rest.report.form.ReportInjectCommentInput; import io.openbas.rest.report.form.ReportInput; -import jakarta.persistence.EntityManager; -import jakarta.persistence.TypedQuery; +import java.util.List; +import java.util.Optional; +import java.util.UUID; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.DisplayName; import org.junit.jupiter.api.Nested; @@ -17,186 +23,168 @@ import org.mockito.junit.jupiter.MockitoExtension; import org.springframework.boot.test.context.SpringBootTest; -import java.util.List; -import java.util.Optional; -import java.util.UUID; - -import static org.junit.jupiter.api.Assertions.assertEquals; -import static org.mockito.ArgumentMatchers.*; -import static org.mockito.Mockito.verify; -import static org.mockito.Mockito.when; - @SpringBootTest @ExtendWith(MockitoExtension.class) public class ReportServiceTest { - @Mock - private ReportRepository reportRepository; - - private ReportService reportService; - - @BeforeEach - void before() { - // Injecting mocks into the controller - reportService = new ReportService(reportRepository); - } - - @DisplayName("Test create a report") + @Mock private ReportRepository reportRepository; + + private ReportService reportService; + + @BeforeEach + void before() { + // Injecting mocks into the controller + reportService = new ReportService(reportRepository); + } + + @DisplayName("Test create a report") + @Test + void createReport() throws Exception { + // -- PREPARE -- + Report report = new Report(); + + ReportInput reportInput = new ReportInput(); + reportInput.setName("test"); + ReportInformationInput reportInformationInput = new ReportInformationInput(); + reportInformationInput.setReportInformationsType(ReportInformationsType.MAIN_INFORMATION); + reportInformationInput.setReportInformationsDisplay(true); + ReportInformationInput reportInformationInput2 = new ReportInformationInput(); + reportInformationInput2.setReportInformationsType(ReportInformationsType.SCORE_DETAILS); + reportInformationInput2.setReportInformationsDisplay(true); + reportInput.setReportInformations(List.of(reportInformationInput, reportInformationInput2)); + + when(reportRepository.save(any(Report.class))).thenReturn(report); + + // -- EXECUTE -- + reportService.updateReport(report, reportInput); + + // -- ASSERT -- + ArgumentCaptor reportCaptor = ArgumentCaptor.forClass(Report.class); + verify(reportRepository).save(reportCaptor.capture()); + Report capturedReport = reportCaptor.getValue(); + assertEquals(reportInput.getName(), capturedReport.getName()); + assertEquals(2, capturedReport.getReportInformations().size()); + ReportInformation reportInformationCaptured = + capturedReport.getReportInformations().stream() + .filter(r -> r.getReportInformationsType() == ReportInformationsType.MAIN_INFORMATION) + .findFirst() + .orElse(null); + assert reportInformationCaptured != null; + assertEquals(true, reportInformationCaptured.getReportInformationsDisplay()); + ReportInformation reportInformationCaptured2 = + capturedReport.getReportInformations().stream() + .filter(r -> r.getReportInformationsType() == ReportInformationsType.SCORE_DETAILS) + .findFirst() + .orElse(null); + assert reportInformationCaptured2 != null; + assertEquals(true, reportInformationCaptured2.getReportInformationsDisplay()); + } + + @DisplayName("Test update a report") + @Test + void updateReport() throws Exception { + // -- PREPARE -- + Report report = new Report(); + report.setName("test"); + ReportInformation reportInformation = new ReportInformation(); + reportInformation.setReportInformationsType(ReportInformationsType.MAIN_INFORMATION); + reportInformation.setReportInformationsDisplay(false); + report.setReportInformations(List.of(reportInformation)); + + ReportInput reportInput = new ReportInput(); + reportInput.setName("new name test"); + ReportInformationInput reportInformationInput = new ReportInformationInput(); + reportInformationInput.setReportInformationsType(ReportInformationsType.MAIN_INFORMATION); + reportInformationInput.setReportInformationsDisplay(true); + reportInput.setReportInformations(List.of(reportInformationInput)); + + when(reportRepository.save(any(Report.class))).thenReturn(report); + + // -- EXECUTE -- + reportService.updateReport(report, reportInput); + + // -- ASSERT -- + ArgumentCaptor reportCaptor = ArgumentCaptor.forClass(Report.class); + verify(reportRepository).save(reportCaptor.capture()); + Report capturedReport = reportCaptor.getValue(); + assertEquals(reportInput.getName(), capturedReport.getName()); + assertEquals(1, capturedReport.getReportInformations().size()); + assertEquals( + true, capturedReport.getReportInformations().getFirst().getReportInformationsDisplay()); + } + + @Nested + @DisplayName("Reports inject comment") + class ReportInjectCommentTest { + @DisplayName("Test update existing report inject comment") @Test - void createReport() throws Exception { - // -- PREPARE -- - Report report = new Report(); - - ReportInput reportInput = new ReportInput(); - reportInput.setName("test"); - ReportInformationInput reportInformationInput = new ReportInformationInput(); - reportInformationInput.setReportInformationsType(ReportInformationsType.MAIN_INFORMATION); - reportInformationInput.setReportInformationsDisplay(true); - ReportInformationInput reportInformationInput2 = new ReportInformationInput(); - reportInformationInput2.setReportInformationsType(ReportInformationsType.SCORE_DETAILS); - reportInformationInput2.setReportInformationsDisplay(true); - reportInput.setReportInformations(List.of(reportInformationInput, reportInformationInput2)); - - when(reportRepository.save(any(Report.class))).thenReturn(report); - - // -- EXECUTE -- - reportService.updateReport(report, reportInput); - - // -- ASSERT -- - ArgumentCaptor reportCaptor = ArgumentCaptor.forClass(Report.class); - verify(reportRepository).save(reportCaptor.capture()); - Report capturedReport= reportCaptor.getValue(); - assertEquals(reportInput.getName(), capturedReport.getName()); - assertEquals(2, capturedReport.getReportInformations().size()); - ReportInformation reportInformationCaptured = capturedReport.getReportInformations().stream() - .filter(r -> r.getReportInformationsType() == ReportInformationsType.MAIN_INFORMATION) - .findFirst() - .orElse(null); - assert reportInformationCaptured != null; - assertEquals(true, reportInformationCaptured.getReportInformationsDisplay()); - ReportInformation reportInformationCaptured2 = capturedReport.getReportInformations().stream() - .filter(r -> r.getReportInformationsType() == ReportInformationsType.SCORE_DETAILS) - .findFirst() - .orElse(null); - assert reportInformationCaptured2 != null; - assertEquals(true, reportInformationCaptured2.getReportInformationsDisplay()); + void updateExistingReportInjectComment() { + // -- PREPARE -- + Report report = new Report(); + report.setName("test"); + report.setId(UUID.randomUUID().toString()); + Inject inject = new Inject(); + inject.setId("fakeID123"); + + // add report inject comment + ReportInjectComment existingReportInjectComment = new ReportInjectComment(); + existingReportInjectComment.setReport(report); + existingReportInjectComment.setComment("comment"); + existingReportInjectComment.setInject(inject); + report.setReportInjectsComments(List.of(existingReportInjectComment)); + + ReportInjectCommentInput commentInput = new ReportInjectCommentInput(); + commentInput.setInjectId(inject.getId()); + commentInput.setComment("New comment"); + + // Mock + when(reportRepository.findReportInjectComment( + eq(UUID.fromString(report.getId())), eq(inject.getId()))) + .thenReturn(Optional.of(existingReportInjectComment)); + + // -- EXECUTE -- + reportService.updateReportInjectComment(report, inject, commentInput); + + // -- ASSERT -- + ArgumentCaptor reportCaptor = ArgumentCaptor.forClass(Report.class); + verify(reportRepository).save(reportCaptor.capture()); + Report capturedReport = reportCaptor.getValue(); + assertEquals(1, capturedReport.getReportInjectsComments().size()); + assertEquals( + commentInput.getComment(), + capturedReport.getReportInjectsComments().getFirst().getComment()); } - @DisplayName("Test update a report") + @DisplayName("Test add new report inject comment") @Test - void updateReport() throws Exception { - // -- PREPARE -- - Report report = new Report(); - report.setName("test"); - ReportInformation reportInformation = new ReportInformation(); - reportInformation.setReportInformationsType(ReportInformationsType.MAIN_INFORMATION); - reportInformation.setReportInformationsDisplay(false); - report.setReportInformations(List.of(reportInformation)); - - ReportInput reportInput = new ReportInput(); - reportInput.setName("new name test"); - ReportInformationInput reportInformationInput = new ReportInformationInput(); - reportInformationInput.setReportInformationsType(ReportInformationsType.MAIN_INFORMATION); - reportInformationInput.setReportInformationsDisplay(true); - reportInput.setReportInformations(List.of(reportInformationInput)); - - when(reportRepository.save(any(Report.class))).thenReturn(report); - - // -- EXECUTE -- - reportService.updateReport(report, reportInput); - - // -- ASSERT -- - ArgumentCaptor reportCaptor = ArgumentCaptor.forClass(Report.class); - verify(reportRepository).save(reportCaptor.capture()); - Report capturedReport= reportCaptor.getValue(); - assertEquals(reportInput.getName(), capturedReport.getName()); - assertEquals(1, capturedReport.getReportInformations().size()); - assertEquals(true, capturedReport.getReportInformations().getFirst().getReportInformationsDisplay()); - } - - @Nested - @DisplayName("Reports inject comment") - class ReportInjectCommentTest { - @DisplayName("Test update existing report inject comment") - @Test - void updateExistingReportInjectComment() { - // -- PREPARE -- - Report report = new Report(); - report.setName("test"); - report.setId(UUID.randomUUID().toString()); - Inject inject = new Inject(); - inject.setId("fakeID123"); - - // add report inject comment - ReportInjectComment existingReportInjectComment = new ReportInjectComment(); - existingReportInjectComment.setReport(report); - existingReportInjectComment.setComment("comment"); - existingReportInjectComment.setInject(inject); - report.setReportInjectsComments(List.of(existingReportInjectComment)); - - ReportInjectCommentInput commentInput = new ReportInjectCommentInput(); - commentInput.setInjectId(inject.getId()); - commentInput.setComment("New comment"); - - // Mock - when(reportRepository.findReportInjectComment(eq(UUID.fromString(report.getId())), eq(inject.getId()))).thenReturn(Optional.of(existingReportInjectComment)); - - // -- EXECUTE -- - reportService.updateReportInjectComment(report, inject, commentInput); - - // -- ASSERT -- - ArgumentCaptor reportCaptor = ArgumentCaptor.forClass(Report.class); - verify(reportRepository).save(reportCaptor.capture()); - Report capturedReport= reportCaptor.getValue(); - assertEquals(1, capturedReport.getReportInjectsComments().size()); - assertEquals(commentInput.getComment(), capturedReport.getReportInjectsComments().getFirst().getComment()); - } - - @DisplayName("Test add new report inject comment") - @Test - void addReportInjectComment() throws Exception { - // -- PREPARE -- - Report report = new Report(); - report.setName("test"); - report.setId(UUID.randomUUID().toString()); - Inject inject = new Inject(); - inject.setId("fakeID123"); - - ReportInjectCommentInput commentInput = new ReportInjectCommentInput(); - commentInput.setInjectId(inject.getId()); - commentInput.setComment("New test comment"); - - // Mock - when(reportRepository.findReportInjectComment(eq(UUID.fromString(report.getId())), eq(inject.getId()))).thenReturn(Optional.empty()); - - // -- EXECUTE -- - reportService.updateReportInjectComment(report, inject, commentInput); - - // -- ASSERT -- - ArgumentCaptor reportCaptor = ArgumentCaptor.forClass(Report.class); - verify(reportRepository).save(reportCaptor.capture()); - Report capturedReport= reportCaptor.getValue(); - assertEquals(1, capturedReport.getReportInjectsComments().size()); - assertEquals(commentInput.getComment(), capturedReport.getReportInjectsComments().getFirst().getComment()); - } + void addReportInjectComment() throws Exception { + // -- PREPARE -- + Report report = new Report(); + report.setName("test"); + report.setId(UUID.randomUUID().toString()); + Inject inject = new Inject(); + inject.setId("fakeID123"); + + ReportInjectCommentInput commentInput = new ReportInjectCommentInput(); + commentInput.setInjectId(inject.getId()); + commentInput.setComment("New test comment"); + + // Mock + when(reportRepository.findReportInjectComment( + eq(UUID.fromString(report.getId())), eq(inject.getId()))) + .thenReturn(Optional.empty()); + + // -- EXECUTE -- + reportService.updateReportInjectComment(report, inject, commentInput); + + // -- ASSERT -- + ArgumentCaptor reportCaptor = ArgumentCaptor.forClass(Report.class); + verify(reportRepository).save(reportCaptor.capture()); + Report capturedReport = reportCaptor.getValue(); + assertEquals(1, capturedReport.getReportInjectsComments().size()); + assertEquals( + commentInput.getComment(), + capturedReport.getReportInjectsComments().getFirst().getComment()); } + } } - - - - - - - - - - - - - - - - - - - diff --git a/openbas-api/src/test/java/io/openbas/service/ScenarioServiceTest.java b/openbas-api/src/test/java/io/openbas/service/ScenarioServiceTest.java index 820c750486..8f4d212d77 100644 --- a/openbas-api/src/test/java/io/openbas/service/ScenarioServiceTest.java +++ b/openbas-api/src/test/java/io/openbas/service/ScenarioServiceTest.java @@ -1,11 +1,16 @@ package io.openbas.service; +import static io.openbas.utils.fixtures.TeamFixture.getTeam; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertNotEquals; + import io.openbas.database.model.*; import io.openbas.database.repository.*; import io.openbas.rest.inject.service.InjectDuplicateService; import io.openbas.utils.ExerciseMapper; import io.openbas.utils.fixtures.ScenarioFixture; import jakarta.transaction.Transactional; +import java.util.*; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.DisplayName; import org.junit.jupiter.api.Test; @@ -13,104 +18,105 @@ import org.mockito.Mock; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.boot.test.context.SpringBootTest; -import static io.openbas.utils.fixtures.TeamFixture.getTeam; -import static io.openbas.utils.fixtures.ScenarioFixture.getScenario; - -import java.util.*; - -import static org.junit.jupiter.api.Assertions.assertEquals; -import static org.junit.jupiter.api.Assertions.assertNotEquals; @SpringBootTest public class ScenarioServiceTest { - @Autowired - ScenarioRepository scenarioRepository; - @Autowired - private TeamRepository teamRepository; - @Autowired - private UserRepository userRepository; - @Autowired - private DocumentRepository documentRepository; - @Autowired - private ScenarioTeamUserRepository scenarioTeamUserRepository; - @Autowired - private ArticleRepository articleRepository; - - @Autowired - InjectRepository injectRepository; + @Autowired ScenarioRepository scenarioRepository; + @Autowired private TeamRepository teamRepository; + @Autowired private UserRepository userRepository; + @Autowired private DocumentRepository documentRepository; + @Autowired private ScenarioTeamUserRepository scenarioTeamUserRepository; + @Autowired private ArticleRepository articleRepository; - @Mock - GrantService grantService; - @Mock - VariableService variableService; - @Mock - ChallengeService challengeService; - @Autowired - private TeamService teamService; - @Mock - FileService fileService; - @Autowired - private InjectDuplicateService injectDuplicateService; - @Autowired - private ExerciseMapper exerciseMapper; + @Autowired InjectRepository injectRepository; + @Mock GrantService grantService; + @Mock VariableService variableService; + @Mock ChallengeService challengeService; + @Autowired private TeamService teamService; + @Mock FileService fileService; + @Autowired private InjectDuplicateService injectDuplicateService; + @Autowired private ExerciseMapper exerciseMapper; - @InjectMocks - private ScenarioService scenarioService; + @InjectMocks private ScenarioService scenarioService; - @BeforeEach - void setUp() { - scenarioService = new ScenarioService(scenarioRepository, teamRepository, userRepository, documentRepository, - scenarioTeamUserRepository, articleRepository, exerciseMapper, grantService, variableService, challengeService, - teamService, fileService, injectDuplicateService - ); - } + @BeforeEach + void setUp() { + scenarioService = + new ScenarioService( + scenarioRepository, + teamRepository, + userRepository, + documentRepository, + scenarioTeamUserRepository, + articleRepository, + exerciseMapper, + grantService, + variableService, + challengeService, + teamService, + fileService, + injectDuplicateService); + } - @DisplayName("Should create new contextual teams during scenario duplication") - @Test - @Transactional(rollbackOn = Exception.class) - void createNewContextualTeamsDuringScenarioDuplication(){ - // -- PREPARE -- - List scenarioTeams = new ArrayList<>();; - Team contextualTeam = this.teamRepository.save(getTeam(null, "fakeTeamName1", true)); - scenarioTeams.add(contextualTeam); - Team noContextualTeam = this.teamRepository.save(getTeam(null, "fakeTeamName2",false)); - scenarioTeams.add(noContextualTeam); + @DisplayName("Should create new contextual teams during scenario duplication") + @Test + @Transactional(rollbackOn = Exception.class) + void createNewContextualTeamsDuringScenarioDuplication() { + // -- PREPARE -- + List scenarioTeams = new ArrayList<>(); + ; + Team contextualTeam = this.teamRepository.save(getTeam(null, "fakeTeamName1", true)); + scenarioTeams.add(contextualTeam); + Team noContextualTeam = this.teamRepository.save(getTeam(null, "fakeTeamName2", false)); + scenarioTeams.add(noContextualTeam); - Inject inject = new Inject(); - inject.setTeams(scenarioTeams); - Set scenarioInjects = new HashSet<>(); - scenarioInjects.add(this.injectRepository.save(inject)); - Scenario scenario = this.scenarioRepository.save(ScenarioFixture.getScenario(scenarioTeams, scenarioInjects)); + Inject inject = new Inject(); + inject.setTeams(scenarioTeams); + Set scenarioInjects = new HashSet<>(); + scenarioInjects.add(this.injectRepository.save(inject)); + Scenario scenario = + this.scenarioRepository.save(ScenarioFixture.getScenario(scenarioTeams, scenarioInjects)); - // -- EXECUTE -- - Scenario scenarioDuplicated = scenarioService.getDuplicateScenario(scenario.getId()); + // -- EXECUTE -- + Scenario scenarioDuplicated = scenarioService.getDuplicateScenario(scenario.getId()); - // -- ASSERT -- - assertNotEquals(scenario.getId(), scenarioDuplicated.getId()); - assertEquals(scenario.getFrom(), scenarioDuplicated.getFrom()); - assertEquals(2, scenarioDuplicated.getTeams().size()); - scenarioDuplicated.getTeams().forEach(team -> { - if (team.getContextual()){ + // -- ASSERT -- + assertNotEquals(scenario.getId(), scenarioDuplicated.getId()); + assertEquals(scenario.getFrom(), scenarioDuplicated.getFrom()); + assertEquals(2, scenarioDuplicated.getTeams().size()); + scenarioDuplicated + .getTeams() + .forEach( + team -> { + if (team.getContextual()) { assertNotEquals(contextualTeam.getId(), team.getId()); assertEquals(contextualTeam.getName(), team.getName()); - } else { + } else { assertEquals(noContextualTeam.getId(), team.getId()); - } - }); - assertEquals(1, scenarioDuplicated.getInjects().size()); - assertEquals(2, scenario.getInjects().get(0).getTeams().size()); - scenarioDuplicated.getInjects().get(0).getTeams().forEach(injectTeam -> { - if (injectTeam.getContextual()){ + } + }); + assertEquals(1, scenarioDuplicated.getInjects().size()); + assertEquals(2, scenario.getInjects().get(0).getTeams().size()); + scenarioDuplicated + .getInjects() + .get(0) + .getTeams() + .forEach( + injectTeam -> { + if (injectTeam.getContextual()) { assertNotEquals(contextualTeam.getId(), injectTeam.getId()); assertEquals( - scenarioDuplicated.getTeams().stream().filter(team -> team.getContextual().equals(true)).findFirst().orElse(new Team()).getId(), - injectTeam.getId() - ); - } else { + scenarioDuplicated.getTeams().stream() + .filter(team -> team.getContextual().equals(true)) + .findFirst() + .orElse(new Team()) + .getId(), + injectTeam.getId()); + } else { assertEquals(noContextualTeam.getId(), injectTeam.getId()); - } - }); - } + } + }); + } } diff --git a/openbas-api/src/test/java/io/openbas/service/VariableServiceTest.java b/openbas-api/src/test/java/io/openbas/service/VariableServiceTest.java index 0092a89d00..92d5caf2a4 100644 --- a/openbas-api/src/test/java/io/openbas/service/VariableServiceTest.java +++ b/openbas-api/src/test/java/io/openbas/service/VariableServiceTest.java @@ -1,29 +1,26 @@ package io.openbas.service; +import static org.junit.jupiter.api.Assertions.*; +import static org.junit.jupiter.api.TestInstance.Lifecycle.PER_CLASS; + import io.openbas.database.model.Exercise; import io.openbas.database.model.Variable; import io.openbas.database.model.Variable.VariableType; import io.openbas.database.repository.ExerciseRepository; +import java.util.List; +import java.util.NoSuchElementException; import org.junit.jupiter.api.*; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.boot.test.context.SpringBootTest; -import java.util.List; -import java.util.NoSuchElementException; - -import static org.junit.jupiter.api.Assertions.*; -import static org.junit.jupiter.api.TestInstance.Lifecycle.PER_CLASS; - @SpringBootTest @TestInstance(PER_CLASS) @TestMethodOrder(MethodOrderer.OrderAnnotation.class) public class VariableServiceTest { - @Autowired - private VariableService variableService; + @Autowired private VariableService variableService; - @Autowired - private ExerciseRepository exerciseRepository; + @Autowired private ExerciseRepository exerciseRepository; static Exercise EXERCISE; static String VARIABLE_ID; @@ -97,5 +94,4 @@ void deleteVariableTest() { this.variableService.deleteVariable(VARIABLE_ID); assertThrows(NoSuchElementException.class, () -> this.variableService.variable(VARIABLE_ID)); } - } diff --git a/openbas-api/src/test/java/io/openbas/utils/CustomMockMultipartFile.java b/openbas-api/src/test/java/io/openbas/utils/CustomMockMultipartFile.java index c95b34cb6a..c056f9a92a 100644 --- a/openbas-api/src/test/java/io/openbas/utils/CustomMockMultipartFile.java +++ b/openbas-api/src/test/java/io/openbas/utils/CustomMockMultipartFile.java @@ -1,20 +1,20 @@ package io.openbas.utils; -import org.springframework.mock.web.MockMultipartFile; - import java.io.IOException; import java.io.InputStream; +import org.springframework.mock.web.MockMultipartFile; -//A private inner class, which extends the MockMultipartFile +// A private inner class, which extends the MockMultipartFile public class CustomMockMultipartFile extends MockMultipartFile { - public CustomMockMultipartFile(String name, String originalFilename, String contentType, byte[] content) { - super(name, originalFilename, contentType, content); - } + public CustomMockMultipartFile( + String name, String originalFilename, String contentType, byte[] content) { + super(name, originalFilename, contentType, content); + } - //Method is overrided, so that it throws an IOException, when it's called - @Override - public InputStream getInputStream() throws IOException { - throw new IOException(); - } + // Method is overrided, so that it throws an IOException, when it's called + @Override + public InputStream getInputStream() throws IOException { + throw new IOException(); + } } diff --git a/openbas-api/src/test/java/io/openbas/utils/JsonUtils.java b/openbas-api/src/test/java/io/openbas/utils/JsonUtils.java index 9befed995a..d21287dc1b 100644 --- a/openbas-api/src/test/java/io/openbas/utils/JsonUtils.java +++ b/openbas-api/src/test/java/io/openbas/utils/JsonUtils.java @@ -3,7 +3,6 @@ import com.fasterxml.jackson.core.type.TypeReference; import com.fasterxml.jackson.databind.ObjectMapper; import com.fasterxml.jackson.datatype.jsr310.JavaTimeModule; - import jakarta.validation.constraints.NotBlank; import jakarta.validation.constraints.NotNull; @@ -36,12 +35,12 @@ public static T asStringJson(@NotBlank final String obj, @NotNull final Clas } } - public static T asStringJson(@NotBlank final String obj, @NotNull final TypeReference typeReference) { + public static T asStringJson( + @NotBlank final String obj, @NotNull final TypeReference typeReference) { try { return getMapper().readValue(obj, typeReference); } catch (Exception e) { throw new RuntimeException(e); } } - } diff --git a/openbas-api/src/test/java/io/openbas/utils/fixtures/ArticleFixture.java b/openbas-api/src/test/java/io/openbas/utils/fixtures/ArticleFixture.java index f0f8b381d0..2320bd0009 100644 --- a/openbas-api/src/test/java/io/openbas/utils/fixtures/ArticleFixture.java +++ b/openbas-api/src/test/java/io/openbas/utils/fixtures/ArticleFixture.java @@ -15,5 +15,4 @@ public static Article getArticle(@NotNull final Channel channel) { article.setChannel(channel); return article; } - } diff --git a/openbas-api/src/test/java/io/openbas/utils/fixtures/AssetGroupFixture.java b/openbas-api/src/test/java/io/openbas/utils/fixtures/AssetGroupFixture.java index 8e463b2e92..0254a3605e 100644 --- a/openbas-api/src/test/java/io/openbas/utils/fixtures/AssetGroupFixture.java +++ b/openbas-api/src/test/java/io/openbas/utils/fixtures/AssetGroupFixture.java @@ -11,5 +11,4 @@ public static AssetGroup createDefaultAssetGroup(@NotNull final String name) { assetGroup.setDescription("An asset group"); return assetGroup; } - } diff --git a/openbas-api/src/test/java/io/openbas/utils/fixtures/DocumentFixture.java b/openbas-api/src/test/java/io/openbas/utils/fixtures/DocumentFixture.java index 5667540c33..951d2dcb2b 100644 --- a/openbas-api/src/test/java/io/openbas/utils/fixtures/DocumentFixture.java +++ b/openbas-api/src/test/java/io/openbas/utils/fixtures/DocumentFixture.java @@ -12,5 +12,4 @@ public static Document getDocumentJpeg() { document.setType("image/jpeg"); return document; } - } diff --git a/openbas-api/src/test/java/io/openbas/utils/fixtures/ExerciseFixture.java b/openbas-api/src/test/java/io/openbas/utils/fixtures/ExerciseFixture.java index 309d0ddfc8..4b0eeae120 100644 --- a/openbas-api/src/test/java/io/openbas/utils/fixtures/ExerciseFixture.java +++ b/openbas-api/src/test/java/io/openbas/utils/fixtures/ExerciseFixture.java @@ -3,47 +3,45 @@ import io.openbas.database.model.Exercise; import io.openbas.database.model.ExerciseStatus; import io.openbas.database.model.Team; - import java.time.Instant; import java.util.List; public class ExerciseFixture { - public static final String EXERCISE_NAME = "Exercise test"; - - public static Exercise getExercise() { - return getExercise(null); - } + public static final String EXERCISE_NAME = "Exercise test"; - public static Exercise getExercise(List exerciseTeams) { - Exercise exercise = new Exercise(); - exercise.setName(EXERCISE_NAME); - if(exerciseTeams != null){ - exercise.setTeams(exerciseTeams); - } - return exercise; - } + public static Exercise getExercise() { + return getExercise(null); + } - public static Exercise createDefaultCrisisExercise() { - Exercise exercise = new Exercise(); - exercise.setName("Crisis exercise"); - exercise.setDescription("A crisis exercise for my enterprise"); - exercise.setSubtitle("A crisis exercise"); - exercise.setFrom("exercise@mail.fr"); - exercise.setCategory("crisis-communication"); - return exercise; + public static Exercise getExercise(List exerciseTeams) { + Exercise exercise = new Exercise(); + exercise.setName(EXERCISE_NAME); + if (exerciseTeams != null) { + exercise.setTeams(exerciseTeams); } - - public static Exercise createDefaultIncidentResponseExercise() { - Exercise exercise = new Exercise(); - exercise.setName("Incident response exercise"); - exercise.setDescription("An incident response exercise for my enterprise"); - exercise.setSubtitle("An incident response exercise"); - exercise.setFrom("exercise@mail.fr"); - exercise.setCategory("incident-response"); - exercise.setStatus(ExerciseStatus.SCHEDULED); - exercise.setStart(Instant.now()); - return exercise; - } - + return exercise; + } + + public static Exercise createDefaultCrisisExercise() { + Exercise exercise = new Exercise(); + exercise.setName("Crisis exercise"); + exercise.setDescription("A crisis exercise for my enterprise"); + exercise.setSubtitle("A crisis exercise"); + exercise.setFrom("exercise@mail.fr"); + exercise.setCategory("crisis-communication"); + return exercise; + } + + public static Exercise createDefaultIncidentResponseExercise() { + Exercise exercise = new Exercise(); + exercise.setName("Incident response exercise"); + exercise.setDescription("An incident response exercise for my enterprise"); + exercise.setSubtitle("An incident response exercise"); + exercise.setFrom("exercise@mail.fr"); + exercise.setCategory("incident-response"); + exercise.setStatus(ExerciseStatus.SCHEDULED); + exercise.setStart(Instant.now()); + return exercise; + } } diff --git a/openbas-api/src/test/java/io/openbas/utils/fixtures/InjectExpectationFixture.java b/openbas-api/src/test/java/io/openbas/utils/fixtures/InjectExpectationFixture.java index f238543e36..b5882b268d 100644 --- a/openbas-api/src/test/java/io/openbas/utils/fixtures/InjectExpectationFixture.java +++ b/openbas-api/src/test/java/io/openbas/utils/fixtures/InjectExpectationFixture.java @@ -52,8 +52,8 @@ public static InjectExpectation createArticleInjectExpectation(Team team, Inject return injectExpectation; } - public static InjectExpectation createManualInjectExpectationWithExercise(Team team, Inject inject, - Exercise exercise, String expectationName) { + public static InjectExpectation createManualInjectExpectationWithExercise( + Team team, Inject inject, Exercise exercise, String expectationName) { InjectExpectation injectExpectation = new InjectExpectation(); injectExpectation.setInject(inject); injectExpectation.setType(InjectExpectation.EXPECTATION_TYPE.MANUAL); @@ -63,7 +63,5 @@ public static InjectExpectation createManualInjectExpectationWithExercise(Team t injectExpectation.setExercise(exercise); injectExpectation.setName(expectationName); return injectExpectation; - } - } diff --git a/openbas-api/src/test/java/io/openbas/utils/fixtures/InjectFixture.java b/openbas-api/src/test/java/io/openbas/utils/fixtures/InjectFixture.java index 42d700b1a1..a1c050739c 100644 --- a/openbas-api/src/test/java/io/openbas/utils/fixtures/InjectFixture.java +++ b/openbas-api/src/test/java/io/openbas/utils/fixtures/InjectFixture.java @@ -3,18 +3,16 @@ import io.openbas.database.model.Inject; import io.openbas.database.model.InjectorContract; -import static io.openbas.injectors.email.EmailContract.TYPE; - public class InjectFixture { - public static final String INJECT_EMAIL_NAME = "Test email inject"; + public static final String INJECT_EMAIL_NAME = "Test email inject"; - public static Inject getInjectForEmailContract(InjectorContract injectorContract) { - Inject inject = new Inject(); - inject.setTitle(INJECT_EMAIL_NAME); - inject.setInjectorContract(injectorContract); - inject.setEnabled(true); - inject.setDependsDuration(0L); - return inject; - } + public static Inject getInjectForEmailContract(InjectorContract injectorContract) { + Inject inject = new Inject(); + inject.setTitle(INJECT_EMAIL_NAME); + inject.setInjectorContract(injectorContract); + inject.setEnabled(true); + inject.setDependsDuration(0L); + return inject; + } } diff --git a/openbas-api/src/test/java/io/openbas/utils/fixtures/KillChainPhaseFixture.java b/openbas-api/src/test/java/io/openbas/utils/fixtures/KillChainPhaseFixture.java index cdda3373c3..524ed90850 100644 --- a/openbas-api/src/test/java/io/openbas/utils/fixtures/KillChainPhaseFixture.java +++ b/openbas-api/src/test/java/io/openbas/utils/fixtures/KillChainPhaseFixture.java @@ -1,12 +1,11 @@ package io.openbas.utils.fixtures; +import static java.lang.String.valueOf; + import io.openbas.database.model.KillChainPhase; import jakarta.validation.constraints.NotBlank; - import java.util.Random; -import static java.lang.String.valueOf; - public class KillChainPhaseFixture { private static final Random RANDOM = new Random(); @@ -19,5 +18,4 @@ public static KillChainPhase getKillChainPhase(@NotBlank final String name) { killChainPhase.setExternalId(valueOf(RANDOM.nextInt())); return killChainPhase; } - } diff --git a/openbas-api/src/test/java/io/openbas/utils/fixtures/ObjectiveFixture.java b/openbas-api/src/test/java/io/openbas/utils/fixtures/ObjectiveFixture.java index 07a1b414f2..b2cb02d3dc 100644 --- a/openbas-api/src/test/java/io/openbas/utils/fixtures/ObjectiveFixture.java +++ b/openbas-api/src/test/java/io/openbas/utils/fixtures/ObjectiveFixture.java @@ -11,5 +11,4 @@ public static Objective getObjective() { objective.setTitle(OBJECTIVE_NAME); return objective; } - } diff --git a/openbas-api/src/test/java/io/openbas/utils/fixtures/PaginationFixture.java b/openbas-api/src/test/java/io/openbas/utils/fixtures/PaginationFixture.java index b3fd111b27..3aeaed1a4e 100644 --- a/openbas-api/src/test/java/io/openbas/utils/fixtures/PaginationFixture.java +++ b/openbas-api/src/test/java/io/openbas/utils/fixtures/PaginationFixture.java @@ -2,27 +2,22 @@ import io.openbas.database.model.Filters; import io.openbas.utils.pagination.SearchPaginationInput; - import java.util.List; public class PaginationFixture { public static SearchPaginationInput.SearchPaginationInputBuilder getDefault() { - return SearchPaginationInput.builder() - .page(0) - .size(10); + return SearchPaginationInput.builder().page(0).size(10); } - public static SearchPaginationInput simpleFilter(String key, String value, Filters.FilterOperator operator) { + public static SearchPaginationInput simpleFilter( + String key, String value, Filters.FilterOperator operator) { Filters.Filter filter = new Filters.Filter(); filter.setKey(key); filter.setValues(List.of(value)); filter.setOperator(operator); Filters.FilterGroup filterGroup = new Filters.FilterGroup(); filterGroup.setFilters(List.of(filter)); - return getDefault() - .filterGroup(filterGroup) - .build(); + return getDefault().filterGroup(filterGroup).build(); } - } diff --git a/openbas-api/src/test/java/io/openbas/utils/fixtures/PayloadFixture.java b/openbas-api/src/test/java/io/openbas/utils/fixtures/PayloadFixture.java index e8ed5e854f..4b8cda1395 100644 --- a/openbas-api/src/test/java/io/openbas/utils/fixtures/PayloadFixture.java +++ b/openbas-api/src/test/java/io/openbas/utils/fixtures/PayloadFixture.java @@ -1,21 +1,20 @@ package io.openbas.utils.fixtures; -import io.openbas.database.model.*; - -import java.util.Collections; - import static io.openbas.database.model.Command.COMMAND_TYPE; import static io.openbas.database.model.DnsResolution.DNS_RESOLUTION_TYPE; import static io.openbas.database.model.Payload.PAYLOAD_SOURCE.MANUAL; import static io.openbas.database.model.Payload.PAYLOAD_STATUS.VERIFIED; +import io.openbas.database.model.*; +import java.util.Collections; + public class PayloadFixture { public static Payload createDefaultCommand() { Command command = new Command("command-id", COMMAND_TYPE, "command payload"); command.setContent("cd .."); command.setExecutor("PowerShell"); - command.setPlatforms(new Endpoint.PLATFORM_TYPE[]{Endpoint.PLATFORM_TYPE.Windows}); + command.setPlatforms(new Endpoint.PLATFORM_TYPE[] {Endpoint.PLATFORM_TYPE.Windows}); command.setSource(MANUAL); command.setStatus(VERIFIED); command.setAttackPatterns(Collections.emptyList()); @@ -23,9 +22,10 @@ public static Payload createDefaultCommand() { } public static Payload createDefaultDnsResolution() { - DnsResolution dnsResolution = new DnsResolution("dns-resolution-id", DNS_RESOLUTION_TYPE, "dns resolution payload"); + DnsResolution dnsResolution = + new DnsResolution("dns-resolution-id", DNS_RESOLUTION_TYPE, "dns resolution payload"); dnsResolution.setHostname("localhost"); - dnsResolution.setPlatforms(new Endpoint.PLATFORM_TYPE[]{Endpoint.PLATFORM_TYPE.Linux}); + dnsResolution.setPlatforms(new Endpoint.PLATFORM_TYPE[] {Endpoint.PLATFORM_TYPE.Linux}); dnsResolution.setSource(MANUAL); dnsResolution.setStatus(VERIFIED); dnsResolution.setAttackPatterns(Collections.emptyList()); @@ -33,13 +33,13 @@ public static Payload createDefaultDnsResolution() { } public static Payload createDefaultExecutable() { - Executable executable = new Executable("executable-id", Executable.EXECUTABLE_TYPE, "executable payload"); - executable.setPlatforms(new Endpoint.PLATFORM_TYPE[]{Endpoint.PLATFORM_TYPE.MacOS}); + Executable executable = + new Executable("executable-id", Executable.EXECUTABLE_TYPE, "executable payload"); + executable.setPlatforms(new Endpoint.PLATFORM_TYPE[] {Endpoint.PLATFORM_TYPE.MacOS}); executable.setExecutableArch(Endpoint.PLATFORM_ARCH.arm64); executable.setSource(MANUAL); executable.setStatus(VERIFIED); executable.setAttackPatterns(Collections.emptyList()); return executable; } - } diff --git a/openbas-api/src/test/java/io/openbas/utils/fixtures/ScenarioFixture.java b/openbas-api/src/test/java/io/openbas/utils/fixtures/ScenarioFixture.java index 3010a9b0a8..af95b6d80f 100644 --- a/openbas-api/src/test/java/io/openbas/utils/fixtures/ScenarioFixture.java +++ b/openbas-api/src/test/java/io/openbas/utils/fixtures/ScenarioFixture.java @@ -1,14 +1,13 @@ package io.openbas.utils.fixtures; +import static io.openbas.database.model.Scenario.SEVERITY.critical; + import io.openbas.database.model.Inject; import io.openbas.database.model.Scenario; import io.openbas.database.model.Team; - import java.util.List; import java.util.Set; -import static io.openbas.database.model.Scenario.SEVERITY.critical; - public class ScenarioFixture { public static Scenario getScenario() { @@ -21,10 +20,10 @@ public static Scenario getScenario(List scenarioTeams, Set scenari scenario.setDescription("A crisis simulation for my enterprise"); scenario.setSubtitle("A crisis simulation"); scenario.setFrom("simulation@mail.fr"); - if(scenarioTeams != null){ + if (scenarioTeams != null) { scenario.setTeams(scenarioTeams); } - if(scenarioInjects != null){ + if (scenarioInjects != null) { scenario.setInjects(scenarioInjects); } return scenario; @@ -50,5 +49,4 @@ public static Scenario createDefaultIncidentResponseScenario() { scenario.setSeverity(critical); return scenario; } - } diff --git a/openbas-api/src/test/java/io/openbas/utils/fixtures/TagFixture.java b/openbas-api/src/test/java/io/openbas/utils/fixtures/TagFixture.java index e68f7f1aef..cfce15436e 100644 --- a/openbas-api/src/test/java/io/openbas/utils/fixtures/TagFixture.java +++ b/openbas-api/src/test/java/io/openbas/utils/fixtures/TagFixture.java @@ -12,5 +12,4 @@ public static Tag getTag() { tag.setColor("#FFFFFF"); return tag; } - } diff --git a/openbas-api/src/test/java/io/openbas/utils/fixtures/TeamFixture.java b/openbas-api/src/test/java/io/openbas/utils/fixtures/TeamFixture.java index 4256560351..826f86c171 100644 --- a/openbas-api/src/test/java/io/openbas/utils/fixtures/TeamFixture.java +++ b/openbas-api/src/test/java/io/openbas/utils/fixtures/TeamFixture.java @@ -2,7 +2,6 @@ import io.openbas.database.model.Team; import io.openbas.database.model.User; - import java.util.ArrayList; public class TeamFixture { @@ -13,14 +12,18 @@ public static Team getTeam(final User user) { return getTeam(user, TEAM_NAME, false); // Call the other method with default value } - public static Team getTeam(final User user, String name, Boolean isContextualTeam ) { + public static Team getTeam(final User user, String name, Boolean isContextualTeam) { Team team = new Team(); team.setName(name); team.setContextual(isContextualTeam); if (user != null) { - team.setUsers(new ArrayList<>(){{add(user);}}); + team.setUsers( + new ArrayList<>() { + { + add(user); + } + }); } return team; } - } diff --git a/openbas-api/src/test/java/io/openbas/utils/fixtures/UserFixture.java b/openbas-api/src/test/java/io/openbas/utils/fixtures/UserFixture.java index b86079c693..f39607d939 100644 --- a/openbas-api/src/test/java/io/openbas/utils/fixtures/UserFixture.java +++ b/openbas-api/src/test/java/io/openbas/utils/fixtures/UserFixture.java @@ -6,39 +6,39 @@ public class UserFixture { - public static final String RAW_PASSWORD = "myPwd24!@"; - public static final String ENCODED_PASSWORD = getEncodePwd("myPwd24!@"); - - private static String getEncodePwd(String rawPws) { - return Argon2PasswordEncoder.defaultsForSpringSecurity_v5_8().encode(rawPws); - } - - public static final String EMAIL = "user2@filigran.io"; - - public static LoginUserInput.LoginUserInputBuilder getDefault() { - return LoginUserInput.builder(); - } - - public static LoginUserInput.LoginUserInputBuilder getDefaultWithPwd() { - return LoginUserInput.builder().password(RAW_PASSWORD); - } - - public static LoginUserInput getLoginUserInput() { - return LoginUserInput.builder().login(EMAIL).password(RAW_PASSWORD).build(); - } - - public static User getUser() { - User user = new User(); - user.setFirstname("Firstname"); - user.setLastname("Lastname"); - user.setEmail(EMAIL); - user.setPassword(ENCODED_PASSWORD); - return user; - } - - public static User getSavedUser() { - User user = getUser(); - user.setId("saved-user-id"); - return user; - } + public static final String RAW_PASSWORD = "myPwd24!@"; + public static final String ENCODED_PASSWORD = getEncodePwd("myPwd24!@"); + + private static String getEncodePwd(String rawPws) { + return Argon2PasswordEncoder.defaultsForSpringSecurity_v5_8().encode(rawPws); + } + + public static final String EMAIL = "user2@filigran.io"; + + public static LoginUserInput.LoginUserInputBuilder getDefault() { + return LoginUserInput.builder(); + } + + public static LoginUserInput.LoginUserInputBuilder getDefaultWithPwd() { + return LoginUserInput.builder().password(RAW_PASSWORD); + } + + public static LoginUserInput getLoginUserInput() { + return LoginUserInput.builder().login(EMAIL).password(RAW_PASSWORD).build(); + } + + public static User getUser() { + User user = new User(); + user.setFirstname("Firstname"); + user.setLastname("Lastname"); + user.setEmail(EMAIL); + user.setPassword(ENCODED_PASSWORD); + return user; + } + + public static User getSavedUser() { + User user = getUser(); + user.setId("saved-user-id"); + return user; + } } diff --git a/openbas-api/src/test/java/io/openbas/utils/mockMapper/MockMapperUtils.java b/openbas-api/src/test/java/io/openbas/utils/mockMapper/MockMapperUtils.java index b8fef37af8..f4e214772a 100644 --- a/openbas-api/src/test/java/io/openbas/utils/mockMapper/MockMapperUtils.java +++ b/openbas-api/src/test/java/io/openbas/utils/mockMapper/MockMapperUtils.java @@ -4,47 +4,46 @@ import io.openbas.database.model.InjectImporter; import io.openbas.database.model.InjectorContract; import io.openbas.database.model.RuleAttribute; - import java.time.Instant; import java.util.ArrayList; import java.util.Map; import java.util.UUID; public class MockMapperUtils { - public static ImportMapper createImportMapper() { - ImportMapper importMapper = new ImportMapper(); - importMapper.setId(UUID.randomUUID().toString()); - importMapper.setName("Test"); - importMapper.setUpdateDate(Instant.now()); - importMapper.setCreationDate(Instant.now()); - importMapper.setInjectTypeColumn("A"); - importMapper.setInjectImporters(new ArrayList<>()); - - importMapper.getInjectImporters().add(createInjectImporter()); - - return importMapper; - } - - private static InjectImporter createInjectImporter() { - InjectImporter injectImporter = new InjectImporter(); - injectImporter.setId(UUID.randomUUID().toString()); - injectImporter.setImportTypeValue("Test"); - InjectorContract injectorContract = new InjectorContract(); - injectorContract.setId(UUID.randomUUID().toString()); - injectImporter.setInjectorContract(injectorContract); - injectImporter.setRuleAttributes(new ArrayList<>()); - - injectImporter.getRuleAttributes().add(createRuleAttribute()); - return injectImporter; - } - - private static RuleAttribute createRuleAttribute() { - RuleAttribute ruleAttribute = new RuleAttribute(); - ruleAttribute.setColumns("Test"); - ruleAttribute.setName("Test"); - ruleAttribute.setId(UUID.randomUUID().toString()); - ruleAttribute.setAdditionalConfig(Map.of("test", "test")); - ruleAttribute.setDefaultValue(""); - return ruleAttribute; - } + public static ImportMapper createImportMapper() { + ImportMapper importMapper = new ImportMapper(); + importMapper.setId(UUID.randomUUID().toString()); + importMapper.setName("Test"); + importMapper.setUpdateDate(Instant.now()); + importMapper.setCreationDate(Instant.now()); + importMapper.setInjectTypeColumn("A"); + importMapper.setInjectImporters(new ArrayList<>()); + + importMapper.getInjectImporters().add(createInjectImporter()); + + return importMapper; + } + + private static InjectImporter createInjectImporter() { + InjectImporter injectImporter = new InjectImporter(); + injectImporter.setId(UUID.randomUUID().toString()); + injectImporter.setImportTypeValue("Test"); + InjectorContract injectorContract = new InjectorContract(); + injectorContract.setId(UUID.randomUUID().toString()); + injectImporter.setInjectorContract(injectorContract); + injectImporter.setRuleAttributes(new ArrayList<>()); + + injectImporter.getRuleAttributes().add(createRuleAttribute()); + return injectImporter; + } + + private static RuleAttribute createRuleAttribute() { + RuleAttribute ruleAttribute = new RuleAttribute(); + ruleAttribute.setColumns("Test"); + ruleAttribute.setName("Test"); + ruleAttribute.setId(UUID.randomUUID().toString()); + ruleAttribute.setAdditionalConfig(Map.of("test", "test")); + ruleAttribute.setDefaultValue(""); + return ruleAttribute; + } } diff --git a/openbas-api/src/test/java/io/openbas/utils/mockUser/WithMockAdminUser.java b/openbas-api/src/test/java/io/openbas/utils/mockUser/WithMockAdminUser.java index 134df59a8f..acf64905b2 100644 --- a/openbas-api/src/test/java/io/openbas/utils/mockUser/WithMockAdminUser.java +++ b/openbas-api/src/test/java/io/openbas/utils/mockUser/WithMockAdminUser.java @@ -1,14 +1,13 @@ package io.openbas.utils.mockUser; -import org.springframework.security.test.context.support.WithSecurityContext; +import static io.openbas.utils.mockUser.WithMockAdminUserSecurityContextFactory.MOCK_USER_ADMIN_EMAIL; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; - -import static io.openbas.utils.mockUser.WithMockAdminUserSecurityContextFactory.MOCK_USER_ADMIN_EMAIL; +import org.springframework.security.test.context.support.WithSecurityContext; @Retention(RetentionPolicy.RUNTIME) @WithSecurityContext(factory = WithMockAdminUserSecurityContextFactory.class) public @interface WithMockAdminUser { - String email() default MOCK_USER_ADMIN_EMAIL; + String email() default MOCK_USER_ADMIN_EMAIL; } diff --git a/openbas-api/src/test/java/io/openbas/utils/mockUser/WithMockAdminUserSecurityContextFactory.java b/openbas-api/src/test/java/io/openbas/utils/mockUser/WithMockAdminUserSecurityContextFactory.java index 23d946dc76..d898db6c1d 100644 --- a/openbas-api/src/test/java/io/openbas/utils/mockUser/WithMockAdminUserSecurityContextFactory.java +++ b/openbas-api/src/test/java/io/openbas/utils/mockUser/WithMockAdminUserSecurityContextFactory.java @@ -1,5 +1,7 @@ package io.openbas.utils.mockUser; +import static io.openbas.service.UserService.buildAuthenticationToken; + import io.openbas.database.model.User; import org.springframework.security.core.Authentication; import org.springframework.security.core.context.SecurityContext; @@ -7,23 +9,22 @@ import org.springframework.security.test.context.support.WithSecurityContextFactory; import org.springframework.stereotype.Component; -import static io.openbas.service.UserService.buildAuthenticationToken; - @Component -public class WithMockAdminUserSecurityContextFactory implements WithSecurityContextFactory { +public class WithMockAdminUserSecurityContextFactory + implements WithSecurityContextFactory { - public static final String MOCK_USER_ADMIN_EMAIL = "admin-email@openbas.io"; - private static final String LANG_EN = "en"; + public static final String MOCK_USER_ADMIN_EMAIL = "admin-email@openbas.io"; + private static final String LANG_EN = "en"; - @Override - public SecurityContext createSecurityContext(WithMockAdminUser customUser) { - User user = new User(); - user.setEmail(MOCK_USER_ADMIN_EMAIL); - user.setLang(LANG_EN); - user.setAdmin(true); - Authentication authentication = buildAuthenticationToken(user); - SecurityContext context = SecurityContextHolder.createEmptyContext(); - context.setAuthentication(authentication); - return context; - } + @Override + public SecurityContext createSecurityContext(WithMockAdminUser customUser) { + User user = new User(); + user.setEmail(MOCK_USER_ADMIN_EMAIL); + user.setLang(LANG_EN); + user.setAdmin(true); + Authentication authentication = buildAuthenticationToken(user); + SecurityContext context = SecurityContextHolder.createEmptyContext(); + context.setAuthentication(authentication); + return context; + } } diff --git a/openbas-api/src/test/java/io/openbas/utils/mockUser/WithMockObserverUser.java b/openbas-api/src/test/java/io/openbas/utils/mockUser/WithMockObserverUser.java index 4eefcc1bf3..c62ae916f1 100644 --- a/openbas-api/src/test/java/io/openbas/utils/mockUser/WithMockObserverUser.java +++ b/openbas-api/src/test/java/io/openbas/utils/mockUser/WithMockObserverUser.java @@ -1,14 +1,13 @@ package io.openbas.utils.mockUser; -import org.springframework.security.test.context.support.WithSecurityContext; +import static io.openbas.utils.mockUser.WithMockObserverUserSecurityContextFactory.MOCK_USER_OBSERVER_EMAIL; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; - -import static io.openbas.utils.mockUser.WithMockObserverUserSecurityContextFactory.MOCK_USER_OBSERVER_EMAIL; +import org.springframework.security.test.context.support.WithSecurityContext; @Retention(RetentionPolicy.RUNTIME) @WithSecurityContext(factory = WithMockObserverUserSecurityContextFactory.class) public @interface WithMockObserverUser { - String email() default MOCK_USER_OBSERVER_EMAIL; + String email() default MOCK_USER_OBSERVER_EMAIL; } diff --git a/openbas-api/src/test/java/io/openbas/utils/mockUser/WithMockObserverUserSecurityContextFactory.java b/openbas-api/src/test/java/io/openbas/utils/mockUser/WithMockObserverUserSecurityContextFactory.java index 6d94f0d3de..4b5678eeff 100644 --- a/openbas-api/src/test/java/io/openbas/utils/mockUser/WithMockObserverUserSecurityContextFactory.java +++ b/openbas-api/src/test/java/io/openbas/utils/mockUser/WithMockObserverUserSecurityContextFactory.java @@ -1,5 +1,8 @@ package io.openbas.utils.mockUser; +import static io.openbas.database.model.Grant.GRANT_TYPE.OBSERVER; +import static io.openbas.service.UserService.buildAuthenticationToken; + import io.openbas.database.model.Grant; import io.openbas.database.model.Group; import io.openbas.database.model.User; @@ -9,6 +12,8 @@ import io.openbas.database.specification.GroupSpecification; import jakarta.annotation.PostConstruct; import jakarta.annotation.PreDestroy; +import java.util.List; +import java.util.Optional; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.security.core.Authentication; import org.springframework.security.core.context.SecurityContext; @@ -16,22 +21,14 @@ import org.springframework.security.test.context.support.WithSecurityContextFactory; import org.springframework.stereotype.Component; -import java.util.List; -import java.util.Optional; - -import static io.openbas.database.model.Grant.GRANT_TYPE.OBSERVER; -import static io.openbas.service.UserService.buildAuthenticationToken; - @Component -public class WithMockObserverUserSecurityContextFactory implements WithSecurityContextFactory { +public class WithMockObserverUserSecurityContextFactory + implements WithSecurityContextFactory { public static final String MOCK_USER_OBSERVER_EMAIL = "observer@openbas.io"; - @Autowired - private GrantRepository grantRepository; - @Autowired - private GroupRepository groupRepository; - @Autowired - private UserRepository userRepository; + @Autowired private GrantRepository grantRepository; + @Autowired private GroupRepository groupRepository; + @Autowired private UserRepository userRepository; @Override public SecurityContext createSecurityContext(WithMockObserverUser customUser) { @@ -49,7 +46,8 @@ private void postConstruct() { @PreDestroy public void preDestroy() { - this.userRepository.deleteById(this.userRepository.findByEmailIgnoreCase(MOCK_USER_OBSERVER_EMAIL).orElseThrow().getId()); + this.userRepository.deleteById( + this.userRepository.findByEmailIgnoreCase(MOCK_USER_OBSERVER_EMAIL).orElseThrow().getId()); } private void createObserverMockUser() { diff --git a/openbas-api/src/test/java/io/openbas/utils/mockUser/WithMockPlannerUser.java b/openbas-api/src/test/java/io/openbas/utils/mockUser/WithMockPlannerUser.java index c960e8d209..b404371e32 100644 --- a/openbas-api/src/test/java/io/openbas/utils/mockUser/WithMockPlannerUser.java +++ b/openbas-api/src/test/java/io/openbas/utils/mockUser/WithMockPlannerUser.java @@ -1,14 +1,13 @@ package io.openbas.utils.mockUser; -import org.springframework.security.test.context.support.WithSecurityContext; +import static io.openbas.utils.mockUser.WithMockPlannerUserSecurityContextFactory.MOCK_USER_PLANNER_EMAIL; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; - -import static io.openbas.utils.mockUser.WithMockPlannerUserSecurityContextFactory.MOCK_USER_PLANNER_EMAIL; +import org.springframework.security.test.context.support.WithSecurityContext; @Retention(RetentionPolicy.RUNTIME) @WithSecurityContext(factory = WithMockPlannerUserSecurityContextFactory.class) public @interface WithMockPlannerUser { - String email() default MOCK_USER_PLANNER_EMAIL; + String email() default MOCK_USER_PLANNER_EMAIL; } diff --git a/openbas-api/src/test/java/io/openbas/utils/mockUser/WithMockPlannerUserSecurityContextFactory.java b/openbas-api/src/test/java/io/openbas/utils/mockUser/WithMockPlannerUserSecurityContextFactory.java index 43dd7d70d7..8595db4b2a 100644 --- a/openbas-api/src/test/java/io/openbas/utils/mockUser/WithMockPlannerUserSecurityContextFactory.java +++ b/openbas-api/src/test/java/io/openbas/utils/mockUser/WithMockPlannerUserSecurityContextFactory.java @@ -1,5 +1,8 @@ package io.openbas.utils.mockUser; +import static io.openbas.database.model.Grant.GRANT_TYPE.PLANNER; +import static io.openbas.service.UserService.buildAuthenticationToken; + import io.openbas.database.model.Grant; import io.openbas.database.model.Group; import io.openbas.database.model.User; @@ -9,6 +12,8 @@ import io.openbas.database.specification.GroupSpecification; import jakarta.annotation.PostConstruct; import jakarta.annotation.PreDestroy; +import java.util.List; +import java.util.Optional; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.security.core.Authentication; import org.springframework.security.core.context.SecurityContext; @@ -16,22 +21,14 @@ import org.springframework.security.test.context.support.WithSecurityContextFactory; import org.springframework.stereotype.Component; -import java.util.List; -import java.util.Optional; - -import static io.openbas.database.model.Grant.GRANT_TYPE.PLANNER; -import static io.openbas.service.UserService.buildAuthenticationToken; - @Component -public class WithMockPlannerUserSecurityContextFactory implements WithSecurityContextFactory { +public class WithMockPlannerUserSecurityContextFactory + implements WithSecurityContextFactory { public static final String MOCK_USER_PLANNER_EMAIL = "planner@openbas.io"; - @Autowired - private GrantRepository grantRepository; - @Autowired - private GroupRepository groupRepository; - @Autowired - private UserRepository userRepository; + @Autowired private GrantRepository grantRepository; + @Autowired private GroupRepository groupRepository; + @Autowired private UserRepository userRepository; @Override public SecurityContext createSecurityContext(WithMockPlannerUser customUser) { @@ -49,7 +46,8 @@ private void postConstruct() { @PreDestroy public void preDestroy() { - this.userRepository.deleteById(this.userRepository.findByEmailIgnoreCase(MOCK_USER_PLANNER_EMAIL).orElseThrow().getId()); + this.userRepository.deleteById( + this.userRepository.findByEmailIgnoreCase(MOCK_USER_PLANNER_EMAIL).orElseThrow().getId()); } private void createPlannerMockUser() { diff --git a/openbas-framework/src/main/java/io/openbas/asset/AssetGroupService.java b/openbas-framework/src/main/java/io/openbas/asset/AssetGroupService.java index a69e423752..bc7e477b23 100644 --- a/openbas-framework/src/main/java/io/openbas/asset/AssetGroupService.java +++ b/openbas-framework/src/main/java/io/openbas/asset/AssetGroupService.java @@ -1,5 +1,11 @@ package io.openbas.asset; +import static io.openbas.database.model.Filters.isEmptyFilterGroup; +import static io.openbas.helper.StreamHelper.fromIterable; +import static io.openbas.utils.FilterUtilsJpa.computeFilterGroupJpa; +import static io.openbas.utils.FilterUtilsRuntime.computeFilterGroupRuntime; +import static java.time.Instant.now; + import io.openbas.database.model.Asset; import io.openbas.database.model.AssetGroup; import io.openbas.database.model.Endpoint; @@ -7,22 +13,15 @@ import io.openbas.database.repository.AssetGroupRepository; import jakarta.validation.constraints.NotBlank; import jakarta.validation.constraints.NotNull; -import lombok.RequiredArgsConstructor; -import org.springframework.data.jpa.domain.Specification; -import org.springframework.stereotype.Service; -import org.springframework.transaction.annotation.Transactional; - import java.util.List; import java.util.Map; import java.util.function.Predicate; import java.util.stream.Collectors; import java.util.stream.Stream; - -import static io.openbas.database.model.Filters.isEmptyFilterGroup; -import static io.openbas.helper.StreamHelper.fromIterable; -import static io.openbas.utils.FilterUtilsJpa.computeFilterGroupJpa; -import static io.openbas.utils.FilterUtilsRuntime.computeFilterGroupRuntime; -import static java.time.Instant.now; +import lombok.RequiredArgsConstructor; +import org.springframework.data.jpa.domain.Specification; +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; @RequiredArgsConstructor @Service @@ -45,7 +44,8 @@ public List assetGroups() { } public List assetGroups(@NotBlank final List assetGroupIds) { - List assetGroups = fromIterable(this.assetGroupRepository.findAllById(assetGroupIds)); + List assetGroups = + fromIterable(this.assetGroupRepository.findAllById(assetGroupIds)); return computeDynamicAssets(assetGroups); } @@ -61,8 +61,7 @@ public AssetGroup updateAssetGroup(@NotNull final AssetGroup assetGroup) { } public AssetGroup updateAssetsOnAssetGroup( - @NotNull final AssetGroup assetGroup, - @NotNull final List assetIds) { + @NotNull final AssetGroup assetGroup, @NotNull final List assetIds) { Iterable assets = this.assetService.assetFromIds(assetIds); assetGroup.setAssets(fromIterable(assets)); assetGroup.setUpdatedAt(now()); @@ -79,33 +78,37 @@ public void deleteAssetGroup(@NotBlank final String assetGroupId) { @Transactional(readOnly = true) public List assetsFromAssetGroup(@NotBlank final String assetGroupId) { AssetGroup assetGroup = this.assetGroup(assetGroupId); - return Stream.concat( - assetGroup.getAssets().stream(), - assetGroup.getDynamicAssets().stream() - ) + return Stream.concat(assetGroup.getAssets().stream(), assetGroup.getDynamicAssets().stream()) .distinct() .collect(Collectors.toList()); } private List computeDynamicAssets(@NotNull final List assetGroups) { - if (assetGroups.stream().noneMatch(assetGroup -> isEmptyFilterGroup(assetGroup.getDynamicFilter()))) { + if (assetGroups.stream() + .noneMatch(assetGroup -> isEmptyFilterGroup(assetGroup.getDynamicFilter()))) { return assetGroups; } List assets = this.assetService.assets(); - assetGroups.forEach(assetGroup -> { - if (!isEmptyFilterGroup(assetGroup.getDynamicFilter())) { - Predicate filters = computeFilterGroupRuntime(assetGroup.getDynamicFilter()); - - List filteredAssets = assets.stream() - .filter(asset -> "Endpoint".equals( - asset.getType())) // Filters for dynamic assets are applicable only to endpoints - .filter(filters) - .toList(); - - assetGroup.setDynamicAssets(filteredAssets); - } - }); + assetGroups.forEach( + assetGroup -> { + if (!isEmptyFilterGroup(assetGroup.getDynamicFilter())) { + Predicate filters = computeFilterGroupRuntime(assetGroup.getDynamicFilter()); + + List filteredAssets = + assets.stream() + .filter( + asset -> + "Endpoint" + .equals( + asset.getType())) // Filters for dynamic assets are applicable + // only to endpoints + .filter(filters) + .toList(); + + assetGroup.setDynamicAssets(filteredAssets); + } + }); return assetGroups; } @@ -114,32 +117,35 @@ public AssetGroup computeDynamicAssets(@NotNull final AssetGroup assetGroup) { return assetGroup; } Specification specification = computeFilterGroupJpa(assetGroup.getDynamicFilter()); - List assets = this.endpointService.endpoints(specification) - .stream() - .map(endpoint -> (Asset) endpoint) - .filter(asset -> asset.getParent() == null && asset.getInject() == null) - .distinct() - .toList(); + List assets = + this.endpointService.endpoints(specification).stream() + .map(endpoint -> (Asset) endpoint) + .filter(asset -> asset.getParent() == null && asset.getInject() == null) + .distinct() + .toList(); assetGroup.setDynamicAssets(assets); return assetGroup; } - /** - * - * */ - public Map> computeDynamicAssetFromRaw(@NotNull List assetGroups) { + /** */ + public Map> computeDynamicAssetFromRaw( + @NotNull List assetGroups) { if (assetGroups.isEmpty()) { return Map.of(); } - return assetGroups.stream().collect(Collectors.toMap(RawAssetGroup::getAsset_group_id, assetGroup -> { - Specification specification = computeFilterGroupJpa(assetGroup.getAssetGroupDynamicFilter()); - return this.endpointService.endpoints(specification) - .stream() - .filter(endpoint -> endpoint.getParent() == null && endpoint.getInject() == null) - .distinct() - .toList(); - })); + return assetGroups.stream() + .collect( + Collectors.toMap( + RawAssetGroup::getAsset_group_id, + assetGroup -> { + Specification specification = + computeFilterGroupJpa(assetGroup.getAssetGroupDynamicFilter()); + return this.endpointService.endpoints(specification).stream() + .filter( + endpoint -> endpoint.getParent() == null && endpoint.getInject() == null) + .distinct() + .toList(); + })); } - } diff --git a/openbas-framework/src/main/java/io/openbas/asset/AssetService.java b/openbas-framework/src/main/java/io/openbas/asset/AssetService.java index 0dcdb46a08..a972739f9b 100644 --- a/openbas-framework/src/main/java/io/openbas/asset/AssetService.java +++ b/openbas-framework/src/main/java/io/openbas/asset/AssetService.java @@ -1,16 +1,15 @@ package io.openbas.asset; +import static io.openbas.helper.StreamHelper.fromIterable; + import io.openbas.database.model.Asset; import io.openbas.database.repository.AssetRepository; import jakarta.validation.constraints.NotBlank; import jakarta.validation.constraints.NotNull; +import java.util.List; import lombok.RequiredArgsConstructor; import org.springframework.stereotype.Service; -import java.util.List; - -import static io.openbas.helper.StreamHelper.fromIterable; - @RequiredArgsConstructor @Service public class AssetService { @@ -36,5 +35,4 @@ public List assetsFromTypes(@NotNull final List types) { public Iterable assetFromIds(@NotNull final List assetIds) { return this.assetRepository.findAllById(assetIds); } - } diff --git a/openbas-framework/src/main/java/io/openbas/asset/EndpointService.java b/openbas-framework/src/main/java/io/openbas/asset/EndpointService.java index 96e681403d..82daf65aa0 100644 --- a/openbas-framework/src/main/java/io/openbas/asset/EndpointService.java +++ b/openbas-framework/src/main/java/io/openbas/asset/EndpointService.java @@ -1,18 +1,14 @@ package io.openbas.asset; +import static io.openbas.helper.StreamHelper.fromIterable; +import static java.time.Instant.now; + import io.openbas.config.OpenBASConfig; import io.openbas.database.model.Endpoint; import io.openbas.database.repository.EndpointRepository; import jakarta.annotation.Resource; import jakarta.validation.constraints.NotBlank; import jakarta.validation.constraints.NotNull; -import lombok.RequiredArgsConstructor; -import org.apache.commons.io.IOUtils; -import org.springframework.beans.factory.annotation.Value; -import org.springframework.data.jpa.domain.Specification; -import org.springframework.stereotype.Service; -import org.springframework.transaction.annotation.Transactional; - import java.io.BufferedInputStream; import java.io.IOException; import java.io.InputStream; @@ -20,9 +16,12 @@ import java.nio.charset.StandardCharsets; import java.util.List; import java.util.Optional; - -import static io.openbas.helper.StreamHelper.fromIterable; -import static java.time.Instant.now; +import lombok.RequiredArgsConstructor; +import org.apache.commons.io.IOUtils; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.data.jpa.domain.Specification; +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; @RequiredArgsConstructor @Service @@ -30,13 +29,13 @@ public class EndpointService { public static String JFROG_BASE = "https://filigran.jfrog.io/artifactory"; - @Resource - private OpenBASConfig openBASConfig; + @Resource private OpenBASConfig openBASConfig; @Value("${openbas.admin.token:#{null}}") private String adminToken; - @Value("${info.app.version:unknown}") String version; + @Value("${info.app.version:unknown}") + String version; private final EndpointRepository endpointRepository; @@ -94,13 +93,15 @@ public void deleteEndpoint(@NotBlank final String endpointId) { this.endpointRepository.deleteById(endpointId); } - public String getFileOrDownloadFromJfrog(String platform, String file, String adminToken) throws IOException { - String extension = switch (platform.toLowerCase()) { - case "windows" -> "ps1"; - case "linux", "macos" -> "sh"; - default -> throw new UnsupportedOperationException(""); - }; - String filename = file + "-" + version + "." + extension; + public String getFileOrDownloadFromJfrog(String platform, String file, String adminToken) + throws IOException { + String extension = + switch (platform.toLowerCase()) { + case "windows" -> "ps1"; + case "linux", "macos" -> "sh"; + default -> throw new UnsupportedOperationException(""); + }; + String filename = file + "-" + version + "." + extension; String resourcePath = "/openbas-agent/" + platform.toLowerCase() + "/"; InputStream in = getClass().getResourceAsStream("/agents" + resourcePath + filename); if (in == null) { // Dev mode, get from artifactory @@ -108,10 +109,12 @@ public String getFileOrDownloadFromJfrog(String platform, String file, String ad in = new BufferedInputStream(new URL(JFROG_BASE + resourcePath + filename).openStream()); } return IOUtils.toString(in, StandardCharsets.UTF_8) - .replace("${OPENBAS_URL}", openBASConfig.getBaseUrlForAgent()) - .replace("${OPENBAS_TOKEN}", adminToken) - .replace("${OPENBAS_UNSECURED_CERTIFICATE}", String.valueOf(openBASConfig.isUnsecuredCertificate())) - .replace("${OPENBAS_WITH_PROXY}", String.valueOf(openBASConfig.isWithProxy())); + .replace("${OPENBAS_URL}", openBASConfig.getBaseUrlForAgent()) + .replace("${OPENBAS_TOKEN}", adminToken) + .replace( + "${OPENBAS_UNSECURED_CERTIFICATE}", + String.valueOf(openBASConfig.isUnsecuredCertificate())) + .replace("${OPENBAS_WITH_PROXY}", String.valueOf(openBASConfig.isWithProxy())); } public String generateInstallCommand(String platform, String token) throws IOException { diff --git a/openbas-framework/src/main/java/io/openbas/asset/QueueService.java b/openbas-framework/src/main/java/io/openbas/asset/QueueService.java index 06db853381..77648e10e7 100644 --- a/openbas-framework/src/main/java/io/openbas/asset/QueueService.java +++ b/openbas-framework/src/main/java/io/openbas/asset/QueueService.java @@ -6,11 +6,10 @@ import com.rabbitmq.client.ConnectionFactory; import io.openbas.config.RabbitmqConfig; import jakarta.annotation.Resource; -import lombok.extern.java.Log; -import org.springframework.stereotype.Service; - import java.io.IOException; import java.util.concurrent.TimeoutException; +import lombok.extern.java.Log; +import org.springframework.stereotype.Service; @Log @Service @@ -19,13 +18,12 @@ public class QueueService { public static final String ROUTING_KEY = "_push_routing_"; public static final String EXCHANGE_KEY = "_amqp.connector.exchange"; - @Resource - protected ObjectMapper mapper; + @Resource protected ObjectMapper mapper; - @Resource - private RabbitmqConfig rabbitmqConfig; + @Resource private RabbitmqConfig rabbitmqConfig; - public void publish(String injectType, String publishedJson) throws IOException, TimeoutException { + public void publish(String injectType, String publishedJson) + throws IOException, TimeoutException { ConnectionFactory factory = new ConnectionFactory(); factory.setHost(rabbitmqConfig.getHostname()); factory.setPort(rabbitmqConfig.getPort()); @@ -44,7 +42,8 @@ public void publish(String injectType, String publishedJson) throws IOException, try { connection.close(); } catch (IOException ex) { - log.severe("Unable to close RabbitMQ connection. You should worry as this could impact performance"); + log.severe( + "Unable to close RabbitMQ connection. You should worry as this could impact performance"); } } } diff --git a/openbas-framework/src/main/java/io/openbas/config/OpenBASAdminConfig.java b/openbas-framework/src/main/java/io/openbas/config/OpenBASAdminConfig.java index ec39dd530e..14c1db6ad3 100644 --- a/openbas-framework/src/main/java/io/openbas/config/OpenBASAdminConfig.java +++ b/openbas-framework/src/main/java/io/openbas/config/OpenBASAdminConfig.java @@ -9,7 +9,6 @@ @ConfigurationProperties(prefix = "openbas.admin") @Data public class OpenBASAdminConfig { - @JsonProperty("admin_token") - private String token; - + @JsonProperty("admin_token") + private String token; } diff --git a/openbas-framework/src/main/java/io/openbas/config/OpenBASConfig.java b/openbas-framework/src/main/java/io/openbas/config/OpenBASConfig.java index 5eee692b9f..15aa6ffbfe 100644 --- a/openbas-framework/src/main/java/io/openbas/config/OpenBASConfig.java +++ b/openbas-framework/src/main/java/io/openbas/config/OpenBASConfig.java @@ -1,5 +1,7 @@ package io.openbas.config; +import static org.springframework.util.StringUtils.hasText; + import com.fasterxml.jackson.annotation.JsonIgnore; import com.fasterxml.jackson.annotation.JsonProperty; import jakarta.validation.constraints.NotBlank; @@ -8,8 +10,6 @@ import org.springframework.boot.context.properties.ConfigurationProperties; import org.springframework.stereotype.Component; -import static org.springframework.util.StringUtils.hasText; - @Component @ConfigurationProperties(prefix = "openbas") @Data @@ -58,14 +58,11 @@ public class OpenBASConfig { @JsonProperty("disabled_dev_features") private String disabledDevFeatures = ""; - @JsonIgnore - private String cookieName = "openbas_token"; + @JsonIgnore private String cookieName = "openbas_token"; - @JsonIgnore - private String cookieDuration = "P1D"; + @JsonIgnore private String cookieDuration = "P1D"; - @JsonIgnore - private boolean cookieSecure = false; + @JsonIgnore private boolean cookieSecure = false; public String getBaseUrl() { return url(baseUrl); @@ -81,7 +78,7 @@ public String getBaseUrl() { private boolean withProxy; public String getBaseUrlForAgent() { - return hasText(agentUrl) ? url(agentUrl) :url(baseUrl); + return hasText(agentUrl) ? url(agentUrl) : url(baseUrl); } // -- PRIVATE -- diff --git a/openbas-framework/src/main/java/io/openbas/config/RabbitmqConfig.java b/openbas-framework/src/main/java/io/openbas/config/RabbitmqConfig.java index ee699dbfcc..c32af2b373 100644 --- a/openbas-framework/src/main/java/io/openbas/config/RabbitmqConfig.java +++ b/openbas-framework/src/main/java/io/openbas/config/RabbitmqConfig.java @@ -47,5 +47,4 @@ public class RabbitmqConfig { @Value("${openbas.rabbitmq.trust.store}") private Resource trustStore; - } diff --git a/openbas-framework/src/main/java/io/openbas/execution/ExecutableInject.java b/openbas-framework/src/main/java/io/openbas/execution/ExecutableInject.java index 87fc73e717..9a76209078 100644 --- a/openbas-framework/src/main/java/io/openbas/execution/ExecutableInject.java +++ b/openbas-framework/src/main/java/io/openbas/execution/ExecutableInject.java @@ -2,51 +2,53 @@ import com.fasterxml.jackson.annotation.JsonIgnore; import io.openbas.database.model.*; -import lombok.Getter; -import lombok.Setter; -import org.springframework.web.multipart.MultipartFile; - import java.util.ArrayList; import java.util.List; -import java.util.Map; +import lombok.Getter; +import org.springframework.web.multipart.MultipartFile; @Getter public class ExecutableInject { - private final Injection injection; - private final int teamSize; - private final boolean direct; - private final boolean runtime; - private final int documentSize; - private final List teams; - private final Exercise exercise; - private final List assets; - private final List assetGroups; - private final List users; - - @JsonIgnore - private final List directAttachments = new ArrayList<>(); - - public ExecutableInject(boolean runtime, boolean direct, Injection injection, - List teams, List assets, List assetGroups, List users) { - this.injection = injection; - this.exercise = injection.getExercise(); - this.runtime = runtime; - this.direct = direct; - this.users = users; - this.teams = teams; - this.assets = assets; - this.assetGroups = assetGroups; - this.teamSize = teams.size(); - this.documentSize = injection.getInject().getDocuments().size(); - } - - public ExecutableInject(boolean runtime, boolean direct, Injection injection, List users) { - this(runtime, direct, injection, List.of(), List.of(), List.of(), users); - } - - public void addDirectAttachment(MultipartFile file) { - this.directAttachments.add(file); - } - + private final Injection injection; + private final int teamSize; + private final boolean direct; + private final boolean runtime; + private final int documentSize; + private final List teams; + private final Exercise exercise; + private final List assets; + private final List assetGroups; + private final List users; + + @JsonIgnore private final List directAttachments = new ArrayList<>(); + + public ExecutableInject( + boolean runtime, + boolean direct, + Injection injection, + List teams, + List assets, + List assetGroups, + List users) { + this.injection = injection; + this.exercise = injection.getExercise(); + this.runtime = runtime; + this.direct = direct; + this.users = users; + this.teams = teams; + this.assets = assets; + this.assetGroups = assetGroups; + this.teamSize = teams.size(); + this.documentSize = injection.getInject().getDocuments().size(); + } + + public ExecutableInject( + boolean runtime, boolean direct, Injection injection, List users) { + this(runtime, direct, injection, List.of(), List.of(), List.of(), users); + } + + public void addDirectAttachment(MultipartFile file) { + this.directAttachments.add(file); + } } diff --git a/openbas-framework/src/main/java/io/openbas/execution/ExecutionContext.java b/openbas-framework/src/main/java/io/openbas/execution/ExecutionContext.java index acda08b0e7..9f41db0f4f 100644 --- a/openbas-framework/src/main/java/io/openbas/execution/ExecutionContext.java +++ b/openbas-framework/src/main/java/io/openbas/execution/ExecutionContext.java @@ -1,8 +1,7 @@ package io.openbas.execution; -import io.openbas.injector_contract.variables.VariableHelper; import io.openbas.database.model.User; - +import io.openbas.injector_contract.variables.VariableHelper; import java.util.HashMap; import java.util.List; diff --git a/openbas-framework/src/main/java/io/openbas/execution/ExecutionContextService.java b/openbas-framework/src/main/java/io/openbas/execution/ExecutionContextService.java index 59a9732e9e..8bf43556a0 100644 --- a/openbas-framework/src/main/java/io/openbas/execution/ExecutionContextService.java +++ b/openbas-framework/src/main/java/io/openbas/execution/ExecutionContextService.java @@ -1,5 +1,7 @@ package io.openbas.execution; +import static io.openbas.injector_contract.variables.VariableHelper.*; + import io.openbas.config.OpenBASConfig; import io.openbas.database.model.Exercise; import io.openbas.database.model.Injection; @@ -10,28 +12,25 @@ import jakarta.annotation.Resource; import jakarta.validation.constraints.NotBlank; import jakarta.validation.constraints.NotNull; +import java.util.List; import lombok.RequiredArgsConstructor; import org.springframework.stereotype.Service; -import java.util.List; - -import static io.openbas.injector_contract.variables.VariableHelper.*; - @RequiredArgsConstructor @Service public class ExecutionContextService { - @Resource - private final OpenBASConfig openBASCOnfig; + @Resource private final OpenBASConfig openBASCOnfig; private final VariableRepository variableRepository; - - public ExecutionContext executionContext(@NotNull final User user, Injection injection, String team) { + public ExecutionContext executionContext( + @NotNull final User user, Injection injection, String team) { return this.executionContext(user, injection, List.of(team)); } - public ExecutionContext executionContext(@NotNull final User user, Injection injection, List teams) { + public ExecutionContext executionContext( + @NotNull final User user, Injection injection, List teams) { ExecutionContext executionContext = new ExecutionContext(user, teams); if (injection.getExercise() != null) { String exerciseId = injection.getExercise().getId(); @@ -47,7 +46,8 @@ public ExecutionContext executionContext(@NotNull final User user, Injection inj return executionContext; } - public ExecutionContext executionContext(@NotNull final User user, Exercise exercise, String team) { + public ExecutionContext executionContext( + @NotNull final User user, Exercise exercise, String team) { ExecutionContext executionContext = new ExecutionContext(user, List.of(team)); if (exercise != null) { fillDynamicVariable(executionContext, exercise.getId()); @@ -57,9 +57,10 @@ public ExecutionContext executionContext(@NotNull final User user, Exercise exer // -- PRIVATE -- - private void fillDynamicVariable(@NotNull ExecutionContext executionContext, @NotBlank final String exerciseId) { - List variables = this.variableRepository.findAll(VariableSpecification.fromExercise(exerciseId)); + private void fillDynamicVariable( + @NotNull ExecutionContext executionContext, @NotBlank final String exerciseId) { + List variables = + this.variableRepository.findAll(VariableSpecification.fromExercise(exerciseId)); variables.forEach((v) -> executionContext.put(v.getKey(), v.getValue())); } - } diff --git a/openbas-framework/src/main/java/io/openbas/execution/ExecutionExecutorService.java b/openbas-framework/src/main/java/io/openbas/execution/ExecutionExecutorService.java index b507031965..28f5d6ffd3 100644 --- a/openbas-framework/src/main/java/io/openbas/execution/ExecutionExecutorService.java +++ b/openbas-framework/src/main/java/io/openbas/execution/ExecutionExecutorService.java @@ -4,104 +4,113 @@ import io.openbas.database.model.Asset; import io.openbas.database.model.Executor; import io.openbas.database.model.Inject; -import io.openbas.database.model.Injector; import io.openbas.executors.caldera.config.CalderaExecutorConfig; import io.openbas.executors.caldera.service.CalderaExecutorContextService; import io.openbas.executors.openbas.service.OpenBASExecutorContextService; import io.openbas.executors.tanium.config.TaniumExecutorConfig; import io.openbas.executors.tanium.service.TaniumExecutorContextService; +import java.util.List; +import java.util.logging.Level; +import java.util.stream.Stream; import lombok.RequiredArgsConstructor; import lombok.extern.java.Log; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Service; -import java.util.List; -import java.util.logging.Level; -import java.util.stream.Stream; - @RequiredArgsConstructor @Service @Log public class ExecutionExecutorService { - private AssetGroupService assetGroupService; + private AssetGroupService assetGroupService; - private CalderaExecutorConfig calderaExecutorConfig; + private CalderaExecutorConfig calderaExecutorConfig; - private CalderaExecutorContextService calderaExecutorContextService; + private CalderaExecutorContextService calderaExecutorContextService; - private TaniumExecutorConfig taniumExecutorConfig; + private TaniumExecutorConfig taniumExecutorConfig; - private TaniumExecutorContextService taniumExecutorContextService; + private TaniumExecutorContextService taniumExecutorContextService; - private OpenBASExecutorContextService openBASExecutorContextService; + private OpenBASExecutorContextService openBASExecutorContextService; - @Autowired - public void setOpenBASExecutorContextService(OpenBASExecutorContextService openBASExecutorContextService) { - this.openBASExecutorContextService = openBASExecutorContextService; - } + @Autowired + public void setOpenBASExecutorContextService( + OpenBASExecutorContextService openBASExecutorContextService) { + this.openBASExecutorContextService = openBASExecutorContextService; + } - @Autowired - public void setAssetGroupService(AssetGroupService assetGroupService) { - this.assetGroupService = assetGroupService; - } + @Autowired + public void setAssetGroupService(AssetGroupService assetGroupService) { + this.assetGroupService = assetGroupService; + } - @Autowired - public void setCalderaExecutorConfig(CalderaExecutorConfig calderaExecutorConfig) { - this.calderaExecutorConfig = calderaExecutorConfig; - } + @Autowired + public void setCalderaExecutorConfig(CalderaExecutorConfig calderaExecutorConfig) { + this.calderaExecutorConfig = calderaExecutorConfig; + } - @Autowired - public void setCalderaExecutorContextService(CalderaExecutorContextService calderaExecutorContextService) { - this.calderaExecutorContextService = calderaExecutorContextService; - } + @Autowired + public void setCalderaExecutorContextService( + CalderaExecutorContextService calderaExecutorContextService) { + this.calderaExecutorContextService = calderaExecutorContextService; + } - @Autowired - public void setTaniumExecutorConfig(TaniumExecutorConfig taniumExecutorConfig) { - this.taniumExecutorConfig = taniumExecutorConfig; - } + @Autowired + public void setTaniumExecutorConfig(TaniumExecutorConfig taniumExecutorConfig) { + this.taniumExecutorConfig = taniumExecutorConfig; + } - @Autowired - public void setTaniumExecutorContextService(TaniumExecutorContextService taniumExecutorContextService) { - this.taniumExecutorContextService = taniumExecutorContextService; - } + @Autowired + public void setTaniumExecutorContextService( + TaniumExecutorContextService taniumExecutorContextService) { + this.taniumExecutorContextService = taniumExecutorContextService; + } - public ExecutableInject launchExecutorContext(ExecutableInject executableInject, Inject inject) throws InterruptedException { - // First, get the assets of this injects - List assets = Stream.concat( + public ExecutableInject launchExecutorContext(ExecutableInject executableInject, Inject inject) + throws InterruptedException { + // First, get the assets of this injects + List assets = + Stream.concat( inject.getAssets().stream(), - inject.getAssetGroups().stream().flatMap(assetGroup -> this.assetGroupService.assetsFromAssetGroup(assetGroup.getId()).stream()) - ).toList(); - assets.forEach(asset -> { - launchExecutorContextForAsset(inject, asset); + inject.getAssetGroups().stream() + .flatMap( + assetGroup -> + this.assetGroupService + .assetsFromAssetGroup(assetGroup.getId()) + .stream())) + .toList(); + assets.forEach( + asset -> { + launchExecutorContextForAsset(inject, asset); }); - return executableInject; - } - - private void launchExecutorContextForAsset(Inject inject, Asset asset) { - Executor executor = asset.getExecutor(); - if (executor == null) { - log.log(Level.SEVERE, "Cannot find the executor for the asset " + asset.getName()); - } else { - switch (executor.getType()) { - case "openbas_caldera" -> { - if (!this.calderaExecutorConfig.isEnable()) { - throw new RuntimeException("Fatal error: Caldera executor is not enabled"); - } - this.calderaExecutorContextService.launchExecutorSubprocess(inject, asset); - } - case "openbas_tanium" -> { - if (!this.taniumExecutorConfig.isEnable()) { - throw new RuntimeException("Fatal error: Tanium executor is not enabled"); - } - this.taniumExecutorContextService.launchExecutorSubprocess(inject, asset); - } - case "openbas_agent" -> { - this.openBASExecutorContextService.launchExecutorSubprocess(inject, asset); - } - default -> { - throw new RuntimeException("Fatal error: Unsupported executor " + executor.getType()); - } - } + return executableInject; + } + + private void launchExecutorContextForAsset(Inject inject, Asset asset) { + Executor executor = asset.getExecutor(); + if (executor == null) { + log.log(Level.SEVERE, "Cannot find the executor for the asset " + asset.getName()); + } else { + switch (executor.getType()) { + case "openbas_caldera" -> { + if (!this.calderaExecutorConfig.isEnable()) { + throw new RuntimeException("Fatal error: Caldera executor is not enabled"); + } + this.calderaExecutorContextService.launchExecutorSubprocess(inject, asset); + } + case "openbas_tanium" -> { + if (!this.taniumExecutorConfig.isEnable()) { + throw new RuntimeException("Fatal error: Tanium executor is not enabled"); + } + this.taniumExecutorContextService.launchExecutorSubprocess(inject, asset); + } + case "openbas_agent" -> { + this.openBASExecutorContextService.launchExecutorSubprocess(inject, asset); + } + default -> { + throw new RuntimeException("Fatal error: Unsupported executor " + executor.getType()); } + } } + } } diff --git a/openbas-framework/src/main/java/io/openbas/execution/Executor.java b/openbas-framework/src/main/java/io/openbas/execution/Executor.java index 8a51efef12..42cdcf9bc7 100644 --- a/openbas-framework/src/main/java/io/openbas/execution/Executor.java +++ b/openbas-framework/src/main/java/io/openbas/execution/Executor.java @@ -1,144 +1,163 @@ package io.openbas.execution; +import static io.openbas.database.model.InjectStatusExecution.traceInfo; + import com.fasterxml.jackson.databind.ObjectMapper; import io.openbas.asset.QueueService; -import io.openbas.database.model.Injector; import io.openbas.database.model.*; +import io.openbas.database.model.Injector; import io.openbas.database.repository.InjectRepository; import io.openbas.database.repository.InjectStatusRepository; import io.openbas.database.repository.InjectorRepository; import jakarta.annotation.Resource; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.context.ApplicationContext; -import org.springframework.stereotype.Component; - import java.time.Duration; import java.time.Instant; import java.util.Optional; - -import static io.openbas.database.model.InjectStatusExecution.traceInfo; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.context.ApplicationContext; +import org.springframework.stereotype.Component; @Component public class Executor { - @Resource - protected ObjectMapper mapper; - - private ApplicationContext context; - - private InjectStatusRepository injectStatusRepository; - - private InjectorRepository injectorRepository; - - private InjectRepository injectRepository; - - private QueueService queueService; - - private ExecutionExecutorService executionExecutorService; - - @Autowired - public void setQueueService(QueueService queueService) { - this.queueService = queueService; - } - - @Autowired - public void setContext(ApplicationContext context) { - this.context = context; - } - - @Autowired - public void setInjectorRepository(InjectorRepository injectorRepository) { - this.injectorRepository = injectorRepository; - } - - @Autowired - public void setInjectStatusRepository(InjectStatusRepository injectStatusRepository) { - this.injectStatusRepository = injectStatusRepository; - } - - @Autowired - public void setExecutionExecutorService(ExecutionExecutorService executionExecutorService) { - this.executionExecutorService = executionExecutorService; + @Resource protected ObjectMapper mapper; + + private ApplicationContext context; + + private InjectStatusRepository injectStatusRepository; + + private InjectorRepository injectorRepository; + + private InjectRepository injectRepository; + + private QueueService queueService; + + private ExecutionExecutorService executionExecutorService; + + @Autowired + public void setQueueService(QueueService queueService) { + this.queueService = queueService; + } + + @Autowired + public void setContext(ApplicationContext context) { + this.context = context; + } + + @Autowired + public void setInjectorRepository(InjectorRepository injectorRepository) { + this.injectorRepository = injectorRepository; + } + + @Autowired + public void setInjectStatusRepository(InjectStatusRepository injectStatusRepository) { + this.injectStatusRepository = injectStatusRepository; + } + + @Autowired + public void setExecutionExecutorService(ExecutionExecutorService executionExecutorService) { + this.executionExecutorService = executionExecutorService; + } + + @Autowired + public void setInjectRepository(InjectRepository injectRepository) { + this.injectRepository = injectRepository; + } + + private InjectStatus executeExternal(ExecutableInject executableInject, Inject inject) { + InjectorContract injectorContract = + inject + .getInjectorContract() + .orElseThrow( + () -> new UnsupportedOperationException("Inject does not have a contract")); + + InjectStatus status = injectStatusRepository.findByInject(inject).orElse(new InjectStatus()); + status.setTrackingSentDate(Instant.now()); + status.setInject(inject); + try { + String jsonInject = mapper.writeValueAsString(executableInject); + status.setName(ExecutionStatus.PENDING); // FIXME: need to be test with HTTP Collector + status + .getTraces() + .add(traceInfo("The inject has been published and is now waiting to be consumed.")); + queueService.publish(injectorContract.getInjector().getType(), jsonInject); + } catch (Exception e) { + status.setName(ExecutionStatus.ERROR); + status.getTraces().add(InjectStatusExecution.traceError(e.getMessage())); + } finally { + return injectStatusRepository.save(status); } - - @Autowired - public void setInjectRepository(InjectRepository injectRepository) { - this.injectRepository = injectRepository; + } + + private InjectStatus executeInternal(ExecutableInject executableInject, Inject inject) { + InjectorContract injectorContract = + inject + .getInjectorContract() + .orElseThrow( + () -> new UnsupportedOperationException("Inject does not have a contract")); + + io.openbas.execution.Injector executor = + this.context.getBean( + injectorContract.getInjector().getType(), io.openbas.execution.Injector.class); + Execution execution = executor.executeInjection(executableInject); + Inject executedInject = injectRepository.findById(inject.getId()).orElseThrow(); + InjectStatus completeStatus = InjectStatus.fromExecution(execution, executedInject); + return injectStatusRepository.save(completeStatus); + } + + public InjectStatus execute(ExecutableInject executableInject) { + boolean isScheduledInject = !executableInject.isDirect(); + // If empty content, inject must be rejected + Inject inject = executableInject.getInjection().getInject(); + if (inject.getContent() == null) { + throw new UnsupportedOperationException("Inject is empty"); } - - private InjectStatus executeExternal(ExecutableInject executableInject, Inject inject) { - InjectorContract injectorContract = inject.getInjectorContract() - .orElseThrow(() -> new UnsupportedOperationException("Inject does not have a contract")); - - InjectStatus status = injectStatusRepository.findByInject(inject).orElse(new InjectStatus()); - status.setTrackingSentDate(Instant.now()); - status.setInject(inject); - try { - String jsonInject = mapper.writeValueAsString(executableInject); - status.setName(ExecutionStatus.PENDING); // FIXME: need to be test with HTTP Collector - status.getTraces().add(traceInfo("The inject has been published and is now waiting to be consumed.")); - queueService.publish(injectorContract.getInjector().getType(), jsonInject); - } catch (Exception e) { - status.setName(ExecutionStatus.ERROR); - status.getTraces().add(InjectStatusExecution.traceError(e.getMessage())); - } finally { - return injectStatusRepository.save(status); - } + // If inject is too old, reject the execution + if (isScheduledInject && !isInInjectableRange(inject)) { + throw new UnsupportedOperationException("Inject is now too old for execution"); } - private InjectStatus executeInternal(ExecutableInject executableInject, Inject inject) { - InjectorContract injectorContract = inject.getInjectorContract() - .orElseThrow(() -> new UnsupportedOperationException("Inject does not have a contract")); - - io.openbas.execution.Injector executor = this.context.getBean(injectorContract.getInjector().getType(), io.openbas.execution.Injector.class); - Execution execution = executor.executeInjection(executableInject); - Inject executedInject = injectRepository.findById(inject.getId()).orElseThrow(); - InjectStatus completeStatus = InjectStatus.fromExecution(execution, executedInject); - return injectStatusRepository.save(completeStatus); - } - - public InjectStatus execute(ExecutableInject executableInject) { - boolean isScheduledInject = !executableInject.isDirect(); - // If empty content, inject must be rejected - Inject inject = executableInject.getInjection().getInject(); - if (inject.getContent() == null) { - throw new UnsupportedOperationException("Inject is empty"); - } - // If inject is too old, reject the execution - if (isScheduledInject && !isInInjectableRange(inject)) { - throw new UnsupportedOperationException("Inject is now too old for execution"); - } - - InjectorContract injectorContract = inject.getInjectorContract().orElseThrow(() -> new UnsupportedOperationException("Inject does not have a contract")); - - // Depending on injector type (internal or external) execution must be done differently - Optional externalInjector = injectorRepository.findByType(injectorContract.getInjector().getType()); - - return externalInjector - .map(Injector::isExternal) - .map(isExternal -> { - ExecutableInject newExecutableInject = executableInject; - if (injectorContract.getNeedsExecutor()) { - try { - newExecutableInject = this.executionExecutorService.launchExecutorContext(executableInject, inject); - } catch (InterruptedException e) { - throw new RuntimeException(e); - } - } - if (isExternal) { - return executeExternal(newExecutableInject, inject); - } else { - return executeInternal(newExecutableInject, inject); - } - }) - .orElseThrow(() -> new IllegalStateException("External injector not found for type: " + injectorContract.getInjector().getType())); - } - - // region utils - private boolean isInInjectableRange(Injection injection) { - Instant now = Instant.now(); - Instant start = now.minus(Duration.parse("PT1H")); - Instant injectWhen = injection.getDate().orElseThrow(); - return injectWhen.isAfter(start) && injectWhen.isBefore(now); - } + InjectorContract injectorContract = + inject + .getInjectorContract() + .orElseThrow( + () -> new UnsupportedOperationException("Inject does not have a contract")); + + // Depending on injector type (internal or external) execution must be done differently + Optional externalInjector = + injectorRepository.findByType(injectorContract.getInjector().getType()); + + return externalInjector + .map(Injector::isExternal) + .map( + isExternal -> { + ExecutableInject newExecutableInject = executableInject; + if (injectorContract.getNeedsExecutor()) { + try { + newExecutableInject = + this.executionExecutorService.launchExecutorContext(executableInject, inject); + } catch (InterruptedException e) { + throw new RuntimeException(e); + } + } + if (isExternal) { + return executeExternal(newExecutableInject, inject); + } else { + return executeInternal(newExecutableInject, inject); + } + }) + .orElseThrow( + () -> + new IllegalStateException( + "External injector not found for type: " + + injectorContract.getInjector().getType())); + } + + // region utils + private boolean isInInjectableRange(Injection injection) { + Instant now = Instant.now(); + Instant start = now.minus(Duration.parse("PT1H")); + Instant injectWhen = injection.getDate().orElseThrow(); + return injectWhen.isAfter(start) && injectWhen.isBefore(now); + } } diff --git a/openbas-framework/src/main/java/io/openbas/execution/Injector.java b/openbas-framework/src/main/java/io/openbas/execution/Injector.java index 13395ed298..656ea7eabb 100644 --- a/openbas-framework/src/main/java/io/openbas/execution/Injector.java +++ b/openbas-framework/src/main/java/io/openbas/execution/Injector.java @@ -1,5 +1,9 @@ package io.openbas.execution; +import static io.openbas.database.model.InjectStatusExecution.traceError; +import static io.openbas.expectation.ExpectationPropertiesConfig.DEFAULT_HUMAN_EXPECTATION_EXPIRATION_TIME; +import static java.util.Optional.ofNullable; + import com.fasterxml.jackson.databind.ObjectMapper; import com.fasterxml.jackson.databind.node.ObjectNode; import io.openbas.database.model.*; @@ -12,10 +16,6 @@ import io.openbas.service.FileService; import jakarta.annotation.Resource; import jakarta.validation.constraints.NotNull; -import org.apache.commons.io.IOUtils; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.transaction.annotation.Transactional; - import java.io.InputStream; import java.time.Duration; import java.time.Instant; @@ -24,22 +24,20 @@ import java.util.Optional; import java.util.Set; import java.util.stream.Collectors; - -import static io.openbas.database.model.InjectStatusExecution.traceError; -import static io.openbas.expectation.ExpectationPropertiesConfig.DEFAULT_HUMAN_EXPECTATION_EXPIRATION_TIME; -import static java.util.Optional.ofNullable; - +import org.apache.commons.io.IOUtils; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.transaction.annotation.Transactional; public abstract class Injector { - @Resource - protected ObjectMapper mapper; + @Resource protected ObjectMapper mapper; private FileService fileService; private DocumentRepository documentRepository; private InjectExpectationRepository injectExpectationRepository; @Autowired - public void setInjectExpectationRepository(InjectExpectationRepository injectExpectationRepository) { + public void setInjectExpectationRepository( + InjectExpectationRepository injectExpectationRepository) { this.injectExpectationRepository = injectExpectationRepository; } @@ -53,15 +51,15 @@ public void setFileService(FileService fileService) { this.fileService = fileService; } - public abstract ExecutionProcess process(Execution execution, ExecutableInject injection) throws Exception; + public abstract ExecutionProcess process(Execution execution, ExecutableInject injection) + throws Exception; public InjectStatusCommandLine getCommandsLines(String externalId) { return null; } private InjectExpectation expectationConverter( - @NotNull final ExecutableInject executableInject, - Expectation expectation) { + @NotNull final ExecutableInject executableInject, Expectation expectation) { InjectExpectation expectationExecution = new InjectExpectation(); return this.expectationConverter(expectationExecution, executableInject, expectation); } @@ -95,8 +93,8 @@ private InjectExpectation expectationConverter( expectationExecution.setExpectedScore(expectation.getScore()); expectationExecution.setExpectationGroup(expectation.isExpectationGroup()); expectationExecution.setExpirationTime( - ofNullable(expectation.getExpirationTime()).orElse(DEFAULT_HUMAN_EXPECTATION_EXPIRATION_TIME) - ); + ofNullable(expectation.getExpirationTime()) + .orElse(DEFAULT_HUMAN_EXPECTATION_EXPIRATION_TIME)); switch (expectation.type()) { case ARTICLE -> { expectationExecution.setName(expectation.getName()); @@ -111,19 +109,22 @@ private InjectExpectation expectationConverter( case DETECTION -> { DetectionExpectation detectionExpectation = (DetectionExpectation) expectation; expectationExecution.setName(detectionExpectation.getName()); - expectationExecution.setDetection(detectionExpectation.getAsset(), detectionExpectation.getAssetGroup()); + expectationExecution.setDetection( + detectionExpectation.getAsset(), detectionExpectation.getAssetGroup()); expectationExecution.setSignatures(detectionExpectation.getInjectExpectationSignatures()); } case PREVENTION -> { PreventionExpectation preventionExpectation = (PreventionExpectation) expectation; expectationExecution.setName(preventionExpectation.getName()); - expectationExecution.setPrevention(preventionExpectation.getAsset(), preventionExpectation.getAssetGroup()); + expectationExecution.setPrevention( + preventionExpectation.getAsset(), preventionExpectation.getAssetGroup()); expectationExecution.setSignatures(preventionExpectation.getInjectExpectationSignatures()); } case MANUAL -> { ManualExpectation manualExpectation = (ManualExpectation) expectation; expectationExecution.setName(((ManualExpectation) expectation).getName()); - expectationExecution.setManual(manualExpectation.getAsset(), manualExpectation.getAssetGroup()); + expectationExecution.setManual( + manualExpectation.getAsset(), manualExpectation.getAssetGroup()); expectationExecution.setDescription(((ManualExpectation) expectation).getDescription()); } default -> throw new IllegalStateException("Unexpected value: " + expectation); @@ -160,45 +161,86 @@ public Execution execute(ExecutableInject executableInject) { List injectExpectationsByUserAndTeam; // If atomicTesting, We create expectation for every player and every team if (isAtomicTesting) { - injectExpectationsByTeam = teams.stream() - .flatMap(team -> expectations.stream() - .map(expectation -> expectationConverter(team, executableInject, expectation))) - .collect(Collectors.toList()); + injectExpectationsByTeam = + teams.stream() + .flatMap( + team -> + expectations.stream() + .map( + expectation -> + expectationConverter(team, executableInject, expectation))) + .collect(Collectors.toList()); - injectExpectationsByUserAndTeam = teams.stream() - .flatMap(team -> team.getUsers().stream() - .flatMap(user -> expectations.stream() - .map(expectation -> expectationConverter(team, user, executableInject, expectation)))) - .toList(); + injectExpectationsByUserAndTeam = + teams.stream() + .flatMap( + team -> + team.getUsers().stream() + .flatMap( + user -> + expectations.stream() + .map( + expectation -> + expectationConverter( + team, + user, + executableInject, + expectation)))) + .toList(); } else { // Create expectations for every enabled player in every team - injectExpectationsByUserAndTeam = teams.stream() - .flatMap(team -> team.getExerciseTeamUsers().stream() - .filter(exerciseTeamUser -> exerciseTeamUser.getExercise().getId() - .equals(executableInject.getInjection().getExercise().getId())) - .flatMap(exerciseTeamUser -> expectations.stream() - .map(expectation -> expectationConverter(team, exerciseTeamUser.getUser(), executableInject, - expectation)))) - .toList(); + injectExpectationsByUserAndTeam = + teams.stream() + .flatMap( + team -> + team.getExerciseTeamUsers().stream() + .filter( + exerciseTeamUser -> + exerciseTeamUser + .getExercise() + .getId() + .equals( + executableInject + .getInjection() + .getExercise() + .getId())) + .flatMap( + exerciseTeamUser -> + expectations.stream() + .map( + expectation -> + expectationConverter( + team, + exerciseTeamUser.getUser(), + executableInject, + expectation)))) + .toList(); // Create a set of teams that have at least one enabled player - Set teamsWithEnabledPlayers = injectExpectationsByUserAndTeam.stream() - .map(InjectExpectation::getTeam) - .collect(Collectors.toSet()); + Set teamsWithEnabledPlayers = + injectExpectationsByUserAndTeam.stream() + .map(InjectExpectation::getTeam) + .collect(Collectors.toSet()); // Add only the expectations where the team has at least one enabled player - injectExpectationsByTeam = teamsWithEnabledPlayers.stream() - .flatMap(team -> expectations.stream() - .map(expectation -> expectationConverter(team, executableInject, expectation))) - .collect(Collectors.toList()); + injectExpectationsByTeam = + teamsWithEnabledPlayers.stream() + .flatMap( + team -> + expectations.stream() + .map( + expectation -> + expectationConverter(team, executableInject, expectation))) + .collect(Collectors.toList()); } injectExpectationsByTeam.addAll(injectExpectationsByUserAndTeam); this.injectExpectationRepository.saveAll(injectExpectationsByTeam); } else if (!assets.isEmpty() || !assetGroups.isEmpty()) { - List injectExpectations = expectations.stream() - .map(expectation -> expectationConverter(executableInject, expectation)) - .toList(); + List injectExpectations = + expectations.stream() + .map(expectation -> expectationConverter(executableInject, expectation)) + .toList(); this.injectExpectationRepository.saveAll(injectExpectations); } } @@ -222,42 +264,49 @@ private boolean isInInjectableRange(Injection injection) { return injectWhen.isAfter(start) && injectWhen.isBefore(now); } - public T contentConvert(@NotNull final ExecutableInject injection, @NotNull final Class converter) + public T contentConvert( + @NotNull final ExecutableInject injection, @NotNull final Class converter) throws Exception { Inject inject = injection.getInjection().getInject(); ObjectNode content = inject.getContent(); return this.mapper.treeToValue(content, converter); } - public List resolveAttachments(Execution execution, ExecutableInject injection, - List documents) { + public List resolveAttachments( + Execution execution, ExecutableInject injection, List documents) { List resolved = new ArrayList<>(); // Add attachments from direct configuration - injection.getDirectAttachments().forEach(doc -> { - try { - byte[] content = IOUtils.toByteArray(doc.getInputStream()); - resolved.add(new DataAttachment(doc.getName(), doc.getOriginalFilename(), content, doc.getContentType())); - } catch (Exception e) { - String message = "Error getting direct attachment " + doc.getName(); - execution.addTrace(traceError(message)); - } - }); + injection + .getDirectAttachments() + .forEach( + doc -> { + try { + byte[] content = IOUtils.toByteArray(doc.getInputStream()); + resolved.add( + new DataAttachment( + doc.getName(), doc.getOriginalFilename(), content, doc.getContentType())); + } catch (Exception e) { + String message = "Error getting direct attachment " + doc.getName(); + execution.addTrace(traceError(message)); + } + }); // Add attachments from configuration - documents.forEach(attachment -> { - String documentId = attachment.getId(); - Optional askedDocument = documentRepository.findById(documentId); - try { - Document doc = askedDocument.orElseThrow(); - InputStream fileInputStream = fileService.getFile(doc).orElseThrow(); - byte[] content = IOUtils.toByteArray(fileInputStream); - resolved.add(new DataAttachment(documentId, doc.getName(), content, doc.getType())); - } catch (Exception e) { - // Can't fetch the attachments, ignore - String docInfo = askedDocument.map(Document::getName).orElse(documentId); - String message = "Error getting doc attachment " + docInfo; - execution.addTrace(traceError(message)); - } - }); + documents.forEach( + attachment -> { + String documentId = attachment.getId(); + Optional askedDocument = documentRepository.findById(documentId); + try { + Document doc = askedDocument.orElseThrow(); + InputStream fileInputStream = fileService.getFile(doc).orElseThrow(); + byte[] content = IOUtils.toByteArray(fileInputStream); + resolved.add(new DataAttachment(documentId, doc.getName(), content, doc.getType())); + } catch (Exception e) { + // Can't fetch the attachments, ignore + String docInfo = askedDocument.map(Document::getName).orElse(documentId); + String message = "Error getting doc attachment " + docInfo; + execution.addTrace(traceError(message)); + } + }); return resolved; } // endregion diff --git a/openbas-framework/src/main/java/io/openbas/execution/ProtectUser.java b/openbas-framework/src/main/java/io/openbas/execution/ProtectUser.java index d452b1ae61..e7636fec74 100644 --- a/openbas-framework/src/main/java/io/openbas/execution/ProtectUser.java +++ b/openbas-framework/src/main/java/io/openbas/execution/ProtectUser.java @@ -1,9 +1,8 @@ package io.openbas.execution; import io.openbas.database.model.User; -import lombok.Data; - import jakarta.validation.constraints.NotNull; +import lombok.Data; @Data public class ProtectUser { @@ -25,5 +24,4 @@ public ProtectUser(@NotNull final User user) { this.pgpKey = user.getPgpKey(); this.phone = user.getPhone(); } - } diff --git a/openbas-framework/src/main/java/io/openbas/executors/caldera/client/CalderaExecutorClient.java b/openbas-framework/src/main/java/io/openbas/executors/caldera/client/CalderaExecutorClient.java index 0fc9403a25..f463e282cf 100644 --- a/openbas-framework/src/main/java/io/openbas/executors/caldera/client/CalderaExecutorClient.java +++ b/openbas-framework/src/main/java/io/openbas/executors/caldera/client/CalderaExecutorClient.java @@ -9,6 +9,11 @@ import io.openbas.executors.caldera.model.Agent; import jakarta.validation.constraints.NotBlank; import jakarta.validation.constraints.NotNull; +import java.io.IOException; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; import lombok.RequiredArgsConstructor; import lombok.extern.java.Log; import org.apache.hc.client5.http.ClientProtocolException; @@ -22,273 +27,295 @@ import org.apache.hc.core5.http.io.entity.StringEntity; import org.springframework.stereotype.Service; -import java.io.IOException; -import java.util.ArrayList; -import java.util.HashMap; -import java.util.List; -import java.util.Map; - @RequiredArgsConstructor @Service @Log public class CalderaExecutorClient { - private static final String KEY_HEADER = "KEY"; + private static final String KEY_HEADER = "KEY"; - private final CalderaExecutorConfig config; - private final ObjectMapper objectMapper = new ObjectMapper(); + private final CalderaExecutorConfig config; + private final ObjectMapper objectMapper = new ObjectMapper(); - // -- AGENTS -- + // -- AGENTS -- - private final static String AGENT_URI = "/agents"; + private static final String AGENT_URI = "/agents"; - public List agents() { - try { - String jsonResponse = this.get(AGENT_URI); - return this.objectMapper.readValue(jsonResponse, new TypeReference<>() { - }); - } catch (IOException e) { - log.severe("Cannot retrieve agent list"); - throw new RuntimeException(e); - } + public List agents() { + try { + String jsonResponse = this.get(AGENT_URI); + return this.objectMapper.readValue(jsonResponse, new TypeReference<>() {}); + } catch (IOException e) { + log.severe("Cannot retrieve agent list"); + throw new RuntimeException(e); } + } - public void deleteAgent(Endpoint endpoint) { - try { - this.delete(this.config.getRestApiV2Url() + AGENT_URI + "/" + endpoint.getExternalReference()); - } catch (IOException e) { - throw new RuntimeException(e); - } + public void deleteAgent(Endpoint endpoint) { + try { + this.delete( + this.config.getRestApiV2Url() + AGENT_URI + "/" + endpoint.getExternalReference()); + } catch (IOException e) { + throw new RuntimeException(e); } + } - // -- ABILITIES -- + // -- ABILITIES -- - private final static String ABILITIES_URI = "/abilities"; + private static final String ABILITIES_URI = "/abilities"; - public List abilities() { - try { - String jsonResponse = this.get(ABILITIES_URI); - return this.objectMapper.readValue(jsonResponse, new TypeReference<>() { - }); - } catch (IOException e) { - throw new RuntimeException(e); - } + public List abilities() { + try { + String jsonResponse = this.get(ABILITIES_URI); + return this.objectMapper.readValue(jsonResponse, new TypeReference<>() {}); + } catch (IOException e) { + throw new RuntimeException(e); } + } - public Ability createSubprocessorAbility(Injector injector) { - try { - List> executors = new ArrayList<>(); - Map injectorExecutorCommands = injector.getExecutorCommands(); - if (injectorExecutorCommands.containsKey(Endpoint.PLATFORM_TYPE.Windows.name() + "." + Endpoint.PLATFORM_ARCH.x86_64)) { - Map executorWindows = new HashMap<>(); - executorWindows.put("platform", "windows"); - executorWindows.put("name", "psh"); - executorWindows.put("command", injectorExecutorCommands.get(Endpoint.PLATFORM_TYPE.Windows.name() + "." + Endpoint.PLATFORM_ARCH.x86_64)); - executors.add(executorWindows); - } else if (injectorExecutorCommands.containsKey(Endpoint.PLATFORM_TYPE.Windows.name() + "." + Endpoint.PLATFORM_ARCH.arm64)) { - Map executorWindows = new HashMap<>(); - executorWindows.put("platform", "windows"); - executorWindows.put("name", "psh"); - executorWindows.put("command", injectorExecutorCommands.get(Endpoint.PLATFORM_TYPE.Windows.name() + "." + Endpoint.PLATFORM_ARCH.arm64)); - executors.add(executorWindows); - } - if (injectorExecutorCommands.containsKey(Endpoint.PLATFORM_TYPE.Linux.name() + "." + Endpoint.PLATFORM_ARCH.x86_64)) { - Map executorLinux = new HashMap<>(); - executorLinux.put("platform", "linux"); - executorLinux.put("name", "sh"); - executorLinux.put("command", injectorExecutorCommands.get(Endpoint.PLATFORM_TYPE.Linux.name() + "." + Endpoint.PLATFORM_ARCH.x86_64)); - executors.add(executorLinux); - } else if (injectorExecutorCommands.containsKey(Endpoint.PLATFORM_TYPE.Linux.name() + "." + Endpoint.PLATFORM_ARCH.arm64)) { - Map executorLinux = new HashMap<>(); - executorLinux.put("platform", "linux"); - executorLinux.put("name", "sh"); - executorLinux.put("command", injectorExecutorCommands.get(Endpoint.PLATFORM_TYPE.Linux.name() + "." + Endpoint.PLATFORM_ARCH.arm64)); - executors.add(executorLinux); - } - if (injectorExecutorCommands.containsKey(Endpoint.PLATFORM_TYPE.MacOS.name() + "." + Endpoint.PLATFORM_ARCH.x86_64)) { - Map executorMac = new HashMap<>(); - executorMac.put("platform", "darwin"); - executorMac.put("name", "sh"); - executorMac.put("command", injectorExecutorCommands.get(Endpoint.PLATFORM_TYPE.MacOS.name() + "." + Endpoint.PLATFORM_ARCH.x86_64)); - executors.add(executorMac); - } else if (injectorExecutorCommands.containsKey(Endpoint.PLATFORM_TYPE.MacOS.name() + "." + Endpoint.PLATFORM_ARCH.arm64)) { - Map executorMac = new HashMap<>(); - executorMac.put("platform", "darwin"); - executorMac.put("name", "sh"); - executorMac.put("command", injectorExecutorCommands.get(Endpoint.PLATFORM_TYPE.MacOS.name() + "." + Endpoint.PLATFORM_ARCH.arm64)); - executors.add(executorMac); - } - Map body = new HashMap<>(); - body.put("name", "caldera-subprocessor-" + injector.getName()); - body.put("tactic", "openbas"); - body.put("technique_id", "openbas"); - body.put("technique_name", "openbas"); - body.put("executors", executors); - String jsonResponse = this.post( - this.config.getRestApiV2Url() + ABILITIES_URI, - body - ); - return this.objectMapper.readValue(jsonResponse, new TypeReference<>() { - }); - } catch (IOException e) { - throw new RuntimeException(e); - } + public Ability createSubprocessorAbility(Injector injector) { + try { + List> executors = new ArrayList<>(); + Map injectorExecutorCommands = injector.getExecutorCommands(); + if (injectorExecutorCommands.containsKey( + Endpoint.PLATFORM_TYPE.Windows.name() + "." + Endpoint.PLATFORM_ARCH.x86_64)) { + Map executorWindows = new HashMap<>(); + executorWindows.put("platform", "windows"); + executorWindows.put("name", "psh"); + executorWindows.put( + "command", + injectorExecutorCommands.get( + Endpoint.PLATFORM_TYPE.Windows.name() + "." + Endpoint.PLATFORM_ARCH.x86_64)); + executors.add(executorWindows); + } else if (injectorExecutorCommands.containsKey( + Endpoint.PLATFORM_TYPE.Windows.name() + "." + Endpoint.PLATFORM_ARCH.arm64)) { + Map executorWindows = new HashMap<>(); + executorWindows.put("platform", "windows"); + executorWindows.put("name", "psh"); + executorWindows.put( + "command", + injectorExecutorCommands.get( + Endpoint.PLATFORM_TYPE.Windows.name() + "." + Endpoint.PLATFORM_ARCH.arm64)); + executors.add(executorWindows); + } + if (injectorExecutorCommands.containsKey( + Endpoint.PLATFORM_TYPE.Linux.name() + "." + Endpoint.PLATFORM_ARCH.x86_64)) { + Map executorLinux = new HashMap<>(); + executorLinux.put("platform", "linux"); + executorLinux.put("name", "sh"); + executorLinux.put( + "command", + injectorExecutorCommands.get( + Endpoint.PLATFORM_TYPE.Linux.name() + "." + Endpoint.PLATFORM_ARCH.x86_64)); + executors.add(executorLinux); + } else if (injectorExecutorCommands.containsKey( + Endpoint.PLATFORM_TYPE.Linux.name() + "." + Endpoint.PLATFORM_ARCH.arm64)) { + Map executorLinux = new HashMap<>(); + executorLinux.put("platform", "linux"); + executorLinux.put("name", "sh"); + executorLinux.put( + "command", + injectorExecutorCommands.get( + Endpoint.PLATFORM_TYPE.Linux.name() + "." + Endpoint.PLATFORM_ARCH.arm64)); + executors.add(executorLinux); + } + if (injectorExecutorCommands.containsKey( + Endpoint.PLATFORM_TYPE.MacOS.name() + "." + Endpoint.PLATFORM_ARCH.x86_64)) { + Map executorMac = new HashMap<>(); + executorMac.put("platform", "darwin"); + executorMac.put("name", "sh"); + executorMac.put( + "command", + injectorExecutorCommands.get( + Endpoint.PLATFORM_TYPE.MacOS.name() + "." + Endpoint.PLATFORM_ARCH.x86_64)); + executors.add(executorMac); + } else if (injectorExecutorCommands.containsKey( + Endpoint.PLATFORM_TYPE.MacOS.name() + "." + Endpoint.PLATFORM_ARCH.arm64)) { + Map executorMac = new HashMap<>(); + executorMac.put("platform", "darwin"); + executorMac.put("name", "sh"); + executorMac.put( + "command", + injectorExecutorCommands.get( + Endpoint.PLATFORM_TYPE.MacOS.name() + "." + Endpoint.PLATFORM_ARCH.arm64)); + executors.add(executorMac); + } + Map body = new HashMap<>(); + body.put("name", "caldera-subprocessor-" + injector.getName()); + body.put("tactic", "openbas"); + body.put("technique_id", "openbas"); + body.put("technique_name", "openbas"); + body.put("executors", executors); + String jsonResponse = this.post(this.config.getRestApiV2Url() + ABILITIES_URI, body); + return this.objectMapper.readValue(jsonResponse, new TypeReference<>() {}); + } catch (IOException e) { + throw new RuntimeException(e); } + } - public Ability createClearAbility(Injector injector) { - try { - List> executors = new ArrayList<>(); - Map injectorExecutorClearCommands = injector.getExecutorClearCommands(); - if (injectorExecutorClearCommands.containsKey(Endpoint.PLATFORM_TYPE.Windows.name() + "." + Endpoint.PLATFORM_ARCH.x86_64)) { - Map executorWindows = new HashMap<>(); - executorWindows.put("platform", "windows"); - executorWindows.put("name", "psh"); - executorWindows.put("command", injectorExecutorClearCommands.get(Endpoint.PLATFORM_TYPE.Windows.name() + "." + Endpoint.PLATFORM_ARCH.x86_64)); - executors.add(executorWindows); - } else if (injectorExecutorClearCommands.containsKey(Endpoint.PLATFORM_TYPE.Windows.name() + "." + Endpoint.PLATFORM_ARCH.arm64)) { - Map executorWindows = new HashMap<>(); - executorWindows.put("platform", "windows"); - executorWindows.put("name", "psh"); - executorWindows.put("command", injectorExecutorClearCommands.get(Endpoint.PLATFORM_TYPE.Windows.name() + "." + Endpoint.PLATFORM_ARCH.arm64)); - executors.add(executorWindows); - } - if (injectorExecutorClearCommands.containsKey(Endpoint.PLATFORM_TYPE.Linux.name() + "." + Endpoint.PLATFORM_ARCH.x86_64)) { - Map executorLinux = new HashMap<>(); - executorLinux.put("platform", "linux"); - executorLinux.put("name", "sh"); - executorLinux.put("command", injectorExecutorClearCommands.get(Endpoint.PLATFORM_TYPE.Linux.name() + "." + Endpoint.PLATFORM_ARCH.x86_64)); - executors.add(executorLinux); - } else if (injectorExecutorClearCommands.containsKey(Endpoint.PLATFORM_TYPE.Linux.name() + "." + Endpoint.PLATFORM_ARCH.arm64)) { - Map executorLinux = new HashMap<>(); - executorLinux.put("platform", "linux"); - executorLinux.put("name", "sh"); - executorLinux.put("command", injectorExecutorClearCommands.get(Endpoint.PLATFORM_TYPE.Linux.name() + "." + Endpoint.PLATFORM_ARCH.arm64)); - executors.add(executorLinux); - } - if (injectorExecutorClearCommands.containsKey(Endpoint.PLATFORM_TYPE.MacOS.name() + "." + Endpoint.PLATFORM_ARCH.x86_64)) { - Map executorMac = new HashMap<>(); - executorMac.put("platform", "darwin"); - executorMac.put("name", "sh"); - executorMac.put("command", injectorExecutorClearCommands.get(Endpoint.PLATFORM_TYPE.MacOS.name() + "." + Endpoint.PLATFORM_ARCH.x86_64)); - executors.add(executorMac); - } else if (injectorExecutorClearCommands.containsKey(Endpoint.PLATFORM_TYPE.MacOS.name() + "." + Endpoint.PLATFORM_ARCH.arm64)) { - Map executorMac = new HashMap<>(); - executorMac.put("platform", "darwin"); - executorMac.put("name", "sh"); - executorMac.put("command", injectorExecutorClearCommands.get(Endpoint.PLATFORM_TYPE.MacOS.name() + "." + Endpoint.PLATFORM_ARCH.arm64)); - executors.add(executorMac); - } - Map body = new HashMap<>(); - body.put("name", "caldera-clear-" + injector.getName()); - body.put("tactic", "openbas"); - body.put("technique_id", "openbas"); - body.put("technique_name", "openbas"); - body.put("executors", executors); - String jsonResponse = this.post( - this.config.getRestApiV2Url() + ABILITIES_URI, - body - ); - return this.objectMapper.readValue(jsonResponse, new TypeReference<>() { - }); - } catch (IOException e) { - throw new RuntimeException(e); - } + public Ability createClearAbility(Injector injector) { + try { + List> executors = new ArrayList<>(); + Map injectorExecutorClearCommands = injector.getExecutorClearCommands(); + if (injectorExecutorClearCommands.containsKey( + Endpoint.PLATFORM_TYPE.Windows.name() + "." + Endpoint.PLATFORM_ARCH.x86_64)) { + Map executorWindows = new HashMap<>(); + executorWindows.put("platform", "windows"); + executorWindows.put("name", "psh"); + executorWindows.put( + "command", + injectorExecutorClearCommands.get( + Endpoint.PLATFORM_TYPE.Windows.name() + "." + Endpoint.PLATFORM_ARCH.x86_64)); + executors.add(executorWindows); + } else if (injectorExecutorClearCommands.containsKey( + Endpoint.PLATFORM_TYPE.Windows.name() + "." + Endpoint.PLATFORM_ARCH.arm64)) { + Map executorWindows = new HashMap<>(); + executorWindows.put("platform", "windows"); + executorWindows.put("name", "psh"); + executorWindows.put( + "command", + injectorExecutorClearCommands.get( + Endpoint.PLATFORM_TYPE.Windows.name() + "." + Endpoint.PLATFORM_ARCH.arm64)); + executors.add(executorWindows); + } + if (injectorExecutorClearCommands.containsKey( + Endpoint.PLATFORM_TYPE.Linux.name() + "." + Endpoint.PLATFORM_ARCH.x86_64)) { + Map executorLinux = new HashMap<>(); + executorLinux.put("platform", "linux"); + executorLinux.put("name", "sh"); + executorLinux.put( + "command", + injectorExecutorClearCommands.get( + Endpoint.PLATFORM_TYPE.Linux.name() + "." + Endpoint.PLATFORM_ARCH.x86_64)); + executors.add(executorLinux); + } else if (injectorExecutorClearCommands.containsKey( + Endpoint.PLATFORM_TYPE.Linux.name() + "." + Endpoint.PLATFORM_ARCH.arm64)) { + Map executorLinux = new HashMap<>(); + executorLinux.put("platform", "linux"); + executorLinux.put("name", "sh"); + executorLinux.put( + "command", + injectorExecutorClearCommands.get( + Endpoint.PLATFORM_TYPE.Linux.name() + "." + Endpoint.PLATFORM_ARCH.arm64)); + executors.add(executorLinux); + } + if (injectorExecutorClearCommands.containsKey( + Endpoint.PLATFORM_TYPE.MacOS.name() + "." + Endpoint.PLATFORM_ARCH.x86_64)) { + Map executorMac = new HashMap<>(); + executorMac.put("platform", "darwin"); + executorMac.put("name", "sh"); + executorMac.put( + "command", + injectorExecutorClearCommands.get( + Endpoint.PLATFORM_TYPE.MacOS.name() + "." + Endpoint.PLATFORM_ARCH.x86_64)); + executors.add(executorMac); + } else if (injectorExecutorClearCommands.containsKey( + Endpoint.PLATFORM_TYPE.MacOS.name() + "." + Endpoint.PLATFORM_ARCH.arm64)) { + Map executorMac = new HashMap<>(); + executorMac.put("platform", "darwin"); + executorMac.put("name", "sh"); + executorMac.put( + "command", + injectorExecutorClearCommands.get( + Endpoint.PLATFORM_TYPE.MacOS.name() + "." + Endpoint.PLATFORM_ARCH.arm64)); + executors.add(executorMac); + } + Map body = new HashMap<>(); + body.put("name", "caldera-clear-" + injector.getName()); + body.put("tactic", "openbas"); + body.put("technique_id", "openbas"); + body.put("technique_name", "openbas"); + body.put("executors", executors); + String jsonResponse = this.post(this.config.getRestApiV2Url() + ABILITIES_URI, body); + return this.objectMapper.readValue(jsonResponse, new TypeReference<>() {}); + } catch (IOException e) { + throw new RuntimeException(e); } + } - public void deleteAbility(Ability ability) { - try { - this.delete(this.config.getRestApiV2Url() + ABILITIES_URI + "/" + ability.getAbility_id()); - } catch (IOException e) { - throw new RuntimeException(e); - } + public void deleteAbility(Ability ability) { + try { + this.delete(this.config.getRestApiV2Url() + ABILITIES_URI + "/" + ability.getAbility_id()); + } catch (IOException e) { + throw new RuntimeException(e); } + } - // -- EXPLOITS -- + // -- EXPLOITS -- - private final static String EXPLOIT_URI = "/exploit"; + private static final String EXPLOIT_URI = "/exploit"; - public void exploit( - @NotBlank final String obfuscator, - @NotBlank final String paw, - @NotBlank final String abilityId, - final List> additionalFields - ) { - try { - Map body = new HashMap<>(); - body.put("obfuscator", obfuscator); - body.put("paw", paw); - body.put("ability_id", abilityId); - body.put("facts", additionalFields); - String result = this.post(this.config.getPluginAccessApiUrl() + EXPLOIT_URI, body); - assert result.contains("complete"); // the exploit is well taken into account - } catch (IOException e) { - throw new RuntimeException(e); - } + public void exploit( + @NotBlank final String obfuscator, + @NotBlank final String paw, + @NotBlank final String abilityId, + final List> additionalFields) { + try { + Map body = new HashMap<>(); + body.put("obfuscator", obfuscator); + body.put("paw", paw); + body.put("ability_id", abilityId); + body.put("facts", additionalFields); + String result = this.post(this.config.getPluginAccessApiUrl() + EXPLOIT_URI, body); + assert result.contains("complete"); // the exploit is well taken into account + } catch (IOException e) { + throw new RuntimeException(e); } + } - // -- PRIVATE -- + // -- PRIVATE -- - private String get(@NotBlank final String uri) throws IOException { - try (CloseableHttpClient httpClient = HttpClients.createDefault()) { - HttpGet httpGet = new HttpGet(this.config.getRestApiV2Url() + uri); - // Headers - httpGet.addHeader(KEY_HEADER, this.config.getApiKey()); + private String get(@NotBlank final String uri) throws IOException { + try (CloseableHttpClient httpClient = HttpClients.createDefault()) { + HttpGet httpGet = new HttpGet(this.config.getRestApiV2Url() + uri); + // Headers + httpGet.addHeader(KEY_HEADER, this.config.getApiKey()); - return httpClient.execute( - httpGet, - response -> EntityUtils.toString(response.getEntity()) - ); - } catch (IOException e) { - throw new ClientProtocolException("Unexpected response for request on: " + uri); - } + return httpClient.execute(httpGet, response -> EntityUtils.toString(response.getEntity())); + } catch (IOException e) { + throw new ClientProtocolException("Unexpected response for request on: " + uri); } + } + private String post(@NotBlank final String url, @NotNull final Map body) + throws IOException { + try (CloseableHttpClient httpClient = HttpClients.createDefault()) { + HttpPost httpPost = new HttpPost(url); + // Headers + httpPost.addHeader(KEY_HEADER, this.config.getApiKey()); + // Body + StringEntity entity = new StringEntity(this.objectMapper.writeValueAsString(body)); + httpPost.setEntity(entity); - private String post( - @NotBlank final String url, - @NotNull final Map body) throws IOException { - try (CloseableHttpClient httpClient = HttpClients.createDefault()) { - HttpPost httpPost = new HttpPost(url); - // Headers - httpPost.addHeader(KEY_HEADER, this.config.getApiKey()); - // Body - StringEntity entity = new StringEntity(this.objectMapper.writeValueAsString(body)); - httpPost.setEntity(entity); - - return httpClient.execute( - httpPost, - response -> EntityUtils.toString(response.getEntity()) - ); - } catch (IOException e) { - throw new ClientProtocolException("Unexpected response for request on: " + url); - } + return httpClient.execute(httpPost, response -> EntityUtils.toString(response.getEntity())); + } catch (IOException e) { + throw new ClientProtocolException("Unexpected response for request on: " + url); } + } - private void patch( - @NotBlank final String url, - @NotNull final Map body) throws IOException { - try (CloseableHttpClient httpClient = HttpClients.createDefault()) { - HttpPatch httpPatch = new HttpPatch(url); - // Headers - httpPatch.addHeader(KEY_HEADER, this.config.getApiKey()); - // Body - StringEntity entity = new StringEntity(this.objectMapper.writeValueAsString(body)); - httpPatch.setEntity(entity); - httpClient.execute(httpPatch); - } catch (IOException e) { - throw new ClientProtocolException("Unexpected response for request on: " + url); - } + private void patch(@NotBlank final String url, @NotNull final Map body) + throws IOException { + try (CloseableHttpClient httpClient = HttpClients.createDefault()) { + HttpPatch httpPatch = new HttpPatch(url); + // Headers + httpPatch.addHeader(KEY_HEADER, this.config.getApiKey()); + // Body + StringEntity entity = new StringEntity(this.objectMapper.writeValueAsString(body)); + httpPatch.setEntity(entity); + httpClient.execute(httpPatch); + } catch (IOException e) { + throw new ClientProtocolException("Unexpected response for request on: " + url); } + } - private void delete(@NotBlank final String url) throws IOException { - try (CloseableHttpClient httpClient = HttpClients.createDefault()) { - HttpDelete httpdelete = new HttpDelete(url); - // Headers - httpdelete.addHeader(KEY_HEADER, this.config.getApiKey()); - httpClient.execute(httpdelete); - } catch (IOException e) { - throw new ClientProtocolException("Unexpected response for request on: " + url); - } + private void delete(@NotBlank final String url) throws IOException { + try (CloseableHttpClient httpClient = HttpClients.createDefault()) { + HttpDelete httpdelete = new HttpDelete(url); + // Headers + httpdelete.addHeader(KEY_HEADER, this.config.getApiKey()); + httpClient.execute(httpdelete); + } catch (IOException e) { + throw new ClientProtocolException("Unexpected response for request on: " + url); } - + } } diff --git a/openbas-framework/src/main/java/io/openbas/executors/caldera/client/model/Ability.java b/openbas-framework/src/main/java/io/openbas/executors/caldera/client/model/Ability.java index 480c84f109..2f5bd700f1 100644 --- a/openbas-framework/src/main/java/io/openbas/executors/caldera/client/model/Ability.java +++ b/openbas-framework/src/main/java/io/openbas/executors/caldera/client/model/Ability.java @@ -1,20 +1,18 @@ package io.openbas.executors.caldera.client.model; import com.fasterxml.jackson.annotation.JsonIgnoreProperties; -import lombok.Data; - import java.util.List; +import lombok.Data; @Data @JsonIgnoreProperties(ignoreUnknown = true) public class Ability { - private String ability_id; - private String tactic; - private String technique_name; - private String technique_id; - private String name; - private String description; - private List executors; - + private String ability_id; + private String tactic; + private String technique_name; + private String technique_id; + private String name; + private String description; + private List executors; } diff --git a/openbas-framework/src/main/java/io/openbas/executors/caldera/client/model/Executor.java b/openbas-framework/src/main/java/io/openbas/executors/caldera/client/model/Executor.java index 1d1a369218..02c9e827dc 100644 --- a/openbas-framework/src/main/java/io/openbas/executors/caldera/client/model/Executor.java +++ b/openbas-framework/src/main/java/io/openbas/executors/caldera/client/model/Executor.java @@ -7,6 +7,6 @@ @JsonIgnoreProperties(ignoreUnknown = true) public class Executor { - private String name; - private String platform; + private String name; + private String platform; } diff --git a/openbas-framework/src/main/java/io/openbas/executors/caldera/client/model/ExploitResult.java b/openbas-framework/src/main/java/io/openbas/executors/caldera/client/model/ExploitResult.java index d94ffb1a6c..48a9be1714 100644 --- a/openbas-framework/src/main/java/io/openbas/executors/caldera/client/model/ExploitResult.java +++ b/openbas-framework/src/main/java/io/openbas/executors/caldera/client/model/ExploitResult.java @@ -7,7 +7,6 @@ @JsonIgnoreProperties(ignoreUnknown = true) public class ExploitResult { - private String linkId; - private String command; - + private String linkId; + private String command; } diff --git a/openbas-framework/src/main/java/io/openbas/executors/caldera/client/model/Fact.java b/openbas-framework/src/main/java/io/openbas/executors/caldera/client/model/Fact.java index 8fe04a286d..da08913570 100644 --- a/openbas-framework/src/main/java/io/openbas/executors/caldera/client/model/Fact.java +++ b/openbas-framework/src/main/java/io/openbas/executors/caldera/client/model/Fact.java @@ -7,7 +7,6 @@ @JsonIgnoreProperties(ignoreUnknown = true) public class Fact { - private String name; - private String value; - + private String name; + private String value; } diff --git a/openbas-framework/src/main/java/io/openbas/executors/caldera/client/model/Link.java b/openbas-framework/src/main/java/io/openbas/executors/caldera/client/model/Link.java index 9534414be7..74ffd874e9 100644 --- a/openbas-framework/src/main/java/io/openbas/executors/caldera/client/model/Link.java +++ b/openbas-framework/src/main/java/io/openbas/executors/caldera/client/model/Link.java @@ -7,12 +7,11 @@ @JsonIgnoreProperties(ignoreUnknown = true) public class Link { - private String id; - private String paw; - private int status; - private String decide; - private Ability ability; - private String finish; - private String command; - + private String id; + private String paw; + private int status; + private String decide; + private Ability ability; + private String finish; + private String command; } diff --git a/openbas-framework/src/main/java/io/openbas/executors/caldera/client/model/Result.java b/openbas-framework/src/main/java/io/openbas/executors/caldera/client/model/Result.java index 0afa985096..eb30aa763b 100644 --- a/openbas-framework/src/main/java/io/openbas/executors/caldera/client/model/Result.java +++ b/openbas-framework/src/main/java/io/openbas/executors/caldera/client/model/Result.java @@ -7,7 +7,6 @@ @JsonIgnoreProperties(ignoreUnknown = true) public class Result { - private Link link; - private String output; - + private Link link; + private String output; } diff --git a/openbas-framework/src/main/java/io/openbas/executors/caldera/config/CalderaExecutorConfig.java b/openbas-framework/src/main/java/io/openbas/executors/caldera/config/CalderaExecutorConfig.java index e3330d9b0a..607253a768 100644 --- a/openbas-framework/src/main/java/io/openbas/executors/caldera/config/CalderaExecutorConfig.java +++ b/openbas-framework/src/main/java/io/openbas/executors/caldera/config/CalderaExecutorConfig.java @@ -1,6 +1,5 @@ package io.openbas.executors.caldera.config; -import io.openbas.executors.caldera.client.model.Ability; import jakarta.validation.constraints.NotBlank; import lombok.Getter; import lombok.Setter; @@ -12,33 +11,24 @@ @ConfigurationProperties(prefix = "executor.caldera") public class CalderaExecutorConfig { - private final static String REST_V2_URI = "/api/v2"; - private final static String PLUGIN_ACCESS_URI = "/plugin/access"; + private static final String REST_V2_URI = "/api/v2"; + private static final String PLUGIN_ACCESS_URI = "/plugin/access"; - @Getter - private boolean enable; + @Getter private boolean enable; - @Getter - @NotBlank - private String id; + @Getter @NotBlank private String id; - @Getter - @NotBlank - private String url; + @Getter @NotBlank private String url; - @Getter - @NotBlank - private String publicUrl; + @Getter @NotBlank private String publicUrl; - @Getter - @NotBlank - private String apiKey; + @Getter @NotBlank private String apiKey; - public String getRestApiV2Url() { - return url + REST_V2_URI; - } + public String getRestApiV2Url() { + return url + REST_V2_URI; + } - public String getPluginAccessApiUrl() { - return url + PLUGIN_ACCESS_URI; - } + public String getPluginAccessApiUrl() { + return url + PLUGIN_ACCESS_URI; + } } diff --git a/openbas-framework/src/main/java/io/openbas/executors/caldera/model/Agent.java b/openbas-framework/src/main/java/io/openbas/executors/caldera/model/Agent.java index 7fa7fe8a48..f61bf9a2d2 100644 --- a/openbas-framework/src/main/java/io/openbas/executors/caldera/model/Agent.java +++ b/openbas-framework/src/main/java/io/openbas/executors/caldera/model/Agent.java @@ -16,5 +16,4 @@ public class Agent { private String architecture; private String[] host_ip_addrs; private String exe_name; - } diff --git a/openbas-framework/src/main/java/io/openbas/executors/caldera/service/CalderaExecutorContextService.java b/openbas-framework/src/main/java/io/openbas/executors/caldera/service/CalderaExecutorContextService.java index b5cc1349a2..dcac12d8f6 100644 --- a/openbas-framework/src/main/java/io/openbas/executors/caldera/service/CalderaExecutorContextService.java +++ b/openbas-framework/src/main/java/io/openbas/executors/caldera/service/CalderaExecutorContextService.java @@ -8,77 +8,99 @@ import io.openbas.executors.caldera.client.model.Ability; import io.openbas.integrations.InjectorService; import jakarta.validation.constraints.NotNull; -import lombok.extern.java.Log; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.stereotype.Service; - import java.util.HashMap; import java.util.List; import java.util.Map; +import lombok.extern.java.Log; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Service; @Log @Service public class CalderaExecutorContextService { - private InjectorService injectorService; + private InjectorService injectorService; - private CalderaExecutorClient calderaExecutorClient; + private CalderaExecutorClient calderaExecutorClient; - @Autowired - public void setInjectorService(InjectorService injectorService) { - this.injectorService = injectorService; - } + @Autowired + public void setInjectorService(InjectorService injectorService) { + this.injectorService = injectorService; + } - @Autowired - public void setCalderaExecutorClient(CalderaExecutorClient calderaExecutorClient) { - this.calderaExecutorClient = calderaExecutorClient; - } + @Autowired + public void setCalderaExecutorClient(CalderaExecutorClient calderaExecutorClient) { + this.calderaExecutorClient = calderaExecutorClient; + } - public final Map injectorExecutorAbilities = new HashMap<>(); - public final Map injectorExecutorClearAbilities = new HashMap<>(); + public final Map injectorExecutorAbilities = new HashMap<>(); + public final Map injectorExecutorClearAbilities = new HashMap<>(); - public void registerAbilities() { - // Create the abilities if not exist for all injectors that need it - List abilities = this.abilities(); - Iterable injectors = injectorService.injectors(); - injectors.forEach(injector -> { - if (injector.getExecutorCommands() != null) { - List filteredAbilities = abilities.stream().filter(ability -> ability.getName().equals("caldera-subprocessor-" + injector.getName())).toList(); - if (!filteredAbilities.isEmpty()) { - Ability existingAbility = filteredAbilities.getFirst(); - calderaExecutorClient.deleteAbility(existingAbility); - } - Ability ability = calderaExecutorClient.createSubprocessorAbility(injector); - this.injectorExecutorAbilities.put(injector.getId(), ability); + public void registerAbilities() { + // Create the abilities if not exist for all injectors that need it + List abilities = this.abilities(); + Iterable injectors = injectorService.injectors(); + injectors.forEach( + injector -> { + if (injector.getExecutorCommands() != null) { + List filteredAbilities = + abilities.stream() + .filter( + ability -> + ability.getName().equals("caldera-subprocessor-" + injector.getName())) + .toList(); + if (!filteredAbilities.isEmpty()) { + Ability existingAbility = filteredAbilities.getFirst(); + calderaExecutorClient.deleteAbility(existingAbility); } - if (injector.getExecutorClearCommands() != null) { - List filteredAbilities = abilities.stream().filter(ability -> ability.getName().equals("caldera-clear-" + injector.getName())).toList(); - if (!filteredAbilities.isEmpty()) { - Ability existingAbility = filteredAbilities.getFirst(); - calderaExecutorClient.deleteAbility(existingAbility); - } - Ability ability = calderaExecutorClient.createClearAbility(injector); - this.injectorExecutorClearAbilities.put(injector.getId(), ability); + Ability ability = calderaExecutorClient.createSubprocessorAbility(injector); + this.injectorExecutorAbilities.put(injector.getId(), ability); + } + if (injector.getExecutorClearCommands() != null) { + List filteredAbilities = + abilities.stream() + .filter( + ability -> ability.getName().equals("caldera-clear-" + injector.getName())) + .toList(); + if (!filteredAbilities.isEmpty()) { + Ability existingAbility = filteredAbilities.getFirst(); + calderaExecutorClient.deleteAbility(existingAbility); } + Ability ability = calderaExecutorClient.createClearAbility(injector); + this.injectorExecutorClearAbilities.put(injector.getId(), ability); + } }); - } + } - public void launchExecutorSubprocess(@NotNull final Inject inject, @NotNull final Asset asset) { - inject.getInjectorContract().map(InjectorContract::getInjector).ifPresent(injector->{ - if (this.injectorExecutorAbilities.containsKey(injector.getId())) { - List> additionalFields = List.of(Map.of("trait", "inject", "value", inject.getId())); - calderaExecutorClient.exploit("base64", asset.getExternalReference(), this.injectorExecutorAbilities.get(injector.getId()).getAbility_id(), additionalFields); - } - }); - } + public void launchExecutorSubprocess(@NotNull final Inject inject, @NotNull final Asset asset) { + inject + .getInjectorContract() + .map(InjectorContract::getInjector) + .ifPresent( + injector -> { + if (this.injectorExecutorAbilities.containsKey(injector.getId())) { + List> additionalFields = + List.of(Map.of("trait", "inject", "value", inject.getId())); + calderaExecutorClient.exploit( + "base64", + asset.getExternalReference(), + this.injectorExecutorAbilities.get(injector.getId()).getAbility_id(), + additionalFields); + } + }); + } - public void launchExecutorClear(@NotNull final Injector injector, @NotNull final Asset asset) { - if (this.injectorExecutorAbilities.containsKey(injector.getId())) { - calderaExecutorClient.exploit("base64", asset.getExternalReference(), this.injectorExecutorClearAbilities.get(injector.getId()).getAbility_id(), List.of()); - } + public void launchExecutorClear(@NotNull final Injector injector, @NotNull final Asset asset) { + if (this.injectorExecutorAbilities.containsKey(injector.getId())) { + calderaExecutorClient.exploit( + "base64", + asset.getExternalReference(), + this.injectorExecutorClearAbilities.get(injector.getId()).getAbility_id(), + List.of()); } + } - private List abilities() { - return calderaExecutorClient.abilities(); - } + private List abilities() { + return calderaExecutorClient.abilities(); + } } diff --git a/openbas-framework/src/main/java/io/openbas/executors/openbas/OpenBASExecutor.java b/openbas-framework/src/main/java/io/openbas/executors/openbas/OpenBASExecutor.java index f2231cc8ed..4106ef6a87 100644 --- a/openbas-framework/src/main/java/io/openbas/executors/openbas/OpenBASExecutor.java +++ b/openbas-framework/src/main/java/io/openbas/executors/openbas/OpenBASExecutor.java @@ -3,28 +3,36 @@ import io.openbas.database.model.Endpoint; import io.openbas.integrations.ExecutorService; import jakarta.annotation.PostConstruct; +import java.util.logging.Level; import lombok.RequiredArgsConstructor; import lombok.extern.java.Log; import org.springframework.stereotype.Service; -import java.util.logging.Level; - @RequiredArgsConstructor @Service @Log public class OpenBASExecutor { - private final ExecutorService executorService; - public static String OPENBAS_EXECUTOR_ID = "2f9a0936-c327-4e95-b406-d161d32a2501"; - public static String OPENBAS_EXECUTOR_TYPE = "openbas_agent"; - public static String OPENBAS_EXECUTOR_NAME = "OpenBAS Agent"; + private final ExecutorService executorService; + public static String OPENBAS_EXECUTOR_ID = "2f9a0936-c327-4e95-b406-d161d32a2501"; + public static String OPENBAS_EXECUTOR_TYPE = "openbas_agent"; + public static String OPENBAS_EXECUTOR_NAME = "OpenBAS Agent"; - @PostConstruct - public void init() { - try { - executorService.register(OPENBAS_EXECUTOR_ID, OPENBAS_EXECUTOR_TYPE, OPENBAS_EXECUTOR_NAME, getClass().getResourceAsStream("/img/icon-openbas.png"), new String[]{Endpoint.PLATFORM_TYPE.Windows.name(), Endpoint.PLATFORM_TYPE.Linux.name(), Endpoint.PLATFORM_TYPE.MacOS.name()}); - } catch (Exception e) { - log.log(Level.SEVERE, "Error creating OpenBAS executor: " + e); - } + @PostConstruct + public void init() { + try { + executorService.register( + OPENBAS_EXECUTOR_ID, + OPENBAS_EXECUTOR_TYPE, + OPENBAS_EXECUTOR_NAME, + getClass().getResourceAsStream("/img/icon-openbas.png"), + new String[] { + Endpoint.PLATFORM_TYPE.Windows.name(), + Endpoint.PLATFORM_TYPE.Linux.name(), + Endpoint.PLATFORM_TYPE.MacOS.name() + }); + } catch (Exception e) { + log.log(Level.SEVERE, "Error creating OpenBAS executor: " + e); } + } } diff --git a/openbas-framework/src/main/java/io/openbas/executors/openbas/service/OpenBASExecutorContextService.java b/openbas-framework/src/main/java/io/openbas/executors/openbas/service/OpenBASExecutorContextService.java index 04a0efd08f..25408c65b5 100644 --- a/openbas-framework/src/main/java/io/openbas/executors/openbas/service/OpenBASExecutorContextService.java +++ b/openbas-framework/src/main/java/io/openbas/executors/openbas/service/OpenBASExecutorContextService.java @@ -3,60 +3,75 @@ import io.openbas.database.model.*; import io.openbas.database.repository.AssetAgentJobRepository; import jakarta.validation.constraints.NotNull; +import java.util.Objects; import lombok.extern.java.Log; import org.hibernate.Hibernate; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Service; -import java.util.Objects; - @Log @Service public class OpenBASExecutorContextService { - private AssetAgentJobRepository assetAgentJobRepository; + private AssetAgentJobRepository assetAgentJobRepository; - @Autowired - public void setAssetAgentJobRepository(AssetAgentJobRepository assetAgentJobRepository) { - this.assetAgentJobRepository = assetAgentJobRepository; - } + @Autowired + public void setAssetAgentJobRepository(AssetAgentJobRepository assetAgentJobRepository) { + this.assetAgentJobRepository = assetAgentJobRepository; + } - private String computeCommand(@NotNull final Inject inject, Endpoint.PLATFORM_TYPE platform, Endpoint.PLATFORM_ARCH arch) { - Injector injector = inject.getInjectorContract() + private String computeCommand( + @NotNull final Inject inject, Endpoint.PLATFORM_TYPE platform, Endpoint.PLATFORM_ARCH arch) { + Injector injector = + inject + .getInjectorContract() .map(InjectorContract::getInjector) - .orElseThrow(() -> new UnsupportedOperationException("Inject does not have a contract")); - - switch (platform) { - case Endpoint.PLATFORM_TYPE.Windows -> { - return injector.getExecutorCommands().get(Endpoint.PLATFORM_TYPE.Windows.name() + "." + arch.name()) - .replace("#{inject}", inject.getId()); - } - case Endpoint.PLATFORM_TYPE.Linux -> { - return injector.getExecutorCommands().get(Endpoint.PLATFORM_TYPE.Linux.name() + "." + arch.name()) - .replace("#{inject}", inject.getId()); - } - case Endpoint.PLATFORM_TYPE.MacOS -> { - return injector.getExecutorCommands().get(Endpoint.PLATFORM_TYPE.MacOS.name() + "." + arch.name()) - .replace("#{inject}", inject.getId()); - } - default -> throw new RuntimeException("Unsupported platform: " + platform); - } - } + .orElseThrow( + () -> new UnsupportedOperationException("Inject does not have a contract")); - public void launchExecutorSubprocess(@NotNull final Inject inject, @NotNull final Asset asset) { - Endpoint.PLATFORM_TYPE platform = Objects.equals(asset.getType(), "Endpoint") ? ((Endpoint) Hibernate.unproxy(asset)).getPlatform() : null; - Endpoint.PLATFORM_ARCH arch = Objects.equals(asset.getType(), "Endpoint") ? ((Endpoint) Hibernate.unproxy(asset)).getArch() : null; - if (platform == null) { - throw new RuntimeException("Unsupported null platform"); - } - AssetAgentJob assetAgentJob = new AssetAgentJob(); - assetAgentJob.setCommand(computeCommand(inject, platform, arch)); - assetAgentJob.setAsset(asset); - assetAgentJob.setInject(inject); - assetAgentJobRepository.save(assetAgentJob); + switch (platform) { + case Endpoint.PLATFORM_TYPE.Windows -> { + return injector + .getExecutorCommands() + .get(Endpoint.PLATFORM_TYPE.Windows.name() + "." + arch.name()) + .replace("#{inject}", inject.getId()); + } + case Endpoint.PLATFORM_TYPE.Linux -> { + return injector + .getExecutorCommands() + .get(Endpoint.PLATFORM_TYPE.Linux.name() + "." + arch.name()) + .replace("#{inject}", inject.getId()); + } + case Endpoint.PLATFORM_TYPE.MacOS -> { + return injector + .getExecutorCommands() + .get(Endpoint.PLATFORM_TYPE.MacOS.name() + "." + arch.name()) + .replace("#{inject}", inject.getId()); + } + default -> throw new RuntimeException("Unsupported platform: " + platform); } + } - public void launchExecutorClear(@NotNull final Injector injector, @NotNull final Asset asset) { - // TODO + public void launchExecutorSubprocess(@NotNull final Inject inject, @NotNull final Asset asset) { + Endpoint.PLATFORM_TYPE platform = + Objects.equals(asset.getType(), "Endpoint") + ? ((Endpoint) Hibernate.unproxy(asset)).getPlatform() + : null; + Endpoint.PLATFORM_ARCH arch = + Objects.equals(asset.getType(), "Endpoint") + ? ((Endpoint) Hibernate.unproxy(asset)).getArch() + : null; + if (platform == null) { + throw new RuntimeException("Unsupported null platform"); } + AssetAgentJob assetAgentJob = new AssetAgentJob(); + assetAgentJob.setCommand(computeCommand(inject, platform, arch)); + assetAgentJob.setAsset(asset); + assetAgentJob.setInject(inject); + assetAgentJobRepository.save(assetAgentJob); + } + + public void launchExecutorClear(@NotNull final Injector injector, @NotNull final Asset asset) { + // TODO + } } diff --git a/openbas-framework/src/main/java/io/openbas/executors/tanium/TaniumExecutor.java b/openbas-framework/src/main/java/io/openbas/executors/tanium/TaniumExecutor.java index c0298a7ebe..fd9d3199b0 100644 --- a/openbas-framework/src/main/java/io/openbas/executors/tanium/TaniumExecutor.java +++ b/openbas-framework/src/main/java/io/openbas/executors/tanium/TaniumExecutor.java @@ -8,29 +8,35 @@ import io.openbas.integrations.ExecutorService; import io.openbas.integrations.InjectorService; import jakarta.annotation.PostConstruct; +import java.time.Duration; import lombok.RequiredArgsConstructor; import org.springframework.scheduling.concurrent.ThreadPoolTaskScheduler; import org.springframework.stereotype.Service; -import java.time.Duration; - @RequiredArgsConstructor @Service public class TaniumExecutor { - private final TaniumExecutorConfig config; - private final ThreadPoolTaskScheduler taskScheduler; - private final TaniumExecutorClient client; - private final EndpointService endpointService; - private final TaniumExecutorContextService taniumExecutorContextService; - private final ExecutorService executorService; - private final InjectorService injectorService; + private final TaniumExecutorConfig config; + private final ThreadPoolTaskScheduler taskScheduler; + private final TaniumExecutorClient client; + private final EndpointService endpointService; + private final TaniumExecutorContextService taniumExecutorContextService; + private final ExecutorService executorService; + private final InjectorService injectorService; - @PostConstruct - public void init() { - TaniumExecutorService service = new TaniumExecutorService(this.executorService, this.client, this.config, this.taniumExecutorContextService, this.endpointService, this.injectorService); - if (this.config.isEnable()) { - this.taskScheduler.scheduleAtFixedRate(service, Duration.ofSeconds(60)); - } + @PostConstruct + public void init() { + TaniumExecutorService service = + new TaniumExecutorService( + this.executorService, + this.client, + this.config, + this.taniumExecutorContextService, + this.endpointService, + this.injectorService); + if (this.config.isEnable()) { + this.taskScheduler.scheduleAtFixedRate(service, Duration.ofSeconds(60)); } + } } diff --git a/openbas-framework/src/main/java/io/openbas/executors/tanium/client/TaniumExecutorClient.java b/openbas-framework/src/main/java/io/openbas/executors/tanium/client/TaniumExecutorClient.java index 2d0776d082..dc6e20a8e4 100644 --- a/openbas-framework/src/main/java/io/openbas/executors/tanium/client/TaniumExecutorClient.java +++ b/openbas-framework/src/main/java/io/openbas/executors/tanium/client/TaniumExecutorClient.java @@ -5,6 +5,9 @@ import io.openbas.executors.tanium.config.TaniumExecutorConfig; import io.openbas.executors.tanium.model.DataEndpoints; import jakarta.validation.constraints.NotNull; +import java.io.IOException; +import java.util.HashMap; +import java.util.Map; import lombok.RequiredArgsConstructor; import org.apache.hc.client5.http.ClientProtocolException; import org.apache.hc.client5.http.classic.methods.HttpPost; @@ -14,85 +17,89 @@ import org.apache.hc.core5.http.io.entity.StringEntity; import org.springframework.stereotype.Service; -import java.io.IOException; -import java.util.HashMap; -import java.util.Map; - @RequiredArgsConstructor @Service public class TaniumExecutorClient { - private static final String KEY_HEADER = "session"; + private static final String KEY_HEADER = "session"; - private final TaniumExecutorConfig config; - private final ObjectMapper objectMapper = new ObjectMapper(); + private final TaniumExecutorConfig config; + private final ObjectMapper objectMapper = new ObjectMapper(); - // -- ENDPOINTS -- + // -- ENDPOINTS -- - public DataEndpoints endpoints() { - try { - String query = "{\n" + - "\tendpoints(filter: {memberOf: {id: " + this.config.getComputerGroupId() + "}}) {\n" + - " edges {\n" + - " node {\n" + - " id\n" + - " computerID\n" + - " name\n" + - " ipAddresses\n" + - " macAddresses\n" + - " eidLastSeen\n" + - " os { platform }\n" + - " processor { architecture }\n" + - " }\n" + - " }\n" + - " }\n" + - "}"; - Map body = new HashMap<>(); - body.put("query", query); - String jsonResponse = this.post(body); - return this.objectMapper.readValue(jsonResponse, new TypeReference<>() { - }); - } catch (IOException e) { - throw new RuntimeException(e); - } + public DataEndpoints endpoints() { + try { + String query = + "{\n" + + "\tendpoints(filter: {memberOf: {id: " + + this.config.getComputerGroupId() + + "}}) {\n" + + " edges {\n" + + " node {\n" + + " id\n" + + " computerID\n" + + " name\n" + + " ipAddresses\n" + + " macAddresses\n" + + " eidLastSeen\n" + + " os { platform }\n" + + " processor { architecture }\n" + + " }\n" + + " }\n" + + " }\n" + + "}"; + Map body = new HashMap<>(); + body.put("query", query); + String jsonResponse = this.post(body); + return this.objectMapper.readValue(jsonResponse, new TypeReference<>() {}); + } catch (IOException e) { + throw new RuntimeException(e); } + } - public void executeAction(String endpointId, Integer packageID, String command) { - try { - String query = "mutation {\n" + - "\tactionCreate(\n" + - " input: { name: \"OpenBAS Action\", package: { id: " + packageID + ", params: [\"" + command.replace("\\", "\\\\").replace("\"", "\\\"") + "\"] }, targets: { actionGroup: { id: " + this.config.getActionGroupId() + " }, endpoints: [" + endpointId + "] } }\n" + - ") {\n " + - " action {\n" + - " id\n" + - " }\n" + - " }\n" + - "}"; - Map body = new HashMap<>(); - body.put("query", query); - this.post(body); - } catch (IOException e) { - throw new RuntimeException(e); - } + public void executeAction(String endpointId, Integer packageID, String command) { + try { + String query = + "mutation {\n" + + "\tactionCreate(\n" + + " input: { name: \"OpenBAS Action\", package: { id: " + + packageID + + ", params: [\"" + + command.replace("\\", "\\\\").replace("\"", "\\\"") + + "\"] }, targets: { actionGroup: { id: " + + this.config.getActionGroupId() + + " }, endpoints: [" + + endpointId + + "] } }\n" + + ") {\n " + + " action {\n" + + " id\n" + + " }\n" + + " }\n" + + "}"; + Map body = new HashMap<>(); + body.put("query", query); + this.post(body); + } catch (IOException e) { + throw new RuntimeException(e); } + } - // -- PRIVATE -- + // -- PRIVATE -- - private String post(@NotNull final Map body) throws IOException { - try (CloseableHttpClient httpClient = HttpClients.createDefault()) { - HttpPost httpPost = new HttpPost(this.config.getGatewayUrl()); - // Headers - httpPost.addHeader(KEY_HEADER, this.config.getApiKey()); - httpPost.addHeader("content-type", "application/json"); - // Body - StringEntity entity = new StringEntity(this.objectMapper.writeValueAsString(body)); - httpPost.setEntity(entity); - return httpClient.execute( - httpPost, - response -> EntityUtils.toString(response.getEntity()) - ); - } catch (IOException e) { - throw new ClientProtocolException("Unexpected response"); - } + private String post(@NotNull final Map body) throws IOException { + try (CloseableHttpClient httpClient = HttpClients.createDefault()) { + HttpPost httpPost = new HttpPost(this.config.getGatewayUrl()); + // Headers + httpPost.addHeader(KEY_HEADER, this.config.getApiKey()); + httpPost.addHeader("content-type", "application/json"); + // Body + StringEntity entity = new StringEntity(this.objectMapper.writeValueAsString(body)); + httpPost.setEntity(entity); + return httpClient.execute(httpPost, response -> EntityUtils.toString(response.getEntity())); + } catch (IOException e) { + throw new ClientProtocolException("Unexpected response"); } + } } diff --git a/openbas-framework/src/main/java/io/openbas/executors/tanium/config/TaniumExecutorConfig.java b/openbas-framework/src/main/java/io/openbas/executors/tanium/config/TaniumExecutorConfig.java index 7111594471..7e9f380685 100644 --- a/openbas-framework/src/main/java/io/openbas/executors/tanium/config/TaniumExecutorConfig.java +++ b/openbas-framework/src/main/java/io/openbas/executors/tanium/config/TaniumExecutorConfig.java @@ -11,40 +11,25 @@ @ConfigurationProperties(prefix = "executor.tanium") public class TaniumExecutorConfig { - private final static String GATEWAY_URI = "/plugin/products/gateway/graphql"; + private static final String GATEWAY_URI = "/plugin/products/gateway/graphql"; - @Getter - private boolean enable; + @Getter private boolean enable; - @Getter - @NotBlank - private String id; + @Getter @NotBlank private String id; - @Getter - @NotBlank - private String url; + @Getter @NotBlank private String url; - @Getter - @NotBlank - private String apiKey; + @Getter @NotBlank private String apiKey; - @Getter - @NotBlank - private Integer computerGroupId = 1; + @Getter @NotBlank private Integer computerGroupId = 1; - @Getter - @NotBlank - private Integer actionGroupId = 4; + @Getter @NotBlank private Integer actionGroupId = 4; - @Getter - @NotBlank - private Integer windowsPackageId; + @Getter @NotBlank private Integer windowsPackageId; - @Getter - @NotBlank - private Integer unixPackageId; + @Getter @NotBlank private Integer unixPackageId; - public String getGatewayUrl() { - return url + GATEWAY_URI; - } + public String getGatewayUrl() { + return url + GATEWAY_URI; + } } diff --git a/openbas-framework/src/main/java/io/openbas/executors/tanium/model/DataEndpoints.java b/openbas-framework/src/main/java/io/openbas/executors/tanium/model/DataEndpoints.java index 78dd96a111..4e56c867bd 100644 --- a/openbas-framework/src/main/java/io/openbas/executors/tanium/model/DataEndpoints.java +++ b/openbas-framework/src/main/java/io/openbas/executors/tanium/model/DataEndpoints.java @@ -7,6 +7,5 @@ @JsonIgnoreProperties(ignoreUnknown = true) public class DataEndpoints { - private Endpoints data; - + private Endpoints data; } diff --git a/openbas-framework/src/main/java/io/openbas/executors/tanium/model/EdgesEndpoints.java b/openbas-framework/src/main/java/io/openbas/executors/tanium/model/EdgesEndpoints.java index bcc19470af..9add626d94 100644 --- a/openbas-framework/src/main/java/io/openbas/executors/tanium/model/EdgesEndpoints.java +++ b/openbas-framework/src/main/java/io/openbas/executors/tanium/model/EdgesEndpoints.java @@ -1,14 +1,12 @@ package io.openbas.executors.tanium.model; import com.fasterxml.jackson.annotation.JsonIgnoreProperties; -import lombok.Data; - import java.util.List; +import lombok.Data; @Data @JsonIgnoreProperties(ignoreUnknown = true) public class EdgesEndpoints { - private List edges; - + private List edges; } diff --git a/openbas-framework/src/main/java/io/openbas/executors/tanium/model/Endpoints.java b/openbas-framework/src/main/java/io/openbas/executors/tanium/model/Endpoints.java index 069bbd7709..237ddf0d8d 100644 --- a/openbas-framework/src/main/java/io/openbas/executors/tanium/model/Endpoints.java +++ b/openbas-framework/src/main/java/io/openbas/executors/tanium/model/Endpoints.java @@ -7,6 +7,5 @@ @JsonIgnoreProperties(ignoreUnknown = true) public class Endpoints { - private EdgesEndpoints endpoints; - + private EdgesEndpoints endpoints; } diff --git a/openbas-framework/src/main/java/io/openbas/executors/tanium/model/NodeEndpoint.java b/openbas-framework/src/main/java/io/openbas/executors/tanium/model/NodeEndpoint.java index 8a58690f2b..09bc97c2e0 100644 --- a/openbas-framework/src/main/java/io/openbas/executors/tanium/model/NodeEndpoint.java +++ b/openbas-framework/src/main/java/io/openbas/executors/tanium/model/NodeEndpoint.java @@ -7,6 +7,5 @@ @JsonIgnoreProperties(ignoreUnknown = true) public class NodeEndpoint { - private TaniumEndpoint node; - + private TaniumEndpoint node; } diff --git a/openbas-framework/src/main/java/io/openbas/executors/tanium/model/Os.java b/openbas-framework/src/main/java/io/openbas/executors/tanium/model/Os.java index d9ebed7458..eaac00f2f8 100644 --- a/openbas-framework/src/main/java/io/openbas/executors/tanium/model/Os.java +++ b/openbas-framework/src/main/java/io/openbas/executors/tanium/model/Os.java @@ -7,6 +7,5 @@ @JsonIgnoreProperties(ignoreUnknown = true) public class Os { - private String platform; - + private String platform; } diff --git a/openbas-framework/src/main/java/io/openbas/executors/tanium/model/Processor.java b/openbas-framework/src/main/java/io/openbas/executors/tanium/model/Processor.java index c8aa71ea20..5d6489bc9b 100644 --- a/openbas-framework/src/main/java/io/openbas/executors/tanium/model/Processor.java +++ b/openbas-framework/src/main/java/io/openbas/executors/tanium/model/Processor.java @@ -7,6 +7,5 @@ @JsonIgnoreProperties(ignoreUnknown = true) public class Processor { - private String architecture; - + private String architecture; } diff --git a/openbas-framework/src/main/java/io/openbas/executors/tanium/model/TaniumEndpoint.java b/openbas-framework/src/main/java/io/openbas/executors/tanium/model/TaniumEndpoint.java index f506d737d7..3ee589d999 100644 --- a/openbas-framework/src/main/java/io/openbas/executors/tanium/model/TaniumEndpoint.java +++ b/openbas-framework/src/main/java/io/openbas/executors/tanium/model/TaniumEndpoint.java @@ -7,13 +7,12 @@ @JsonIgnoreProperties(ignoreUnknown = true) public class TaniumEndpoint { - private String id; - private String computerID; - private String name; - private String[] ipAddresses; - private String[] macAddresses; - private Os os; - private Processor processor; - private String eidLastSeen; - + private String id; + private String computerID; + private String name; + private String[] ipAddresses; + private String[] macAddresses; + private Os os; + private Processor processor; + private String eidLastSeen; } diff --git a/openbas-framework/src/main/java/io/openbas/executors/tanium/service/TaniumExecutorContextService.java b/openbas-framework/src/main/java/io/openbas/executors/tanium/service/TaniumExecutorContextService.java index 6807b5235e..d0c745da6a 100644 --- a/openbas-framework/src/main/java/io/openbas/executors/tanium/service/TaniumExecutorContextService.java +++ b/openbas-framework/src/main/java/io/openbas/executors/tanium/service/TaniumExecutorContextService.java @@ -8,65 +8,90 @@ import io.openbas.executors.tanium.client.TaniumExecutorClient; import io.openbas.executors.tanium.config.TaniumExecutorConfig; import jakarta.validation.constraints.NotNull; +import java.util.Base64; +import java.util.Objects; import lombok.extern.java.Log; import org.hibernate.Hibernate; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Service; -import java.util.Base64; -import java.util.Objects; - @Log @Service public class TaniumExecutorContextService { - private TaniumExecutorConfig taniumExecutorConfig; + private TaniumExecutorConfig taniumExecutorConfig; - private TaniumExecutorClient taniumExecutorClient; + private TaniumExecutorClient taniumExecutorClient; - @Autowired - public void setTaniumExecutorConfig(TaniumExecutorConfig taniumExecutorConfig) { - this.taniumExecutorConfig = taniumExecutorConfig; - } + @Autowired + public void setTaniumExecutorConfig(TaniumExecutorConfig taniumExecutorConfig) { + this.taniumExecutorConfig = taniumExecutorConfig; + } - @Autowired - public void setTaniumExecutorClient(TaniumExecutorClient taniumExecutorClient) { - this.taniumExecutorClient = taniumExecutorClient; - } + @Autowired + public void setTaniumExecutorClient(TaniumExecutorClient taniumExecutorClient) { + this.taniumExecutorClient = taniumExecutorClient; + } - public void launchExecutorSubprocess(@NotNull final Inject inject, @NotNull final Asset asset) { - Injector injector = inject.getInjectorContract() + public void launchExecutorSubprocess(@NotNull final Inject inject, @NotNull final Asset asset) { + Injector injector = + inject + .getInjectorContract() .map(InjectorContract::getInjector) - .orElseThrow(() -> new UnsupportedOperationException("Inject does not have a contract")); + .orElseThrow( + () -> new UnsupportedOperationException("Inject does not have a contract")); - Endpoint.PLATFORM_TYPE platform = Objects.equals(asset.getType(), "Endpoint") ? ((Endpoint) Hibernate.unproxy(asset)).getPlatform(): null; - Endpoint.PLATFORM_ARCH arch = Objects.equals(asset.getType(), "Endpoint") ? ((Endpoint) Hibernate.unproxy(asset)).getArch(): null; - if( platform == null || arch == null ) { - throw new RuntimeException("Unsupported platform: " + platform + " (arch:" + arch + ")"); - } - switch (platform ) { - case Endpoint.PLATFORM_TYPE.Windows -> { - String command = injector.getExecutorCommands().get(Endpoint.PLATFORM_TYPE.Windows.name() + "." + arch.name()) - .replace("\"#{location}\"", "$PWD.Path") - .replace("#{inject}", inject.getId()); - this.taniumExecutorClient.executeAction(asset.getExternalReference(), this.taniumExecutorConfig.getWindowsPackageId(), Base64.getEncoder().encodeToString(command.getBytes())); - } - case Endpoint.PLATFORM_TYPE.Linux -> { - String command = injector.getExecutorCommands().get(Endpoint.PLATFORM_TYPE.Linux.name() + "." + arch.name()) - .replace("\"#{location}\"", "$(pwd)") - .replace("#{inject}", inject.getId()); - this.taniumExecutorClient.executeAction(asset.getExternalReference(), this.taniumExecutorConfig.getUnixPackageId(), Base64.getEncoder().encodeToString(command.getBytes())); - } - case Endpoint.PLATFORM_TYPE.MacOS -> { - String command = injector.getExecutorCommands().get(Endpoint.PLATFORM_TYPE.MacOS.name() + "." + arch.name()) - .replace("\"#{location}\"", "$(pwd)") - .replace("#{inject}", inject.getId()); - this.taniumExecutorClient.executeAction(asset.getExternalReference(), this.taniumExecutorConfig.getUnixPackageId(), Base64.getEncoder().encodeToString(command.getBytes())); - } - default -> throw new RuntimeException("Unsupported platform: " + platform); - }; + Endpoint.PLATFORM_TYPE platform = + Objects.equals(asset.getType(), "Endpoint") + ? ((Endpoint) Hibernate.unproxy(asset)).getPlatform() + : null; + Endpoint.PLATFORM_ARCH arch = + Objects.equals(asset.getType(), "Endpoint") + ? ((Endpoint) Hibernate.unproxy(asset)).getArch() + : null; + if (platform == null || arch == null) { + throw new RuntimeException("Unsupported platform: " + platform + " (arch:" + arch + ")"); } - - public void launchExecutorClear(@NotNull final Injector injector, @NotNull final Asset asset) { - + switch (platform) { + case Endpoint.PLATFORM_TYPE.Windows -> { + String command = + injector + .getExecutorCommands() + .get(Endpoint.PLATFORM_TYPE.Windows.name() + "." + arch.name()) + .replace("\"#{location}\"", "$PWD.Path") + .replace("#{inject}", inject.getId()); + this.taniumExecutorClient.executeAction( + asset.getExternalReference(), + this.taniumExecutorConfig.getWindowsPackageId(), + Base64.getEncoder().encodeToString(command.getBytes())); + } + case Endpoint.PLATFORM_TYPE.Linux -> { + String command = + injector + .getExecutorCommands() + .get(Endpoint.PLATFORM_TYPE.Linux.name() + "." + arch.name()) + .replace("\"#{location}\"", "$(pwd)") + .replace("#{inject}", inject.getId()); + this.taniumExecutorClient.executeAction( + asset.getExternalReference(), + this.taniumExecutorConfig.getUnixPackageId(), + Base64.getEncoder().encodeToString(command.getBytes())); + } + case Endpoint.PLATFORM_TYPE.MacOS -> { + String command = + injector + .getExecutorCommands() + .get(Endpoint.PLATFORM_TYPE.MacOS.name() + "." + arch.name()) + .replace("\"#{location}\"", "$(pwd)") + .replace("#{inject}", inject.getId()); + this.taniumExecutorClient.executeAction( + asset.getExternalReference(), + this.taniumExecutorConfig.getUnixPackageId(), + Base64.getEncoder().encodeToString(command.getBytes())); + } + default -> throw new RuntimeException("Unsupported platform: " + platform); } + ; + } + + public void launchExecutorClear(@NotNull final Injector injector, @NotNull final Asset asset) {} } diff --git a/openbas-framework/src/main/java/io/openbas/executors/tanium/service/TaniumExecutorService.java b/openbas-framework/src/main/java/io/openbas/executors/tanium/service/TaniumExecutorService.java index fc4c53735a..782e0feb6c 100644 --- a/openbas-framework/src/main/java/io/openbas/executors/tanium/service/TaniumExecutorService.java +++ b/openbas-framework/src/main/java/io/openbas/executors/tanium/service/TaniumExecutorService.java @@ -1,5 +1,8 @@ package io.openbas.executors.tanium.service; +import static java.time.Instant.now; +import static java.time.ZoneOffset.UTC; + import io.openbas.asset.EndpointService; import io.openbas.database.model.Asset; import io.openbas.database.model.Endpoint; @@ -13,166 +16,189 @@ import io.openbas.integrations.InjectorService; import jakarta.validation.constraints.NotBlank; import jakarta.validation.constraints.NotNull; -import lombok.extern.java.Log; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty; -import org.springframework.stereotype.Service; - import java.time.Instant; import java.time.LocalDateTime; import java.time.ZonedDateTime; import java.time.format.DateTimeFormatter; import java.util.*; import java.util.logging.Level; - -import static java.time.Instant.now; -import static java.time.ZoneOffset.UTC; +import lombok.extern.java.Log; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty; +import org.springframework.stereotype.Service; @ConditionalOnProperty(prefix = "executor.tanium", name = "enable") @Log @Service public class TaniumExecutorService implements Runnable { - private static final int CLEAR_TTL = 1800000; // 30 minutes - private static final int DELETE_TTL = 86400000; // 24 hours - private static final String TANIUM_EXECUTOR_TYPE = "openbas_tanium"; - private static final String TANIUM_EXECUTOR_NAME = "Tanium"; - - private final TaniumExecutorClient client; - - private final EndpointService endpointService; - - private final TaniumExecutorContextService taniumExecutorContextService; - - private final InjectorService injectorService; - - private Executor executor = null; - - public static Endpoint.PLATFORM_TYPE toPlatform(@NotBlank final String platform) { - return switch (platform) { - case "Linux" -> Endpoint.PLATFORM_TYPE.Linux; - case "Windows" -> Endpoint.PLATFORM_TYPE.Windows; - case "MacOS" -> Endpoint.PLATFORM_TYPE.MacOS; - default -> Endpoint.PLATFORM_TYPE.Unknown; - }; - } - - public static Endpoint.PLATFORM_ARCH toArch(@NotBlank final String arch) { - return switch (arch) { - case "x64-based PC", "x86_64" -> Endpoint.PLATFORM_ARCH.x86_64; - case "arm64-based PC", "arm64" -> Endpoint.PLATFORM_ARCH.arm64; - default -> Endpoint.PLATFORM_ARCH.Unknown; - }; - } - - @Autowired - public TaniumExecutorService( - ExecutorService executorService, - TaniumExecutorClient client, - TaniumExecutorConfig config, - TaniumExecutorContextService taniumExecutorContextService, - EndpointService endpointService, - InjectorService injectorService - ) { - this.client = client; - this.endpointService = endpointService; - this.taniumExecutorContextService = taniumExecutorContextService; - this.injectorService = injectorService; - try { - if (config.isEnable()) { - this.executor = executorService.register(config.getId(), TANIUM_EXECUTOR_TYPE, TANIUM_EXECUTOR_NAME, getClass().getResourceAsStream("/img/icon-tanium.png"), new String[]{Endpoint.PLATFORM_TYPE.Windows.name(), Endpoint.PLATFORM_TYPE.Linux.name(), Endpoint.PLATFORM_TYPE.MacOS.name()}); - } else { - executorService.remove(config.getId()); - } - } catch (Exception e) { - log.log(Level.SEVERE, "Error creating Tanium executor: " + e); - } + private static final int CLEAR_TTL = 1800000; // 30 minutes + private static final int DELETE_TTL = 86400000; // 24 hours + private static final String TANIUM_EXECUTOR_TYPE = "openbas_tanium"; + private static final String TANIUM_EXECUTOR_NAME = "Tanium"; + + private final TaniumExecutorClient client; + + private final EndpointService endpointService; + + private final TaniumExecutorContextService taniumExecutorContextService; + + private final InjectorService injectorService; + + private Executor executor = null; + + public static Endpoint.PLATFORM_TYPE toPlatform(@NotBlank final String platform) { + return switch (platform) { + case "Linux" -> Endpoint.PLATFORM_TYPE.Linux; + case "Windows" -> Endpoint.PLATFORM_TYPE.Windows; + case "MacOS" -> Endpoint.PLATFORM_TYPE.MacOS; + default -> Endpoint.PLATFORM_TYPE.Unknown; + }; + } + + public static Endpoint.PLATFORM_ARCH toArch(@NotBlank final String arch) { + return switch (arch) { + case "x64-based PC", "x86_64" -> Endpoint.PLATFORM_ARCH.x86_64; + case "arm64-based PC", "arm64" -> Endpoint.PLATFORM_ARCH.arm64; + default -> Endpoint.PLATFORM_ARCH.Unknown; + }; + } + + @Autowired + public TaniumExecutorService( + ExecutorService executorService, + TaniumExecutorClient client, + TaniumExecutorConfig config, + TaniumExecutorContextService taniumExecutorContextService, + EndpointService endpointService, + InjectorService injectorService) { + this.client = client; + this.endpointService = endpointService; + this.taniumExecutorContextService = taniumExecutorContextService; + this.injectorService = injectorService; + try { + if (config.isEnable()) { + this.executor = + executorService.register( + config.getId(), + TANIUM_EXECUTOR_TYPE, + TANIUM_EXECUTOR_NAME, + getClass().getResourceAsStream("/img/icon-tanium.png"), + new String[] { + Endpoint.PLATFORM_TYPE.Windows.name(), + Endpoint.PLATFORM_TYPE.Linux.name(), + Endpoint.PLATFORM_TYPE.MacOS.name() + }); + } else { + executorService.remove(config.getId()); + } + } catch (Exception e) { + log.log(Level.SEVERE, "Error creating Tanium executor: " + e); } - - @Override - public void run() { - log.info("Running Tanium executor endpoints gathering..."); - List nodeEndpoints = this.client.endpoints().getData().getEndpoints().getEdges().stream().toList(); - List endpoints = toEndpoint(nodeEndpoints).stream().filter(Asset::getActive).toList(); - log.info("Tanium executor provisioning based on " + endpoints.size() + " assets"); - endpoints.forEach(endpoint -> { - List existingEndpoints = this.endpointService.findAssetsForInjectionByHostname(endpoint.getHostname()).stream().filter(endpoint1 -> Arrays.stream(endpoint1.getIps()).anyMatch(s -> Arrays.stream(endpoint.getIps()).toList().contains(s))).toList(); - if (existingEndpoints.isEmpty()) { - Optional endpointByExternalReference = endpointService.findByExternalReference(endpoint.getExternalReference()); - if (endpointByExternalReference.isPresent()) { - this.updateEndpoint(endpoint, List.of(endpointByExternalReference.get())); - } else { - this.endpointService.createEndpoint(endpoint); - } + } + + @Override + public void run() { + log.info("Running Tanium executor endpoints gathering..."); + List nodeEndpoints = + this.client.endpoints().getData().getEndpoints().getEdges().stream().toList(); + List endpoints = toEndpoint(nodeEndpoints).stream().filter(Asset::getActive).toList(); + log.info("Tanium executor provisioning based on " + endpoints.size() + " assets"); + endpoints.forEach( + endpoint -> { + List existingEndpoints = + this.endpointService.findAssetsForInjectionByHostname(endpoint.getHostname()).stream() + .filter( + endpoint1 -> + Arrays.stream(endpoint1.getIps()) + .anyMatch(s -> Arrays.stream(endpoint.getIps()).toList().contains(s))) + .toList(); + if (existingEndpoints.isEmpty()) { + Optional endpointByExternalReference = + endpointService.findByExternalReference(endpoint.getExternalReference()); + if (endpointByExternalReference.isPresent()) { + this.updateEndpoint(endpoint, List.of(endpointByExternalReference.get())); } else { - this.updateEndpoint(endpoint, existingEndpoints); + this.endpointService.createEndpoint(endpoint); } + } else { + this.updateEndpoint(endpoint, existingEndpoints); + } }); - List inactiveEndpoints = toEndpoint(nodeEndpoints).stream().filter(endpoint -> !endpoint.getActive()).toList(); - inactiveEndpoints.forEach(endpoint -> { - Optional optionalExistingEndpoint = this.endpointService.findByExternalReference(endpoint.getExternalReference()); - if (optionalExistingEndpoint.isPresent()) { - Endpoint existingEndpoint = optionalExistingEndpoint.get(); - if ((now().toEpochMilli() - existingEndpoint.getClearedAt().toEpochMilli()) > DELETE_TTL) { - log.info("Found stale endpoint " + existingEndpoint.getName() + ", deleting it..."); - this.endpointService.deleteEndpoint(existingEndpoint.getId()); - } + List inactiveEndpoints = + toEndpoint(nodeEndpoints).stream().filter(endpoint -> !endpoint.getActive()).toList(); + inactiveEndpoints.forEach( + endpoint -> { + Optional optionalExistingEndpoint = + this.endpointService.findByExternalReference(endpoint.getExternalReference()); + if (optionalExistingEndpoint.isPresent()) { + Endpoint existingEndpoint = optionalExistingEndpoint.get(); + if ((now().toEpochMilli() - existingEndpoint.getClearedAt().toEpochMilli()) + > DELETE_TTL) { + log.info("Found stale endpoint " + existingEndpoint.getName() + ", deleting it..."); + this.endpointService.deleteEndpoint(existingEndpoint.getId()); } + } }); + } + + // -- PRIVATE -- + + private List toEndpoint(@NotNull final List nodeEndpoints) { + return nodeEndpoints.stream() + .map( + (nodeEndpoint) -> { + TaniumEndpoint taniumEndpoint = nodeEndpoint.getNode(); + Endpoint endpoint = new Endpoint(); + endpoint.setExecutor(this.executor); + endpoint.setExternalReference(taniumEndpoint.getId()); + endpoint.setName(taniumEndpoint.getName()); + endpoint.setDescription("Asset collected by Tanium executor context."); + endpoint.setIps(taniumEndpoint.getIpAddresses()); + endpoint.setHostname(taniumEndpoint.getName()); + endpoint.setPlatform(toPlatform(taniumEndpoint.getOs().getPlatform())); + endpoint.setArch(toArch(taniumEndpoint.getProcessor().getArchitecture())); + endpoint.setLastSeen(toInstant(taniumEndpoint.getEidLastSeen())); + return endpoint; + }) + .toList(); + } + + private void updateEndpoint( + @NotNull final Endpoint external, @NotNull final List existingList) { + Endpoint matchingExistingEndpoint = existingList.getFirst(); + matchingExistingEndpoint.setLastSeen(external.getLastSeen()); + matchingExistingEndpoint.setName(external.getName()); + matchingExistingEndpoint.setIps(external.getIps()); + matchingExistingEndpoint.setHostname(external.getHostname()); + matchingExistingEndpoint.setExternalReference(external.getExternalReference()); + matchingExistingEndpoint.setPlatform(external.getPlatform()); + matchingExistingEndpoint.setArch(external.getArch()); + matchingExistingEndpoint.setExecutor(this.executor); + if ((now().toEpochMilli() - matchingExistingEndpoint.getClearedAt().toEpochMilli()) + > CLEAR_TTL) { + try { + log.info("Clearing endpoint " + matchingExistingEndpoint.getHostname()); + Iterable injectors = injectorService.injectors(); + injectors.forEach( + injector -> { + if (injector.getExecutorClearCommands() != null) { + this.taniumExecutorContextService.launchExecutorClear( + injector, matchingExistingEndpoint); + } + }); + matchingExistingEndpoint.setClearedAt(now()); + } catch (RuntimeException e) { + log.info("Failed clear agents"); + } } - - // -- PRIVATE -- - - private List toEndpoint(@NotNull final List nodeEndpoints) { - return nodeEndpoints.stream() - .map((nodeEndpoint) -> { - TaniumEndpoint taniumEndpoint = nodeEndpoint.getNode(); - Endpoint endpoint = new Endpoint(); - endpoint.setExecutor(this.executor); - endpoint.setExternalReference(taniumEndpoint.getId()); - endpoint.setName(taniumEndpoint.getName()); - endpoint.setDescription("Asset collected by Tanium executor context."); - endpoint.setIps(taniumEndpoint.getIpAddresses()); - endpoint.setHostname(taniumEndpoint.getName()); - endpoint.setPlatform(toPlatform(taniumEndpoint.getOs().getPlatform())); - endpoint.setArch(toArch(taniumEndpoint.getProcessor().getArchitecture())); - endpoint.setLastSeen(toInstant(taniumEndpoint.getEidLastSeen())); - return endpoint; - }) - .toList(); - } - - private void updateEndpoint(@NotNull final Endpoint external, @NotNull final List existingList) { - Endpoint matchingExistingEndpoint = existingList.getFirst(); - matchingExistingEndpoint.setLastSeen(external.getLastSeen()); - matchingExistingEndpoint.setName(external.getName()); - matchingExistingEndpoint.setIps(external.getIps()); - matchingExistingEndpoint.setHostname(external.getHostname()); - matchingExistingEndpoint.setExternalReference(external.getExternalReference()); - matchingExistingEndpoint.setPlatform(external.getPlatform()); - matchingExistingEndpoint.setArch(external.getArch()); - matchingExistingEndpoint.setExecutor(this.executor); - if ((now().toEpochMilli() - matchingExistingEndpoint.getClearedAt().toEpochMilli()) > CLEAR_TTL) { - try { - log.info("Clearing endpoint " + matchingExistingEndpoint.getHostname()); - Iterable injectors = injectorService.injectors(); - injectors.forEach(injector -> { - if (injector.getExecutorClearCommands() != null) { - this.taniumExecutorContextService.launchExecutorClear(injector, matchingExistingEndpoint); - } - }); - matchingExistingEndpoint.setClearedAt(now()); - } catch (RuntimeException e) { - log.info("Failed clear agents"); - } - } - this.endpointService.updateEndpoint(matchingExistingEndpoint); - } - - private Instant toInstant(@NotNull final String lastSeen) { - String pattern = "yyyy-MM-dd'T'HH:mm:ss'Z'"; - DateTimeFormatter dateTimeFormatter = DateTimeFormatter.ofPattern(pattern, Locale.getDefault()); - LocalDateTime localDateTime = LocalDateTime.parse(lastSeen, dateTimeFormatter); - ZonedDateTime zonedDateTime = localDateTime.atZone(UTC); - return zonedDateTime.toInstant(); - } + this.endpointService.updateEndpoint(matchingExistingEndpoint); + } + + private Instant toInstant(@NotNull final String lastSeen) { + String pattern = "yyyy-MM-dd'T'HH:mm:ss'Z'"; + DateTimeFormatter dateTimeFormatter = DateTimeFormatter.ofPattern(pattern, Locale.getDefault()); + LocalDateTime localDateTime = LocalDateTime.parse(lastSeen, dateTimeFormatter); + ZonedDateTime zonedDateTime = localDateTime.atZone(UTC); + return zonedDateTime.toInstant(); + } } diff --git a/openbas-framework/src/main/java/io/openbas/expectation/ExpectationBuilderService.java b/openbas-framework/src/main/java/io/openbas/expectation/ExpectationBuilderService.java index 4e929ba70b..6319582e5d 100644 --- a/openbas-framework/src/main/java/io/openbas/expectation/ExpectationBuilderService.java +++ b/openbas-framework/src/main/java/io/openbas/expectation/ExpectationBuilderService.java @@ -1,11 +1,11 @@ package io.openbas.expectation; +import static io.openbas.database.model.InjectExpectation.EXPECTATION_TYPE.*; + import io.openbas.model.inject.form.Expectation; import lombok.RequiredArgsConstructor; import org.springframework.stereotype.Service; -import static io.openbas.database.model.InjectExpectation.EXPECTATION_TYPE.*; - @RequiredArgsConstructor @Service public class ExpectationBuilderService { @@ -20,7 +20,8 @@ public Expectation buildPreventionExpectation() { preventionExpectation.setType(PREVENTION); preventionExpectation.setName("Expect inject to be prevented"); preventionExpectation.setScore(DEFAULT_TECHNICAL_EXPECTATION_SCORE); - preventionExpectation.setExpirationTime(this.expectationPropertiesConfig.getPreventionExpirationTime()); + preventionExpectation.setExpirationTime( + this.expectationPropertiesConfig.getPreventionExpirationTime()); return preventionExpectation; } @@ -29,7 +30,8 @@ public Expectation buildDetectionExpectation() { detectionExpectation.setType(DETECTION); detectionExpectation.setName("Expect inject to be detected"); detectionExpectation.setScore(DEFAULT_TECHNICAL_EXPECTATION_SCORE); - detectionExpectation.setExpirationTime(this.expectationPropertiesConfig.getDetectionExpirationTime()); + detectionExpectation.setExpirationTime( + this.expectationPropertiesConfig.getDetectionExpirationTime()); return detectionExpectation; } @@ -38,7 +40,8 @@ public Expectation buildChallengeExpectation() { challengeExpectation.setType(CHALLENGE); challengeExpectation.setName("Expect targets to complete the challenge(s)"); challengeExpectation.setScore(DEFAULT_HUMAN_EXPECTATION_SCORE); - challengeExpectation.setExpirationTime(this.expectationPropertiesConfig.getChallengeExpirationTime()); + challengeExpectation.setExpirationTime( + this.expectationPropertiesConfig.getChallengeExpirationTime()); return challengeExpectation; } @@ -47,8 +50,8 @@ public Expectation buildArticleExpectation() { articleExpectation.setType(ARTICLE); articleExpectation.setName("Expect targets to read the article(s)"); articleExpectation.setScore(DEFAULT_HUMAN_EXPECTATION_SCORE); - articleExpectation.setExpirationTime(this.expectationPropertiesConfig.getArticleExpirationTime()); + articleExpectation.setExpirationTime( + this.expectationPropertiesConfig.getArticleExpirationTime()); return articleExpectation; } - } diff --git a/openbas-framework/src/main/java/io/openbas/expectation/ExpectationPropertiesConfig.java b/openbas-framework/src/main/java/io/openbas/expectation/ExpectationPropertiesConfig.java index f48eecbc38..abb778a505 100644 --- a/openbas-framework/src/main/java/io/openbas/expectation/ExpectationPropertiesConfig.java +++ b/openbas-framework/src/main/java/io/openbas/expectation/ExpectationPropertiesConfig.java @@ -1,11 +1,11 @@ package io.openbas.expectation; +import static java.util.Optional.ofNullable; + import lombok.Setter; import org.springframework.beans.factory.annotation.Value; import org.springframework.stereotype.Component; -import static java.util.Optional.ofNullable; - @Component @Setter public class ExpectationPropertiesConfig { @@ -16,19 +16,25 @@ public class ExpectationPropertiesConfig { @Value("${openbas.expectation.technical.expiration-time:#{null}}") private Long technicalExpirationTime; + @Value("${openbas.expectation.detection.expiration-time:#{null}}") private Long detectionExpirationTime; + @Value("${openbas.expectation.prevention.expiration-time:#{null}}") private Long preventionExpirationTime; @Value("${openbas.expectation.human.expiration-time:#{null}}") private Long humanExpirationTime; + @Value("${openbas.expectation.challenge.expiration-time:#{null}}") private Long challengeExpirationTime; + @Value("${openbas.expectation.article.expiration-time:#{null}}") private Long articleExpirationTime; + @Value("${openbas.expectation.manual.expiration-time:#{null}}") private Long manualExpirationTime; + @Value("${openbas.expectation.manual.default-score-value:#{null}}") private Integer defaultManualExpectationScore; @@ -36,45 +42,35 @@ public long getDetectionExpirationTime() { return ofNullable(this.detectionExpirationTime) .orElse( ofNullable(this.technicalExpirationTime) - .orElse(DEFAULT_TECHNICAL_EXPECTATION_EXPIRATION_TIME) - ); + .orElse(DEFAULT_TECHNICAL_EXPECTATION_EXPIRATION_TIME)); } public long getPreventionExpirationTime() { return ofNullable(this.preventionExpirationTime) .orElse( ofNullable(this.technicalExpirationTime) - .orElse(DEFAULT_TECHNICAL_EXPECTATION_EXPIRATION_TIME) - ); + .orElse(DEFAULT_TECHNICAL_EXPECTATION_EXPIRATION_TIME)); } public long getChallengeExpirationTime() { return ofNullable(this.challengeExpirationTime) .orElse( - ofNullable(this.humanExpirationTime) - .orElse(DEFAULT_HUMAN_EXPECTATION_EXPIRATION_TIME) - ); + ofNullable(this.humanExpirationTime).orElse(DEFAULT_HUMAN_EXPECTATION_EXPIRATION_TIME)); } public long getArticleExpirationTime() { return ofNullable(this.articleExpirationTime) .orElse( - ofNullable(this.humanExpirationTime) - .orElse(DEFAULT_HUMAN_EXPECTATION_EXPIRATION_TIME) - ); + ofNullable(this.humanExpirationTime).orElse(DEFAULT_HUMAN_EXPECTATION_EXPIRATION_TIME)); } public long getManualExpirationTime() { return ofNullable(this.manualExpirationTime) .orElse( - ofNullable(this.humanExpirationTime) - .orElse(DEFAULT_HUMAN_EXPECTATION_EXPIRATION_TIME) - ); + ofNullable(this.humanExpirationTime).orElse(DEFAULT_HUMAN_EXPECTATION_EXPIRATION_TIME)); } public int getDefaultExpectationScoreValue() { - return ofNullable(this.defaultManualExpectationScore) - .orElse(DEFAULT_MANUAL_EXPECTATION_SCORE); + return ofNullable(this.defaultManualExpectationScore).orElse(DEFAULT_MANUAL_EXPECTATION_SCORE); } - } diff --git a/openbas-framework/src/main/java/io/openbas/helper/StreamHelper.java b/openbas-framework/src/main/java/io/openbas/helper/StreamHelper.java index d6aa6f15e9..9baefca1a5 100644 --- a/openbas-framework/src/main/java/io/openbas/helper/StreamHelper.java +++ b/openbas-framework/src/main/java/io/openbas/helper/StreamHelper.java @@ -1,5 +1,7 @@ package io.openbas.helper; +import static java.util.stream.StreamSupport.stream; + import java.util.Iterator; import java.util.List; import java.util.Set; @@ -7,29 +9,24 @@ import java.util.stream.Stream; import java.util.stream.StreamSupport; -import static java.util.stream.StreamSupport.stream; - public class StreamHelper { - private StreamHelper() { - - } + private StreamHelper() {} - public static List fromIterable(Iterable results) { - return stream(results.spliterator(), false).collect(Collectors.toList()); - } + public static List fromIterable(Iterable results) { + return stream(results.spliterator(), false).collect(Collectors.toList()); + } - public static Set iterableToSet(Iterable results) { - return StreamSupport.stream(results.spliterator(), false) - .collect(Collectors.toSet()); - } + public static Set iterableToSet(Iterable results) { + return StreamSupport.stream(results.spliterator(), false).collect(Collectors.toSet()); + } - public static Stream asStream(Iterator sourceIterator) { - return asStream(sourceIterator, false); - } + public static Stream asStream(Iterator sourceIterator) { + return asStream(sourceIterator, false); + } - public static Stream asStream(Iterator sourceIterator, boolean parallel) { - Iterable iterable = () -> sourceIterator; - return StreamSupport.stream(iterable.spliterator(), parallel); - } + public static Stream asStream(Iterator sourceIterator, boolean parallel) { + Iterable iterable = () -> sourceIterator; + return StreamSupport.stream(iterable.spliterator(), parallel); + } } diff --git a/openbas-framework/src/main/java/io/openbas/helper/SupportedLanguage.java b/openbas-framework/src/main/java/io/openbas/helper/SupportedLanguage.java index 4d932d26e0..c48cbf8ce4 100644 --- a/openbas-framework/src/main/java/io/openbas/helper/SupportedLanguage.java +++ b/openbas-framework/src/main/java/io/openbas/helper/SupportedLanguage.java @@ -1,25 +1,26 @@ package io.openbas.helper; public enum SupportedLanguage { - fr, en; + fr, + en; - @Override - public String toString() { - return name().toLowerCase(); - } + @Override + public String toString() { + return name().toLowerCase(); + } - /** - * Returns a SupportedLanguage enum constant representing the specified value. - * - * @param value the value to search for - * @return the SupportedLanguage enum constant representing the specified value. - */ - public static SupportedLanguage of(String value) { - switch (value.toLowerCase()) { - case "auto": - return en; - default: - return valueOf(value); - } + /** + * Returns a SupportedLanguage enum constant representing the specified value. + * + * @param value the value to search for + * @return the SupportedLanguage enum constant representing the specified value. + */ + public static SupportedLanguage of(String value) { + switch (value.toLowerCase()) { + case "auto": + return en; + default: + return valueOf(value); } + } } diff --git a/openbas-framework/src/main/java/io/openbas/helper/TemplateExceptionManager.java b/openbas-framework/src/main/java/io/openbas/helper/TemplateExceptionManager.java index 416e5dc8de..263fbdf7d2 100644 --- a/openbas-framework/src/main/java/io/openbas/helper/TemplateExceptionManager.java +++ b/openbas-framework/src/main/java/io/openbas/helper/TemplateExceptionManager.java @@ -3,15 +3,15 @@ import freemarker.core.Environment; import freemarker.template.TemplateException; import freemarker.template.TemplateExceptionHandler; - import java.io.IOException; public class TemplateExceptionManager implements TemplateExceptionHandler { - public void handleTemplateException(TemplateException te, Environment env, java.io.Writer out) throws TemplateException { - try { - out.write("${" + te.getBlamedExpressionString() + "}"); - } catch (IOException e) { - throw new TemplateException("Failed to print error message. Cause: " + e, env); - } + public void handleTemplateException(TemplateException te, Environment env, java.io.Writer out) + throws TemplateException { + try { + out.write("${" + te.getBlamedExpressionString() + "}"); + } catch (IOException e) { + throw new TemplateException("Failed to print error message. Cause: " + e, env); } + } } diff --git a/openbas-framework/src/main/java/io/openbas/helper/TemplateHelper.java b/openbas-framework/src/main/java/io/openbas/helper/TemplateHelper.java index f2eec4d022..e518941bbf 100644 --- a/openbas-framework/src/main/java/io/openbas/helper/TemplateHelper.java +++ b/openbas-framework/src/main/java/io/openbas/helper/TemplateHelper.java @@ -3,17 +3,17 @@ import freemarker.template.Configuration; import freemarker.template.Template; import io.openbas.execution.ExecutionContext; -import org.springframework.ui.freemarker.FreeMarkerTemplateUtils; - import java.io.StringReader; +import org.springframework.ui.freemarker.FreeMarkerTemplateUtils; public class TemplateHelper { - public static String buildContextualContent(String content, ExecutionContext context) throws Exception { - if (content == null) return ""; - Configuration cfg = new Configuration(Configuration.VERSION_2_3_31); - cfg.setTemplateExceptionHandler(new TemplateExceptionManager()); - cfg.setLogTemplateExceptions(false); - Template template = new Template("template", new StringReader(content), cfg); - return FreeMarkerTemplateUtils.processTemplateIntoString(template, context); - } + public static String buildContextualContent(String content, ExecutionContext context) + throws Exception { + if (content == null) return ""; + Configuration cfg = new Configuration(Configuration.VERSION_2_3_31); + cfg.setTemplateExceptionHandler(new TemplateExceptionManager()); + cfg.setLogTemplateExceptions(false); + Template template = new Template("template", new StringReader(content), cfg); + return FreeMarkerTemplateUtils.processTemplateIntoString(template, context); + } } diff --git a/openbas-framework/src/main/java/io/openbas/inject_expectation/InjectExpectationService.java b/openbas-framework/src/main/java/io/openbas/inject_expectation/InjectExpectationService.java index a40fe015cd..3a808e557d 100644 --- a/openbas-framework/src/main/java/io/openbas/inject_expectation/InjectExpectationService.java +++ b/openbas-framework/src/main/java/io/openbas/inject_expectation/InjectExpectationService.java @@ -1,5 +1,10 @@ package io.openbas.inject_expectation; +import static io.openbas.database.model.InjectExpectation.EXPECTATION_TYPE.*; +import static io.openbas.helper.StreamHelper.fromIterable; +import static io.openbas.inject_expectation.InjectExpectationUtils.computeResult; +import static java.time.Instant.now; + import io.openbas.asset.AssetGroupService; import io.openbas.atomic_testing.TargetType; import io.openbas.database.model.Asset; @@ -11,185 +16,189 @@ import io.openbas.database.specification.InjectExpectationSpecification; import jakarta.validation.constraints.NotBlank; import jakarta.validation.constraints.NotNull; -import lombok.RequiredArgsConstructor; -import org.springframework.data.jpa.domain.Specification; -import org.springframework.stereotype.Service; - import java.util.Collections; import java.util.List; import java.util.Optional; import java.util.stream.Stream; - -import static io.openbas.database.model.InjectExpectation.EXPECTATION_TYPE.*; -import static io.openbas.helper.StreamHelper.fromIterable; -import static io.openbas.inject_expectation.InjectExpectationUtils.computeResult; -import static java.time.Instant.now; +import lombok.RequiredArgsConstructor; +import org.springframework.data.jpa.domain.Specification; +import org.springframework.stereotype.Service; @RequiredArgsConstructor @Service public class InjectExpectationService { - private final InjectExpectationRepository injectExpectationRepository; - private final InjectRepository injectRepository; - private final AssetGroupService assetGroupService; - - // -- CRUD -- - - public Optional findInjectExpectation(@NotBlank final String injectExpectationId) { - return this.injectExpectationRepository.findById(injectExpectationId); - } - - public InjectExpectation computeExpectation( - @NotNull final InjectExpectation expectation, - @NotBlank final String sourceId, - @NotBlank final String sourceType, - @NotBlank final String sourceName, - @NotBlank final String result, - @NotBlank final Boolean success - ) { - if (success) { - computeResult(expectation, sourceId, sourceType, sourceName, result, expectation.getExpectedScore()); - expectation.setScore(expectation.getExpectedScore()); - } else if (expectation.getScore() == null) { - computeResult(expectation, sourceId, sourceType, sourceName, result, 0.0); - expectation.setScore(0.0); - } - return this.update(expectation); - } - - public void computeExpectationGroup( - @NotNull final InjectExpectation expectationAssetGroup, - @NotNull final List expectationAssets, - @NotBlank final String sourceId, - @NotBlank final String sourceType, - @NotBlank final String sourceName - ) { - boolean success; - if (expectationAssetGroup.isExpectationGroup()) { - success = expectationAssets.stream().anyMatch((e) -> e.getExpectedScore().equals(e.getScore())); - } else { - success = expectationAssets.stream().allMatch((e) -> e.getExpectedScore().equals(e.getScore())); - } - computeResult(expectationAssetGroup, sourceId, sourceType, sourceName, success ? "SUCCESS" : "FAILED", success ? expectationAssetGroup.getExpectedScore() : 0); - expectationAssetGroup.setScore(success ? expectationAssetGroup.getExpectedScore() : 0.0); - this.update(expectationAssetGroup); - } - - public InjectExpectation update(@NotNull InjectExpectation injectExpectation) { - injectExpectation.setUpdatedAt(now()); - Inject inject = injectExpectation.getInject(); - inject.setUpdatedAt(now()); - this.injectRepository.save(inject); - return this.injectExpectationRepository.save(injectExpectation); + private final InjectExpectationRepository injectExpectationRepository; + private final InjectRepository injectRepository; + private final AssetGroupService assetGroupService; + + // -- CRUD -- + + public Optional findInjectExpectation( + @NotBlank final String injectExpectationId) { + return this.injectExpectationRepository.findById(injectExpectationId); + } + + public InjectExpectation computeExpectation( + @NotNull final InjectExpectation expectation, + @NotBlank final String sourceId, + @NotBlank final String sourceType, + @NotBlank final String sourceName, + @NotBlank final String result, + @NotBlank final Boolean success) { + if (success) { + computeResult( + expectation, sourceId, sourceType, sourceName, result, expectation.getExpectedScore()); + expectation.setScore(expectation.getExpectedScore()); + } else if (expectation.getScore() == null) { + computeResult(expectation, sourceId, sourceType, sourceName, result, 0.0); + expectation.setScore(0.0); } - - // -- ALL -- - - public List expectationsNotFill() { - return fromIterable(this.injectExpectationRepository.findAll()) - .stream() - .filter(e -> e.getResults().stream().toList().isEmpty()) - .toList(); - } - - public List expectationsNotFill(@NotBlank final String source) { - return fromIterable(this.injectExpectationRepository.findAll()) - .stream() - .filter(e -> e.getResults().stream().noneMatch(r -> source.equals(r.getSourceId()))) - .toList(); + return this.update(expectation); + } + + public void computeExpectationGroup( + @NotNull final InjectExpectation expectationAssetGroup, + @NotNull final List expectationAssets, + @NotBlank final String sourceId, + @NotBlank final String sourceType, + @NotBlank final String sourceName) { + boolean success; + if (expectationAssetGroup.isExpectationGroup()) { + success = + expectationAssets.stream().anyMatch((e) -> e.getExpectedScore().equals(e.getScore())); + } else { + success = + expectationAssets.stream().allMatch((e) -> e.getExpectedScore().equals(e.getScore())); } - - - // -- PREVENTION -- - - public List preventionExpectationsNotFill(@NotBlank final String source) { - return this.injectExpectationRepository.findAll( - Specification.where(InjectExpectationSpecification.type(PREVENTION)) - ) - .stream() - .filter(e -> e.getAsset() != null) - .filter(e -> e.getResults().stream().noneMatch(r -> source.equals(r.getSourceId()))) - .toList(); + computeResult( + expectationAssetGroup, + sourceId, + sourceType, + sourceName, + success ? "SUCCESS" : "FAILED", + success ? expectationAssetGroup.getExpectedScore() : 0); + expectationAssetGroup.setScore(success ? expectationAssetGroup.getExpectedScore() : 0.0); + this.update(expectationAssetGroup); + } + + public InjectExpectation update(@NotNull InjectExpectation injectExpectation) { + injectExpectation.setUpdatedAt(now()); + Inject inject = injectExpectation.getInject(); + inject.setUpdatedAt(now()); + this.injectRepository.save(inject); + return this.injectExpectationRepository.save(injectExpectation); + } + + // -- ALL -- + + public List expectationsNotFill() { + return fromIterable(this.injectExpectationRepository.findAll()).stream() + .filter(e -> e.getResults().stream().toList().isEmpty()) + .toList(); + } + + public List expectationsNotFill(@NotBlank final String source) { + return fromIterable(this.injectExpectationRepository.findAll()).stream() + .filter(e -> e.getResults().stream().noneMatch(r -> source.equals(r.getSourceId()))) + .toList(); + } + + // -- PREVENTION -- + + public List preventionExpectationsNotFill(@NotBlank final String source) { + return this.injectExpectationRepository + .findAll(Specification.where(InjectExpectationSpecification.type(PREVENTION))) + .stream() + .filter(e -> e.getAsset() != null) + .filter(e -> e.getResults().stream().noneMatch(r -> source.equals(r.getSourceId()))) + .toList(); + } + + public List preventionExpectationsNotFill() { + return this.injectExpectationRepository + .findAll(Specification.where(InjectExpectationSpecification.type(PREVENTION))) + .stream() + .filter(e -> e.getAsset() != null) + .filter(e -> e.getResults().stream().toList().isEmpty()) + .toList(); + } + + // -- DETECTION -- + + public List expectationsForAssets( + @NotNull final Inject inject, + @NotNull final AssetGroup assetGroup, + @NotNull final InjectExpectation.EXPECTATION_TYPE expectationType) { + AssetGroup resolvedAssetGroup = assetGroupService.assetGroup(assetGroup.getId()); + List assetIds = + Stream.concat( + resolvedAssetGroup.getAssets().stream(), + resolvedAssetGroup.getDynamicAssets().stream()) + .map(Asset::getId) + .distinct() + .toList(); + return this.injectExpectationRepository.findAll( + Specification.where(InjectExpectationSpecification.type(expectationType)) + .and(InjectExpectationSpecification.fromAssets(inject.getId(), assetIds))); + } + + public List detectionExpectationsNotFill(@NotBlank final String source) { + return this.injectExpectationRepository + .findAll(Specification.where(InjectExpectationSpecification.type(DETECTION))) + .stream() + .filter(e -> e.getAsset() != null) + .filter(e -> e.getResults().stream().noneMatch(r -> source.equals(r.getSourceId()))) + .toList(); + } + + public List detectionExpectationsNotFill() { + return this.injectExpectationRepository + .findAll(Specification.where(InjectExpectationSpecification.type(DETECTION))) + .stream() + .filter(e -> e.getAsset() != null) + .filter(e -> e.getResults().stream().toList().isEmpty()) + .toList(); + } + + // -- MANUAL + + public List manualExpectationsNotFill(@NotBlank final String source) { + return this.injectExpectationRepository + .findAll(Specification.where(InjectExpectationSpecification.type(MANUAL))) + .stream() + .filter(e -> e.getResults().stream().noneMatch(r -> source.equals(r.getSourceId()))) + .toList(); + } + + public List manualExpectationsNotFill() { + return this.injectExpectationRepository + .findAll(Specification.where(InjectExpectationSpecification.type(MANUAL))) + .stream() + .filter(e -> e.getResults().stream().toList().isEmpty()) + .toList(); + } + + // -- BY TARGET TYPE + + public List findExpectationsByInjectAndTargetAndTargetType( + @NotBlank final String injectId, + @NotBlank final String targetId, + @NotBlank final String parentTargetId, + @NotBlank final String targetType) { + try { + TargetType targetTypeEnum = TargetType.valueOf(targetType); + return switch (targetTypeEnum) { + case TEAMS -> injectExpectationRepository.findAllByInjectAndTeam(injectId, targetId); + case PLAYER -> + injectExpectationRepository.findAllByInjectAndTeamAndPlayer( + injectId, parentTargetId, targetId); + case ASSETS -> injectExpectationRepository.findAllByInjectAndAsset(injectId, targetId); + case ASSETS_GROUPS -> + injectExpectationRepository.findAllByInjectAndAssetGroup(injectId, targetId); + }; + } catch (IllegalArgumentException e) { + return Collections.emptyList(); } - - public List preventionExpectationsNotFill() { - return this.injectExpectationRepository.findAll( - Specification.where(InjectExpectationSpecification.type(PREVENTION)) - ) - .stream() - .filter(e -> e.getAsset() != null) - .filter(e -> e.getResults().stream().toList().isEmpty()) - .toList(); - } - - // -- DETECTION -- - - public List expectationsForAssets( - @NotNull final Inject inject, - @NotNull final AssetGroup assetGroup, - @NotNull final InjectExpectation.EXPECTATION_TYPE expectationType) { - AssetGroup resolvedAssetGroup = assetGroupService.assetGroup(assetGroup.getId()); - List assetIds = Stream.concat(resolvedAssetGroup.getAssets().stream(), resolvedAssetGroup.getDynamicAssets().stream()).map(Asset::getId).distinct().toList(); - return this.injectExpectationRepository.findAll(Specification.where(InjectExpectationSpecification.type(expectationType)).and(InjectExpectationSpecification.fromAssets(inject.getId(), assetIds))); - } - - public List detectionExpectationsNotFill(@NotBlank final String source) { - return this.injectExpectationRepository - .findAll(Specification.where(InjectExpectationSpecification.type(DETECTION))) - .stream() - .filter(e -> e.getAsset() != null) - .filter(e -> e.getResults().stream().noneMatch(r -> source.equals(r.getSourceId()))) - .toList(); - } - - public List detectionExpectationsNotFill() { - return this.injectExpectationRepository.findAll( - Specification.where(InjectExpectationSpecification.type(DETECTION)) - ) - .stream() - .filter(e -> e.getAsset() != null) - .filter(e -> e.getResults().stream().toList().isEmpty()) - .toList(); - } - - // -- MANUAL - - public List manualExpectationsNotFill(@NotBlank final String source) { - return this.injectExpectationRepository - .findAll(Specification.where(InjectExpectationSpecification.type(MANUAL))) - .stream() - .filter(e -> e.getResults().stream().noneMatch(r -> source.equals(r.getSourceId()))) - .toList(); - } - - public List manualExpectationsNotFill() { - return this.injectExpectationRepository.findAll( - Specification.where(InjectExpectationSpecification.type(MANUAL)) - ) - .stream() - .filter(e -> e.getResults().stream().toList().isEmpty()) - .toList(); - } - - // -- BY TARGET TYPE - - public List findExpectationsByInjectAndTargetAndTargetType( - @NotBlank final String injectId, - @NotBlank final String targetId, - @NotBlank final String parentTargetId, - @NotBlank final String targetType) { - try { - TargetType targetTypeEnum = TargetType.valueOf(targetType); - return switch (targetTypeEnum) { - case TEAMS -> injectExpectationRepository.findAllByInjectAndTeam(injectId, targetId); - case PLAYER -> injectExpectationRepository.findAllByInjectAndTeamAndPlayer(injectId, parentTargetId, targetId); - case ASSETS -> injectExpectationRepository.findAllByInjectAndAsset(injectId, targetId); - case ASSETS_GROUPS -> injectExpectationRepository.findAllByInjectAndAssetGroup(injectId, targetId); - }; - } catch (IllegalArgumentException e) { - return Collections.emptyList(); - } - - } - + } } diff --git a/openbas-framework/src/main/java/io/openbas/inject_expectation/InjectExpectationUtils.java b/openbas-framework/src/main/java/io/openbas/inject_expectation/InjectExpectationUtils.java index 4b56ddc389..eaa97252d2 100644 --- a/openbas-framework/src/main/java/io/openbas/inject_expectation/InjectExpectationUtils.java +++ b/openbas-framework/src/main/java/io/openbas/inject_expectation/InjectExpectationUtils.java @@ -1,60 +1,52 @@ package io.openbas.inject_expectation; +import static io.openbas.database.model.InjectStatusExecution.EXECUTION_TYPE_COMMAND; + import io.openbas.database.model.InjectExpectation; import io.openbas.database.model.InjectExpectationResult; import io.openbas.database.model.InjectStatusExecution; import jakarta.validation.constraints.NotBlank; import jakarta.validation.constraints.NotNull; - import java.time.Instant; import java.util.List; import java.util.Optional; -import static io.openbas.database.model.InjectStatusExecution.EXECUTION_TYPE_COMMAND; - public class InjectExpectationUtils { - public static List resultsBySourceId( - @NotNull final InjectExpectation expectation, - @NotBlank final String sourceId) { - return expectation.getResults() - .stream() - .filter(e -> sourceId.equals(e.getSourceId())) - .toList(); - } + public static List resultsBySourceId( + @NotNull final InjectExpectation expectation, @NotBlank final String sourceId) { + return expectation.getResults().stream().filter(e -> sourceId.equals(e.getSourceId())).toList(); + } - public static void computeResult( - @NotNull final InjectExpectation expectation, - @NotBlank final String sourceId, - @NotBlank final String sourceType, - @NotBlank final String sourceName, - @NotBlank final String result, - @NotBlank final Double score - ) { - Optional exists = expectation.getResults() - .stream() - .filter(r -> sourceId.equals(r.getSourceId())) - .findAny(); - if (exists.isPresent()) { - exists.get().setResult(result); - } else { - InjectExpectationResult expectationResult = InjectExpectationResult.builder() - .sourceId(sourceId) - .sourceType(sourceType) - .sourceName(sourceName) - .result(result) - .date(Instant.now().toString()) - .score(score) - .build(); - expectation.getResults().add(expectationResult); - } + public static void computeResult( + @NotNull final InjectExpectation expectation, + @NotBlank final String sourceId, + @NotBlank final String sourceType, + @NotBlank final String sourceName, + @NotBlank final String result, + @NotBlank final Double score) { + Optional exists = + expectation.getResults().stream().filter(r -> sourceId.equals(r.getSourceId())).findAny(); + if (exists.isPresent()) { + exists.get().setResult(result); + } else { + InjectExpectationResult expectationResult = + InjectExpectationResult.builder() + .sourceId(sourceId) + .sourceType(sourceType) + .sourceName(sourceName) + .result(result) + .date(Instant.now().toString()) + .score(score) + .build(); + expectation.getResults().add(expectationResult); } + } - public static Optional getCommandLine(@NotNull final InjectExpectation expectation) { - return expectation.getInject() - .getStatus().orElseThrow().getTraces().stream() - .filter(trace -> trace.getCategory().equals(EXECUTION_TYPE_COMMAND)) - .findFirst() - .map(InjectStatusExecution::getMessage); - } + public static Optional getCommandLine(@NotNull final InjectExpectation expectation) { + return expectation.getInject().getStatus().orElseThrow().getTraces().stream() + .filter(trace -> trace.getCategory().equals(EXECUTION_TYPE_COMMAND)) + .findFirst() + .map(InjectStatusExecution::getMessage); + } } diff --git a/openbas-framework/src/main/java/io/openbas/injector_contract/Contract.java b/openbas-framework/src/main/java/io/openbas/injector_contract/Contract.java index 4526308a5c..4919b7518a 100644 --- a/openbas-framework/src/main/java/io/openbas/injector_contract/Contract.java +++ b/openbas-framework/src/main/java/io/openbas/injector_contract/Contract.java @@ -8,119 +8,123 @@ import jakarta.validation.constraints.NotBlank; import jakarta.validation.constraints.NotEmpty; import jakarta.validation.constraints.NotNull; -import lombok.Getter; -import lombok.Setter; - import java.util.ArrayList; import java.util.HashMap; import java.util.List; import java.util.Map; +import lombok.Getter; +import lombok.Setter; @Getter public class Contract { - @NotNull - private final ContractConfig config; - - @NotBlank - @Setter - @JsonProperty("contract_id") - private String id; - - @NotEmpty - @Setter - private Map label; - - @NotNull - private final boolean manual; - - @NotEmpty - @Setter - private List fields; - - @NotEmpty - private final List variables = new ArrayList<>(); - - @NotNull - private final Map context = new HashMap<>(); - - @NotEmpty - @Setter - @JsonProperty("contract_attack_patterns_external_ids") - private List attackPatternsExternalIds = new ArrayList<>(); - - @Setter - @JsonProperty("is_atomic_testing") - private boolean isAtomicTesting = true; - - @Setter - @JsonProperty("needs_executor") - private boolean needsExecutor = false; - - @Setter - @JsonProperty("platforms") - private List platforms = new ArrayList<>(); - - private Contract( - @NotNull final ContractConfig config, - @NotBlank final String id, - @NotEmpty final Map label, - final boolean manual, - @NotEmpty final List fields, - final List platforms, - final boolean needsExecutor - ) { - this.config = config; - this.id = id; - this.label = label; - this.manual = manual; - this.fields = fields; - this.needsExecutor = needsExecutor; - this.platforms = platforms; - - // Default variables linked to ExecutionContext - // User variables - this.variables.add(VariableHelper.userVariable); - // Exercise variables - this.variables.add(VariableHelper.exerciceVariable); - // Teams - this.variables.add(VariableHelper.teamVariable); - // Direct uris - this.variables.addAll(VariableHelper.uriVariables); - } - - public static Contract manualContract( - @NotNull final ContractConfig config, - @NotBlank final String id, - @NotEmpty final Map label, - @NotEmpty final List fields, - final List platforms, - final boolean needsExecutor) { - Contract contract = new Contract(config, id, label, true, fields, platforms == null ? List.of(PLATFORM_TYPE.Generic) : platforms, needsExecutor); - contract.setAtomicTesting(false); - return contract; - } - - public static Contract executableContract( - @NotNull final ContractConfig config, - @NotBlank final String id, - @NotEmpty final Map label, - @NotEmpty final List fields, - final List platforms, - final boolean needsExecutor - ) { - return new Contract(config, id, label, false, fields, platforms == null ? List.of(PLATFORM_TYPE.Generic) : platforms, needsExecutor); - } - - public void addContext(String key, String value) { - this.context.put(key, value); - } - - public void addVariable(ContractVariable variable) { - variables.add(0, variable); - } - - public void addAttackPattern(String id) { - attackPatternsExternalIds.add(id); - } + @NotNull private final ContractConfig config; + + @NotBlank + @Setter + @JsonProperty("contract_id") + private String id; + + @NotEmpty @Setter private Map label; + + @NotNull private final boolean manual; + + @NotEmpty @Setter private List fields; + + @NotEmpty private final List variables = new ArrayList<>(); + + @NotNull private final Map context = new HashMap<>(); + + @NotEmpty + @Setter + @JsonProperty("contract_attack_patterns_external_ids") + private List attackPatternsExternalIds = new ArrayList<>(); + + @Setter + @JsonProperty("is_atomic_testing") + private boolean isAtomicTesting = true; + + @Setter + @JsonProperty("needs_executor") + private boolean needsExecutor = false; + + @Setter + @JsonProperty("platforms") + private List platforms = new ArrayList<>(); + + private Contract( + @NotNull final ContractConfig config, + @NotBlank final String id, + @NotEmpty final Map label, + final boolean manual, + @NotEmpty final List fields, + final List platforms, + final boolean needsExecutor) { + this.config = config; + this.id = id; + this.label = label; + this.manual = manual; + this.fields = fields; + this.needsExecutor = needsExecutor; + this.platforms = platforms; + + // Default variables linked to ExecutionContext + // User variables + this.variables.add(VariableHelper.userVariable); + // Exercise variables + this.variables.add(VariableHelper.exerciceVariable); + // Teams + this.variables.add(VariableHelper.teamVariable); + // Direct uris + this.variables.addAll(VariableHelper.uriVariables); + } + + public static Contract manualContract( + @NotNull final ContractConfig config, + @NotBlank final String id, + @NotEmpty final Map label, + @NotEmpty final List fields, + final List platforms, + final boolean needsExecutor) { + Contract contract = + new Contract( + config, + id, + label, + true, + fields, + platforms == null ? List.of(PLATFORM_TYPE.Generic) : platforms, + needsExecutor); + contract.setAtomicTesting(false); + return contract; + } + + public static Contract executableContract( + @NotNull final ContractConfig config, + @NotBlank final String id, + @NotEmpty final Map label, + @NotEmpty final List fields, + final List platforms, + final boolean needsExecutor) { + return new Contract( + config, + id, + label, + false, + fields, + platforms == null ? List.of(PLATFORM_TYPE.Generic) : platforms, + needsExecutor); + } + + public void addContext(String key, String value) { + this.context.put(key, value); + } + + public void addVariable(ContractVariable variable) { + variables.add(0, variable); + } + + public void addAttackPattern(String id) { + attackPatternsExternalIds.add(id); + } } diff --git a/openbas-framework/src/main/java/io/openbas/injector_contract/ContractCardinality.java b/openbas-framework/src/main/java/io/openbas/injector_contract/ContractCardinality.java index 4ba8beabd4..97f169b911 100644 --- a/openbas-framework/src/main/java/io/openbas/injector_contract/ContractCardinality.java +++ b/openbas-framework/src/main/java/io/openbas/injector_contract/ContractCardinality.java @@ -4,8 +4,8 @@ @SuppressWarnings("PackageAccessibility") public enum ContractCardinality { - @JsonProperty("1") - One, - @JsonProperty("n") - Multiple + @JsonProperty("1") + One, + @JsonProperty("n") + Multiple } diff --git a/openbas-framework/src/main/java/io/openbas/injector_contract/ContractConfig.java b/openbas-framework/src/main/java/io/openbas/injector_contract/ContractConfig.java index 8322c223b3..444dc929e9 100644 --- a/openbas-framework/src/main/java/io/openbas/injector_contract/ContractConfig.java +++ b/openbas-framework/src/main/java/io/openbas/injector_contract/ContractConfig.java @@ -1,9 +1,8 @@ package io.openbas.injector_contract; import io.openbas.helper.SupportedLanguage; -import lombok.Getter; - import java.util.Map; +import lombok.Getter; @Getter public class ContractConfig { @@ -16,12 +15,17 @@ public class ContractConfig { private final String color_dark; private final String color_light; - public ContractConfig(String type, Map label, String color_dark, String color_light, String icon, boolean expose) { + public ContractConfig( + String type, + Map label, + String color_dark, + String color_light, + String icon, + boolean expose) { this.type = type; this.expose = expose; this.color_dark = color_dark; this.color_light = color_light; this.label = label; } - } diff --git a/openbas-framework/src/main/java/io/openbas/injector_contract/ContractDef.java b/openbas-framework/src/main/java/io/openbas/injector_contract/ContractDef.java index 8b38a4e2e7..77b9eba267 100644 --- a/openbas-framework/src/main/java/io/openbas/injector_contract/ContractDef.java +++ b/openbas-framework/src/main/java/io/openbas/injector_contract/ContractDef.java @@ -1,50 +1,49 @@ package io.openbas.injector_contract; import io.openbas.injector_contract.fields.ContractElement; - import java.util.ArrayList; import java.util.Arrays; import java.util.List; public class ContractDef { - private final List fields = new ArrayList<>(); + private final List fields = new ArrayList<>(); - private ContractDef() { - //private constructor - } + private ContractDef() { + // private constructor + } - public static ContractDef contractBuilder() { - return new ContractDef(); - } + public static ContractDef contractBuilder() { + return new ContractDef(); + } - public ContractDef addFields(List fields) { - this.fields.addAll(fields); - return this; - } + public ContractDef addFields(List fields) { + this.fields.addAll(fields); + return this; + } - public ContractDef mandatory(ContractElement element) { - this.fields.add(element); - return this; - } - - public ContractDef mandatoryGroup(ContractElement... elements) { - List keys = Arrays.stream(elements).map(ContractElement::getKey).toList(); - for (ContractElement element : elements) { - element.setMandatory(false); - element.setMandatoryGroups(keys); - this.fields.add(element); - } - return this; - } - - public ContractDef optional(ContractElement element) { - element.setMandatory(false); - this.fields.add(element); - return this; - } + public ContractDef mandatory(ContractElement element) { + this.fields.add(element); + return this; + } - public List build() { - return this.fields; + public ContractDef mandatoryGroup(ContractElement... elements) { + List keys = Arrays.stream(elements).map(ContractElement::getKey).toList(); + for (ContractElement element : elements) { + element.setMandatory(false); + element.setMandatoryGroups(keys); + this.fields.add(element); } + return this; + } + + public ContractDef optional(ContractElement element) { + element.setMandatory(false); + this.fields.add(element); + return this; + } + + public List build() { + return this.fields; + } } diff --git a/openbas-framework/src/main/java/io/openbas/injector_contract/ContractField.java b/openbas-framework/src/main/java/io/openbas/injector_contract/ContractField.java index 101aa2f651..6fbb89ffae 100644 --- a/openbas-framework/src/main/java/io/openbas/injector_contract/ContractField.java +++ b/openbas-framework/src/main/java/io/openbas/injector_contract/ContractField.java @@ -2,61 +2,66 @@ public class ContractField { - private String name; + private String name; - private ContractType type; + private ContractType type; - private boolean mandatory; + private boolean mandatory; - private boolean readOnly; + private boolean readOnly; - private ContractCardinality cardinality; + private ContractCardinality cardinality; - ContractField(String name, ContractType type, ContractCardinality cardinality, Boolean mandatory, Boolean readOnly) { - this.name = name; - this.type = type; - this.cardinality = cardinality; - this.mandatory = mandatory; - this.readOnly = readOnly; - } + ContractField( + String name, + ContractType type, + ContractCardinality cardinality, + Boolean mandatory, + Boolean readOnly) { + this.name = name; + this.type = type; + this.cardinality = cardinality; + this.mandatory = mandatory; + this.readOnly = readOnly; + } - public String getName() { - return name; - } + public String getName() { + return name; + } - public void setName(String name) { - this.name = name; - } + public void setName(String name) { + this.name = name; + } - public ContractType getType() { - return type; - } + public ContractType getType() { + return type; + } - public void setType(ContractType type) { - this.type = type; - } + public void setType(ContractType type) { + this.type = type; + } - public ContractCardinality getCardinality() { - return cardinality; - } + public ContractCardinality getCardinality() { + return cardinality; + } - public void setCardinality(ContractCardinality cardinality) { - this.cardinality = cardinality; - } + public void setCardinality(ContractCardinality cardinality) { + this.cardinality = cardinality; + } - public boolean isMandatory() { - return mandatory; - } + public boolean isMandatory() { + return mandatory; + } - public void setMandatory(boolean mandatory) { - this.mandatory = mandatory; - } + public void setMandatory(boolean mandatory) { + this.mandatory = mandatory; + } - public boolean isReadOnly() { - return readOnly; - } + public boolean isReadOnly() { + return readOnly; + } - public void setReadOnly(boolean readOnly) { - this.readOnly = readOnly; - } + public void setReadOnly(boolean readOnly) { + this.readOnly = readOnly; + } } diff --git a/openbas-framework/src/main/java/io/openbas/injector_contract/ContractType.java b/openbas-framework/src/main/java/io/openbas/injector_contract/ContractType.java index 4a9dc969c1..64491f5b67 100644 --- a/openbas-framework/src/main/java/io/openbas/injector_contract/ContractType.java +++ b/openbas-framework/src/main/java/io/openbas/injector_contract/ContractType.java @@ -3,34 +3,34 @@ import com.fasterxml.jackson.annotation.JsonProperty; public enum ContractType { - @JsonProperty("text") - Text, - @JsonProperty("number") - Number, - @JsonProperty("tuple") - Tuple, - @JsonProperty("checkbox") - Checkbox, - @JsonProperty("textarea") - Textarea, - @JsonProperty("select") - Select, - @JsonProperty("article") - Article, - @JsonProperty("challenge") - Challenge, - @JsonProperty("dependency-select") - DependencySelect, - @JsonProperty("attachment") - Attachment, - @JsonProperty("team") - Team, - @JsonProperty("expectation") - Expectation, - @JsonProperty("asset") - Asset, - @JsonProperty("asset-group") - AssetGroup, - @JsonProperty("payload") - Payload, + @JsonProperty("text") + Text, + @JsonProperty("number") + Number, + @JsonProperty("tuple") + Tuple, + @JsonProperty("checkbox") + Checkbox, + @JsonProperty("textarea") + Textarea, + @JsonProperty("select") + Select, + @JsonProperty("article") + Article, + @JsonProperty("challenge") + Challenge, + @JsonProperty("dependency-select") + DependencySelect, + @JsonProperty("attachment") + Attachment, + @JsonProperty("team") + Team, + @JsonProperty("expectation") + Expectation, + @JsonProperty("asset") + Asset, + @JsonProperty("asset-group") + AssetGroup, + @JsonProperty("payload") + Payload, } diff --git a/openbas-framework/src/main/java/io/openbas/injector_contract/ContractVariable.java b/openbas-framework/src/main/java/io/openbas/injector_contract/ContractVariable.java index 5ac2aab2bf..d5f954c925 100644 --- a/openbas-framework/src/main/java/io/openbas/injector_contract/ContractVariable.java +++ b/openbas-framework/src/main/java/io/openbas/injector_contract/ContractVariable.java @@ -1,26 +1,21 @@ package io.openbas.injector_contract; import io.openbas.database.model.Variable.VariableType; -import lombok.Getter; - import jakarta.validation.constraints.NotBlank; import jakarta.validation.constraints.NotNull; import java.util.List; +import lombok.Getter; @Getter public class ContractVariable { - @NotBlank - private final String key; + @NotBlank private final String key; - @NotBlank - private final String label; + @NotBlank private final String label; - @NotNull - private final VariableType type; + @NotNull private final VariableType type; - @NotNull - private final ContractCardinality cardinality; + @NotNull private final ContractCardinality cardinality; private final List children; @@ -53,5 +48,4 @@ public static ContractVariable variable( final List children) { return new ContractVariable(key, label, type, cardinality, children); } - } diff --git a/openbas-framework/src/main/java/io/openbas/injector_contract/Contractor.java b/openbas-framework/src/main/java/io/openbas/injector_contract/Contractor.java index 1fd4d9d624..01a02bd653 100644 --- a/openbas-framework/src/main/java/io/openbas/injector_contract/Contractor.java +++ b/openbas-framework/src/main/java/io/openbas/injector_contract/Contractor.java @@ -4,13 +4,13 @@ public abstract class Contractor { - public abstract boolean isExpose(); + public abstract boolean isExpose(); - public abstract String getType(); + public abstract String getType(); - public abstract ContractorIcon getIcon(); + public abstract ContractorIcon getIcon(); - public abstract ContractConfig getConfig(); + public abstract ContractConfig getConfig(); - public abstract List contracts() throws Exception; + public abstract List contracts() throws Exception; } diff --git a/openbas-framework/src/main/java/io/openbas/injector_contract/ContractorIcon.java b/openbas-framework/src/main/java/io/openbas/injector_contract/ContractorIcon.java index 21e91c5c8c..4d1ec5e58b 100644 --- a/openbas-framework/src/main/java/io/openbas/injector_contract/ContractorIcon.java +++ b/openbas-framework/src/main/java/io/openbas/injector_contract/ContractorIcon.java @@ -1,17 +1,16 @@ package io.openbas.injector_contract; +import java.io.InputStream; import lombok.Getter; import lombok.Setter; -import java.io.InputStream; - @Getter @Setter public class ContractorIcon { - private InputStream data; + private InputStream data; - public ContractorIcon(InputStream data) { - this.data = data; - } + public ContractorIcon(InputStream data) { + this.data = data; + } } diff --git a/openbas-framework/src/main/java/io/openbas/injector_contract/fields/ContractArticle.java b/openbas-framework/src/main/java/io/openbas/injector_contract/fields/ContractArticle.java index e12162ac4e..bfc120dfdc 100644 --- a/openbas-framework/src/main/java/io/openbas/injector_contract/fields/ContractArticle.java +++ b/openbas-framework/src/main/java/io/openbas/injector_contract/fields/ContractArticle.java @@ -5,16 +5,17 @@ public class ContractArticle extends ContractCardinalityElement { - public ContractArticle(String key, String label, ContractCardinality cardinality) { - super(key, label, cardinality); - } + public ContractArticle(String key, String label, ContractCardinality cardinality) { + super(key, label, cardinality); + } - public static ContractArticle articleField(String key, String label, ContractCardinality cardinality) { - return new ContractArticle(key, label, cardinality); - } + public static ContractArticle articleField( + String key, String label, ContractCardinality cardinality) { + return new ContractArticle(key, label, cardinality); + } - @Override - public ContractType getType() { - return ContractType.Article; - } + @Override + public ContractType getType() { + return ContractType.Article; + } } diff --git a/openbas-framework/src/main/java/io/openbas/injector_contract/fields/ContractAsset.java b/openbas-framework/src/main/java/io/openbas/injector_contract/fields/ContractAsset.java index 4282ab42f8..400ea3bed8 100644 --- a/openbas-framework/src/main/java/io/openbas/injector_contract/fields/ContractAsset.java +++ b/openbas-framework/src/main/java/io/openbas/injector_contract/fields/ContractAsset.java @@ -9,7 +9,8 @@ public ContractAsset(String key, String label, ContractCardinality cardinality) super(key, label, cardinality); } - public static ContractAsset assetField(String key, String label, ContractCardinality cardinality) { + public static ContractAsset assetField( + String key, String label, ContractCardinality cardinality) { return new ContractAsset(key, label, cardinality); } diff --git a/openbas-framework/src/main/java/io/openbas/injector_contract/fields/ContractAssetGroup.java b/openbas-framework/src/main/java/io/openbas/injector_contract/fields/ContractAssetGroup.java index d13b4ae1bb..42d12ea919 100644 --- a/openbas-framework/src/main/java/io/openbas/injector_contract/fields/ContractAssetGroup.java +++ b/openbas-framework/src/main/java/io/openbas/injector_contract/fields/ContractAssetGroup.java @@ -9,7 +9,8 @@ public ContractAssetGroup(String key, String label, ContractCardinality cardinal super(key, label, cardinality); } - public static ContractAssetGroup assetGroupField(String key, String label, ContractCardinality cardinality) { + public static ContractAssetGroup assetGroupField( + String key, String label, ContractCardinality cardinality) { return new ContractAssetGroup(key, label, cardinality); } diff --git a/openbas-framework/src/main/java/io/openbas/injector_contract/fields/ContractAttachment.java b/openbas-framework/src/main/java/io/openbas/injector_contract/fields/ContractAttachment.java index f9a9c5aa3a..0fb2cc2328 100644 --- a/openbas-framework/src/main/java/io/openbas/injector_contract/fields/ContractAttachment.java +++ b/openbas-framework/src/main/java/io/openbas/injector_contract/fields/ContractAttachment.java @@ -5,16 +5,17 @@ public class ContractAttachment extends ContractCardinalityElement { - public ContractAttachment(String key, String label, ContractCardinality cardinality) { - super(key, label, cardinality); - } + public ContractAttachment(String key, String label, ContractCardinality cardinality) { + super(key, label, cardinality); + } - public static ContractAttachment attachmentField(String key, String label, ContractCardinality cardinality) { - return new ContractAttachment(key, label, cardinality); - } + public static ContractAttachment attachmentField( + String key, String label, ContractCardinality cardinality) { + return new ContractAttachment(key, label, cardinality); + } - @Override - public ContractType getType() { - return ContractType.Attachment; - } + @Override + public ContractType getType() { + return ContractType.Attachment; + } } diff --git a/openbas-framework/src/main/java/io/openbas/injector_contract/fields/ContractCardinalityElement.java b/openbas-framework/src/main/java/io/openbas/injector_contract/fields/ContractCardinalityElement.java index e20ba53da6..4ea2db1309 100644 --- a/openbas-framework/src/main/java/io/openbas/injector_contract/fields/ContractCardinalityElement.java +++ b/openbas-framework/src/main/java/io/openbas/injector_contract/fields/ContractCardinalityElement.java @@ -1,23 +1,20 @@ package io.openbas.injector_contract.fields; import io.openbas.injector_contract.ContractCardinality; -import lombok.Getter; -import lombok.Setter; - import java.util.ArrayList; import java.util.List; +import lombok.Getter; +import lombok.Setter; @Getter public abstract class ContractCardinalityElement extends ContractElement { private final ContractCardinality cardinality; - @Setter - private List defaultValue = new ArrayList<>(); + @Setter private List defaultValue = new ArrayList<>(); public ContractCardinalityElement(String key, String label, ContractCardinality cardinality) { super(key, label); this.cardinality = cardinality; } - } diff --git a/openbas-framework/src/main/java/io/openbas/injector_contract/fields/ContractChallenge.java b/openbas-framework/src/main/java/io/openbas/injector_contract/fields/ContractChallenge.java index f57991f945..60a66b3ca9 100644 --- a/openbas-framework/src/main/java/io/openbas/injector_contract/fields/ContractChallenge.java +++ b/openbas-framework/src/main/java/io/openbas/injector_contract/fields/ContractChallenge.java @@ -5,16 +5,17 @@ public class ContractChallenge extends ContractCardinalityElement { - public ContractChallenge(String key, String label, ContractCardinality cardinality) { - super(key, label, cardinality); - } + public ContractChallenge(String key, String label, ContractCardinality cardinality) { + super(key, label, cardinality); + } - public static ContractChallenge challengeField(String key, String label, ContractCardinality cardinality) { - return new ContractChallenge(key, label, cardinality); - } + public static ContractChallenge challengeField( + String key, String label, ContractCardinality cardinality) { + return new ContractChallenge(key, label, cardinality); + } - @Override - public ContractType getType() { - return ContractType.Challenge; - } + @Override + public ContractType getType() { + return ContractType.Challenge; + } } diff --git a/openbas-framework/src/main/java/io/openbas/injector_contract/fields/ContractCheckbox.java b/openbas-framework/src/main/java/io/openbas/injector_contract/fields/ContractCheckbox.java index c827242ad3..91b47d9a02 100644 --- a/openbas-framework/src/main/java/io/openbas/injector_contract/fields/ContractCheckbox.java +++ b/openbas-framework/src/main/java/io/openbas/injector_contract/fields/ContractCheckbox.java @@ -1,37 +1,36 @@ package io.openbas.injector_contract.fields; import io.openbas.injector_contract.ContractType; +import java.util.List; import lombok.Getter; import lombok.Setter; -import java.util.List; - @Setter @Getter public class ContractCheckbox extends ContractElement { - private boolean defaultValue = false; - - public ContractCheckbox(String key, String label) { - super(key, label); - } - - public static ContractCheckbox checkboxField(String key, String label, boolean checked) { - ContractCheckbox contractCheckbox = new ContractCheckbox(key, label); - contractCheckbox.setDefaultValue(checked); - return contractCheckbox; - } - - public static ContractCheckbox checkboxField(String key, String label, boolean checked, List linkedFields) { - ContractCheckbox contractCheckbox = new ContractCheckbox(key, label); - contractCheckbox.setDefaultValue(checked); - contractCheckbox.setLinkedFields(linkedFields); - return contractCheckbox; - } - - @Override - public ContractType getType() { - return ContractType.Checkbox; - } - + private boolean defaultValue = false; + + public ContractCheckbox(String key, String label) { + super(key, label); + } + + public static ContractCheckbox checkboxField(String key, String label, boolean checked) { + ContractCheckbox contractCheckbox = new ContractCheckbox(key, label); + contractCheckbox.setDefaultValue(checked); + return contractCheckbox; + } + + public static ContractCheckbox checkboxField( + String key, String label, boolean checked, List linkedFields) { + ContractCheckbox contractCheckbox = new ContractCheckbox(key, label); + contractCheckbox.setDefaultValue(checked); + contractCheckbox.setLinkedFields(linkedFields); + return contractCheckbox; + } + + @Override + public ContractType getType() { + return ContractType.Checkbox; + } } diff --git a/openbas-framework/src/main/java/io/openbas/injector_contract/fields/ContractDependencySelect.java b/openbas-framework/src/main/java/io/openbas/injector_contract/fields/ContractDependencySelect.java index a4f98c0d12..b9acb6746e 100644 --- a/openbas-framework/src/main/java/io/openbas/injector_contract/fields/ContractDependencySelect.java +++ b/openbas-framework/src/main/java/io/openbas/injector_contract/fields/ContractDependencySelect.java @@ -2,39 +2,41 @@ import io.openbas.injector_contract.ContractCardinality; import io.openbas.injector_contract.ContractType; -import lombok.Getter; -import lombok.Setter; - import java.util.HashMap; import java.util.Map; +import lombok.Getter; +import lombok.Setter; @Getter public class ContractDependencySelect extends ContractCardinalityElement { - private final String dependencyField; - @Setter - private Map> choices = new HashMap<>(); - - public ContractDependencySelect(String key, String label, String dependencyField, ContractCardinality cardinality) { - super(key, label, cardinality); - this.dependencyField = dependencyField; - } - - public static ContractDependencySelect dependencySelectField(String key, String label, String dependencyField, Map> choices) { - ContractDependencySelect contractSelect = new ContractDependencySelect(key, label, dependencyField, ContractCardinality.One); - contractSelect.setChoices(choices); - return contractSelect; - } - - public static ContractDependencySelect dependencyMultiSelectField(String key, String label, String dependencyField, Map> choices) { - ContractDependencySelect contractSelect = new ContractDependencySelect(key, label, dependencyField, ContractCardinality.Multiple); - contractSelect.setChoices(choices); - return contractSelect; - } - - @Override - public ContractType getType() { - return ContractType.DependencySelect; - } - + private final String dependencyField; + @Setter private Map> choices = new HashMap<>(); + + public ContractDependencySelect( + String key, String label, String dependencyField, ContractCardinality cardinality) { + super(key, label, cardinality); + this.dependencyField = dependencyField; + } + + public static ContractDependencySelect dependencySelectField( + String key, String label, String dependencyField, Map> choices) { + ContractDependencySelect contractSelect = + new ContractDependencySelect(key, label, dependencyField, ContractCardinality.One); + contractSelect.setChoices(choices); + return contractSelect; + } + + public static ContractDependencySelect dependencyMultiSelectField( + String key, String label, String dependencyField, Map> choices) { + ContractDependencySelect contractSelect = + new ContractDependencySelect(key, label, dependencyField, ContractCardinality.Multiple); + contractSelect.setChoices(choices); + return contractSelect; + } + + @Override + public ContractType getType() { + return ContractType.DependencySelect; + } } diff --git a/openbas-framework/src/main/java/io/openbas/injector_contract/fields/ContractElement.java b/openbas-framework/src/main/java/io/openbas/injector_contract/fields/ContractElement.java index 7d309b9817..0c997f490c 100644 --- a/openbas-framework/src/main/java/io/openbas/injector_contract/fields/ContractElement.java +++ b/openbas-framework/src/main/java/io/openbas/injector_contract/fields/ContractElement.java @@ -2,38 +2,37 @@ import io.openbas.injector_contract.ContractType; import io.openbas.model.LinkedFieldModel; -import lombok.Getter; -import lombok.Setter; - import java.util.ArrayList; import java.util.List; +import lombok.Getter; +import lombok.Setter; @Getter @Setter public abstract class ContractElement { - private String key; + private String key; - private String label; + private String label; - private boolean mandatory = true; + private boolean mandatory = true; - private boolean readOnly = false; + private boolean readOnly = false; - private List mandatoryGroups; + private List mandatoryGroups; - private List linkedFields = new ArrayList<>(); + private List linkedFields = new ArrayList<>(); - private List linkedValues = new ArrayList<>(); + private List linkedValues = new ArrayList<>(); - public ContractElement(String key, String label) { - this.key = key; - this.label = label; - } + public ContractElement(String key, String label) { + this.key = key; + this.label = label; + } - public void setLinkedFields(List linkedFields) { - this.linkedFields = linkedFields.stream().map(LinkedFieldModel::fromField).toList(); - } + public void setLinkedFields(List linkedFields) { + this.linkedFields = linkedFields.stream().map(LinkedFieldModel::fromField).toList(); + } - public abstract ContractType getType(); + public abstract ContractType getType(); } diff --git a/openbas-framework/src/main/java/io/openbas/injector_contract/fields/ContractExpectations.java b/openbas-framework/src/main/java/io/openbas/injector_contract/fields/ContractExpectations.java index 4f732cd99c..0693c5abbf 100644 --- a/openbas-framework/src/main/java/io/openbas/injector_contract/fields/ContractExpectations.java +++ b/openbas-framework/src/main/java/io/openbas/injector_contract/fields/ContractExpectations.java @@ -1,15 +1,14 @@ package io.openbas.injector_contract.fields; +import static io.openbas.injector_contract.ContractCardinality.Multiple; + import io.openbas.injector_contract.ContractType; import io.openbas.model.inject.form.Expectation; import jakarta.validation.constraints.NotBlank; import jakarta.validation.constraints.NotEmpty; import jakarta.validation.constraints.NotNull; -import lombok.Getter; - import java.util.List; - -import static io.openbas.injector_contract.ContractCardinality.Multiple; +import lombok.Getter; @Getter public class ContractExpectations extends ContractCardinalityElement { @@ -25,8 +24,7 @@ private ContractExpectations( } public static ContractExpectations expectationsField( - @NotBlank final String key, - @NotBlank final String label) { + @NotBlank final String key, @NotBlank final String label) { return new ContractExpectations(key, label, List.of()); } @@ -41,5 +39,4 @@ public static ContractExpectations expectationsField( public ContractType getType() { return ContractType.Expectation; } - } diff --git a/openbas-framework/src/main/java/io/openbas/injector_contract/fields/ContractNumber.java b/openbas-framework/src/main/java/io/openbas/injector_contract/fields/ContractNumber.java index d4021f0043..32c6b89327 100644 --- a/openbas-framework/src/main/java/io/openbas/injector_contract/fields/ContractNumber.java +++ b/openbas-framework/src/main/java/io/openbas/injector_contract/fields/ContractNumber.java @@ -1,49 +1,53 @@ package io.openbas.injector_contract.fields; import io.openbas.injector_contract.ContractType; +import java.util.List; import lombok.Getter; import lombok.Setter; -import java.util.List; - @Setter @Getter public class ContractNumber extends ContractElement { - private String defaultValue = ""; - - public ContractNumber(String key, String label) { - super(key, label); - } - - public static ContractNumber textField(String key, String label) { - return new ContractNumber(key, label); - } - - public static ContractNumber numberField(String key, String label, String defaultValue) { - ContractNumber contractNumber = new ContractNumber(key, label); - contractNumber.setDefaultValue(defaultValue); - return contractNumber; - } - - public static ContractNumber numberField(String key, String label, String defaultValue, List linkedFields) { - ContractNumber contractNumber = new ContractNumber(key, label); - contractNumber.setDefaultValue(defaultValue); - contractNumber.setLinkedFields(linkedFields); - return contractNumber; - } - - public static ContractNumber numberField(String key, String label, String defaultValue, List linkedFields, List linkedValues) { - ContractNumber contractNumber = new ContractNumber(key, label); - contractNumber.setDefaultValue(defaultValue); - contractNumber.setLinkedFields(linkedFields); - contractNumber.setLinkedValues(linkedValues); - return contractNumber; - } - - @Override - public ContractType getType() { - return ContractType.Number; - } - + private String defaultValue = ""; + + public ContractNumber(String key, String label) { + super(key, label); + } + + public static ContractNumber textField(String key, String label) { + return new ContractNumber(key, label); + } + + public static ContractNumber numberField(String key, String label, String defaultValue) { + ContractNumber contractNumber = new ContractNumber(key, label); + contractNumber.setDefaultValue(defaultValue); + return contractNumber; + } + + public static ContractNumber numberField( + String key, String label, String defaultValue, List linkedFields) { + ContractNumber contractNumber = new ContractNumber(key, label); + contractNumber.setDefaultValue(defaultValue); + contractNumber.setLinkedFields(linkedFields); + return contractNumber; + } + + public static ContractNumber numberField( + String key, + String label, + String defaultValue, + List linkedFields, + List linkedValues) { + ContractNumber contractNumber = new ContractNumber(key, label); + contractNumber.setDefaultValue(defaultValue); + contractNumber.setLinkedFields(linkedFields); + contractNumber.setLinkedValues(linkedValues); + return contractNumber; + } + + @Override + public ContractType getType() { + return ContractType.Number; + } } diff --git a/openbas-framework/src/main/java/io/openbas/injector_contract/fields/ContractPayload.java b/openbas-framework/src/main/java/io/openbas/injector_contract/fields/ContractPayload.java index 731ace86bf..cdfce26969 100644 --- a/openbas-framework/src/main/java/io/openbas/injector_contract/fields/ContractPayload.java +++ b/openbas-framework/src/main/java/io/openbas/injector_contract/fields/ContractPayload.java @@ -9,7 +9,8 @@ public ContractPayload(String key, String label, ContractCardinality cardinality super(key, label, cardinality); } - public static ContractPayload payloadField(String key, String label, ContractCardinality cardinality) { + public static ContractPayload payloadField( + String key, String label, ContractCardinality cardinality) { return new ContractPayload(key, label, cardinality); } diff --git a/openbas-framework/src/main/java/io/openbas/injector_contract/fields/ContractSelect.java b/openbas-framework/src/main/java/io/openbas/injector_contract/fields/ContractSelect.java index cd91ed44c4..f6d0bf5df6 100644 --- a/openbas-framework/src/main/java/io/openbas/injector_contract/fields/ContractSelect.java +++ b/openbas-framework/src/main/java/io/openbas/injector_contract/fields/ContractSelect.java @@ -2,12 +2,11 @@ import io.openbas.injector_contract.ContractCardinality; import io.openbas.injector_contract.ContractType; -import lombok.Getter; -import lombok.Setter; - import java.util.HashMap; import java.util.List; import java.util.Map; +import lombok.Getter; +import lombok.Setter; @Setter @Getter @@ -26,17 +25,15 @@ public static ContractSelect selectField(String key, String label, Map choices, - String def) { + String key, String label, Map choices, String def) { ContractSelect contractSelect = new ContractSelect(key, label, ContractCardinality.One); contractSelect.setChoices(choices); contractSelect.setDefaultValue(List.of(def)); return contractSelect; } - public static ContractSelect multiSelectField(String key, String label, Map choices) { + public static ContractSelect multiSelectField( + String key, String label, Map choices) { ContractSelect contractSelect = new ContractSelect(key, label, ContractCardinality.Multiple); contractSelect.setChoices(choices); return contractSelect; @@ -46,5 +43,4 @@ public static ContractSelect multiSelectField(String key, String label, Map linkedFields) { - ContractText contractText = new ContractText(key, label); - contractText.setDefaultValue(defaultValue); - contractText.setLinkedFields(linkedFields); - return contractText; - } - - @Override - public ContractType getType() { - return ContractType.Text; - } - + private String defaultValue = ""; + + public ContractText(String key, String label) { + super(key, label); + } + + public static ContractText textField(String key, String label) { + return new ContractText(key, label); + } + + public static ContractText textField(String key, String label, String defaultValue) { + ContractText contractText = new ContractText(key, label); + contractText.setDefaultValue(defaultValue); + return contractText; + } + + public static ContractText textField( + String key, String label, String defaultValue, List linkedFields) { + ContractText contractText = new ContractText(key, label); + contractText.setDefaultValue(defaultValue); + contractText.setLinkedFields(linkedFields); + return contractText; + } + + @Override + public ContractType getType() { + return ContractType.Text; + } } diff --git a/openbas-framework/src/main/java/io/openbas/injector_contract/fields/ContractTextArea.java b/openbas-framework/src/main/java/io/openbas/injector_contract/fields/ContractTextArea.java index b4bea6904d..437c70b404 100644 --- a/openbas-framework/src/main/java/io/openbas/injector_contract/fields/ContractTextArea.java +++ b/openbas-framework/src/main/java/io/openbas/injector_contract/fields/ContractTextArea.java @@ -1,47 +1,45 @@ package io.openbas.injector_contract.fields; import io.openbas.injector_contract.ContractType; +import java.util.List; import lombok.Getter; import lombok.Setter; -import java.util.List; - @Getter public class ContractTextArea extends ContractElement { - @Setter - private String defaultValue = ""; - private final boolean richText; - - public ContractTextArea(String key, String label, boolean richText) { - super(key, label); - this.richText = richText; - } - - public static ContractTextArea textareaField(String key, String label) { - return new ContractTextArea(key, label, false); - } - - public static ContractTextArea richTextareaField(String key, String label) { - return new ContractTextArea(key, label, true); - } - - public static ContractTextArea richTextareaField(String key, String label, String defaultValue) { - ContractTextArea contractText = new ContractTextArea(key, label, true); - contractText.setDefaultValue(defaultValue); - return contractText; - } - - public static ContractTextArea richTextareaField(String key, String label, String defaultValue, List linkedFields) { - ContractTextArea contractText = new ContractTextArea(key, label, true); - contractText.setDefaultValue(defaultValue); - contractText.setLinkedFields(linkedFields); - return contractText; - } - - @Override - public ContractType getType() { - return ContractType.Textarea; - } - + @Setter private String defaultValue = ""; + private final boolean richText; + + public ContractTextArea(String key, String label, boolean richText) { + super(key, label); + this.richText = richText; + } + + public static ContractTextArea textareaField(String key, String label) { + return new ContractTextArea(key, label, false); + } + + public static ContractTextArea richTextareaField(String key, String label) { + return new ContractTextArea(key, label, true); + } + + public static ContractTextArea richTextareaField(String key, String label, String defaultValue) { + ContractTextArea contractText = new ContractTextArea(key, label, true); + contractText.setDefaultValue(defaultValue); + return contractText; + } + + public static ContractTextArea richTextareaField( + String key, String label, String defaultValue, List linkedFields) { + ContractTextArea contractText = new ContractTextArea(key, label, true); + contractText.setDefaultValue(defaultValue); + contractText.setLinkedFields(linkedFields); + return contractText; + } + + @Override + public ContractType getType() { + return ContractType.Textarea; + } } diff --git a/openbas-framework/src/main/java/io/openbas/injector_contract/fields/ContractTuple.java b/openbas-framework/src/main/java/io/openbas/injector_contract/fields/ContractTuple.java index dd4abafb28..6dd6defe8d 100644 --- a/openbas-framework/src/main/java/io/openbas/injector_contract/fields/ContractTuple.java +++ b/openbas-framework/src/main/java/io/openbas/injector_contract/fields/ContractTuple.java @@ -10,35 +10,36 @@ @Getter public class ContractTuple extends ContractCardinalityElement { - public static final String FILE_PREFIX = "file :: "; - - private String attachmentKey; - - public ContractTuple(String key, String label, ContractCardinality cardinality) { - super(key, label, cardinality); - } - - public static ContractTuple tupleField(String key, String label) { - return new ContractTuple(key, label, ContractCardinality.Multiple); - } - - public static ContractTuple tupleField(String key, String label, ContractAttachment attachmentContract) { - ContractTuple contractTuple = new ContractTuple(key, label, ContractCardinality.Multiple); - contractTuple.setAttachmentKey(attachmentContract.getKey()); - return contractTuple; - } - - @Override - public ContractType getType() { - return ContractType.Tuple; - } - - public Boolean isContractAttachment() { - return attachmentKey != null; - } - - @JsonProperty("tupleFilePrefix") - public String tupleFilePrefix() { - return FILE_PREFIX; - } + public static final String FILE_PREFIX = "file :: "; + + private String attachmentKey; + + public ContractTuple(String key, String label, ContractCardinality cardinality) { + super(key, label, cardinality); + } + + public static ContractTuple tupleField(String key, String label) { + return new ContractTuple(key, label, ContractCardinality.Multiple); + } + + public static ContractTuple tupleField( + String key, String label, ContractAttachment attachmentContract) { + ContractTuple contractTuple = new ContractTuple(key, label, ContractCardinality.Multiple); + contractTuple.setAttachmentKey(attachmentContract.getKey()); + return contractTuple; + } + + @Override + public ContractType getType() { + return ContractType.Tuple; + } + + public Boolean isContractAttachment() { + return attachmentKey != null; + } + + @JsonProperty("tupleFilePrefix") + public String tupleFilePrefix() { + return FILE_PREFIX; + } } diff --git a/openbas-framework/src/main/java/io/openbas/injector_contract/variables/VariableHelper.java b/openbas-framework/src/main/java/io/openbas/injector_contract/variables/VariableHelper.java index 2ad0db0190..d6e3c98561 100644 --- a/openbas-framework/src/main/java/io/openbas/injector_contract/variables/VariableHelper.java +++ b/openbas-framework/src/main/java/io/openbas/injector_contract/variables/VariableHelper.java @@ -1,14 +1,13 @@ package io.openbas.injector_contract.variables; -import io.openbas.injector_contract.ContractVariable; -import io.openbas.database.model.Variable.VariableType; - -import java.util.List; - import static io.openbas.injector_contract.ContractCardinality.Multiple; import static io.openbas.injector_contract.ContractCardinality.One; import static io.openbas.injector_contract.ContractVariable.variable; +import io.openbas.database.model.Variable.VariableType; +import io.openbas.injector_contract.ContractVariable; +import java.util.List; + public class VariableHelper { public static final String USER = "user"; @@ -20,30 +19,43 @@ public class VariableHelper { public static final String SCOREBOARD_URI = "scoreboard_uri"; public static final String LESSONS_URI = "lessons_uri"; - public static final ContractVariable userVariable = variable(USER, "User that will receive the injection", - VariableType.String, One, List.of( - variable(USER + ".id", "Id of the user in the platform", VariableType.String, One), - variable(USER + ".email", "Email of the user", VariableType.String, One), - variable(USER + ".firstname", "Firstname of the user", VariableType.String, One), - variable(USER + ".lastname", "Lastname of the user", VariableType.String, One), - variable(USER + ".lang", "Lang of the user", VariableType.String, One) - )); - - public static final ContractVariable exerciceVariable = variable(EXERCISE, "Exercise of the current injection", - VariableType.Object, One, List.of( - variable(EXERCISE + ".id", "Id of the user in the platform", VariableType.String, One), - variable(EXERCISE + ".name", "Name of the exercise", VariableType.String, One), - variable(EXERCISE + ".description", "Description of the exercise", VariableType.String, One) - )); - - public static final ContractVariable teamVariable = variable(TEAMS, "List of team name for the injection", - VariableType.String, Multiple); - - public static final List uriVariables = List.of( - variable(PLAYER_URI, "Player interface platform link", VariableType.String, One), - variable(CHALLENGES_URI, "Challenges interface platform link", VariableType.String, One), - variable(SCOREBOARD_URI, "Scoreboard interface platform link", VariableType.String, One), - variable(LESSONS_URI, "Lessons learned interface platform link", VariableType.String, One) - ); - + public static final ContractVariable userVariable = + variable( + USER, + "User that will receive the injection", + VariableType.String, + One, + List.of( + variable(USER + ".id", "Id of the user in the platform", VariableType.String, One), + variable(USER + ".email", "Email of the user", VariableType.String, One), + variable(USER + ".firstname", "Firstname of the user", VariableType.String, One), + variable(USER + ".lastname", "Lastname of the user", VariableType.String, One), + variable(USER + ".lang", "Lang of the user", VariableType.String, One))); + + public static final ContractVariable exerciceVariable = + variable( + EXERCISE, + "Exercise of the current injection", + VariableType.Object, + One, + List.of( + variable( + EXERCISE + ".id", "Id of the user in the platform", VariableType.String, One), + variable(EXERCISE + ".name", "Name of the exercise", VariableType.String, One), + variable( + EXERCISE + ".description", + "Description of the exercise", + VariableType.String, + One))); + + public static final ContractVariable teamVariable = + variable(TEAMS, "List of team name for the injection", VariableType.String, Multiple); + + public static final List uriVariables = + List.of( + variable(PLAYER_URI, "Player interface platform link", VariableType.String, One), + variable(CHALLENGES_URI, "Challenges interface platform link", VariableType.String, One), + variable(SCOREBOARD_URI, "Scoreboard interface platform link", VariableType.String, One), + variable( + LESSONS_URI, "Lessons learned interface platform link", VariableType.String, One)); } diff --git a/openbas-framework/src/main/java/io/openbas/integrations/CollectorService.java b/openbas-framework/src/main/java/io/openbas/integrations/CollectorService.java index e77265a8f6..fdc655dbe0 100644 --- a/openbas-framework/src/main/java/io/openbas/integrations/CollectorService.java +++ b/openbas-framework/src/main/java/io/openbas/integrations/CollectorService.java @@ -1,64 +1,63 @@ package io.openbas.integrations; +import static io.openbas.service.FileService.COLLECTORS_IMAGES_BASE_PATH; + import com.fasterxml.jackson.databind.ObjectMapper; import io.openbas.database.model.Collector; -import io.openbas.database.model.Injector; import io.openbas.database.repository.CollectorRepository; import io.openbas.service.FileService; import jakarta.annotation.Resource; import jakarta.transaction.Transactional; +import java.io.InputStream; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Service; -import java.io.InputStream; - -import static io.openbas.service.FileService.COLLECTORS_IMAGES_BASE_PATH; - @Service public class CollectorService { - @Resource - protected ObjectMapper mapper; + @Resource protected ObjectMapper mapper; - private FileService fileService; + private FileService fileService; - private CollectorRepository collectorRepository; + private CollectorRepository collectorRepository; - @Resource - public void setFileService(FileService fileService) { - this.fileService = fileService; - } + @Resource + public void setFileService(FileService fileService) { + this.fileService = fileService; + } - @Autowired - public void setCollectorRepository(CollectorRepository collectorRepository) { - this.collectorRepository = collectorRepository; - } + @Autowired + public void setCollectorRepository(CollectorRepository collectorRepository) { + this.collectorRepository = collectorRepository; + } - @Transactional - public void register(String id, String type, String name, InputStream iconData) throws Exception { - if (iconData != null) { - fileService.uploadStream(COLLECTORS_IMAGES_BASE_PATH, type + ".png", iconData); - } - Collector collector = collectorRepository.findById(id).orElse(null); - if( collector == null ) { - Collector collectorChecking = collectorRepository.findByType(type).orElse(null); - if (collectorChecking != null ) { - throw new Exception("The collector " + type + " already exists with a different ID, please delete it or contact your administrator."); - } - } - if (collector != null) { - collector.setName(name); - collector.setExternal(false); - collector.setType(type); - collectorRepository.save(collector); - } else { - // save the collector - Collector newCollector = new Collector(); - newCollector.setId(id); - newCollector.setName(name); - newCollector.setType(type); - collectorRepository.save(newCollector); - } + @Transactional + public void register(String id, String type, String name, InputStream iconData) throws Exception { + if (iconData != null) { + fileService.uploadStream(COLLECTORS_IMAGES_BASE_PATH, type + ".png", iconData); } - + Collector collector = collectorRepository.findById(id).orElse(null); + if (collector == null) { + Collector collectorChecking = collectorRepository.findByType(type).orElse(null); + if (collectorChecking != null) { + throw new Exception( + "The collector " + + type + + " already exists with a different ID, please delete it or contact your administrator."); + } + } + if (collector != null) { + collector.setName(name); + collector.setExternal(false); + collector.setType(type); + collectorRepository.save(collector); + } else { + // save the collector + Collector newCollector = new Collector(); + newCollector.setId(id); + newCollector.setName(name); + newCollector.setType(type); + collectorRepository.save(newCollector); + } + } } diff --git a/openbas-framework/src/main/java/io/openbas/integrations/ExecutorService.java b/openbas-framework/src/main/java/io/openbas/integrations/ExecutorService.java index 741d0cedc2..963b7fae99 100644 --- a/openbas-framework/src/main/java/io/openbas/integrations/ExecutorService.java +++ b/openbas-framework/src/main/java/io/openbas/integrations/ExecutorService.java @@ -1,73 +1,79 @@ package io.openbas.integrations; +import static io.openbas.service.FileService.EXECUTORS_IMAGES_BASE_PATH; + import com.fasterxml.jackson.databind.ObjectMapper; import io.openbas.database.model.Executor; import io.openbas.database.repository.ExecutorRepository; import io.openbas.service.FileService; import jakarta.annotation.Resource; import jakarta.transaction.Transactional; +import java.io.InputStream; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Service; -import java.io.InputStream; - -import static io.openbas.service.FileService.EXECUTORS_IMAGES_BASE_PATH; - @Service public class ExecutorService { - @Resource - protected ObjectMapper mapper; + @Resource protected ObjectMapper mapper; - private FileService fileService; + private FileService fileService; - private ExecutorRepository executorRepository; + private ExecutorRepository executorRepository; - @Resource - public void setFileService(FileService fileService) { - this.fileService = fileService; - } + @Resource + public void setFileService(FileService fileService) { + this.fileService = fileService; + } - @Autowired - public void setExecutorRepository(ExecutorRepository executorRepository) { - this.executorRepository = executorRepository; - } + @Autowired + public void setExecutorRepository(ExecutorRepository executorRepository) { + this.executorRepository = executorRepository; + } - @Transactional - public Executor register(String id, String type, String name, InputStream iconData, String[] platforms) throws Exception { - if (iconData != null) { - fileService.uploadStream(EXECUTORS_IMAGES_BASE_PATH, type + ".png", iconData); - } - Executor executor = executorRepository.findById(id).orElse(null); - if( executor == null ) { - Executor executorChecking = executorRepository.findByType(type).orElse(null); - if (executorChecking != null ) { - throw new Exception("The executor " + type + " already exists with a different ID, please delete it or contact your administrator."); - } - } - if (executor != null) { - executor.setName(name); - executor.setType(type); - executor.setPlatforms(platforms); - executorRepository.save(executor); - } else { - // save the executor - Executor newExecutor = new Executor(); - newExecutor.setId(id); - newExecutor.setName(name); - newExecutor.setType(type); - newExecutor.setPlatforms(platforms); - executorRepository.save(newExecutor); - } - return executor; + @Transactional + public Executor register( + String id, String type, String name, InputStream iconData, String[] platforms) + throws Exception { + if (iconData != null) { + fileService.uploadStream(EXECUTORS_IMAGES_BASE_PATH, type + ".png", iconData); } - - @Transactional - public void remove(String id) { - executorRepository.findById(id).ifPresent(executor -> executorRepository.deleteById(id)); + Executor executor = executorRepository.findById(id).orElse(null); + if (executor == null) { + Executor executorChecking = executorRepository.findByType(type).orElse(null); + if (executorChecking != null) { + throw new Exception( + "The executor " + + type + + " already exists with a different ID, please delete it or contact your administrator."); + } } - @Transactional - public void removeFromType(String type) { - executorRepository.findByType(type).ifPresent(executor -> executorRepository.deleteById(executor.getId())); + if (executor != null) { + executor.setName(name); + executor.setType(type); + executor.setPlatforms(platforms); + executorRepository.save(executor); + } else { + // save the executor + Executor newExecutor = new Executor(); + newExecutor.setId(id); + newExecutor.setName(name); + newExecutor.setType(type); + newExecutor.setPlatforms(platforms); + executorRepository.save(newExecutor); } + return executor; + } + + @Transactional + public void remove(String id) { + executorRepository.findById(id).ifPresent(executor -> executorRepository.deleteById(id)); + } + + @Transactional + public void removeFromType(String type) { + executorRepository + .findByType(type) + .ifPresent(executor -> executorRepository.deleteById(executor.getId())); + } } diff --git a/openbas-framework/src/main/java/io/openbas/integrations/InjectorService.java b/openbas-framework/src/main/java/io/openbas/integrations/InjectorService.java index eb426f3cf6..a8f4131009 100644 --- a/openbas-framework/src/main/java/io/openbas/integrations/InjectorService.java +++ b/openbas-framework/src/main/java/io/openbas/integrations/InjectorService.java @@ -1,5 +1,8 @@ package io.openbas.integrations; +import static io.openbas.helper.StreamHelper.fromIterable; +import static io.openbas.service.FileService.INJECTORS_IMAGES_BASE_PATH; + import com.fasterxml.jackson.core.JsonProcessingException; import com.fasterxml.jackson.databind.ObjectMapper; import io.openbas.database.model.AttackPattern; @@ -14,9 +17,6 @@ import io.openbas.service.FileService; import jakarta.annotation.Resource; import jakarta.transaction.Transactional; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.stereotype.Service; - import java.io.InputStream; import java.time.Instant; import java.util.ArrayList; @@ -24,184 +24,222 @@ import java.util.Map; import java.util.Optional; import java.util.stream.Collectors; - -import static io.openbas.helper.StreamHelper.fromIterable; -import static io.openbas.service.FileService.INJECTORS_IMAGES_BASE_PATH; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Service; @Service public class InjectorService { - @Resource - protected ObjectMapper mapper; - - private FileService fileService; - - private InjectorRepository injectorRepository; - - private InjectorContractRepository injectorContractRepository; - - private AttackPatternRepository attackPatternRepository; - - private PayloadService payloadService; - - @Resource - public void setFileService(FileService fileService) { - this.fileService = fileService; + @Resource protected ObjectMapper mapper; + + private FileService fileService; + + private InjectorRepository injectorRepository; + + private InjectorContractRepository injectorContractRepository; + + private AttackPatternRepository attackPatternRepository; + + private PayloadService payloadService; + + @Resource + public void setFileService(FileService fileService) { + this.fileService = fileService; + } + + @Autowired + public void setAttackPatternRepository(AttackPatternRepository attackPatternRepository) { + this.attackPatternRepository = attackPatternRepository; + } + + @Autowired + public void setInjectorRepository(InjectorRepository injectorRepository) { + this.injectorRepository = injectorRepository; + } + + @Autowired + public void setInjectorContractRepository(InjectorContractRepository injectorContractRepository) { + this.injectorContractRepository = injectorContractRepository; + } + + @Autowired + public void setPayloadService(PayloadService payloadService) { + this.payloadService = payloadService; + } + + @Transactional + public void register( + String id, + String name, + Contractor contractor, + Boolean isCustomizable, + String category, + Map executorCommands, + Map executorClearCommands, + Boolean isPayloads) + throws Exception { + if (!contractor.isExpose()) { + Injector injector = injectorRepository.findById(id).orElse(null); + if (injector != null) { + injectorRepository.deleteById(id); + return; + } + return; } - - @Autowired - public void setAttackPatternRepository(AttackPatternRepository attackPatternRepository) { - this.attackPatternRepository = attackPatternRepository; + if (contractor.getIcon() != null) { + InputStream iconData = contractor.getIcon().getData(); + fileService.uploadStream(INJECTORS_IMAGES_BASE_PATH, contractor.getType() + ".png", iconData); } - - @Autowired - public void setInjectorRepository(InjectorRepository injectorRepository) { - this.injectorRepository = injectorRepository; + // We need to support upsert for registration + Injector injector = injectorRepository.findById(id).orElse(null); + if (injector == null) { + Injector injectorChecking = injectorRepository.findByType(contractor.getType()).orElse(null); + if (injectorChecking != null) { + throw new Exception( + "The injector " + + contractor.getType() + + " already exists with a different ID, please delete it or contact your administrator."); + } } - - @Autowired - public void setInjectorContractRepository(InjectorContractRepository injectorContractRepository) { - this.injectorContractRepository = injectorContractRepository; - } - - @Autowired - public void setPayloadService(PayloadService payloadService) { - this.payloadService = payloadService; - } - - @Transactional - public void register(String id, String name, Contractor contractor, Boolean isCustomizable, String category, Map executorCommands, Map executorClearCommands, Boolean isPayloads) throws Exception { - if(!contractor.isExpose()) { - Injector injector = injectorRepository.findById(id).orElse(null); - if( injector != null ) { - injectorRepository.deleteById(id); - return; - } - return; - } - if (contractor.getIcon() != null) { - InputStream iconData = contractor.getIcon().getData(); - fileService.uploadStream(INJECTORS_IMAGES_BASE_PATH, contractor.getType() + ".png", iconData); - } - // We need to support upsert for registration - Injector injector = injectorRepository.findById(id).orElse(null); - if( injector == null ) { - Injector injectorChecking = injectorRepository.findByType(contractor.getType()).orElse(null); - if (injectorChecking != null ) { - throw new Exception("The injector " + contractor.getType() + " already exists with a different ID, please delete it or contact your administrator."); - } - } - // Check error to avoid changing ID - List contracts = contractor.contracts(); - if (injector != null) { - injector.setName(name); - injector.setExternal(false); - injector.setCustomContracts(isCustomizable); - injector.setType(contractor.getType()); - injector.setCategory(category); - injector.setExecutorCommands(executorCommands); - injector.setExecutorClearCommands(executorClearCommands); - injector.setPayloads(isPayloads); - injector.setUpdatedAt(Instant.now()); - List existing = new ArrayList<>(); - List toUpdates = new ArrayList<>(); - List toDeletes = new ArrayList<>(); - injector.getContracts() - .forEach(contract -> { - Optional current = contracts.stream().filter(c -> c.getId().equals(contract.getId())).findFirst(); + // Check error to avoid changing ID + List contracts = contractor.contracts(); + if (injector != null) { + injector.setName(name); + injector.setExternal(false); + injector.setCustomContracts(isCustomizable); + injector.setType(contractor.getType()); + injector.setCategory(category); + injector.setExecutorCommands(executorCommands); + injector.setExecutorClearCommands(executorClearCommands); + injector.setPayloads(isPayloads); + injector.setUpdatedAt(Instant.now()); + List existing = new ArrayList<>(); + List toUpdates = new ArrayList<>(); + List toDeletes = new ArrayList<>(); + injector + .getContracts() + .forEach( + contract -> { + Optional current = + contracts.stream().filter(c -> c.getId().equals(contract.getId())).findFirst(); if (current.isPresent()) { - existing.add(contract.getId()); - contract.setManual(current.get().isManual()); - contract.setAtomicTesting(current.get().isAtomicTesting()); - contract.setPlatforms(current.get().getPlatforms().toArray(new PLATFORM_TYPE[0])); - contract.setNeedsExecutor(current.get().isNeedsExecutor()); - Map labels = current.get().getLabel().entrySet().stream() - .collect(Collectors.toMap(e -> e.getKey().toString(), Map.Entry::getValue)); - contract.setLabels(labels); - // If no override of TTPs, retrieve those of the contract - if (contract.getAttackPatterns().isEmpty()) { - if (!current.get().getAttackPatternsExternalIds().isEmpty()) { - List attackPatterns = fromIterable(attackPatternRepository.findAllByExternalIdInIgnoreCase(current.get().getAttackPatternsExternalIds())); - contract.setAttackPatterns(attackPatterns); - } + existing.add(contract.getId()); + contract.setManual(current.get().isManual()); + contract.setAtomicTesting(current.get().isAtomicTesting()); + contract.setPlatforms(current.get().getPlatforms().toArray(new PLATFORM_TYPE[0])); + contract.setNeedsExecutor(current.get().isNeedsExecutor()); + Map labels = + current.get().getLabel().entrySet().stream() + .collect( + Collectors.toMap(e -> e.getKey().toString(), Map.Entry::getValue)); + contract.setLabels(labels); + // If no override of TTPs, retrieve those of the contract + if (contract.getAttackPatterns().isEmpty()) { + if (!current.get().getAttackPatternsExternalIds().isEmpty()) { + List attackPatterns = + fromIterable( + attackPatternRepository.findAllByExternalIdInIgnoreCase( + current.get().getAttackPatternsExternalIds())); + contract.setAttackPatterns(attackPatterns); + } + } + try { + contract.setContent(mapper.writeValueAsString(current.get())); + } catch (JsonProcessingException e) { + throw new RuntimeException(e); + } + toUpdates.add(contract); + } else if (!contract.getCustom() + && (!injector.isPayloads() || contract.getPayload() == null)) { + toDeletes.add(contract.getId()); + } + }); + List toCreates = + contracts.stream() + .filter(c -> !existing.contains(c.getId())) + .map( + in -> { + InjectorContract injectorContract = new InjectorContract(); + injectorContract.setId(in.getId()); + injectorContract.setManual(in.isManual()); + injectorContract.setAtomicTesting(in.isAtomicTesting()); + injectorContract.setPlatforms(in.getPlatforms().toArray(new PLATFORM_TYPE[0])); + injectorContract.setNeedsExecutor(in.isNeedsExecutor()); + Map labels = + in.getLabel().entrySet().stream() + .collect( + Collectors.toMap(e -> e.getKey().toString(), Map.Entry::getValue)); + injectorContract.setLabels(labels); + injectorContract.setInjector(injector); + if (!in.getAttackPatternsExternalIds().isEmpty()) { + List attackPatterns = + fromIterable( + attackPatternRepository.findAllByExternalIdInIgnoreCase( + in.getAttackPatternsExternalIds())); + injectorContract.setAttackPatterns(attackPatterns); + } else { + injectorContract.setAttackPatterns(new ArrayList<>()); } try { - contract.setContent(mapper.writeValueAsString(current.get())); + injectorContract.setContent(mapper.writeValueAsString(in)); } catch (JsonProcessingException e) { - throw new RuntimeException(e); + throw new RuntimeException(e); } - toUpdates.add(contract); - } else if(!contract.getCustom() && (!injector.isPayloads() || contract.getPayload() == null)) { - toDeletes.add(contract.getId()); - } - }); - List toCreates = contracts.stream().filter(c -> !existing.contains(c.getId())).map(in -> { - InjectorContract injectorContract = new InjectorContract(); - injectorContract.setId(in.getId()); - injectorContract.setManual(in.isManual()); - injectorContract.setAtomicTesting(in.isAtomicTesting()); - injectorContract.setPlatforms(in.getPlatforms().toArray(new PLATFORM_TYPE[0])); - injectorContract.setNeedsExecutor(in.isNeedsExecutor()); - Map labels = in.getLabel().entrySet().stream() - .collect(Collectors.toMap(e -> e.getKey().toString(), Map.Entry::getValue)); - injectorContract.setLabels(labels); - injectorContract.setInjector(injector); - if (!in.getAttackPatternsExternalIds().isEmpty()) { - List attackPatterns = fromIterable(attackPatternRepository.findAllByExternalIdInIgnoreCase(in.getAttackPatternsExternalIds())); - injectorContract.setAttackPatterns(attackPatterns); - } else { - injectorContract.setAttackPatterns(new ArrayList<>()); - } - try { - injectorContract.setContent(mapper.writeValueAsString(in)); - } catch (JsonProcessingException e) { - throw new RuntimeException(e); - } - return injectorContract; - }).toList(); - injectorContractRepository.deleteAllById(toDeletes); - injectorContractRepository.saveAll(toCreates); - injectorContractRepository.saveAll(toUpdates); - injectorRepository.save(injector); - } else { - // save the injector - Injector newInjector = new Injector(); - newInjector.setId(id); - newInjector.setName(name); - newInjector.setType(contractor.getType()); - newInjector.setCategory(category); - newInjector.setCustomContracts(isCustomizable); - newInjector.setExecutorCommands(executorCommands); - newInjector.setExecutorClearCommands(executorClearCommands); - newInjector.setPayloads(isPayloads); - Injector savedInjector = injectorRepository.save(newInjector); - // Save the contracts - List injectorContracts = contracts.stream().map(in -> { - InjectorContract injectorContract = new InjectorContract(); - injectorContract.setId(in.getId()); - injectorContract.setManual(in.isManual()); - injectorContract.setAtomicTesting(in.isAtomicTesting()); - injectorContract.setPlatforms(in.getPlatforms().toArray(new PLATFORM_TYPE[0])); - injectorContract.setNeedsExecutor(in.isNeedsExecutor()); - Map labels = in.getLabel().entrySet().stream() - .collect(Collectors.toMap(e -> e.getKey().toString(), Map.Entry::getValue)); - injectorContract.setLabels(labels); - injectorContract.setInjector(savedInjector); - if (!in.getAttackPatternsExternalIds().isEmpty()) { - injectorContract.setAttackPatterns(fromIterable(attackPatternRepository.findAllById(in.getAttackPatternsExternalIds()))); - } - try { - injectorContract.setContent(mapper.writeValueAsString(in)); - } catch (JsonProcessingException e) { - throw new RuntimeException(e); - } - return injectorContract; - }).toList(); - injectorContractRepository.saveAll(injectorContracts); - } + return injectorContract; + }) + .toList(); + injectorContractRepository.deleteAllById(toDeletes); + injectorContractRepository.saveAll(toCreates); + injectorContractRepository.saveAll(toUpdates); + injectorRepository.save(injector); + } else { + // save the injector + Injector newInjector = new Injector(); + newInjector.setId(id); + newInjector.setName(name); + newInjector.setType(contractor.getType()); + newInjector.setCategory(category); + newInjector.setCustomContracts(isCustomizable); + newInjector.setExecutorCommands(executorCommands); + newInjector.setExecutorClearCommands(executorClearCommands); + newInjector.setPayloads(isPayloads); + Injector savedInjector = injectorRepository.save(newInjector); + // Save the contracts + List injectorContracts = + contracts.stream() + .map( + in -> { + InjectorContract injectorContract = new InjectorContract(); + injectorContract.setId(in.getId()); + injectorContract.setManual(in.isManual()); + injectorContract.setAtomicTesting(in.isAtomicTesting()); + injectorContract.setPlatforms(in.getPlatforms().toArray(new PLATFORM_TYPE[0])); + injectorContract.setNeedsExecutor(in.isNeedsExecutor()); + Map labels = + in.getLabel().entrySet().stream() + .collect( + Collectors.toMap(e -> e.getKey().toString(), Map.Entry::getValue)); + injectorContract.setLabels(labels); + injectorContract.setInjector(savedInjector); + if (!in.getAttackPatternsExternalIds().isEmpty()) { + injectorContract.setAttackPatterns( + fromIterable( + attackPatternRepository.findAllById( + in.getAttackPatternsExternalIds()))); + } + try { + injectorContract.setContent(mapper.writeValueAsString(in)); + } catch (JsonProcessingException e) { + throw new RuntimeException(e); + } + return injectorContract; + }) + .toList(); + injectorContractRepository.saveAll(injectorContracts); } + } - public Iterable injectors() { - return injectorRepository.findAll(); - } + public Iterable injectors() { + return injectorRepository.findAll(); + } } diff --git a/openbas-framework/src/main/java/io/openbas/integrations/PayloadService.java b/openbas-framework/src/main/java/io/openbas/integrations/PayloadService.java index 187e089bf3..57e8a1a88e 100644 --- a/openbas-framework/src/main/java/io/openbas/integrations/PayloadService.java +++ b/openbas-framework/src/main/java/io/openbas/integrations/PayloadService.java @@ -1,5 +1,16 @@ package io.openbas.integrations; +import static io.openbas.helper.StreamHelper.fromIterable; +import static io.openbas.helper.SupportedLanguage.en; +import static io.openbas.helper.SupportedLanguage.fr; +import static io.openbas.injector_contract.Contract.executableContract; +import static io.openbas.injector_contract.ContractCardinality.Multiple; +import static io.openbas.injector_contract.ContractDef.contractBuilder; +import static io.openbas.injector_contract.fields.ContractAsset.assetField; +import static io.openbas.injector_contract.fields.ContractAssetGroup.assetGroupField; +import static io.openbas.injector_contract.fields.ContractExpectations.expectationsField; +import static io.openbas.injector_contract.fields.ContractText.textField; + import com.fasterxml.jackson.core.JsonProcessingException; import com.fasterxml.jackson.databind.ObjectMapper; import io.openbas.database.model.*; @@ -19,32 +30,17 @@ import jakarta.annotation.Resource; import jakarta.validation.constraints.NotBlank; import jakarta.validation.constraints.NotNull; +import java.util.*; import lombok.RequiredArgsConstructor; import org.hibernate.Hibernate; import org.springframework.beans.BeanUtils; import org.springframework.stereotype.Service; -import java.util.*; - -import static io.openbas.database.model.Payload.PAYLOAD_SOURCE.MANUAL; -import static io.openbas.database.model.Payload.PAYLOAD_STATUS.VERIFIED; -import static io.openbas.helper.StreamHelper.fromIterable; -import static io.openbas.helper.SupportedLanguage.en; -import static io.openbas.helper.SupportedLanguage.fr; -import static io.openbas.injector_contract.Contract.executableContract; -import static io.openbas.injector_contract.ContractCardinality.Multiple; -import static io.openbas.injector_contract.ContractDef.contractBuilder; -import static io.openbas.injector_contract.fields.ContractAsset.assetField; -import static io.openbas.injector_contract.fields.ContractAssetGroup.assetGroupField; -import static io.openbas.injector_contract.fields.ContractExpectations.expectationsField; -import static io.openbas.injector_contract.fields.ContractText.textField; - @RequiredArgsConstructor @Service public class PayloadService { - @Resource - protected ObjectMapper mapper; + @Resource protected ObjectMapper mapper; private final PayloadRepository payloadRepository; private final InjectorRepository injectorRepository; @@ -58,8 +54,8 @@ public void updateInjectorContractsForPayload(Payload payload) { } private void updateInjectorContract(Injector injector, Payload payload) { - Optional injectorContract = injectorContractRepository.findInjectorContractByInjectorAndPayload( - injector, payload); + Optional injectorContract = + injectorContractRepository.findInjectorContractByInjectorAndPayload(injector, payload); if (injectorContract.isPresent()) { InjectorContract existingInjectorContract = injectorContract.get(); Contract contract = buildContract(existingInjectorContract.getId(), injector, payload); @@ -70,8 +66,10 @@ private void updateInjectorContract(Injector injector, Payload payload) { existingInjectorContract.setInjector(injector); existingInjectorContract.setPayload(payload); existingInjectorContract.setPlatforms(payload.getPlatforms()); - existingInjectorContract.setAttackPatterns(fromIterable(attackPatternRepository.findAllById( - payload.getAttackPatterns().stream().map(AttackPattern::getId).toList()))); + existingInjectorContract.setAttackPatterns( + fromIterable( + attackPatternRepository.findAllById( + payload.getAttackPatterns().stream().map(AttackPattern::getId).toList()))); existingInjectorContract.setAtomicTesting(true); try { existingInjectorContract.setContent(mapper.writeValueAsString(contract)); @@ -91,8 +89,10 @@ private void updateInjectorContract(Injector injector, Payload payload) { newInjectorContract.setInjector(injector); newInjectorContract.setPayload(payload); newInjectorContract.setPlatforms(payload.getPlatforms()); - newInjectorContract.setAttackPatterns(fromIterable(attackPatternRepository.findAllById( - payload.getAttackPatterns().stream().map(AttackPattern::getId).toList()))); + newInjectorContract.setAttackPatterns( + fromIterable( + attackPatternRepository.findAllById( + payload.getAttackPatterns().stream().map(AttackPattern::getId).toList()))); newInjectorContract.setAtomicTesting(true); try { newInjectorContract.setContent(mapper.writeValueAsString(contract)); @@ -103,11 +103,19 @@ private void updateInjectorContract(Injector injector, Payload payload) { } } - private Contract buildContract(@NotNull final String contractId, @NotNull final Injector injector, + private Contract buildContract( + @NotNull final String contractId, + @NotNull final Injector injector, @NotNull final Payload payload) { Map labels = Map.of(en, injector.getName(), fr, injector.getName()); - ContractConfig contractConfig = new ContractConfig(injector.getType(), labels, "#000000", "#000000", - "/img/icon-" + injector.getType() + ".png", true); + ContractConfig contractConfig = + new ContractConfig( + injector.getType(), + labels, + "#000000", + "#000000", + "/img/icon-" + injector.getType() + ".png", + true); ContractAsset assetField = assetField("assets", "Assets", Multiple); ContractAssetGroup assetGroupField = assetGroupField("assetgroups", "Asset groups", Multiple); ContractExpectations expectationsField = expectations(); @@ -115,10 +123,16 @@ private Contract buildContract(@NotNull final String contractId, @NotNull final builder.mandatoryGroup(assetField, assetGroupField); builder.optional(expectationsField); if (payload.getArguments() != null) { - payload.getArguments().forEach(payloadArgument -> { - builder.mandatory( - textField(payloadArgument.getKey(), payloadArgument.getKey(), payloadArgument.getDefaultValue())); - }); + payload + .getArguments() + .forEach( + payloadArgument -> { + builder.mandatory( + textField( + payloadArgument.getKey(), + payloadArgument.getKey(), + payloadArgument.getDefaultValue())); + }); } return executableContract( contractConfig, @@ -126,8 +140,7 @@ private Contract buildContract(@NotNull final String contractId, @NotNull final Map.of(en, payload.getName(), fr, payload.getName()), builder.build(), Arrays.asList(payload.getPlatforms()), - true - ); + true); } private ContractExpectations expectations() { @@ -136,9 +149,7 @@ private ContractExpectations expectations() { "Expectations", List.of( this.expectationBuilderService.buildPreventionExpectation(), - this.expectationBuilderService.buildDetectionExpectation() - ) - ); + this.expectationBuilderService.buildDetectionExpectation())); } public Payload duplicate(@NotBlank final String payloadId) { @@ -177,19 +188,22 @@ public Payload duplicate(@NotBlank final String payloadId) { duplicate = payloadRepository.save(duplicateNetworkTraffic); break; default: - throw new UnsupportedOperationException("Payload type " + origin.getType() + " is not supported"); + throw new UnsupportedOperationException( + "Payload type " + origin.getType() + " is not supported"); } this.updateInjectorContractsForPayload(duplicate); return duplicate; } - private void duplicateCommonProperties(@org.jetbrains.annotations.NotNull final T origin, @org.jetbrains.annotations.NotNull T duplicate) { - BeanUtils.copyProperties(origin, duplicate); - duplicate.setId(null); - duplicate.setName(StringUtils.duplicateString(origin.getName())); - duplicate.setAttackPatterns(new ArrayList<>(origin.getAttackPatterns())); - duplicate.setTags(new HashSet<>(origin.getTags())); - duplicate.setExternalId(null); - duplicate.setCollector(null); - } + private void duplicateCommonProperties( + @org.jetbrains.annotations.NotNull final T origin, + @org.jetbrains.annotations.NotNull T duplicate) { + BeanUtils.copyProperties(origin, duplicate); + duplicate.setId(null); + duplicate.setName(StringUtils.duplicateString(origin.getName())); + duplicate.setAttackPatterns(new ArrayList<>(origin.getAttackPatterns())); + duplicate.setTags(new HashSet<>(origin.getTags())); + duplicate.setExternalId(null); + duplicate.setCollector(null); + } } diff --git a/openbas-framework/src/main/java/io/openbas/model/ExecutionProcess.java b/openbas-framework/src/main/java/io/openbas/model/ExecutionProcess.java index 60d9a9afe6..6346334341 100644 --- a/openbas-framework/src/main/java/io/openbas/model/ExecutionProcess.java +++ b/openbas-framework/src/main/java/io/openbas/model/ExecutionProcess.java @@ -1,20 +1,19 @@ package io.openbas.model; +import java.util.List; import lombok.Getter; import lombok.Setter; -import java.util.List; - @Getter @Setter public class ExecutionProcess { - private boolean async; + private boolean async; - private List expectations; + private List expectations; - public ExecutionProcess(boolean async, List expectations) { - this.async = async; - this.expectations = expectations; - } + public ExecutionProcess(boolean async, List expectations) { + this.async = async; + this.expectations = expectations; + } } diff --git a/openbas-framework/src/main/java/io/openbas/model/Expectation.java b/openbas-framework/src/main/java/io/openbas/model/Expectation.java index 574f5a210d..b4235aca00 100644 --- a/openbas-framework/src/main/java/io/openbas/model/Expectation.java +++ b/openbas-framework/src/main/java/io/openbas/model/Expectation.java @@ -14,8 +14,6 @@ default boolean isExpectationGroup() { String getName(); - /** - * Expiration time in seconds - */ + /** Expiration time in seconds */ Long getExpirationTime(); } diff --git a/openbas-framework/src/main/java/io/openbas/model/LinkedFieldModel.java b/openbas-framework/src/main/java/io/openbas/model/LinkedFieldModel.java index cc2d566906..7732185b62 100644 --- a/openbas-framework/src/main/java/io/openbas/model/LinkedFieldModel.java +++ b/openbas-framework/src/main/java/io/openbas/model/LinkedFieldModel.java @@ -5,32 +5,32 @@ public class LinkedFieldModel { - private String key; + private String key; - private ContractType type; + private ContractType type; - private LinkedFieldModel(String key, ContractType type) { - this.key = key; - this.type = type; - } + private LinkedFieldModel(String key, ContractType type) { + this.key = key; + this.type = type; + } - public static LinkedFieldModel fromField(ContractElement fieldContract) { - return new LinkedFieldModel(fieldContract.getKey(), fieldContract.getType()); - } + public static LinkedFieldModel fromField(ContractElement fieldContract) { + return new LinkedFieldModel(fieldContract.getKey(), fieldContract.getType()); + } - public String getKey() { - return key; - } + public String getKey() { + return key; + } - public void setKey(String key) { - this.key = key; - } + public void setKey(String key) { + this.key = key; + } - public ContractType getType() { - return type; - } + public ContractType getType() { + return type; + } - public void setType(ContractType type) { - this.type = type; - } + public void setType(ContractType type) { + this.type = type; + } } diff --git a/openbas-framework/src/main/java/io/openbas/model/PairModel.java b/openbas-framework/src/main/java/io/openbas/model/PairModel.java index 6d398c1951..ed0eedeae0 100644 --- a/openbas-framework/src/main/java/io/openbas/model/PairModel.java +++ b/openbas-framework/src/main/java/io/openbas/model/PairModel.java @@ -6,34 +6,34 @@ @JsonIgnoreProperties(ignoreUnknown = true) public class PairModel { - @JsonProperty("key") - private String key; + @JsonProperty("key") + private String key; - @JsonProperty("value") - private String value; + @JsonProperty("value") + private String value; - public PairModel() { - // Default constructor - } + public PairModel() { + // Default constructor + } - public PairModel(String key, String value) { - this.key = key; - this.value = value; - } + public PairModel(String key, String value) { + this.key = key; + this.value = value; + } - public String getKey() { - return key; - } + public String getKey() { + return key; + } - public void setKey(String key) { - this.key = key; - } + public void setKey(String key) { + this.key = key; + } - public String getValue() { - return value; - } + public String getValue() { + return value; + } - public void setValue(String value) { - this.value = value; - } + public void setValue(String value) { + this.value = value; + } } diff --git a/openbas-framework/src/main/java/io/openbas/model/expectation/ChallengeExpectation.java b/openbas-framework/src/main/java/io/openbas/model/expectation/ChallengeExpectation.java index df7b275c36..ec6b370ec1 100644 --- a/openbas-framework/src/main/java/io/openbas/model/expectation/ChallengeExpectation.java +++ b/openbas-framework/src/main/java/io/openbas/model/expectation/ChallengeExpectation.java @@ -3,11 +3,10 @@ import io.openbas.database.model.Challenge; import io.openbas.database.model.InjectExpectation; import io.openbas.model.Expectation; +import java.util.Objects; import lombok.Getter; import lombok.Setter; -import java.util.Objects; - @Getter @Setter public class ChallengeExpectation implements Expectation { @@ -18,7 +17,8 @@ public class ChallengeExpectation implements Expectation { private String name; private Long expirationTime; - public ChallengeExpectation(io.openbas.model.inject.form.Expectation expectation, Challenge challenge) { + public ChallengeExpectation( + io.openbas.model.inject.form.Expectation expectation, Challenge challenge) { setScore(Objects.requireNonNullElse(expectation.getScore(), 100.0)); setChallenge(challenge); setName(challenge.getName()); @@ -30,5 +30,4 @@ public ChallengeExpectation(io.openbas.model.inject.form.Expectation expectation public InjectExpectation.EXPECTATION_TYPE type() { return InjectExpectation.EXPECTATION_TYPE.CHALLENGE; } - } diff --git a/openbas-framework/src/main/java/io/openbas/model/expectation/ChannelExpectation.java b/openbas-framework/src/main/java/io/openbas/model/expectation/ChannelExpectation.java index 0c1ccd5521..f82111a202 100644 --- a/openbas-framework/src/main/java/io/openbas/model/expectation/ChannelExpectation.java +++ b/openbas-framework/src/main/java/io/openbas/model/expectation/ChannelExpectation.java @@ -3,11 +3,10 @@ import io.openbas.database.model.Article; import io.openbas.database.model.InjectExpectation; import io.openbas.model.Expectation; +import java.util.Objects; import lombok.Getter; import lombok.Setter; -import java.util.Objects; - @Getter @Setter public class ChannelExpectation implements Expectation { @@ -18,7 +17,6 @@ public class ChannelExpectation implements Expectation { private String name; private Long expirationTime; - public ChannelExpectation(io.openbas.model.inject.form.Expectation expectation, Article article) { setScore(Objects.requireNonNullElse(score, 100.0)); setArticle(article); @@ -31,5 +29,4 @@ public ChannelExpectation(io.openbas.model.inject.form.Expectation expectation, public InjectExpectation.EXPECTATION_TYPE type() { return InjectExpectation.EXPECTATION_TYPE.ARTICLE; } - } diff --git a/openbas-framework/src/main/java/io/openbas/model/expectation/DetectionExpectation.java b/openbas-framework/src/main/java/io/openbas/model/expectation/DetectionExpectation.java index 98ad040547..76335cc30c 100644 --- a/openbas-framework/src/main/java/io/openbas/model/expectation/DetectionExpectation.java +++ b/openbas-framework/src/main/java/io/openbas/model/expectation/DetectionExpectation.java @@ -1,5 +1,7 @@ package io.openbas.model.expectation; +import static io.openbas.database.model.InjectExpectation.EXPECTATION_TYPE.DETECTION; + import io.openbas.database.model.Asset; import io.openbas.database.model.AssetGroup; import io.openbas.database.model.InjectExpectation; @@ -7,14 +9,11 @@ import io.openbas.model.Expectation; import jakarta.validation.constraints.NotBlank; import jakarta.validation.constraints.NotNull; -import lombok.Getter; -import lombok.Setter; - -import javax.annotation.Nullable; import java.util.List; import java.util.Objects; - -import static io.openbas.database.model.InjectExpectation.EXPECTATION_TYPE.DETECTION; +import javax.annotation.Nullable; +import lombok.Getter; +import lombok.Setter; @Getter @Setter @@ -29,8 +28,7 @@ public class DetectionExpectation implements Expectation { private Long expirationTime; private List injectExpectationSignatures; - private DetectionExpectation() { - } + private DetectionExpectation() {} @Override public InjectExpectation.EXPECTATION_TYPE type() { @@ -44,8 +42,7 @@ public static DetectionExpectation detectionExpectationForAsset( @NotNull final Asset asset, final boolean expectationGroup, final Long expirationTime, - final List expectationSignatures - ) { + final List expectationSignatures) { DetectionExpectation detectionExpectation = new DetectionExpectation(); detectionExpectation.setScore(Objects.requireNonNullElse(score, 100.0)); detectionExpectation.setName(name); @@ -64,8 +61,7 @@ public static DetectionExpectation detectionExpectationForAssetGroup( @NotNull final AssetGroup assetGroup, final boolean expectationGroup, final Long expirationTime, - final List expectationSignatures - ) { + final List expectationSignatures) { DetectionExpectation detectionExpectation = new DetectionExpectation(); detectionExpectation.setScore(Objects.requireNonNullElse(score, 100.0)); detectionExpectation.setName(name); @@ -76,5 +72,4 @@ public static DetectionExpectation detectionExpectationForAssetGroup( detectionExpectation.setInjectExpectationSignatures(expectationSignatures); return detectionExpectation; } - } diff --git a/openbas-framework/src/main/java/io/openbas/model/expectation/ManualExpectation.java b/openbas-framework/src/main/java/io/openbas/model/expectation/ManualExpectation.java index f08e838492..04d7258068 100644 --- a/openbas-framework/src/main/java/io/openbas/model/expectation/ManualExpectation.java +++ b/openbas-framework/src/main/java/io/openbas/model/expectation/ManualExpectation.java @@ -1,18 +1,17 @@ package io.openbas.model.expectation; +import static io.openbas.database.model.InjectExpectation.EXPECTATION_TYPE; + import io.openbas.database.model.Asset; import io.openbas.database.model.AssetGroup; import io.openbas.model.Expectation; import jakarta.validation.constraints.NotBlank; import jakarta.validation.constraints.NotNull; +import java.util.Objects; +import javax.annotation.Nullable; import lombok.Getter; import lombok.Setter; -import javax.annotation.Nullable; -import java.util.Objects; - -import static io.openbas.database.model.InjectExpectation.EXPECTATION_TYPE; - @Getter @Setter public class ManualExpectation implements Expectation { @@ -25,8 +24,7 @@ public class ManualExpectation implements Expectation { private boolean expectationGroup; private Long expirationTime; - public ManualExpectation() { - } + public ManualExpectation() {} public ManualExpectation(final Double score) { this.score = Objects.requireNonNullElse(score, 100.0); @@ -46,8 +44,7 @@ public static ManualExpectation manualExpectationForAsset( final String description, @NotNull final Asset asset, final Long expirationTime, - final boolean expectationGroup - ) { + final boolean expectationGroup) { ManualExpectation manualExpectation = new ManualExpectation(); manualExpectation.setScore(Objects.requireNonNullElse(score, 100.0)); manualExpectation.setName(name); @@ -64,8 +61,7 @@ public static ManualExpectation manualExpectationForAssetGroup( final String description, @NotNull final AssetGroup assetGroup, final Long expirationTime, - final boolean expectationGroup - ) { + final boolean expectationGroup) { ManualExpectation manualExpectation = new ManualExpectation(); manualExpectation.setScore(Objects.requireNonNullElse(score, 100.0)); manualExpectation.setName(name); @@ -80,5 +76,4 @@ public static ManualExpectation manualExpectationForAssetGroup( public EXPECTATION_TYPE type() { return EXPECTATION_TYPE.MANUAL; } - } diff --git a/openbas-framework/src/main/java/io/openbas/model/expectation/PreventionExpectation.java b/openbas-framework/src/main/java/io/openbas/model/expectation/PreventionExpectation.java index 814894a4b1..88d0703b8b 100644 --- a/openbas-framework/src/main/java/io/openbas/model/expectation/PreventionExpectation.java +++ b/openbas-framework/src/main/java/io/openbas/model/expectation/PreventionExpectation.java @@ -1,5 +1,7 @@ package io.openbas.model.expectation; +import static io.openbas.database.model.InjectExpectation.EXPECTATION_TYPE.PREVENTION; + import io.openbas.database.model.Asset; import io.openbas.database.model.AssetGroup; import io.openbas.database.model.InjectExpectation.EXPECTATION_TYPE; @@ -7,14 +9,11 @@ import io.openbas.model.Expectation; import jakarta.validation.constraints.NotBlank; import jakarta.validation.constraints.NotNull; -import lombok.Getter; -import lombok.Setter; - -import javax.annotation.Nullable; import java.util.List; import java.util.Objects; - -import static io.openbas.database.model.InjectExpectation.EXPECTATION_TYPE.PREVENTION; +import javax.annotation.Nullable; +import lombok.Getter; +import lombok.Setter; @Getter @Setter @@ -29,8 +28,7 @@ public class PreventionExpectation implements Expectation { private Long expirationTime; private List injectExpectationSignatures; - private PreventionExpectation() { - } + private PreventionExpectation() {} @Override public EXPECTATION_TYPE type() { @@ -44,8 +42,7 @@ public static PreventionExpectation preventionExpectationForAsset( @NotNull final Asset asset, final boolean expectationGroup, final Long expirationTime, - final List expectationSignatures - ) { + final List expectationSignatures) { PreventionExpectation preventionExpectation = new PreventionExpectation(); preventionExpectation.setScore(Objects.requireNonNullElse(score, 100.0)); preventionExpectation.setName(name); @@ -64,8 +61,7 @@ public static PreventionExpectation preventionExpectationForAssetGroup( @NotNull final AssetGroup assetGroup, final boolean expectationGroup, @NotNull final Long expirationTime, - final List expectationSignatures - ) { + final List expectationSignatures) { PreventionExpectation preventionExpectation = new PreventionExpectation(); preventionExpectation.setScore(Objects.requireNonNullElse(score, 100.0)); preventionExpectation.setName(name); @@ -76,5 +72,4 @@ public static PreventionExpectation preventionExpectationForAssetGroup( preventionExpectation.setInjectExpectationSignatures(expectationSignatures); return preventionExpectation; } - } diff --git a/openbas-framework/src/main/java/io/openbas/model/inject/form/Expectation.java b/openbas-framework/src/main/java/io/openbas/model/inject/form/Expectation.java index 8cffe09a2b..75429d3798 100644 --- a/openbas-framework/src/main/java/io/openbas/model/inject/form/Expectation.java +++ b/openbas-framework/src/main/java/io/openbas/model/inject/form/Expectation.java @@ -22,10 +22,7 @@ public class Expectation { @JsonProperty("expectation_expectation_group") private boolean expectationGroup; - /** - * Expiration time in seconds - */ + /** Expiration time in seconds */ @JsonProperty("expectation_expiration_time") private Long expirationTime; - } diff --git a/openbas-framework/src/main/java/io/openbas/utils/FilterUtilsJpa.java b/openbas-framework/src/main/java/io/openbas/utils/FilterUtilsJpa.java index f5c82333dc..e1ef448dcd 100644 --- a/openbas-framework/src/main/java/io/openbas/utils/FilterUtilsJpa.java +++ b/openbas-framework/src/main/java/io/openbas/utils/FilterUtilsJpa.java @@ -1,5 +1,12 @@ package io.openbas.utils; +import static io.openbas.database.model.Filters.FilterMode.and; +import static io.openbas.database.model.Filters.FilterMode.or; +import static io.openbas.utils.JpaUtils.toPath; +import static io.openbas.utils.OperationUtilsJpa.*; +import static io.openbas.utils.schema.SchemaUtils.getFilterableProperties; +import static io.openbas.utils.schema.SchemaUtils.retrieveProperty; + import io.openbas.database.model.Base; import io.openbas.database.model.Filters.Filter; import io.openbas.database.model.Filters.FilterGroup; @@ -12,34 +19,21 @@ import jakarta.persistence.criteria.Join; import jakarta.persistence.criteria.Predicate; import jakarta.validation.constraints.NotNull; -import org.jetbrains.annotations.Nullable; -import org.springframework.data.jpa.domain.Specification; - import java.time.Instant; import java.util.*; import java.util.function.BiFunction; import java.util.function.Function; - -import static io.openbas.database.model.Filters.FilterMode.and; -import static io.openbas.database.model.Filters.FilterMode.or; -import static io.openbas.utils.JpaUtils.toPath; -import static io.openbas.utils.OperationUtilsJpa.*; -import static io.openbas.utils.schema.SchemaUtils.getFilterableProperties; -import static io.openbas.utils.schema.SchemaUtils.retrieveProperty; +import org.jetbrains.annotations.Nullable; +import org.springframework.data.jpa.domain.Specification; public class FilterUtilsJpa { - private FilterUtilsJpa() { + private FilterUtilsJpa() {} - } - - public record Option(String id, String label) { - - } + public record Option(String id, String label) {} private static final Specification EMPTY_SPECIFICATION = (root, query, cb) -> cb.conjunction(); - @SuppressWarnings("unchecked") public static Specification computeFilterGroupJpa( @Nullable final FilterGroup filterGroup) { @@ -48,8 +42,7 @@ public static Specification computeFilterGroupJpa( @SuppressWarnings("unchecked") public static Specification computeFilterGroupJpa( - @Nullable final FilterGroup filterGroup, - Map> joinMap) { + @Nullable final FilterGroup filterGroup, Map> joinMap) { if (filterGroup == null) { return (Specification) EMPTY_SPECIFICATION; } @@ -57,10 +50,12 @@ public static Specification computeFilterGroupJpa( FilterMode mode = Optional.ofNullable(filterGroup.getMode()).orElse(and); if (!filters.isEmpty()) { - List> list = filters - .stream() - .map((Function>) f -> FilterUtilsJpa.computeFilter(f, joinMap)) - .toList(); + List> list = + filters.stream() + .map( + (Function>) + f -> FilterUtilsJpa.computeFilter(f, joinMap)) + .toList(); Specification result = null; for (Specification el : list) { if (result == null) { @@ -81,8 +76,7 @@ public static Specification computeFilterGroupJpa( @SuppressWarnings("unchecked") private static Specification computeFilter( - @Nullable final Filter filter, - Map> joinMap) { + @Nullable final Filter filter, Map> joinMap) { if (filter == null) { return (Specification) EMPTY_SPECIFICATION; } @@ -91,17 +85,19 @@ private static Specification computeFilter( return (root, query, cb) -> { List propertySchemas; try { - propertySchemas = SchemaUtils.schemaWithSubtypes(root.getJavaType()); + propertySchemas = SchemaUtils.schemaWithSubtypes(root.getJavaType()); } catch (ClassNotFoundException e) { - throw new RuntimeException(e); + throw new RuntimeException(e); } List filterableProperties = getFilterableProperties(propertySchemas); PropertySchema filterableProperty = retrieveProperty(filterableProperties, filterKey); Expression paths = toPath(filterableProperty, root, joinMap); // In case of join table, we will use ID so type is String return toPredicate( - paths, filter, cb, filterableProperty.getJoinTable() != null ? String.class : filterableProperty.getType() - ); + paths, + filter, + cb, + filterableProperty.getJoinTable() != null ? String.class : filterableProperty.getType()); }; } @@ -110,9 +106,8 @@ private static Predicate toPredicate( @NotNull final Filter filter, @NotNull final CriteriaBuilder cb, @NotNull final Class type) { - BiFunction, List, Predicate> operation = computeOperation( - filter.getOperator(), cb, type - ); + BiFunction, List, Predicate> operation = + computeOperation(filter.getOperator(), cb, type); return operation.apply(paths, filter.getValues()); } @@ -126,30 +121,41 @@ private static BiFunction, List, Predicate> computeOpe throw new IllegalArgumentException("Operator cannot be null"); } if (operator.equals(FilterOperator.not_contains)) { - return (Expression paths, List texts) -> notContainsTexts((Expression) paths, cb, texts, type); + return (Expression paths, List texts) -> + notContainsTexts((Expression) paths, cb, texts, type); } else if (operator.equals(FilterOperator.contains)) { - return (Expression paths, List texts) -> containsTexts((Expression) paths, cb, texts, type); + return (Expression paths, List texts) -> + containsTexts((Expression) paths, cb, texts, type); } else if (operator.equals(FilterOperator.not_starts_with)) { - return (Expression paths, List texts) -> notStartWithTexts((Expression) paths, cb, texts, type); + return (Expression paths, List texts) -> + notStartWithTexts((Expression) paths, cb, texts, type); } else if (operator.equals(FilterOperator.starts_with)) { - return (Expression paths, List texts) -> startWithTexts((Expression) paths, cb, texts, type); + return (Expression paths, List texts) -> + startWithTexts((Expression) paths, cb, texts, type); } else if (operator.equals(FilterOperator.empty)) { - return (Expression paths, List texts) -> empty((Expression) paths, cb, type); + return (Expression paths, List texts) -> + empty((Expression) paths, cb, type); } else if (operator.equals(FilterOperator.not_empty)) { - return (Expression paths, List texts) -> notEmpty((Expression) paths, cb, type); + return (Expression paths, List texts) -> + notEmpty((Expression) paths, cb, type); } else if (operator.equals(FilterOperator.gt)) { - return (Expression paths, List texts) -> greaterThanTexts((Expression) paths, cb, texts); + return (Expression paths, List texts) -> + greaterThanTexts((Expression) paths, cb, texts); } else if (operator.equals(FilterOperator.gte)) { - return (Expression paths, List texts) -> greaterThanOrEqualTexts((Expression) paths, cb, texts); + return (Expression paths, List texts) -> + greaterThanOrEqualTexts((Expression) paths, cb, texts); } else if (operator.equals(FilterOperator.lt)) { - return (Expression paths, List texts) -> lessThanTexts((Expression) paths, cb, texts); + return (Expression paths, List texts) -> + lessThanTexts((Expression) paths, cb, texts); } else if (operator.equals(FilterOperator.lte)) { - return (Expression paths, List texts) -> lessThanOrEqualTexts((Expression) paths, cb, texts); + return (Expression paths, List texts) -> + lessThanOrEqualTexts((Expression) paths, cb, texts); } else if (operator.equals(FilterOperator.not_eq)) { - return (Expression paths, List texts) -> notEqualsTexts((Expression) paths, cb, texts, type); + return (Expression paths, List texts) -> + notEqualsTexts((Expression) paths, cb, texts, type); } else { // Default case -> equals - return (Expression paths, List texts) -> equalsTexts((Expression) paths, cb, texts, type); + return (Expression paths, List texts) -> + equalsTexts((Expression) paths, cb, texts, type); } } - } diff --git a/openbas-framework/src/main/java/io/openbas/utils/FilterUtilsRuntime.java b/openbas-framework/src/main/java/io/openbas/utils/FilterUtilsRuntime.java index 25eae3d90c..b630f68e64 100644 --- a/openbas-framework/src/main/java/io/openbas/utils/FilterUtilsRuntime.java +++ b/openbas-framework/src/main/java/io/openbas/utils/FilterUtilsRuntime.java @@ -1,5 +1,10 @@ package io.openbas.utils; +import static io.openbas.database.model.Filters.FilterMode.and; +import static io.openbas.database.model.Filters.FilterMode.or; +import static io.openbas.utils.schema.SchemaUtils.getFilterableProperties; +import static io.openbas.utils.schema.SchemaUtils.retrieveProperty; + import io.openbas.database.model.Filters.Filter; import io.openbas.database.model.Filters.FilterGroup; import io.openbas.database.model.Filters.FilterMode; @@ -7,27 +12,20 @@ import io.openbas.utils.schema.PropertySchema; import io.openbas.utils.schema.SchemaUtils; import jakarta.validation.constraints.NotNull; - -import javax.annotation.Nullable; import java.lang.reflect.Field; import java.util.*; import java.util.function.BiFunction; import java.util.function.Predicate; - -import static io.openbas.database.model.Filters.FilterMode.and; -import static io.openbas.database.model.Filters.FilterMode.or; -import static io.openbas.utils.schema.SchemaUtils.getFilterableProperties; -import static io.openbas.utils.schema.SchemaUtils.retrieveProperty; +import javax.annotation.Nullable; public class FilterUtilsRuntime { - private FilterUtilsRuntime() { - - } + private FilterUtilsRuntime() {} private static final Predicate EMPTY_PREDICATE = (value) -> true; - public static Predicate computeFilterGroupRuntime(@Nullable final FilterGroup filterGroup) { + public static Predicate computeFilterGroupRuntime( + @Nullable final FilterGroup filterGroup) { if (filterGroup == null) { return EMPTY_PREDICATE; } @@ -35,10 +33,8 @@ public static Predicate computeFilterGroupRuntime(@Nullable final Filter FilterMode mode = Optional.ofNullable(filterGroup.getMode()).orElse(and); if (!filters.isEmpty()) { - List> list = filters - .stream() - .map(FilterUtilsRuntime::computeFilter) - .toList(); + List> list = + filters.stream().map(FilterUtilsRuntime::computeFilter).toList(); Predicate result = null; for (Predicate el : list) { if (result == null) { @@ -86,9 +82,8 @@ private static boolean getPropertyValue(Map.Entry, Object> entry, if (entry.getKey().isAssignableFrom(Map.class) || entry.getKey().getName().contains("ImmutableCollections")) { - return ((Map) entry.getValue()).values() - .stream() - .anyMatch(v -> operation.apply(v, filter.getValues())); + return ((Map) entry.getValue()) + .values().stream().anyMatch(v -> operation.apply(v, filter.getValues())); } else if (entry.getKey().isArray()) { return Arrays.stream(((Object[]) entry.getValue())) .anyMatch(v -> operation.apply(v, filter.getValues())); @@ -98,7 +93,8 @@ private static boolean getPropertyValue(Map.Entry, Object> entry, } @SuppressWarnings("unchecked") - private static Map.Entry, Object> getPropertyInfo(Object obj, PropertySchema propertySchema) { + private static Map.Entry, Object> getPropertyInfo( + Object obj, PropertySchema propertySchema) { if (obj == null) { return null; } @@ -119,7 +115,8 @@ private static Map.Entry, Object> getPropertyInfo(Object obj, Prop // -- OPERATOR -- - private static BiFunction, Boolean> computeOperation(@NotNull final FilterOperator operator) { + private static BiFunction, Boolean> computeOperation( + @NotNull final FilterOperator operator) { if (operator == null) { // Default case return OperationUtilsRuntime::equalsTexts; @@ -143,5 +140,4 @@ private static BiFunction, Boolean> computeOperation(@NotNu return OperationUtilsRuntime::equalsTexts; } } - } diff --git a/openbas-framework/src/main/java/io/openbas/utils/JpaUtils.java b/openbas-framework/src/main/java/io/openbas/utils/JpaUtils.java index d29de14259..8202e3a80f 100644 --- a/openbas-framework/src/main/java/io/openbas/utils/JpaUtils.java +++ b/openbas-framework/src/main/java/io/openbas/utils/JpaUtils.java @@ -1,23 +1,19 @@ package io.openbas.utils; +import static org.springframework.util.StringUtils.hasText; + import io.openbas.database.model.Base; import io.openbas.utils.schema.PropertySchema; import jakarta.persistence.criteria.*; import jakarta.validation.constraints.NotNull; - import java.util.Map; -import static org.springframework.util.StringUtils.hasText; - public class JpaUtils { - private JpaUtils() { - - } + private JpaUtils() {} private static Path computePath( - @NotNull final From from, - @NotNull final String key) { + @NotNull final From from, @NotNull final String key) { String[] jsonPaths = key.split("\\."); // Deep path -> use join @@ -93,30 +89,23 @@ public static Expression toPath( // -- FUNCTION -- public static Expression arrayAggOnId( - @NotNull final CriteriaBuilder cb, - @NotNull final Join join) { + @NotNull final CriteriaBuilder cb, @NotNull final Join join) { return cb.function( "array_remove", String[].class, cb.function("array_agg", String[].class, join.get("id")), - cb.nullLiteral(String.class) - ); + cb.nullLiteral(String.class)); } // -- JOIN -- - public static Join createLeftJoin( - Root root, - String attributeName) { + public static Join createLeftJoin(Root root, String attributeName) { return root.join(attributeName, JoinType.LEFT); } public static Expression createJoinArrayAggOnId( - CriteriaBuilder cb, - Root root, - String attributeName) { + CriteriaBuilder cb, Root root, String attributeName) { Join join = createLeftJoin(root, attributeName); return arrayAggOnId(cb, join); } - } diff --git a/openbas-framework/src/main/java/io/openbas/utils/OperationUtilsJpa.java b/openbas-framework/src/main/java/io/openbas/utils/OperationUtilsJpa.java index 7bd3995a31..a8bc1b0a15 100644 --- a/openbas-framework/src/main/java/io/openbas/utils/OperationUtilsJpa.java +++ b/openbas-framework/src/main/java/io/openbas/utils/OperationUtilsJpa.java @@ -1,40 +1,36 @@ package io.openbas.utils; +import static org.springframework.util.StringUtils.hasText; + import jakarta.persistence.criteria.CriteriaBuilder; import jakarta.persistence.criteria.Expression; import jakarta.persistence.criteria.Predicate; - import java.time.Instant; import java.util.List; import java.util.Map; -import static org.springframework.util.StringUtils.hasText; - public class OperationUtilsJpa { - private OperationUtilsJpa() { - - } + private OperationUtilsJpa() {} // -- NOT CONTAINS -- public static Predicate notContainsTexts( - Expression paths, CriteriaBuilder cb, - List texts, Class type) { + Expression paths, CriteriaBuilder cb, List texts, Class type) { if (isEmpty(texts)) { return cb.conjunction(); } - Predicate[] predicates = texts.stream() - .map(text -> notContainsText(paths, cb, text, type)) - .toArray(Predicate[]::new); + Predicate[] predicates = + texts.stream() + .map(text -> notContainsText(paths, cb, text, type)) + .toArray(Predicate[]::new); return cb.or(predicates); } public static Predicate notContainsText( - Expression paths, CriteriaBuilder cb, - String text, Class type) { + Expression paths, CriteriaBuilder cb, String text, Class type) { if (isEmpty(text)) { return cb.conjunction(); } @@ -45,19 +41,19 @@ public static Predicate notContainsText( // -- CONTAINS -- public static Predicate containsTexts( - Expression paths, CriteriaBuilder cb, - List texts, - Class type) { + Expression paths, CriteriaBuilder cb, List texts, Class type) { if (isEmpty(texts)) { return cb.conjunction(); } - Predicate[] predicates = texts.stream().map(text -> containsText(paths, cb, text, type)).toArray(Predicate[]::new); + Predicate[] predicates = + texts.stream().map(text -> containsText(paths, cb, text, type)).toArray(Predicate[]::new); return cb.or(predicates); } - public static Predicate containsText(Expression paths, CriteriaBuilder cb, String text, Class type) { + public static Predicate containsText( + Expression paths, CriteriaBuilder cb, String text, Class type) { if (isEmpty(text)) { return cb.conjunction(); } @@ -67,32 +63,27 @@ public static Predicate containsText(Expression paths, CriteriaBuilder c return cb.like(values, "%" + text.toLowerCase() + "%"); } if (type.isArray() || type.isAssignableFrom(List.class)) { - return cb.like( - lower(arrayToString(paths, cb), cb), - "%" + text.toLowerCase() + "%" - ); + return cb.like(lower(arrayToString(paths, cb), cb), "%" + text.toLowerCase() + "%"); } - return cb.and( - cb.like(cb.lower(paths), "%" + text.toLowerCase() + "%"), - cb.isNotNull(paths) - ); + return cb.and(cb.like(cb.lower(paths), "%" + text.toLowerCase() + "%"), cb.isNotNull(paths)); } // -- NOT EQUALS -- - public static Predicate notEqualsTexts(Expression paths, CriteriaBuilder cb, List texts, Class type) { + public static Predicate notEqualsTexts( + Expression paths, CriteriaBuilder cb, List texts, Class type) { if (isEmpty(texts)) { return cb.conjunction(); } - Predicate[] predicates = texts.stream().map(text -> notEqualsText( - paths, cb, text, type - )).toArray(Predicate[]::new); + Predicate[] predicates = + texts.stream().map(text -> notEqualsText(paths, cb, text, type)).toArray(Predicate[]::new); return cb.or(predicates); } - private static Predicate notEqualsText(Expression paths, CriteriaBuilder cb, String text, Class type) { + private static Predicate notEqualsText( + Expression paths, CriteriaBuilder cb, String text, Class type) { if (isEmpty(text)) { return cb.conjunction(); } @@ -102,19 +93,20 @@ private static Predicate notEqualsText(Expression paths, CriteriaBuilder // -- EQUALS -- - public static Predicate equalsTexts(Expression paths, CriteriaBuilder cb, List texts, Class type) { + public static Predicate equalsTexts( + Expression paths, CriteriaBuilder cb, List texts, Class type) { if (isEmpty(texts)) { return cb.conjunction(); } - Predicate[] predicates = texts.stream().map(text -> equalsText( - paths, cb, text, type - )).toArray(Predicate[]::new); + Predicate[] predicates = + texts.stream().map(text -> equalsText(paths, cb, text, type)).toArray(Predicate[]::new); return cb.or(predicates); } - private static Predicate equalsText(Expression paths, CriteriaBuilder cb, String text, Class type) { + private static Predicate equalsText( + Expression paths, CriteriaBuilder cb, String text, Class type) { if (isEmpty(text)) { return cb.conjunction(); } @@ -132,17 +124,22 @@ private static Predicate equalsText(Expression paths, CriteriaBuilder cb // -- NOT START WITH -- - public static Predicate notStartWithTexts(Expression paths, CriteriaBuilder cb, List texts, Class type) { + public static Predicate notStartWithTexts( + Expression paths, CriteriaBuilder cb, List texts, Class type) { if (isEmpty(texts)) { return cb.conjunction(); } - Predicate[] predicates = texts.stream().map(text -> notStartWithText(paths, cb, text, type)).toArray(Predicate[]::new); + Predicate[] predicates = + texts.stream() + .map(text -> notStartWithText(paths, cb, text, type)) + .toArray(Predicate[]::new); return cb.or(predicates); } - public static Predicate notStartWithText(Expression paths, CriteriaBuilder cb, String text, Class type) { + public static Predicate notStartWithText( + Expression paths, CriteriaBuilder cb, String text, Class type) { if (isEmpty(text)) { return cb.conjunction(); } @@ -152,17 +149,20 @@ public static Predicate notStartWithText(Expression paths, CriteriaBuild // -- START WITH -- - public static Predicate startWithTexts(Expression paths, CriteriaBuilder cb, List texts, Class type) { + public static Predicate startWithTexts( + Expression paths, CriteriaBuilder cb, List texts, Class type) { if (isEmpty(texts)) { return cb.conjunction(); } - Predicate[] predicates = texts.stream().map(text -> startWithText(paths, cb, text, type)).toArray(Predicate[]::new); + Predicate[] predicates = + texts.stream().map(text -> startWithText(paths, cb, text, type)).toArray(Predicate[]::new); return cb.or(predicates); } - public static Predicate startWithText(Expression paths, CriteriaBuilder cb, String text, Class type) { + public static Predicate startWithText( + Expression paths, CriteriaBuilder cb, String text, Class type) { if (isEmpty(text)) { return cb.conjunction(); } @@ -193,28 +193,25 @@ public static Predicate empty(Expression paths, CriteriaBuilder cb, Clas if (type.equals(Instant.class) || type.isEnum()) { return cb.isNull(finalPaths); } - return cb.or( - cb.isNull(finalPaths), - cb.equal(finalPaths, ""), - cb.equal(finalPaths, " ") - ); + return cb.or(cb.isNull(finalPaths), cb.equal(finalPaths, ""), cb.equal(finalPaths, " ")); } // -- DATE -- - public static Predicate greaterThanTexts(Expression paths, CriteriaBuilder cb, List texts) { + public static Predicate greaterThanTexts( + Expression paths, CriteriaBuilder cb, List texts) { if (isEmpty(texts)) { return cb.conjunction(); } - Predicate[] predicates = texts.stream() - .map(value -> greaterThanText(paths, cb, value)) - .toArray(Predicate[]::new); + Predicate[] predicates = + texts.stream().map(value -> greaterThanText(paths, cb, value)).toArray(Predicate[]::new); return cb.or(predicates); } - public static Predicate greaterThanText(Expression paths, CriteriaBuilder cb, String text) { + public static Predicate greaterThanText( + Expression paths, CriteriaBuilder cb, String text) { if (isEmpty(text)) { return cb.conjunction(); } @@ -222,19 +219,22 @@ public static Predicate greaterThanText(Expression paths, CriteriaBuild return cb.greaterThan(paths, Instant.parse(text)); } - public static Predicate greaterThanOrEqualTexts(Expression paths, CriteriaBuilder cb, List texts) { + public static Predicate greaterThanOrEqualTexts( + Expression paths, CriteriaBuilder cb, List texts) { if (isEmpty(texts)) { return cb.conjunction(); } - Predicate[] predicates = texts.stream() - .map(value -> greaterThanOrEqualText(paths, cb, value)) - .toArray(Predicate[]::new); + Predicate[] predicates = + texts.stream() + .map(value -> greaterThanOrEqualText(paths, cb, value)) + .toArray(Predicate[]::new); return cb.or(predicates); } - public static Predicate greaterThanOrEqualText(Expression paths, CriteriaBuilder cb, String text) { + public static Predicate greaterThanOrEqualText( + Expression paths, CriteriaBuilder cb, String text) { if (isEmpty(text)) { return cb.conjunction(); } @@ -242,14 +242,14 @@ public static Predicate greaterThanOrEqualText(Expression paths, Criter return cb.greaterThanOrEqualTo(paths, Instant.parse(text)); } - public static Predicate lessThanTexts(Expression paths, CriteriaBuilder cb, List texts) { + public static Predicate lessThanTexts( + Expression paths, CriteriaBuilder cb, List texts) { if (isEmpty(texts)) { return cb.conjunction(); } - Predicate[] predicates = texts.stream() - .map(value -> lessThanText(paths, cb, value)) - .toArray(Predicate[]::new); + Predicate[] predicates = + texts.stream().map(value -> lessThanText(paths, cb, value)).toArray(Predicate[]::new); return cb.or(predicates); } @@ -262,19 +262,22 @@ public static Predicate lessThanText(Expression paths, CriteriaBuilder return cb.lessThan(paths, Instant.parse(text)); } - public static Predicate lessThanOrEqualTexts(Expression paths, CriteriaBuilder cb, List texts) { + public static Predicate lessThanOrEqualTexts( + Expression paths, CriteriaBuilder cb, List texts) { if (isEmpty(texts)) { return cb.conjunction(); } - Predicate[] predicates = texts.stream() - .map(value -> lessThanOrEqualText(paths, cb, value)) - .toArray(Predicate[]::new); + Predicate[] predicates = + texts.stream() + .map(value -> lessThanOrEqualText(paths, cb, value)) + .toArray(Predicate[]::new); return cb.or(predicates); } - public static Predicate lessThanOrEqualText(Expression paths, CriteriaBuilder cb, String text) { + public static Predicate lessThanOrEqualText( + Expression paths, CriteriaBuilder cb, String text) { if (isEmpty(text)) { return cb.conjunction(); } @@ -284,29 +287,30 @@ public static Predicate lessThanOrEqualText(Expression paths, CriteriaB // -- CUSTOM FUNCTION -- - private static Expression lowerArray(Expression paths, CriteriaBuilder cb) { + private static Expression lowerArray(Expression paths, CriteriaBuilder cb) { return stringToArray(lower(arrayToString(paths, cb), cb), cb); } // -- BASE FUNCTION -- - private static Expression arrayPosition(Expression paths, CriteriaBuilder cb, Expression text) { + private static Expression arrayPosition( + Expression paths, CriteriaBuilder cb, Expression text) { return cb.function("array_position", Boolean.class, paths, text); } - private static Expression lower(Expression paths, CriteriaBuilder cb) { + private static Expression lower(Expression paths, CriteriaBuilder cb) { return cb.function("lower", String.class, paths); } - private static Expression stringToArray(Expression paths, CriteriaBuilder cb) { + private static Expression stringToArray(Expression paths, CriteriaBuilder cb) { return cb.function("string_to_array", String[].class, paths, cb.literal(" && ")); } - private static Expression arrayToString(Expression paths, CriteriaBuilder cb) { + private static Expression arrayToString(Expression paths, CriteriaBuilder cb) { return cb.function("array_to_string", String.class, paths, cb.literal(" && ")); } - private static Expression avals(Expression paths, CriteriaBuilder cb) { + private static Expression avals(Expression paths, CriteriaBuilder cb) { return cb.function("avals", String[].class, paths); } @@ -317,5 +321,4 @@ private static boolean isEmpty(List texts) { private static boolean isEmpty(String text) { return !hasText(text); } - } diff --git a/openbas-framework/src/main/java/io/openbas/utils/OperationUtilsRuntime.java b/openbas-framework/src/main/java/io/openbas/utils/OperationUtilsRuntime.java index a5870bd5bf..9d2bbc4f1f 100644 --- a/openbas-framework/src/main/java/io/openbas/utils/OperationUtilsRuntime.java +++ b/openbas-framework/src/main/java/io/openbas/utils/OperationUtilsRuntime.java @@ -2,14 +2,14 @@ import jakarta.validation.constraints.NotBlank; import jakarta.validation.constraints.NotNull; - import java.util.List; public class OperationUtilsRuntime { // -- NOT CONTAINS -- - public static boolean notContainsTexts(@NotNull final Object value, @NotNull final List texts) { + public static boolean notContainsTexts( + @NotNull final Object value, @NotNull final List texts) { return texts.stream().anyMatch(text -> notContainsText(value, text)); } @@ -19,7 +19,8 @@ public static boolean notContainsText(@NotNull final Object value, @NotBlank fin // -- CONTAINS -- - public static boolean containsTexts(@NotNull final Object value, @NotNull final List texts) { + public static boolean containsTexts( + @NotNull final Object value, @NotNull final List texts) { return texts.stream().anyMatch(text -> containsText(value, text)); } @@ -29,7 +30,8 @@ public static boolean containsText(@NotNull final Object value, @NotBlank final // -- NOT EQUALS -- - public static boolean notEqualsTexts(@NotNull final Object value, @NotNull final List texts) { + public static boolean notEqualsTexts( + @NotNull final Object value, @NotNull final List texts) { return texts.stream().anyMatch(text -> notEqualsText(value, text)); } @@ -39,7 +41,8 @@ public static boolean notEqualsText(@NotNull final Object value, @NotBlank final // -- EQUALS -- - public static boolean equalsTexts(@NotNull final Object value, @NotNull final List texts) { + public static boolean equalsTexts( + @NotNull final Object value, @NotNull final List texts) { return texts.stream().anyMatch(text -> equalsText(value, text)); } @@ -53,7 +56,8 @@ public static boolean equalsText(@NotNull final Object value, @NotBlank final St // -- NOT START WITH -- - public static boolean notStartWithTexts(@NotNull final Object value, @NotNull final List texts) { + public static boolean notStartWithTexts( + @NotNull final Object value, @NotNull final List texts) { return texts.stream().anyMatch(text -> notStartWithText(value, text)); } @@ -63,7 +67,8 @@ public static boolean notStartWithText(@NotNull final Object value, @NotBlank fi // -- START WITH -- - public static boolean startWithTexts(@NotNull final Object value, @NotNull final List texts) { + public static boolean startWithTexts( + @NotNull final Object value, @NotNull final List texts) { return texts.stream().anyMatch(text -> startWithText(value, text)); } diff --git a/openbas-framework/src/main/java/io/openbas/utils/StringUtils.java b/openbas-framework/src/main/java/io/openbas/utils/StringUtils.java index 743eb1fe4e..649ea5708b 100644 --- a/openbas-framework/src/main/java/io/openbas/utils/StringUtils.java +++ b/openbas-framework/src/main/java/io/openbas/utils/StringUtils.java @@ -4,9 +4,7 @@ public class StringUtils { - private StringUtils() { - - } + private StringUtils() {} public static final int MAX_SIZE_OF_STRING = 255; @@ -18,6 +16,7 @@ public static String duplicateString(@NotBlank final String originName) { return newName; } - public static String getName(String firstName, String lastName) { return firstName + " " + lastName; } - + public static String getName(String firstName, String lastName) { + return firstName + " " + lastName; + } } diff --git a/openbas-framework/src/main/java/io/openbas/utils/SubclassScanner.java b/openbas-framework/src/main/java/io/openbas/utils/SubclassScanner.java index 8ce1ad500a..f9acec9f6b 100644 --- a/openbas-framework/src/main/java/io/openbas/utils/SubclassScanner.java +++ b/openbas-framework/src/main/java/io/openbas/utils/SubclassScanner.java @@ -1,23 +1,24 @@ package io.openbas.utils; -import org.springframework.context.annotation.ClassPathScanningCandidateComponentProvider; -import org.springframework.core.type.filter.AssignableTypeFilter; - import java.util.Set; import java.util.stream.Collectors; +import org.springframework.context.annotation.ClassPathScanningCandidateComponentProvider; +import org.springframework.core.type.filter.AssignableTypeFilter; public class SubclassScanner { - public static Set> getSubclasses(String basePackage, Class clazz) { - ClassPathScanningCandidateComponentProvider provider = new ClassPathScanningCandidateComponentProvider(false); - provider.addIncludeFilter(new AssignableTypeFilter(clazz)); - return provider.findCandidateComponents(basePackage).stream() - .map(beanDefinition -> { - try { - return Class.forName(beanDefinition.getBeanClassName()); - } catch (ClassNotFoundException e) { - return null; - } + public static Set> getSubclasses(String basePackage, Class clazz) { + ClassPathScanningCandidateComponentProvider provider = + new ClassPathScanningCandidateComponentProvider(false); + provider.addIncludeFilter(new AssignableTypeFilter(clazz)); + return provider.findCandidateComponents(basePackage).stream() + .map( + beanDefinition -> { + try { + return Class.forName(beanDefinition.getBeanClassName()); + } catch (ClassNotFoundException e) { + return null; + } }) - .collect(Collectors.toSet()); - } + .collect(Collectors.toSet()); + } } diff --git a/openbas-framework/src/main/java/io/openbas/utils/schema/PropertySchema.java b/openbas-framework/src/main/java/io/openbas/utils/schema/PropertySchema.java index 54579f58ab..e1637aa792 100644 --- a/openbas-framework/src/main/java/io/openbas/utils/schema/PropertySchema.java +++ b/openbas-framework/src/main/java/io/openbas/utils/schema/PropertySchema.java @@ -1,29 +1,26 @@ package io.openbas.utils.schema; +import static lombok.AccessLevel.NONE; +import static org.springframework.util.StringUtils.hasText; + import jakarta.validation.constraints.NotBlank; import jakarta.validation.constraints.NotNull; +import java.util.List; +import java.util.Optional; import lombok.Builder; import lombok.Getter; import lombok.Singular; -import java.util.List; -import java.util.Optional; - -import static lombok.AccessLevel.NONE; -import static org.springframework.util.StringUtils.hasText; - @Builder @Getter public class PropertySchema { - @NotBlank - private final String name; + @NotBlank private final String name; @Getter(NONE) private final String jsonName; - @NotNull - private final Class type; + @NotNull private final Class type; private final boolean unicity; private final boolean mandatory; @@ -70,5 +67,4 @@ public PropertySchema build() { return super.build(); } } - } diff --git a/openbas-framework/src/main/java/io/openbas/utils/schema/SchemaUtils.java b/openbas-framework/src/main/java/io/openbas/utils/schema/SchemaUtils.java index fe8e2c8e0b..2e2fbbb9f8 100644 --- a/openbas-framework/src/main/java/io/openbas/utils/schema/SchemaUtils.java +++ b/openbas-framework/src/main/java/io/openbas/utils/schema/SchemaUtils.java @@ -1,5 +1,7 @@ package io.openbas.utils.schema; +import static org.springframework.util.StringUtils.hasText; + import com.fasterxml.jackson.annotation.JsonProperty; import io.openbas.annotation.Queryable; import io.openbas.utils.SubclassScanner; @@ -8,7 +10,6 @@ import jakarta.validation.constraints.Email; import jakarta.validation.constraints.NotBlank; import jakarta.validation.constraints.NotNull; - import java.lang.annotation.Annotation; import java.lang.reflect.Field; import java.lang.reflect.Method; @@ -18,41 +19,38 @@ import java.util.concurrent.ConcurrentHashMap; import java.util.stream.Collectors; -import static org.springframework.util.StringUtils.hasText; - public class SchemaUtils { - private SchemaUtils() { - - } + private SchemaUtils() {} - private static final List> REQUIRED_ANNOTATIONS = List.of( - NotNull.class, - NotBlank.class, - Email.class - ); + private static final List> REQUIRED_ANNOTATIONS = + List.of(NotNull.class, NotBlank.class, Email.class); private static final String BASE_CLASS_PACKAGE = "io.openbas.database.model"; - private static final ConcurrentHashMap, List> cacheMap = new ConcurrentHashMap<>(); + private static final ConcurrentHashMap, List> cacheMap = + new ConcurrentHashMap<>(); // -- SCHEMA -- - public static List schemaWithSubtypes(@NotNull Class clazz) throws ClassNotFoundException { + public static List schemaWithSubtypes(@NotNull Class clazz) + throws ClassNotFoundException { List> propertySchemasAll = new ArrayList<>(); propertySchemasAll.add(schema(clazz)); - propertySchemasAll - .addAll(SubclassScanner.getSubclasses(BASE_CLASS_PACKAGE, clazz) - .stream() - .map(SchemaUtils::schema) - .toList()); - - return propertySchemasAll.stream().flatMap(List::stream) - .collect(Collectors.toMap( - PropertySchema::getName, - propertySchema -> propertySchema, - (existing, replacement) -> existing - )) - .values().stream().toList(); + propertySchemasAll.addAll( + SubclassScanner.getSubclasses(BASE_CLASS_PACKAGE, clazz).stream() + .map(SchemaUtils::schema) + .toList()); + + return propertySchemasAll.stream() + .flatMap(List::stream) + .collect( + Collectors.toMap( + PropertySchema::getName, + propertySchema -> propertySchema, + (existing, replacement) -> existing)) + .values() + .stream() + .toList(); } public static List schema(@NotNull Class clazz) { @@ -80,14 +78,18 @@ private static List computeProperties(@NotNull Field[] fields) { } private static PropertySchema buildPropertySchemaFromField(Field field) { - PropertySchema.PropertySchemaBuilder builder = PropertySchema.builder() - .name(field.getName()) - .type(field.getType()) - .multiple(field.getType().isArray() || Collection.class.isAssignableFrom(field.getType())); - - if (field.getType().isEnum() || (field.getType().isArray() && field.getType().getComponentType().isEnum())) { + PropertySchema.PropertySchemaBuilder builder = + PropertySchema.builder() + .name(field.getName()) + .type(field.getType()) + .multiple( + field.getType().isArray() || Collection.class.isAssignableFrom(field.getType())); + + if (field.getType().isEnum() + || (field.getType().isArray() && field.getType().getComponentType().isEnum())) { builder.availableValues( - getEnumNames(field.getType().isArray() ? field.getType().getComponentType() : field.getType())); + getEnumNames( + field.getType().isArray() ? field.getType().getComponentType() : field.getType())); } for (Annotation annotation : field.getDeclaredAnnotations()) { @@ -106,19 +108,24 @@ private static List computeMethods(@NotNull Method[] methods) { } private static PropertySchema buildPropertySchemaFromMethod(Method method) { - PropertySchema.PropertySchemaBuilder builder = PropertySchema.builder() - .name(method.getName()) - .type(method.getReturnType()) - .multiple(method.getReturnType().isArray() || Collection.class.isAssignableFrom(method.getReturnType())); + PropertySchema.PropertySchemaBuilder builder = + PropertySchema.builder() + .name(method.getName()) + .type(method.getReturnType()) + .multiple( + method.getReturnType().isArray() + || Collection.class.isAssignableFrom(method.getReturnType())); if (method.getReturnType().isEnum()) { builder.availableValues(getEnumNames(method.getReturnType())); - } else if (method.getReturnType().isArray() || method.getGenericReturnType() instanceof ParameterizedType) { + } else if (method.getReturnType().isArray() + || method.getGenericReturnType() instanceof ParameterizedType) { Class enumType = null; if (method.getReturnType().isArray()) { enumType = method.getReturnType().getComponentType(); } else { - Type typeArgument = ((ParameterizedType) method.getGenericReturnType()).getActualTypeArguments()[0]; + Type typeArgument = + ((ParameterizedType) method.getGenericReturnType()).getActualTypeArguments()[0]; if (typeArgument instanceof Class) { enumType = (Class) typeArgument; } @@ -153,11 +160,13 @@ private static void processAnnotations( } else if (REQUIRED_ANNOTATIONS.contains(annotation.annotationType())) { builder.mandatory(true); } else if (annotation.annotationType().equals(Queryable.class)) { - Queryable queryable = member instanceof Field - ? ((Field) member).getAnnotation(Queryable.class) - : ((Method) member).getAnnotation(Queryable.class); + Queryable queryable = + member instanceof Field + ? ((Field) member).getAnnotation(Queryable.class) + : ((Method) member).getAnnotation(Queryable.class); if (queryable != null) { - builder.searchable(queryable.searchable()) + builder + .searchable(queryable.searchable()) .filterable(queryable.filterable()) .dynamicValues(queryable.dynamicValues()) .sortable(queryable.sortable()) @@ -169,11 +178,13 @@ private static void processAnnotations( } } } else if (annotation.annotationType().equals(JoinTable.class)) { - builder.joinTable(PropertySchema.JoinTable.builder().joinOn(((Field) member).getName()).build()); + builder.joinTable( + PropertySchema.JoinTable.builder().joinOn(((Field) member).getName()).build()); } } - public static PropertySchema retrieveProperty(List propertySchemas, String jsonFieldPath) { + public static PropertySchema retrieveProperty( + List propertySchemas, String jsonFieldPath) { if (jsonFieldPath.contains("\\.")) { throw new IllegalArgumentException("Deep path is not allowed"); } @@ -182,15 +193,21 @@ public static PropertySchema retrieveProperty(List propertySchem .filter(p -> jsonFieldPath.equals(p.getJsonName())) .findFirst() .orElseThrow( - () -> new IllegalArgumentException("This path is not handled by Queryable annotation: " + jsonFieldPath)); + () -> + new IllegalArgumentException( + "This path is not handled by Queryable annotation: " + jsonFieldPath)); } public static List getSearchableProperties(List propertySchemas) { - return propertySchemas.stream().filter(PropertySchema::isSearchable).collect(Collectors.toList()); + return propertySchemas.stream() + .filter(PropertySchema::isSearchable) + .collect(Collectors.toList()); } public static List getFilterableProperties(List propertySchemas) { - return propertySchemas.stream().filter(PropertySchema::isFilterable).collect(Collectors.toList()); + return propertySchemas.stream() + .filter(PropertySchema::isFilterable) + .collect(Collectors.toList()); } public static List getSortableProperties(List propertySchemas) { diff --git a/openbas-framework/src/test/java/io/openbas/App.java b/openbas-framework/src/test/java/io/openbas/App.java index 0c2aa134c9..b15244996f 100644 --- a/openbas-framework/src/test/java/io/openbas/App.java +++ b/openbas-framework/src/test/java/io/openbas/App.java @@ -6,7 +6,7 @@ @SpringBootApplication public class App { - public static void main(String[] args) { - SpringApplication.run(App.class, args); - } + public static void main(String[] args) { + SpringApplication.run(App.class, args); + } } diff --git a/openbas-model/src/main/java/io/openbas/annotation/Ipv4OrIpv6Constraint.java b/openbas-model/src/main/java/io/openbas/annotation/Ipv4OrIpv6Constraint.java index e92ffa1892..74b313c4a3 100644 --- a/openbas-model/src/main/java/io/openbas/annotation/Ipv4OrIpv6Constraint.java +++ b/openbas-model/src/main/java/io/openbas/annotation/Ipv4OrIpv6Constraint.java @@ -1,24 +1,23 @@ package io.openbas.annotation; -import io.openbas.validator.Ipv4OrIpv6Validator; +import static java.lang.annotation.ElementType.FIELD; +import static java.lang.annotation.RetentionPolicy.RUNTIME; +import io.openbas.validator.Ipv4OrIpv6Validator; import jakarta.validation.Constraint; import jakarta.validation.Payload; import jakarta.validation.ReportAsSingleViolation; import java.lang.annotation.Retention; import java.lang.annotation.Target; -import static java.lang.annotation.ElementType.FIELD; -import static java.lang.annotation.RetentionPolicy.RUNTIME; - @Target(FIELD) @Retention(RUNTIME) @Constraint(validatedBy = Ipv4OrIpv6Validator.class) @ReportAsSingleViolation public @interface Ipv4OrIpv6Constraint { - String message() default "must be ipv4 or ipv6"; + String message() default "must be ipv4 or ipv6"; - Class[] groups() default {}; + Class[] groups() default {}; - Class[] payload() default {}; + Class[] payload() default {}; } diff --git a/openbas-model/src/main/java/io/openbas/annotation/Queryable.java b/openbas-model/src/main/java/io/openbas/annotation/Queryable.java index dd65dadd1d..132f60db09 100644 --- a/openbas-model/src/main/java/io/openbas/annotation/Queryable.java +++ b/openbas-model/src/main/java/io/openbas/annotation/Queryable.java @@ -9,10 +9,14 @@ @Target({ElementType.FIELD, ElementType.METHOD}) public @interface Queryable { boolean searchable() default false; + boolean filterable() default false; + boolean dynamicValues() default false; + boolean sortable() default false; String path() default ""; + Class clazz() default String.class; } diff --git a/openbas-model/src/main/java/io/openbas/config/MinioConfig.java b/openbas-model/src/main/java/io/openbas/config/MinioConfig.java index 944f18235a..aee01c4c06 100644 --- a/openbas-model/src/main/java/io/openbas/config/MinioConfig.java +++ b/openbas-model/src/main/java/io/openbas/config/MinioConfig.java @@ -1,72 +1,68 @@ package io.openbas.config; +import jakarta.validation.constraints.NotNull; import org.springframework.boot.context.properties.ConfigurationProperties; import org.springframework.stereotype.Component; -import jakarta.validation.constraints.NotNull; - @Component @ConfigurationProperties(prefix = "minio") public class MinioConfig { - @NotNull - private String endpoint; + @NotNull private String endpoint; - @NotNull - private String accessKey; + @NotNull private String accessKey; - @NotNull - private String accessSecret; + @NotNull private String accessSecret; - private int port = 9000; - private String bucket = "openbas"; - private boolean secure = false; + private int port = 9000; + private String bucket = "openbas"; + private boolean secure = false; - public String getAccessKey() { - return accessKey; - } + public String getAccessKey() { + return accessKey; + } - public void setAccessKey(String accessKey) { - this.accessKey = accessKey; - } + public void setAccessKey(String accessKey) { + this.accessKey = accessKey; + } - public String getAccessSecret() { - return accessSecret; - } + public String getAccessSecret() { + return accessSecret; + } - public void setAccessSecret(String accessSecret) { - this.accessSecret = accessSecret; - } + public void setAccessSecret(String accessSecret) { + this.accessSecret = accessSecret; + } - public String getEndpoint() { - return endpoint; - } + public String getEndpoint() { + return endpoint; + } - public void setEndpoint(String endpoint) { - this.endpoint = endpoint; - } + public void setEndpoint(String endpoint) { + this.endpoint = endpoint; + } - public String getBucket() { - return bucket; - } + public String getBucket() { + return bucket; + } - public void setBucket(String bucket) { - this.bucket = bucket; - } + public void setBucket(String bucket) { + this.bucket = bucket; + } - public int getPort() { - return port; - } + public int getPort() { + return port; + } - public void setPort(int port) { - this.port = port; - } + public void setPort(int port) { + this.port = port; + } - public boolean isSecure() { - return secure; - } + public boolean isSecure() { + return secure; + } - public void setSecure(boolean secure) { - this.secure = secure; - } + public void setSecure(boolean secure) { + this.secure = secure; + } } diff --git a/openbas-model/src/main/java/io/openbas/database/audit/BaseEvent.java b/openbas-model/src/main/java/io/openbas/database/audit/BaseEvent.java index 7f6c3edd73..2b8d0039e1 100644 --- a/openbas-model/src/main/java/io/openbas/database/audit/BaseEvent.java +++ b/openbas-model/src/main/java/io/openbas/database/audit/BaseEvent.java @@ -6,77 +6,79 @@ import com.fasterxml.jackson.databind.ObjectMapper; import io.openbas.database.model.Base; import jakarta.persistence.Id; +import java.lang.reflect.Field; import lombok.Getter; import org.springframework.web.context.request.RequestAttributes; import org.springframework.web.context.request.RequestContextHolder; -import java.lang.reflect.Field; - @Getter public class BaseEvent implements Cloneable { - @JsonIgnore - private final String sessionId; - @JsonIgnore - private final Base instance; - @JsonProperty("event_type") - private String type; - @JsonProperty("attribute_id") - private String attributeId; - @JsonProperty("attribute_schema") - private String schema; - @JsonProperty("instance") - private JsonNode instanceData; - @JsonProperty("listened") - private boolean listened; + @JsonIgnore private final String sessionId; + @JsonIgnore private final Base instance; - public BaseEvent(String type, Base data, ObjectMapper mapper) { - this.type = type; - this.instance = data; - this.instanceData = mapper.valueToTree(instance); - this.listened = data.isListened(); - RequestAttributes requestAttributes = RequestContextHolder.getRequestAttributes(); - this.sessionId = requestAttributes != null ? requestAttributes.getSessionId() : null; - Class currentClass = data.getClass(); - boolean isTargetClass = currentClass.getSuperclass().equals(Object.class); - Class baseClass = isTargetClass ? currentClass : currentClass.getSuperclass(); - String className = baseClass.getSimpleName().toLowerCase(); - Field[] fields = baseClass.getDeclaredFields(); - for (Field field : fields) { - if (field.isAnnotationPresent(Id.class)) { - this.attributeId = field.getAnnotation(JsonProperty.class).value(); - } - } - this.schema = className + (className.endsWith("s") ? "es" : "s"); - } + @JsonProperty("event_type") + private String type; - public void setType(String type) { - this.type = type; - } + @JsonProperty("attribute_id") + private String attributeId; - public void setAttributeId(String attributeId) { - this.attributeId = attributeId; - } + @JsonProperty("attribute_schema") + private String schema; - public void setSchema(String schema) { - this.schema = schema; - } + @JsonProperty("instance") + private JsonNode instanceData; - public void setInstanceData(JsonNode instanceData) { - this.instanceData = instanceData; - } + @JsonProperty("listened") + private boolean listened; - @JsonIgnore - public boolean isUserObserver(final boolean isAdmin) { - return this.instance.isUserHasAccess(isAdmin); + public BaseEvent(String type, Base data, ObjectMapper mapper) { + this.type = type; + this.instance = data; + this.instanceData = mapper.valueToTree(instance); + this.listened = data.isListened(); + RequestAttributes requestAttributes = RequestContextHolder.getRequestAttributes(); + this.sessionId = requestAttributes != null ? requestAttributes.getSessionId() : null; + Class currentClass = data.getClass(); + boolean isTargetClass = currentClass.getSuperclass().equals(Object.class); + Class baseClass = isTargetClass ? currentClass : currentClass.getSuperclass(); + String className = baseClass.getSimpleName().toLowerCase(); + Field[] fields = baseClass.getDeclaredFields(); + for (Field field : fields) { + if (field.isAnnotationPresent(Id.class)) { + this.attributeId = field.getAnnotation(JsonProperty.class).value(); + } } + this.schema = className + (className.endsWith("s") ? "es" : "s"); + } + + public void setType(String type) { + this.type = type; + } + + public void setAttributeId(String attributeId) { + this.attributeId = attributeId; + } + + public void setSchema(String schema) { + this.schema = schema; + } + + public void setInstanceData(JsonNode instanceData) { + this.instanceData = instanceData; + } + + @JsonIgnore + public boolean isUserObserver(final boolean isAdmin) { + return this.instance.isUserHasAccess(isAdmin); + } - @Override - public BaseEvent clone() { - try { - return (BaseEvent) super.clone(); - } catch (CloneNotSupportedException e) { - throw new AssertionError(); - } + @Override + public BaseEvent clone() { + try { + return (BaseEvent) super.clone(); + } catch (CloneNotSupportedException e) { + throw new AssertionError(); } + } } diff --git a/openbas-model/src/main/java/io/openbas/database/audit/ModelBaseListener.java b/openbas-model/src/main/java/io/openbas/database/audit/ModelBaseListener.java index cce12a11e4..54afdb400b 100644 --- a/openbas-model/src/main/java/io/openbas/database/audit/ModelBaseListener.java +++ b/openbas-model/src/main/java/io/openbas/database/audit/ModelBaseListener.java @@ -13,37 +13,36 @@ @Component public class ModelBaseListener { - public static final String DATA_PERSIST = "DATA_FETCH_SUCCESS"; - public static final String DATA_UPDATE = "DATA_UPDATE_SUCCESS"; - public static final String DATA_DELETE = "DATA_DELETE_SUCCESS"; - - @Resource - protected ObjectMapper mapper; - - private ApplicationEventPublisher appPublisher; - - @Autowired - public void setApplicationEventPublisher(ApplicationEventPublisher applicationEventPublisher) { - this.appPublisher = applicationEventPublisher; - } - - @PostPersist - void postPersist(Object base) { - Base instance = (Base) base; - BaseEvent event = new BaseEvent(DATA_PERSIST, instance, mapper); - appPublisher.publishEvent(event); - } - - @PostUpdate - void postUpdate(Object base) { - Base instance = (Base) base; - BaseEvent event = new BaseEvent(DATA_UPDATE, instance, mapper); - appPublisher.publishEvent(event); - } - - @PreRemove - void preRemove(Object base) { - Base instance = (Base) base; - appPublisher.publishEvent(new BaseEvent(DATA_DELETE, instance, mapper)); - } + public static final String DATA_PERSIST = "DATA_FETCH_SUCCESS"; + public static final String DATA_UPDATE = "DATA_UPDATE_SUCCESS"; + public static final String DATA_DELETE = "DATA_DELETE_SUCCESS"; + + @Resource protected ObjectMapper mapper; + + private ApplicationEventPublisher appPublisher; + + @Autowired + public void setApplicationEventPublisher(ApplicationEventPublisher applicationEventPublisher) { + this.appPublisher = applicationEventPublisher; + } + + @PostPersist + void postPersist(Object base) { + Base instance = (Base) base; + BaseEvent event = new BaseEvent(DATA_PERSIST, instance, mapper); + appPublisher.publishEvent(event); + } + + @PostUpdate + void postUpdate(Object base) { + Base instance = (Base) base; + BaseEvent event = new BaseEvent(DATA_UPDATE, instance, mapper); + appPublisher.publishEvent(event); + } + + @PreRemove + void preRemove(Object base) { + Base instance = (Base) base; + appPublisher.publishEvent(new BaseEvent(DATA_DELETE, instance, mapper)); + } } diff --git a/openbas-model/src/main/java/io/openbas/database/converter/ContentConverter.java b/openbas-model/src/main/java/io/openbas/database/converter/ContentConverter.java index d0c1521115..4efd807ab8 100644 --- a/openbas-model/src/main/java/io/openbas/database/converter/ContentConverter.java +++ b/openbas-model/src/main/java/io/openbas/database/converter/ContentConverter.java @@ -3,7 +3,6 @@ import com.fasterxml.jackson.core.JsonProcessingException; import com.fasterxml.jackson.databind.ObjectMapper; import com.fasterxml.jackson.databind.node.ObjectNode; - import jakarta.annotation.Resource; import jakarta.persistence.AttributeConverter; import jakarta.persistence.Converter; @@ -12,30 +11,28 @@ @Converter public class ContentConverter implements AttributeConverter { - @Resource - private ObjectMapper mapper; + @Resource private ObjectMapper mapper; - @Override - public String convertToDatabaseColumn(ObjectNode meta) { - try { - return mapper.writeValueAsString(meta); - } catch (JsonProcessingException ex) { - return null; - // or throw an error - } + @Override + public String convertToDatabaseColumn(ObjectNode meta) { + try { + return mapper.writeValueAsString(meta); + } catch (JsonProcessingException ex) { + return null; + // or throw an error } + } - @Override - public ObjectNode convertToEntityAttribute(String dbData) { - try { - if(dbData == null) { - return null; - } - return mapper.readValue(dbData, ObjectNode.class); - } catch (IOException ex) { - // logger.error("Unexpected IOEx decoding json from database: " + dbData); - return null; - } + @Override + public ObjectNode convertToEntityAttribute(String dbData) { + try { + if (dbData == null) { + return null; + } + return mapper.readValue(dbData, ObjectNode.class); + } catch (IOException ex) { + // logger.error("Unexpected IOEx decoding json from database: " + dbData); + return null; } - + } } diff --git a/openbas-model/src/main/java/io/openbas/database/converter/ExecutionConverter.java b/openbas-model/src/main/java/io/openbas/database/converter/ExecutionConverter.java index bfb299756b..8422bf3d7b 100644 --- a/openbas-model/src/main/java/io/openbas/database/converter/ExecutionConverter.java +++ b/openbas-model/src/main/java/io/openbas/database/converter/ExecutionConverter.java @@ -3,7 +3,6 @@ import com.fasterxml.jackson.core.JsonProcessingException; import com.fasterxml.jackson.databind.ObjectMapper; import io.openbas.database.model.Execution; - import jakarta.annotation.Resource; import jakarta.persistence.AttributeConverter; import jakarta.persistence.Converter; @@ -12,30 +11,28 @@ @Converter(autoApply = true) public class ExecutionConverter implements AttributeConverter { - @Resource - private ObjectMapper mapper; + @Resource private ObjectMapper mapper; - @Override - public String convertToDatabaseColumn(Execution meta) { - try { - return mapper.writeValueAsString(meta); - } catch (JsonProcessingException ex) { - return null; - // or throw an error - } + @Override + public String convertToDatabaseColumn(Execution meta) { + try { + return mapper.writeValueAsString(meta); + } catch (JsonProcessingException ex) { + return null; + // or throw an error } + } - @Override - public Execution convertToEntityAttribute(String dbData) { - if (dbData == null) { - return null; - } - try { - return mapper.readValue(dbData, Execution.class); - } catch (IOException ex) { - // logger.error("Unexpected IOEx decoding json from database: " + dbData); - return null; - } + @Override + public Execution convertToEntityAttribute(String dbData) { + if (dbData == null) { + return null; } - + try { + return mapper.readValue(dbData, Execution.class); + } catch (IOException ex) { + // logger.error("Unexpected IOEx decoding json from database: " + dbData); + return null; + } + } } diff --git a/openbas-model/src/main/java/io/openbas/database/converter/InjectStatusCommandLineConverter.java b/openbas-model/src/main/java/io/openbas/database/converter/InjectStatusCommandLineConverter.java index f8f55efb9b..ba404cacfc 100644 --- a/openbas-model/src/main/java/io/openbas/database/converter/InjectStatusCommandLineConverter.java +++ b/openbas-model/src/main/java/io/openbas/database/converter/InjectStatusCommandLineConverter.java @@ -6,36 +6,34 @@ import jakarta.annotation.Resource; import jakarta.persistence.AttributeConverter; import jakarta.persistence.Converter; - import java.io.IOException; @Converter(autoApply = true) -public class InjectStatusCommandLineConverter implements AttributeConverter { +public class InjectStatusCommandLineConverter + implements AttributeConverter { - @Resource - private ObjectMapper mapper; + @Resource private ObjectMapper mapper; - @Override - public String convertToDatabaseColumn(InjectStatusCommandLine meta) { - try { - return mapper.writeValueAsString(meta); - } catch (JsonProcessingException ex) { - return null; - // or throw an error - } + @Override + public String convertToDatabaseColumn(InjectStatusCommandLine meta) { + try { + return mapper.writeValueAsString(meta); + } catch (JsonProcessingException ex) { + return null; + // or throw an error } + } - @Override - public InjectStatusCommandLine convertToEntityAttribute(String dbData) { - if (dbData == null) { - return null; - } - try { - return mapper.readValue(dbData, InjectStatusCommandLine.class); - } catch (IOException ex) { - // logger.error("Unexpected IOEx decoding json from database: " + dbData); - return null; - } + @Override + public InjectStatusCommandLine convertToEntityAttribute(String dbData) { + if (dbData == null) { + return null; } - -} \ No newline at end of file + try { + return mapper.readValue(dbData, InjectStatusCommandLine.class); + } catch (IOException ex) { + // logger.error("Unexpected IOEx decoding json from database: " + dbData); + return null; + } + } +} diff --git a/openbas-model/src/main/java/io/openbas/database/converter/InjectStatusExecutionConverter.java b/openbas-model/src/main/java/io/openbas/database/converter/InjectStatusExecutionConverter.java index de3725d714..724ec4b0fb 100644 --- a/openbas-model/src/main/java/io/openbas/database/converter/InjectStatusExecutionConverter.java +++ b/openbas-model/src/main/java/io/openbas/database/converter/InjectStatusExecutionConverter.java @@ -6,38 +6,38 @@ import jakarta.annotation.Resource; import jakarta.persistence.AttributeConverter; import jakarta.persistence.Converter; - import java.io.IOException; import java.util.ArrayList; import java.util.List; @Converter(autoApply = true) -public class InjectStatusExecutionConverter implements AttributeConverter, String> { +public class InjectStatusExecutionConverter + implements AttributeConverter, String> { - @Resource - private ObjectMapper mapper; + @Resource private ObjectMapper mapper; - @Override - public String convertToDatabaseColumn(List meta) { - try { - return mapper.writeValueAsString(meta); - } catch (JsonProcessingException ex) { - return null; - // or throw an error - } + @Override + public String convertToDatabaseColumn(List meta) { + try { + return mapper.writeValueAsString(meta); + } catch (JsonProcessingException ex) { + return null; + // or throw an error } + } - @Override - public List convertToEntityAttribute(String dbData) { - if (dbData == null) { - return new ArrayList<>(); - } - try { - return mapper.readValue(dbData, mapper.getTypeFactory().constructCollectionType(List.class, InjectStatusExecution.class)); - } catch (IOException ex) { - // logger.error("Unexpected IOEx decoding json from database: " + dbData); - return new ArrayList<>(); - } + @Override + public List convertToEntityAttribute(String dbData) { + if (dbData == null) { + return new ArrayList<>(); } - -} \ No newline at end of file + try { + return mapper.readValue( + dbData, + mapper.getTypeFactory().constructCollectionType(List.class, InjectStatusExecution.class)); + } catch (IOException ex) { + // logger.error("Unexpected IOEx decoding json from database: " + dbData); + return new ArrayList<>(); + } + } +} diff --git a/openbas-model/src/main/java/io/openbas/database/criteria/GenericCriteria.java b/openbas-model/src/main/java/io/openbas/database/criteria/GenericCriteria.java index 0c5c98dd82..d9501757b4 100644 --- a/openbas-model/src/main/java/io/openbas/database/criteria/GenericCriteria.java +++ b/openbas-model/src/main/java/io/openbas/database/criteria/GenericCriteria.java @@ -10,9 +10,7 @@ public class GenericCriteria { - private GenericCriteria() { - - } + private GenericCriteria() {} public static Long countQuery( @NotNull final CriteriaBuilder cb, @@ -30,5 +28,4 @@ public static Long countQuery( } return entityManager.createQuery(countQuery).getSingleResult(); } - } diff --git a/openbas-model/src/main/java/io/openbas/database/model/Article.java b/openbas-model/src/main/java/io/openbas/database/model/Article.java index 8eb1e44745..669b9003f9 100644 --- a/openbas-model/src/main/java/io/openbas/database/model/Article.java +++ b/openbas-model/src/main/java/io/openbas/database/model/Article.java @@ -1,25 +1,23 @@ package io.openbas.database.model; +import static java.time.Instant.now; + import com.fasterxml.jackson.annotation.JsonIgnore; import com.fasterxml.jackson.annotation.JsonProperty; import com.fasterxml.jackson.databind.annotation.JsonSerialize; import io.openbas.database.audit.ModelBaseListener; import io.openbas.helper.MonoIdDeserializer; import io.openbas.helper.MultiIdListDeserializer; +import jakarta.persistence.*; import jakarta.validation.constraints.NotBlank; import jakarta.validation.constraints.NotNull; -import lombok.Getter; -import lombok.Setter; -import org.hibernate.annotations.UuidGenerator; - -import jakarta.persistence.*; - import java.time.Instant; import java.util.ArrayList; import java.util.List; import java.util.Objects; - -import static java.time.Instant.now; +import lombok.Getter; +import lombok.Setter; +import org.hibernate.annotations.UuidGenerator; @Getter @Setter @@ -28,104 +26,104 @@ @EntityListeners(ModelBaseListener.class) public class Article implements Base { - @Id - @Column(name = "article_id") - @GeneratedValue(generator = "UUID") - @UuidGenerator - @JsonProperty("article_id") - @NotBlank - private String id; - - @Column(name = "article_created_at") - @JsonProperty("article_created_at") - @NotNull - private Instant createdAt = now(); - - @Column(name = "article_updated_at") - @JsonProperty("article_updated_at") - @NotNull - private Instant updatedAt = now(); - - @Column(name = "article_name") - @JsonProperty("article_name") - private String name; - - @Column(name = "article_content") - @JsonProperty("article_content") - private String content; - - @Column(name = "article_author") - @JsonProperty("article_author") - private String author; - - @Column(name = "article_shares") - @JsonProperty("article_shares") - private Integer shares; - - @Column(name = "article_likes") - @JsonProperty("article_likes") - private Integer likes; - - @Column(name = "article_comments") - @JsonProperty("article_comments") - private Integer comments; - - @ManyToOne(fetch = FetchType.LAZY) - @JoinColumn(name = "article_exercise") - @JsonSerialize(using = MonoIdDeserializer.class) - @JsonProperty("article_exercise") - private Exercise exercise; - - @ManyToOne(fetch = FetchType.LAZY) - @JoinColumn(name = "article_scenario") - @JsonSerialize(using = MonoIdDeserializer.class) - @JsonProperty("article_scenario") - private Scenario scenario; - - @ManyToOne(fetch = FetchType.LAZY) - @JoinColumn(name = "article_channel") - @JsonSerialize(using = MonoIdDeserializer.class) - @JsonProperty("article_channel") - @NotNull - private Channel channel; - - @ManyToMany(fetch = FetchType.LAZY) - @JoinTable(name = "articles_documents", - joinColumns = @JoinColumn(name = "article_id"), - inverseJoinColumns = @JoinColumn(name = "document_id")) - @JsonSerialize(using = MultiIdListDeserializer.class) - @JsonProperty("article_documents") - private List documents = new ArrayList<>(); - - @JsonIgnore - @Override - public boolean isUserHasAccess(User user) { - return getExercise().isUserHasAccess(user); - } - - @Transient - private Instant virtualPublication; - - @JsonProperty("article_virtual_publication") - public Instant getVirtualPublication() { - return virtualPublication; - } - - @JsonProperty("article_is_scheduled") - public boolean isScheduledPublication() { - return virtualPublication != null; - } - - @Override - public boolean equals(Object o) { - if (this == o) return true; - if (o == null || !Base.class.isAssignableFrom(o.getClass())) return false; - Base base = (Base) o; - return id.equals(base.getId()); - } - - @Override - public int hashCode() { - return Objects.hash(id); - } + @Id + @Column(name = "article_id") + @GeneratedValue(generator = "UUID") + @UuidGenerator + @JsonProperty("article_id") + @NotBlank + private String id; + + @Column(name = "article_created_at") + @JsonProperty("article_created_at") + @NotNull + private Instant createdAt = now(); + + @Column(name = "article_updated_at") + @JsonProperty("article_updated_at") + @NotNull + private Instant updatedAt = now(); + + @Column(name = "article_name") + @JsonProperty("article_name") + private String name; + + @Column(name = "article_content") + @JsonProperty("article_content") + private String content; + + @Column(name = "article_author") + @JsonProperty("article_author") + private String author; + + @Column(name = "article_shares") + @JsonProperty("article_shares") + private Integer shares; + + @Column(name = "article_likes") + @JsonProperty("article_likes") + private Integer likes; + + @Column(name = "article_comments") + @JsonProperty("article_comments") + private Integer comments; + + @ManyToOne(fetch = FetchType.LAZY) + @JoinColumn(name = "article_exercise") + @JsonSerialize(using = MonoIdDeserializer.class) + @JsonProperty("article_exercise") + private Exercise exercise; + + @ManyToOne(fetch = FetchType.LAZY) + @JoinColumn(name = "article_scenario") + @JsonSerialize(using = MonoIdDeserializer.class) + @JsonProperty("article_scenario") + private Scenario scenario; + + @ManyToOne(fetch = FetchType.LAZY) + @JoinColumn(name = "article_channel") + @JsonSerialize(using = MonoIdDeserializer.class) + @JsonProperty("article_channel") + @NotNull + private Channel channel; + + @ManyToMany(fetch = FetchType.LAZY) + @JoinTable( + name = "articles_documents", + joinColumns = @JoinColumn(name = "article_id"), + inverseJoinColumns = @JoinColumn(name = "document_id")) + @JsonSerialize(using = MultiIdListDeserializer.class) + @JsonProperty("article_documents") + private List documents = new ArrayList<>(); + + @JsonIgnore + @Override + public boolean isUserHasAccess(User user) { + return getExercise().isUserHasAccess(user); + } + + @Transient private Instant virtualPublication; + + @JsonProperty("article_virtual_publication") + public Instant getVirtualPublication() { + return virtualPublication; + } + + @JsonProperty("article_is_scheduled") + public boolean isScheduledPublication() { + return virtualPublication != null; + } + + @Override + public boolean equals(Object o) { + if (this == o) return true; + if (o == null || !Base.class.isAssignableFrom(o.getClass())) return false; + Base base = (Base) o; + return id.equals(base.getId()); + } + + @Override + public int hashCode() { + return Objects.hash(id); + } } diff --git a/openbas-model/src/main/java/io/openbas/database/model/Asset.java b/openbas-model/src/main/java/io/openbas/database/model/Asset.java index a6edd7dbfa..36908a2ef2 100644 --- a/openbas-model/src/main/java/io/openbas/database/model/Asset.java +++ b/openbas-model/src/main/java/io/openbas/database/model/Asset.java @@ -1,5 +1,9 @@ package io.openbas.database.model; +import static jakarta.persistence.DiscriminatorType.STRING; +import static java.time.Instant.now; +import static lombok.AccessLevel.NONE; + import com.fasterxml.jackson.annotation.JsonProperty; import com.fasterxml.jackson.databind.annotation.JsonSerialize; import io.openbas.annotation.Queryable; @@ -10,19 +14,14 @@ import jakarta.persistence.*; import jakarta.validation.constraints.NotBlank; import jakarta.validation.constraints.NotNull; -import lombok.Data; -import lombok.Setter; -import org.hibernate.annotations.UuidGenerator; - import java.time.Instant; import java.util.HashSet; import java.util.List; import java.util.Objects; import java.util.Set; - -import static jakarta.persistence.DiscriminatorType.STRING; -import static java.time.Instant.now; -import static lombok.AccessLevel.NONE; +import lombok.Data; +import lombok.Setter; +import org.hibernate.annotations.UuidGenerator; @Data @Entity @@ -78,7 +77,8 @@ public class Asset implements Base { @Queryable(filterable = true, sortable = true, dynamicValues = true, path = "tags.id") @ManyToMany(fetch = FetchType.LAZY) - @JoinTable(name = "assets_tags", + @JoinTable( + name = "assets_tags", joinColumns = @JoinColumn(name = "asset_id"), inverseJoinColumns = @JoinColumn(name = "tag_id")) @JsonSerialize(using = MultiIdSetDeserializer.class) @@ -112,7 +112,8 @@ public class Asset implements Base { @JsonProperty("asset_active") public boolean getActive() { - return this.getLastSeen() != null && (now().toEpochMilli() - this.getLastSeen().toEpochMilli()) < ACTIVE_THRESHOLD; + return this.getLastSeen() != null + && (now().toEpochMilli() - this.getLastSeen().toEpochMilli()) < ACTIVE_THRESHOLD; } // -- AUDIT -- @@ -132,9 +133,7 @@ public int hashCode() { return Objects.hash(id); } - public Asset() { - - } + public Asset() {} public Asset(String id, String type, String name) { this.name = name; diff --git a/openbas-model/src/main/java/io/openbas/database/model/AssetAgentJob.java b/openbas-model/src/main/java/io/openbas/database/model/AssetAgentJob.java index b4d7f9c445..87ee806289 100644 --- a/openbas-model/src/main/java/io/openbas/database/model/AssetAgentJob.java +++ b/openbas-model/src/main/java/io/openbas/database/model/AssetAgentJob.java @@ -6,66 +6,65 @@ import io.openbas.helper.MonoIdDeserializer; import jakarta.persistence.*; import jakarta.validation.constraints.NotBlank; +import java.util.Objects; import lombok.Data; import lombok.Getter; import org.hibernate.annotations.UuidGenerator; -import java.util.Objects; - @Data @Entity @Table(name = "asset_agent_jobs") @EntityListeners(ModelBaseListener.class) public class AssetAgentJob implements Base { - @Id - @Column(name = "asset_agent_id") - @GeneratedValue(generator = "UUID") - @UuidGenerator - @JsonProperty("asset_agent_id") - @NotBlank - private String id; + @Id + @Column(name = "asset_agent_id") + @GeneratedValue(generator = "UUID") + @UuidGenerator + @JsonProperty("asset_agent_id") + @NotBlank + private String id; - @Getter - @ManyToOne(fetch = FetchType.EAGER) - @JoinColumn(name = "asset_agent_inject") - @JsonSerialize(using = MonoIdDeserializer.class) - @JsonProperty("asset_agent_inject") - private Inject inject; + @Getter + @ManyToOne(fetch = FetchType.EAGER) + @JoinColumn(name = "asset_agent_inject") + @JsonSerialize(using = MonoIdDeserializer.class) + @JsonProperty("asset_agent_inject") + private Inject inject; - @Getter - @ManyToOne(fetch = FetchType.EAGER) - @JoinColumn(name = "asset_agent_asset") - @JsonSerialize(using = MonoIdDeserializer.class) - @JsonProperty("asset_agent_asset") - private Asset asset; + @Getter + @ManyToOne(fetch = FetchType.EAGER) + @JoinColumn(name = "asset_agent_asset") + @JsonSerialize(using = MonoIdDeserializer.class) + @JsonProperty("asset_agent_asset") + private Asset asset; - @Getter - @Column(name = "asset_agent_command") - @JsonProperty("asset_agent_command") - @NotBlank - private String command; + @Getter + @Column(name = "asset_agent_command") + @JsonProperty("asset_agent_command") + @NotBlank + private String command; - @Override - public String toString() { - return id; - } + @Override + public String toString() { + return id; + } - @Override - public boolean equals(Object o) { - if (this == o) return true; - if (o == null || !Base.class.isAssignableFrom(o.getClass())) return false; - Base base = (Base) o; - return id.equals(base.getId()); - } + @Override + public boolean equals(Object o) { + if (this == o) return true; + if (o == null || !Base.class.isAssignableFrom(o.getClass())) return false; + Base base = (Base) o; + return id.equals(base.getId()); + } - @Override - public int hashCode() { - return Objects.hash(id); - } + @Override + public int hashCode() { + return Objects.hash(id); + } - @Override - public String getId() { - return id; - } + @Override + public String getId() { + return id; + } } diff --git a/openbas-model/src/main/java/io/openbas/database/model/AssetGroup.java b/openbas-model/src/main/java/io/openbas/database/model/AssetGroup.java index 610bbda864..9be0ede300 100644 --- a/openbas-model/src/main/java/io/openbas/database/model/AssetGroup.java +++ b/openbas-model/src/main/java/io/openbas/database/model/AssetGroup.java @@ -1,5 +1,8 @@ package io.openbas.database.model; +import static java.time.Instant.now; +import static lombok.AccessLevel.NONE; + import com.fasterxml.jackson.annotation.JsonProperty; import com.fasterxml.jackson.databind.annotation.JsonSerialize; import io.hypersistence.utils.hibernate.type.json.JsonType; @@ -11,29 +14,21 @@ import jakarta.persistence.*; import jakarta.validation.constraints.NotBlank; import jakarta.validation.constraints.NotNull; +import java.time.Instant; +import java.util.*; import lombok.Data; import lombok.Getter; import org.hibernate.annotations.Type; import org.hibernate.annotations.UuidGenerator; -import java.time.Instant; -import java.util.*; - -import static java.time.Instant.now; -import static lombok.AccessLevel.NONE; - @Data @Entity @Table(name = "asset_groups") @EntityListeners(ModelBaseListener.class) @NamedEntityGraphs({ - @NamedEntityGraph( - name = "AssetGroup.tags-assets", - attributeNodes = { - @NamedAttributeNode("tags"), - @NamedAttributeNode("assets") - } - ) + @NamedEntityGraph( + name = "AssetGroup.tags-assets", + attributeNodes = {@NamedAttributeNode("tags"), @NamedAttributeNode("assets")}) }) public class AssetGroup implements Base { @@ -64,7 +59,8 @@ public class AssetGroup implements Base { private FilterGroup dynamicFilter; @ManyToMany(fetch = FetchType.EAGER) - @JoinTable(name = "asset_groups_assets", + @JoinTable( + name = "asset_groups_assets", joinColumns = @JoinColumn(name = "asset_group_id"), inverseJoinColumns = @JoinColumn(name = "asset_id")) @JsonSerialize(using = MultiIdListDeserializer.class) @@ -85,7 +81,8 @@ public List getDynamicAssets() { // -- TAG -- @ManyToMany(fetch = FetchType.LAZY) - @JoinTable(name = "asset_groups_tags", + @JoinTable( + name = "asset_groups_tags", joinColumns = @JoinColumn(name = "asset_group_id"), inverseJoinColumns = @JoinColumn(name = "tag_id")) @JsonSerialize(using = MultiIdSetDeserializer.class) diff --git a/openbas-model/src/main/java/io/openbas/database/model/AssetGroupAsset.java b/openbas-model/src/main/java/io/openbas/database/model/AssetGroupAsset.java index 6c54bb329c..ec86678b90 100644 --- a/openbas-model/src/main/java/io/openbas/database/model/AssetGroupAsset.java +++ b/openbas-model/src/main/java/io/openbas/database/model/AssetGroupAsset.java @@ -1,9 +1,8 @@ package io.openbas.database.model; -import lombok.Data; - import jakarta.persistence.*; import java.io.Serializable; +import lombok.Data; @Data @Entity @@ -24,7 +23,5 @@ public static class AssetGroupAssetId implements Serializable { private String assetGroupId; private String assetId; - } - } diff --git a/openbas-model/src/main/java/io/openbas/database/model/AttackPattern.java b/openbas-model/src/main/java/io/openbas/database/model/AttackPattern.java index 5d8bda2f0c..cbe7498841 100644 --- a/openbas-model/src/main/java/io/openbas/database/model/AttackPattern.java +++ b/openbas-model/src/main/java/io/openbas/database/model/AttackPattern.java @@ -1,5 +1,7 @@ package io.openbas.database.model; +import static java.time.Instant.now; + import com.fasterxml.jackson.annotation.JsonProperty; import com.fasterxml.jackson.databind.annotation.JsonSerialize; import io.hypersistence.utils.hibernate.type.array.StringArrayType; @@ -9,16 +11,13 @@ import io.openbas.helper.MultiIdListDeserializer; import jakarta.persistence.*; import jakarta.validation.constraints.NotBlank; -import lombok.Data; -import org.hibernate.annotations.Type; -import org.hibernate.annotations.UuidGenerator; - import java.time.Instant; import java.util.ArrayList; import java.util.List; import java.util.Objects; - -import static java.time.Instant.now; +import lombok.Data; +import org.hibernate.annotations.Type; +import org.hibernate.annotations.UuidGenerator; @Data @Entity @@ -83,7 +82,8 @@ public class AttackPattern implements Base { private AttackPattern parent; @ManyToMany(fetch = FetchType.LAZY) - @JoinTable(name = "attack_patterns_kill_chain_phases", + @JoinTable( + name = "attack_patterns_kill_chain_phases", joinColumns = @JoinColumn(name = "attack_pattern_id"), inverseJoinColumns = @JoinColumn(name = "phase_id")) @JsonSerialize(using = MultiIdListDeserializer.class) diff --git a/openbas-model/src/main/java/io/openbas/database/model/BannerMessage.java b/openbas-model/src/main/java/io/openbas/database/model/BannerMessage.java index 273c0ff8a1..efca2f636c 100644 --- a/openbas-model/src/main/java/io/openbas/database/model/BannerMessage.java +++ b/openbas-model/src/main/java/io/openbas/database/model/BannerMessage.java @@ -3,8 +3,14 @@ public class BannerMessage { public enum BANNER_KEYS { - IMAP_UNAVAILABLE("imap_unavailable", BANNER_LEVEL.ERROR, "IMAP service is not responding, your injectors may be impacted."), - CALDERA_UNAVAILABLE("caldera_unavailable", BANNER_LEVEL.ERROR, "Executor Caldera is not responding, your exercises may be impacted."); + IMAP_UNAVAILABLE( + "imap_unavailable", + BANNER_LEVEL.ERROR, + "IMAP service is not responding, your injectors may be impacted."), + CALDERA_UNAVAILABLE( + "caldera_unavailable", + BANNER_LEVEL.ERROR, + "Executor Caldera is not responding, your exercises may be impacted."); private final String key; private final BANNER_LEVEL level; @@ -36,5 +42,4 @@ public enum BANNER_LEVEL { ERROR, FATAL } - } diff --git a/openbas-model/src/main/java/io/openbas/database/model/Base.java b/openbas-model/src/main/java/io/openbas/database/model/Base.java index b74df1c7e0..07afb3a201 100644 --- a/openbas-model/src/main/java/io/openbas/database/model/Base.java +++ b/openbas-model/src/main/java/io/openbas/database/model/Base.java @@ -5,25 +5,25 @@ import org.springframework.beans.BeanUtils; public interface Base { - String getId(); + String getId(); - void setId(String id); + void setId(String id); - default boolean isUserHasAccess(final boolean isAdmin) { - return isAdmin; - } + default boolean isUserHasAccess(final boolean isAdmin) { + return isAdmin; + } - default boolean isUserHasAccess(User user) { - return this.isUserHasAccess(user.isAdmin()); - } + default boolean isUserHasAccess(User user) { + return this.isUserHasAccess(user.isAdmin()); + } - @JsonIgnore - @Transient - default void setUpdateAttributes(Object input) { - BeanUtils.copyProperties(input, this); - } + @JsonIgnore + @Transient + default void setUpdateAttributes(Object input) { + BeanUtils.copyProperties(input, this); + } - default boolean isListened() { - return true; - } + default boolean isListened() { + return true; + } } diff --git a/openbas-model/src/main/java/io/openbas/database/model/BaseInjectStatus.java b/openbas-model/src/main/java/io/openbas/database/model/BaseInjectStatus.java index 063a5f973c..4e3104057c 100644 --- a/openbas-model/src/main/java/io/openbas/database/model/BaseInjectStatus.java +++ b/openbas-model/src/main/java/io/openbas/database/model/BaseInjectStatus.java @@ -6,14 +6,13 @@ import io.openbas.database.converter.InjectStatusExecutionConverter; import jakarta.persistence.*; import jakarta.validation.constraints.NotNull; -import lombok.Getter; -import lombok.Setter; -import org.hibernate.annotations.UuidGenerator; - import java.time.Instant; import java.util.ArrayList; import java.util.List; import java.util.Objects; +import lombok.Getter; +import lombok.Setter; +import org.hibernate.annotations.UuidGenerator; @Setter @Getter @@ -54,6 +53,7 @@ public abstract class BaseInjectStatus implements Base { @Column(name = "tracking_total_execution_time") @JsonProperty("tracking_total_execution_time") private Long trackingTotalExecutionTime; + // endregion // region count @@ -68,6 +68,7 @@ public abstract class BaseInjectStatus implements Base { @Column(name = "tracking_total_success") @JsonProperty("tracking_total_success") private Integer trackingTotalSuccess; + // endregion @Queryable(searchable = true, path = "inject.title") @@ -102,5 +103,4 @@ public boolean equals(Object o) { public int hashCode() { return Objects.hash(id); } - } diff --git a/openbas-model/src/main/java/io/openbas/database/model/Challenge.java b/openbas-model/src/main/java/io/openbas/database/model/Challenge.java index aad574f86f..18adc18196 100644 --- a/openbas-model/src/main/java/io/openbas/database/model/Challenge.java +++ b/openbas-model/src/main/java/io/openbas/database/model/Challenge.java @@ -1,5 +1,7 @@ package io.openbas.database.model; +import static java.time.Instant.now; + import com.fasterxml.jackson.annotation.JsonProperty; import com.fasterxml.jackson.databind.annotation.JsonSerialize; import io.openbas.database.audit.ModelBaseListener; @@ -9,15 +11,12 @@ import jakarta.persistence.*; import jakarta.validation.constraints.NotBlank; import jakarta.validation.constraints.NotNull; +import java.time.Instant; +import java.util.*; import lombok.Getter; import lombok.Setter; import org.hibernate.annotations.UuidGenerator; -import java.time.Instant; -import java.util.*; - -import static java.time.Instant.now; - @Getter @Setter @Entity @@ -25,105 +24,104 @@ @EntityListeners(ModelBaseListener.class) public class Challenge implements Base { - @Id - @Column(name = "challenge_id") - @GeneratedValue(generator = "UUID") - @UuidGenerator - @JsonProperty("challenge_id") - @NotBlank - private String id; - - @Column(name = "challenge_created_at") - @JsonProperty("challenge_created_at") - @NotNull - private Instant createdAt = now(); - - @Column(name = "challenge_updated_at") - @JsonProperty("challenge_updated_at") - @NotNull - private Instant updatedAt = now(); - - @Column(name = "challenge_name") - @JsonProperty("challenge_name") - private String name; - - @Column(name = "challenge_category") - @JsonProperty("challenge_category") - private String category; - - @Column(name = "challenge_content") - @JsonProperty("challenge_content") - private String content; - - @Column(name = "challenge_score") - @JsonProperty("challenge_score") - private Double score; - - @Column(name = "challenge_max_attempts") - @JsonProperty("challenge_max_attempts") - private Integer maxAttempts; - - // CascadeType.ALL is required here because Flags are embedded - @OneToMany(mappedBy = "challenge", fetch = FetchType.LAZY, cascade = CascadeType.ALL) - @JsonProperty("challenge_flags") - @JsonSerialize(using = MultiModelDeserializer.class) - private List flags = new ArrayList<>(); - - @ManyToMany(fetch = FetchType.LAZY) - @JoinTable(name = "challenges_tags", - joinColumns = @JoinColumn(name = "challenge_id"), - inverseJoinColumns = @JoinColumn(name = "tag_id")) - @JsonSerialize(using = MultiIdSetDeserializer.class) - @JsonProperty("challenge_tags") - private Set tags = new HashSet<>(); - - @ManyToMany(fetch = FetchType.LAZY) - @JoinTable(name = "challenges_documents", - joinColumns = @JoinColumn(name = "challenge_id"), - inverseJoinColumns = @JoinColumn(name = "document_id")) - @JsonSerialize(using = MultiIdListDeserializer.class) - @JsonProperty("challenge_documents") - private List documents = new ArrayList<>(); - - @Transient - private List exerciseIds = new ArrayList<>(); - - @Transient - private List scenarioIds = new ArrayList<>(); - - @Transient - private Instant virtualPublication; - - @JsonProperty("challenge_virtual_publication") - public Instant getVirtualPublication() { - return virtualPublication; - } - - @Override - public boolean isUserHasAccess(User user) { - return user.isAdmin(); - } - - @JsonProperty("challenge_exercises") - public List getExerciseIds() { - return exerciseIds; - } - - @JsonProperty("challenge_scenarios") - public List getScenarioIds() { - return scenarioIds; - } - - @Override - public boolean equals(Object o) { - if (this == o) return true; - if (o == null || !Base.class.isAssignableFrom(o.getClass())) return false; - Base base = (Base) o; - return id.equals(base.getId()); - } - - @Override - public int hashCode() { - return Objects.hash(id); - } + @Id + @Column(name = "challenge_id") + @GeneratedValue(generator = "UUID") + @UuidGenerator + @JsonProperty("challenge_id") + @NotBlank + private String id; + + @Column(name = "challenge_created_at") + @JsonProperty("challenge_created_at") + @NotNull + private Instant createdAt = now(); + + @Column(name = "challenge_updated_at") + @JsonProperty("challenge_updated_at") + @NotNull + private Instant updatedAt = now(); + + @Column(name = "challenge_name") + @JsonProperty("challenge_name") + private String name; + + @Column(name = "challenge_category") + @JsonProperty("challenge_category") + private String category; + + @Column(name = "challenge_content") + @JsonProperty("challenge_content") + private String content; + + @Column(name = "challenge_score") + @JsonProperty("challenge_score") + private Double score; + + @Column(name = "challenge_max_attempts") + @JsonProperty("challenge_max_attempts") + private Integer maxAttempts; + + // CascadeType.ALL is required here because Flags are embedded + @OneToMany(mappedBy = "challenge", fetch = FetchType.LAZY, cascade = CascadeType.ALL) + @JsonProperty("challenge_flags") + @JsonSerialize(using = MultiModelDeserializer.class) + private List flags = new ArrayList<>(); + + @ManyToMany(fetch = FetchType.LAZY) + @JoinTable( + name = "challenges_tags", + joinColumns = @JoinColumn(name = "challenge_id"), + inverseJoinColumns = @JoinColumn(name = "tag_id")) + @JsonSerialize(using = MultiIdSetDeserializer.class) + @JsonProperty("challenge_tags") + private Set tags = new HashSet<>(); + + @ManyToMany(fetch = FetchType.LAZY) + @JoinTable( + name = "challenges_documents", + joinColumns = @JoinColumn(name = "challenge_id"), + inverseJoinColumns = @JoinColumn(name = "document_id")) + @JsonSerialize(using = MultiIdListDeserializer.class) + @JsonProperty("challenge_documents") + private List documents = new ArrayList<>(); + + @Transient private List exerciseIds = new ArrayList<>(); + + @Transient private List scenarioIds = new ArrayList<>(); + + @Transient private Instant virtualPublication; + + @JsonProperty("challenge_virtual_publication") + public Instant getVirtualPublication() { + return virtualPublication; + } + + @Override + public boolean isUserHasAccess(User user) { + return user.isAdmin(); + } + + @JsonProperty("challenge_exercises") + public List getExerciseIds() { + return exerciseIds; + } + + @JsonProperty("challenge_scenarios") + public List getScenarioIds() { + return scenarioIds; + } + + @Override + public boolean equals(Object o) { + if (this == o) return true; + if (o == null || !Base.class.isAssignableFrom(o.getClass())) return false; + Base base = (Base) o; + return id.equals(base.getId()); + } + + @Override + public int hashCode() { + return Objects.hash(id); + } } diff --git a/openbas-model/src/main/java/io/openbas/database/model/ChallengeFlag.java b/openbas-model/src/main/java/io/openbas/database/model/ChallengeFlag.java index 078c0f45e3..dcb423d336 100644 --- a/openbas-model/src/main/java/io/openbas/database/model/ChallengeFlag.java +++ b/openbas-model/src/main/java/io/openbas/database/model/ChallengeFlag.java @@ -1,18 +1,17 @@ package io.openbas.database.model; +import static java.time.Instant.now; + import com.fasterxml.jackson.annotation.JsonProperty; import com.fasterxml.jackson.databind.annotation.JsonSerialize; import io.openbas.database.audit.ModelBaseListener; import io.openbas.helper.MonoIdDeserializer; -import lombok.Getter; -import lombok.Setter; -import org.hibernate.annotations.UuidGenerator; - import jakarta.persistence.*; import java.time.Instant; import java.util.Objects; - -import static java.time.Instant.now; +import lombok.Getter; +import lombok.Setter; +import org.hibernate.annotations.UuidGenerator; @Setter @Entity @@ -20,67 +19,67 @@ @EntityListeners(ModelBaseListener.class) public class ChallengeFlag implements Base { - public enum FLAG_TYPE { - VALUE, - VALUE_CASE, - REGEXP, - } + public enum FLAG_TYPE { + VALUE, + VALUE_CASE, + REGEXP, + } - @Id - @Column(name = "flag_id") - @GeneratedValue(generator = "UUID") - @UuidGenerator - @JsonProperty("flag_id") - private String id; + @Id + @Column(name = "flag_id") + @GeneratedValue(generator = "UUID") + @UuidGenerator + @JsonProperty("flag_id") + private String id; - @Getter - @Column(name = "flag_created_at") - @JsonProperty("flag_created_at") - private Instant createdAt = now(); + @Getter + @Column(name = "flag_created_at") + @JsonProperty("flag_created_at") + private Instant createdAt = now(); - @Getter - @Column(name = "flag_updated_at") - @JsonProperty("flag_updated_at") - private Instant updatedAt = now(); + @Getter + @Column(name = "flag_updated_at") + @JsonProperty("flag_updated_at") + private Instant updatedAt = now(); - @Getter - @Column(name = "flag_type") - @JsonProperty("flag_type") - @Enumerated(EnumType.STRING) - private FLAG_TYPE type; + @Getter + @Column(name = "flag_type") + @JsonProperty("flag_type") + @Enumerated(EnumType.STRING) + private FLAG_TYPE type; - @Getter - @Column(name = "flag_value") - @JsonProperty("flag_value") - private String value; + @Getter + @Column(name = "flag_value") + @JsonProperty("flag_value") + private String value; - @Getter - @ManyToOne(fetch = FetchType.LAZY) - @JsonSerialize(using = MonoIdDeserializer.class) - @JoinColumn(name = "flag_challenge") - @JsonProperty("flag_challenge") - private Challenge challenge; + @Getter + @ManyToOne(fetch = FetchType.LAZY) + @JsonSerialize(using = MonoIdDeserializer.class) + @JoinColumn(name = "flag_challenge") + @JsonProperty("flag_challenge") + private Challenge challenge; - @Override - public String getId() { - return id; - } + @Override + public String getId() { + return id; + } - @Override - public boolean isUserHasAccess(User user) { - return challenge.isUserHasAccess(user); - } + @Override + public boolean isUserHasAccess(User user) { + return challenge.isUserHasAccess(user); + } @Override - public boolean equals(Object o) { - if (this == o) return true; - if (o == null || !Base.class.isAssignableFrom(o.getClass())) return false; - Base base = (Base) o; - return id.equals(base.getId()); - } + public boolean equals(Object o) { + if (this == o) return true; + if (o == null || !Base.class.isAssignableFrom(o.getClass())) return false; + Base base = (Base) o; + return id.equals(base.getId()); + } - @Override - public int hashCode() { - return Objects.hash(id); - } + @Override + public int hashCode() { + return Objects.hash(id); + } } diff --git a/openbas-model/src/main/java/io/openbas/database/model/Channel.java b/openbas-model/src/main/java/io/openbas/database/model/Channel.java index ce63999d37..356178f900 100644 --- a/openbas-model/src/main/java/io/openbas/database/model/Channel.java +++ b/openbas-model/src/main/java/io/openbas/database/model/Channel.java @@ -1,21 +1,20 @@ package io.openbas.database.model; +import static java.time.Instant.now; + import com.fasterxml.jackson.annotation.JsonProperty; import com.fasterxml.jackson.databind.annotation.JsonSerialize; import io.openbas.database.audit.ModelBaseListener; import io.openbas.helper.MonoIdDeserializer; +import jakarta.persistence.*; import jakarta.validation.constraints.NotBlank; import jakarta.validation.constraints.NotNull; -import lombok.Setter; -import org.hibernate.annotations.UuidGenerator; - -import jakarta.persistence.*; import java.time.Instant; import java.util.ArrayList; import java.util.List; import java.util.Objects; - -import static java.time.Instant.now; +import lombok.Setter; +import org.hibernate.annotations.UuidGenerator; @Setter @Entity @@ -23,147 +22,147 @@ @EntityListeners(ModelBaseListener.class) public class Channel implements Base { - @Id - @Column(name = "channel_id") - @GeneratedValue(generator = "UUID") - @UuidGenerator - @JsonProperty("channel_id") - @NotBlank - private String id; - - @Column(name = "channel_created_at") - @JsonProperty("channel_created_at") - @NotNull - private Instant createdAt = now(); - - @Column(name = "channel_updated_at") - @JsonProperty("channel_updated_at") - @NotNull - private Instant updatedAt = now(); - - @Column(name = "channel_type") - @JsonProperty("channel_type") - private String type; - - @Column(name = "channel_name") - @JsonProperty("channel_name") - private String name; - - @Column(name = "channel_description") - @JsonProperty("channel_description") - private String description; - - @Column(name = "channel_mode") - @JsonProperty("channel_mode") - private String mode; - - @Column(name = "channel_primary_color_dark") - @JsonProperty("channel_primary_color_dark") - private String primaryColorDark; - - @Column(name = "channel_primary_color_light") - @JsonProperty("channel_primary_color_light") - private String primaryColorLight; - - @Column(name = "channel_secondary_color_dark") - @JsonProperty("channel_secondary_color_dark") - private String secondaryColorDark; - - @Column(name = "channel_secondary_color_light") - @JsonProperty("channel_secondary_color_light") - private String secondaryColorLight; - - @ManyToOne(fetch = FetchType.LAZY) - @JoinColumn(name = "channel_logo_dark") - @JsonSerialize(using = MonoIdDeserializer.class) - @JsonProperty("channel_logo_dark") - private Document logoDark; - - @ManyToOne(fetch = FetchType.LAZY) - @JoinColumn(name = "channel_logo_light") - @JsonSerialize(using = MonoIdDeserializer.class) - @JsonProperty("channel_logo_light") - private Document logoLight; - - @Override - public String getId() { - return id; - } - - @Override - public boolean isUserHasAccess(User user) { - return user.isAdmin(); - } + @Id + @Column(name = "channel_id") + @GeneratedValue(generator = "UUID") + @UuidGenerator + @JsonProperty("channel_id") + @NotBlank + private String id; + + @Column(name = "channel_created_at") + @JsonProperty("channel_created_at") + @NotNull + private Instant createdAt = now(); + + @Column(name = "channel_updated_at") + @JsonProperty("channel_updated_at") + @NotNull + private Instant updatedAt = now(); + + @Column(name = "channel_type") + @JsonProperty("channel_type") + private String type; + + @Column(name = "channel_name") + @JsonProperty("channel_name") + private String name; + + @Column(name = "channel_description") + @JsonProperty("channel_description") + private String description; + + @Column(name = "channel_mode") + @JsonProperty("channel_mode") + private String mode; + + @Column(name = "channel_primary_color_dark") + @JsonProperty("channel_primary_color_dark") + private String primaryColorDark; + + @Column(name = "channel_primary_color_light") + @JsonProperty("channel_primary_color_light") + private String primaryColorLight; + + @Column(name = "channel_secondary_color_dark") + @JsonProperty("channel_secondary_color_dark") + private String secondaryColorDark; + + @Column(name = "channel_secondary_color_light") + @JsonProperty("channel_secondary_color_light") + private String secondaryColorLight; + + @ManyToOne(fetch = FetchType.LAZY) + @JoinColumn(name = "channel_logo_dark") + @JsonSerialize(using = MonoIdDeserializer.class) + @JsonProperty("channel_logo_dark") + private Document logoDark; + + @ManyToOne(fetch = FetchType.LAZY) + @JoinColumn(name = "channel_logo_light") + @JsonSerialize(using = MonoIdDeserializer.class) + @JsonProperty("channel_logo_light") + private Document logoLight; + + @Override + public String getId() { + return id; + } + + @Override + public boolean isUserHasAccess(User user) { + return user.isAdmin(); + } public String getType() { - return type; - } + return type; + } public String getName() { - return name; - } + return name; + } public String getDescription() { - return description; - } + return description; + } public String getMode() { - return mode; - } + return mode; + } public String getPrimaryColorDark() { - return primaryColorDark; - } + return primaryColorDark; + } public String getPrimaryColorLight() { - return primaryColorLight; - } + return primaryColorLight; + } public String getSecondaryColorDark() { - return secondaryColorDark; - } + return secondaryColorDark; + } public String getSecondaryColorLight() { - return secondaryColorLight; - } + return secondaryColorLight; + } public Document getLogoDark() { - return logoDark; - } + return logoDark; + } public Document getLogoLight() { - return logoLight; - } + return logoLight; + } public Instant getCreatedAt() { - return createdAt; - } + return createdAt; + } public Instant getUpdatedAt() { - return updatedAt; - } + return updatedAt; + } public List getLogos() { - List logos = new ArrayList<>(); - if (logoLight != null) { - logos.add(logoLight); - } - if (logoDark != null) { - logos.add(logoDark); - } - return logos; - } - - @Override - public boolean equals(Object o) { - if (this == o) return true; - if (o == null || !Base.class.isAssignableFrom(o.getClass())) return false; - Base base = (Base) o; - return id.equals(base.getId()); - } - - @Override - public int hashCode() { - return Objects.hash(id); - } + List logos = new ArrayList<>(); + if (logoLight != null) { + logos.add(logoLight); + } + if (logoDark != null) { + logos.add(logoDark); + } + return logos; + } + + @Override + public boolean equals(Object o) { + if (this == o) return true; + if (o == null || !Base.class.isAssignableFrom(o.getClass())) return false; + Base base = (Base) o; + return id.equals(base.getId()); + } + + @Override + public int hashCode() { + return Objects.hash(id); + } } diff --git a/openbas-model/src/main/java/io/openbas/database/model/Collector.java b/openbas-model/src/main/java/io/openbas/database/model/Collector.java index c53281f26b..1447efb372 100644 --- a/openbas-model/src/main/java/io/openbas/database/model/Collector.java +++ b/openbas-model/src/main/java/io/openbas/database/model/Collector.java @@ -1,18 +1,17 @@ package io.openbas.database.model; +import static java.time.Instant.now; + import com.fasterxml.jackson.annotation.JsonIgnore; import com.fasterxml.jackson.annotation.JsonProperty; import io.openbas.database.audit.ModelBaseListener; import jakarta.persistence.*; import jakarta.validation.constraints.NotBlank; import jakarta.validation.constraints.NotNull; -import lombok.Getter; -import lombok.Setter; - import java.time.Instant; import java.util.Objects; - -import static java.time.Instant.now; +import lombok.Getter; +import lombok.Setter; @Getter @Setter @@ -21,70 +20,70 @@ @EntityListeners(ModelBaseListener.class) public class Collector implements Base { - @Id - @Column(name = "collector_id") - @JsonProperty("collector_id") - @NotBlank - private String id; - - @Column(name = "collector_name") - @JsonProperty("collector_name") - @NotBlank - private String name; - - @Column(name = "collector_type") - @JsonProperty("collector_type") - @NotBlank - private String type; - - @Column(name = "collector_period") - @JsonProperty("collector_period") - private int period; - - @Column(name = "collector_external") - @JsonProperty("collector_external") - private boolean external = false; - - @Column(name = "collector_created_at") - @JsonProperty("collector_created_at") - @NotNull - private Instant createdAt = now(); - - @Column(name = "collector_updated_at") - @JsonProperty("collector_updated_at") - @NotNull - private Instant updatedAt = now(); - - @Column(name = "collector_last_execution") - @JsonProperty("collector_last_execution") - private Instant lastExecution; - - @OneToOne(fetch = FetchType.LAZY) - @JoinColumn(name = "collector_security_platform") - @JsonProperty("collector_security_platform") - private SecurityPlatform securityPlatform; - - @JsonIgnore - @Override - public boolean isUserHasAccess(User user) { - return user.isAdmin(); - } - - @Override - public String toString() { - return name; - } - - @Override - public boolean equals(Object o) { - if (this == o) return true; - if (o == null || !Base.class.isAssignableFrom(o.getClass())) return false; - Base base = (Base) o; - return id.equals(base.getId()); - } - - @Override - public int hashCode() { - return Objects.hash(id); - } + @Id + @Column(name = "collector_id") + @JsonProperty("collector_id") + @NotBlank + private String id; + + @Column(name = "collector_name") + @JsonProperty("collector_name") + @NotBlank + private String name; + + @Column(name = "collector_type") + @JsonProperty("collector_type") + @NotBlank + private String type; + + @Column(name = "collector_period") + @JsonProperty("collector_period") + private int period; + + @Column(name = "collector_external") + @JsonProperty("collector_external") + private boolean external = false; + + @Column(name = "collector_created_at") + @JsonProperty("collector_created_at") + @NotNull + private Instant createdAt = now(); + + @Column(name = "collector_updated_at") + @JsonProperty("collector_updated_at") + @NotNull + private Instant updatedAt = now(); + + @Column(name = "collector_last_execution") + @JsonProperty("collector_last_execution") + private Instant lastExecution; + + @OneToOne(fetch = FetchType.LAZY) + @JoinColumn(name = "collector_security_platform") + @JsonProperty("collector_security_platform") + private SecurityPlatform securityPlatform; + + @JsonIgnore + @Override + public boolean isUserHasAccess(User user) { + return user.isAdmin(); + } + + @Override + public String toString() { + return name; + } + + @Override + public boolean equals(Object o) { + if (this == o) return true; + if (o == null || !Base.class.isAssignableFrom(o.getClass())) return false; + Base base = (Base) o; + return id.equals(base.getId()); + } + + @Override + public int hashCode() { + return Objects.hash(id); + } } diff --git a/openbas-model/src/main/java/io/openbas/database/model/Comcheck.java b/openbas-model/src/main/java/io/openbas/database/model/Comcheck.java index 9f9b119ce3..42a0d7cc31 100644 --- a/openbas-model/src/main/java/io/openbas/database/model/Comcheck.java +++ b/openbas-model/src/main/java/io/openbas/database/model/Comcheck.java @@ -5,17 +5,16 @@ import io.openbas.database.audit.ModelBaseListener; import io.openbas.helper.MonoIdDeserializer; import io.openbas.helper.MultiIdListDeserializer; +import jakarta.persistence.*; import jakarta.validation.constraints.NotBlank; import jakarta.validation.constraints.NotNull; -import lombok.Getter; -import lombok.Setter; -import org.hibernate.annotations.UuidGenerator; - -import jakarta.persistence.*; import java.time.Instant; import java.util.ArrayList; import java.util.List; import java.util.Objects; +import lombok.Getter; +import lombok.Setter; +import org.hibernate.annotations.UuidGenerator; @Setter @Getter @@ -24,81 +23,82 @@ @EntityListeners(ModelBaseListener.class) public class Comcheck implements Base { - public enum COMCHECK_STATUS { - RUNNING, - EXPIRED, - FINISHED - } - - @Id - @Column(name = "comcheck_id") - @GeneratedValue(generator = "UUID") - @UuidGenerator - @JsonProperty("comcheck_id") - @NotBlank - private String id; - - @Column(name = "comcheck_name") - @JsonProperty("comcheck_name") - private String name; - - @Column(name = "comcheck_start_date") - @JsonProperty("comcheck_start_date") - @NotNull - private Instant start; - - @Column(name = "comcheck_end_date") - @JsonProperty("comcheck_end_date") - @NotNull - private Instant end; - - @Column(name = "comcheck_state") - @JsonProperty("comcheck_state") - @Enumerated(EnumType.STRING) - private COMCHECK_STATUS state = COMCHECK_STATUS.RUNNING; - - @Column(name = "comcheck_subject") - @JsonProperty("comcheck_subject") - private String subject; - - @Column(name = "comcheck_message") - @JsonProperty("comcheck_message") - private String message; - - @ManyToOne(fetch = FetchType.LAZY) - @JoinColumn(name = "comcheck_exercise") - @JsonSerialize(using = MonoIdDeserializer.class) - @JsonProperty("comcheck_exercise") - private Exercise exercise; - - // CascadeType.ALL is required here because comcheck statuses are embedded - @OneToMany(mappedBy = "comcheck", fetch = FetchType.LAZY, cascade = CascadeType.ALL) - @JsonSerialize(using = MultiIdListDeserializer.class) - @JsonProperty("comcheck_statuses") - private List comcheckStatus = new ArrayList<>(); - - // region transient - @JsonProperty("comcheck_users_number") - public long getUsersNumber() { - return getComcheckStatus().size(); // One status for each user. - } - // endregion + public enum COMCHECK_STATUS { + RUNNING, + EXPIRED, + FINISHED + } + + @Id + @Column(name = "comcheck_id") + @GeneratedValue(generator = "UUID") + @UuidGenerator + @JsonProperty("comcheck_id") + @NotBlank + private String id; + + @Column(name = "comcheck_name") + @JsonProperty("comcheck_name") + private String name; + + @Column(name = "comcheck_start_date") + @JsonProperty("comcheck_start_date") + @NotNull + private Instant start; + + @Column(name = "comcheck_end_date") + @JsonProperty("comcheck_end_date") + @NotNull + private Instant end; + + @Column(name = "comcheck_state") + @JsonProperty("comcheck_state") + @Enumerated(EnumType.STRING) + private COMCHECK_STATUS state = COMCHECK_STATUS.RUNNING; + + @Column(name = "comcheck_subject") + @JsonProperty("comcheck_subject") + private String subject; + + @Column(name = "comcheck_message") + @JsonProperty("comcheck_message") + private String message; + + @ManyToOne(fetch = FetchType.LAZY) + @JoinColumn(name = "comcheck_exercise") + @JsonSerialize(using = MonoIdDeserializer.class) + @JsonProperty("comcheck_exercise") + private Exercise exercise; + + // CascadeType.ALL is required here because comcheck statuses are embedded + @OneToMany(mappedBy = "comcheck", fetch = FetchType.LAZY, cascade = CascadeType.ALL) + @JsonSerialize(using = MultiIdListDeserializer.class) + @JsonProperty("comcheck_statuses") + private List comcheckStatus = new ArrayList<>(); + + // region transient + @JsonProperty("comcheck_users_number") + public long getUsersNumber() { + return getComcheckStatus().size(); // One status for each user. + } + + // endregion + + @Override + public boolean isUserHasAccess(User user) { + return exercise.isUserHasAccess(user); + } @Override - public boolean isUserHasAccess(User user) { - return exercise.isUserHasAccess(user); - } + public boolean equals(Object o) { + if (this == o) return true; + if (o == null || !Base.class.isAssignableFrom(o.getClass())) return false; + Base base = (Base) o; + return id.equals(base.getId()); + } @Override - public boolean equals(Object o) { - if (this == o) return true; - if (o == null || !Base.class.isAssignableFrom(o.getClass())) return false; - Base base = (Base) o; - return id.equals(base.getId()); - } - - @Override - public int hashCode() { - return Objects.hash(id); - } + public int hashCode() { + return Objects.hash(id); + } } diff --git a/openbas-model/src/main/java/io/openbas/database/model/ComcheckStatus.java b/openbas-model/src/main/java/io/openbas/database/model/ComcheckStatus.java index 997213f42f..a44defd49f 100644 --- a/openbas-model/src/main/java/io/openbas/database/model/ComcheckStatus.java +++ b/openbas-model/src/main/java/io/openbas/database/model/ComcheckStatus.java @@ -1,142 +1,146 @@ package io.openbas.database.model; +import static io.openbas.database.model.Comcheck.COMCHECK_STATUS.EXPIRED; +import static java.util.Optional.ofNullable; + import com.fasterxml.jackson.annotation.JsonProperty; import com.fasterxml.jackson.databind.annotation.JsonSerialize; import io.openbas.database.audit.ModelBaseListener; import io.openbas.helper.MonoIdDeserializer; -import org.hibernate.annotations.UuidGenerator; - import jakarta.persistence.*; import java.time.Instant; import java.util.Objects; import java.util.Optional; - -import static io.openbas.database.model.Comcheck.COMCHECK_STATUS.EXPIRED; -import static java.util.Optional.ofNullable; +import org.hibernate.annotations.UuidGenerator; @Entity @Table(name = "comchecks_statuses") @EntityListeners(ModelBaseListener.class) public class ComcheckStatus implements Base { - public enum CHECK_STATUS { - RUNNING, - SUCCESS, - FAILURE - } - - @Id - @Column(name = "status_id") - @GeneratedValue(generator = "UUID") - @UuidGenerator - @JsonProperty("comcheckstatus_id") - private String id; - - @ManyToOne(fetch = FetchType.LAZY) - @JoinColumn(name = "status_user") - @JsonSerialize(using = MonoIdDeserializer.class) - @JsonProperty("comcheckstatus_user") - private User user; - - @ManyToOne(fetch = FetchType.LAZY) - @JoinColumn(name = "status_comcheck") - @JsonSerialize(using = MonoIdDeserializer.class) - @JsonProperty("comcheckstatus_comcheck") - private Comcheck comcheck; - - @Column(name = "status_sent_date") - @JsonProperty("comcheckstatus_sent_date") - private Instant lastSent; - - @Column(name = "status_receive_date") - @JsonProperty("comcheckstatus_receive_date") - private Instant receiveDate; - - @Column(name = "status_sent_retry") - @JsonProperty("comcheckstatus_sent_retry") - private int sentNumber = 0; - - public ComcheckStatus() { - // Default constructor - } - - public ComcheckStatus(User user) { - this.user = user; - } - - // region transient - @JsonProperty("comcheckstatus_state") - public CHECK_STATUS getState() { - return getReceiveDate().map(receive -> CHECK_STATUS.SUCCESS) - .orElseGet(() -> EXPIRED.equals(getComcheck().getState()) - ? CHECK_STATUS.FAILURE : CHECK_STATUS.RUNNING); - } - // endregion - - @Override - public String getId() { - return id; - } - - @Override - public boolean isUserHasAccess(User user) { - return comcheck.isUserHasAccess(user); - } - - public void setId(String id) { - this.id = id; - } - - public User getUser() { - return user; - } - - public void setUser(User user) { - this.user = user; - } - - public Comcheck getComcheck() { - return comcheck; - } - - public void setComcheck(Comcheck comcheck) { - this.comcheck = comcheck; - } - - public Optional getLastSent() { - return ofNullable(lastSent); - } - - public void setLastSent(Instant lastSent) { - this.lastSent = lastSent; - } - - public int getSentNumber() { - return sentNumber; - } - - public void setSentNumber(int sentNumber) { - this.sentNumber = sentNumber; - } - - public Optional getReceiveDate() { - return ofNullable(receiveDate); - } - - public void setReceiveDate(Instant receiveDate) { - this.receiveDate = receiveDate; - } - - @Override - public boolean equals(Object o) { - if (this == o) return true; - if (o == null || !Base.class.isAssignableFrom(o.getClass())) return false; - Base base = (Base) o; - return id.equals(base.getId()); - } - - @Override - public int hashCode() { - return Objects.hash(id); - } + public enum CHECK_STATUS { + RUNNING, + SUCCESS, + FAILURE + } + + @Id + @Column(name = "status_id") + @GeneratedValue(generator = "UUID") + @UuidGenerator + @JsonProperty("comcheckstatus_id") + private String id; + + @ManyToOne(fetch = FetchType.LAZY) + @JoinColumn(name = "status_user") + @JsonSerialize(using = MonoIdDeserializer.class) + @JsonProperty("comcheckstatus_user") + private User user; + + @ManyToOne(fetch = FetchType.LAZY) + @JoinColumn(name = "status_comcheck") + @JsonSerialize(using = MonoIdDeserializer.class) + @JsonProperty("comcheckstatus_comcheck") + private Comcheck comcheck; + + @Column(name = "status_sent_date") + @JsonProperty("comcheckstatus_sent_date") + private Instant lastSent; + + @Column(name = "status_receive_date") + @JsonProperty("comcheckstatus_receive_date") + private Instant receiveDate; + + @Column(name = "status_sent_retry") + @JsonProperty("comcheckstatus_sent_retry") + private int sentNumber = 0; + + public ComcheckStatus() { + // Default constructor + } + + public ComcheckStatus(User user) { + this.user = user; + } + + // region transient + @JsonProperty("comcheckstatus_state") + public CHECK_STATUS getState() { + return getReceiveDate() + .map(receive -> CHECK_STATUS.SUCCESS) + .orElseGet( + () -> + EXPIRED.equals(getComcheck().getState()) + ? CHECK_STATUS.FAILURE + : CHECK_STATUS.RUNNING); + } + + // endregion + + @Override + public String getId() { + return id; + } + + @Override + public boolean isUserHasAccess(User user) { + return comcheck.isUserHasAccess(user); + } + + public void setId(String id) { + this.id = id; + } + + public User getUser() { + return user; + } + + public void setUser(User user) { + this.user = user; + } + + public Comcheck getComcheck() { + return comcheck; + } + + public void setComcheck(Comcheck comcheck) { + this.comcheck = comcheck; + } + + public Optional getLastSent() { + return ofNullable(lastSent); + } + + public void setLastSent(Instant lastSent) { + this.lastSent = lastSent; + } + + public int getSentNumber() { + return sentNumber; + } + + public void setSentNumber(int sentNumber) { + this.sentNumber = sentNumber; + } + + public Optional getReceiveDate() { + return ofNullable(receiveDate); + } + + public void setReceiveDate(Instant receiveDate) { + this.receiveDate = receiveDate; + } + + @Override + public boolean equals(Object o) { + if (this == o) return true; + if (o == null || !Base.class.isAssignableFrom(o.getClass())) return false; + Base base = (Base) o; + return id.equals(base.getId()); + } + + @Override + public int hashCode() { + return Objects.hash(id); + } } diff --git a/openbas-model/src/main/java/io/openbas/database/model/Command.java b/openbas-model/src/main/java/io/openbas/database/model/Command.java index 3717d19d11..ca8ff7f717 100644 --- a/openbas-model/src/main/java/io/openbas/database/model/Command.java +++ b/openbas-model/src/main/java/io/openbas/database/model/Command.java @@ -35,9 +35,7 @@ public class Command extends Payload { @NotNull private String content; - public Command() { - - } + public Command() {} public Command(String id, String type, String name) { super(id, type, name); diff --git a/openbas-model/src/main/java/io/openbas/database/model/Communication.java b/openbas-model/src/main/java/io/openbas/database/model/Communication.java index 8091fe468f..a6ede4a122 100644 --- a/openbas-model/src/main/java/io/openbas/database/model/Communication.java +++ b/openbas-model/src/main/java/io/openbas/database/model/Communication.java @@ -1,5 +1,7 @@ package io.openbas.database.model; +import static java.time.Instant.now; + import com.fasterxml.jackson.annotation.JsonIgnore; import com.fasterxml.jackson.annotation.JsonProperty; import com.fasterxml.jackson.databind.annotation.JsonSerialize; @@ -10,17 +12,14 @@ import jakarta.persistence.*; import jakarta.validation.constraints.NotBlank; import jakarta.validation.constraints.NotNull; -import lombok.Setter; -import org.apache.commons.lang3.StringUtils; -import org.hibernate.annotations.Type; -import org.hibernate.annotations.UuidGenerator; - import java.time.Instant; import java.util.ArrayList; import java.util.List; import java.util.Objects; - -import static java.time.Instant.now; +import lombok.Setter; +import org.apache.commons.lang3.StringUtils; +import org.hibernate.annotations.Type; +import org.hibernate.annotations.UuidGenerator; @Setter @Entity @@ -28,157 +27,162 @@ @EntityListeners(ModelBaseListener.class) public class Communication implements Base { - @Id - @Column(name = "communication_id") - @GeneratedValue(generator = "UUID") - @UuidGenerator - @JsonProperty("communication_id") - @NotBlank - private String id; - - @Column(name = "communication_message_id") - @JsonProperty("communication_message_id") - @NotBlank - private String identifier; - - @Column(name = "communication_received_at") - @JsonProperty("communication_received_at") - @NotNull - private Instant receivedAt = now(); - - @Column(name = "communication_sent_at") - @JsonProperty("communication_sent_at") - @NotNull - private Instant sentAt = now(); - - @Column(name = "communication_subject") - @JsonProperty("communication_subject") - private String subject; - - @Column(name = "communication_content") - @JsonProperty("communication_content") - private String content; - - @Column(name = "communication_content_html") - @JsonProperty("communication_content_html") - private String contentHtml; - - @Type(StringArrayType.class) - @Column(name = "communication_attachments", columnDefinition = "text[]") - @JsonProperty("communication_attachments") - private String[] attachments; - - @ManyToOne(fetch = FetchType.LAZY) - @JoinColumn(name = "communication_inject") - @JsonSerialize(using = MonoIdDeserializer.class) - @JsonProperty("communication_inject") - private Inject inject; - - @ManyToMany(fetch = FetchType.LAZY) - @JoinTable(name = "communications_users", - joinColumns = @JoinColumn(name = "communication_id"), - inverseJoinColumns = @JoinColumn(name = "user_id")) - @JsonSerialize(using = MultiIdListDeserializer.class) - @JsonProperty("communication_users") - private List users = new ArrayList<>(); - - @Column(name = "communication_ack") - @JsonProperty("communication_ack") - private Boolean ack = false; - - @Column(name = "communication_animation") - @JsonProperty("communication_animation") - private Boolean animation = false; - - @Column(name = "communication_from") - @JsonProperty("communication_from") - @NotBlank - private String from; - - @Column(name = "communication_to") - @JsonProperty("communication_to") - @NotBlank - private String to; - - @Override - public String getId() { - return id; - } + @Id + @Column(name = "communication_id") + @GeneratedValue(generator = "UUID") + @UuidGenerator + @JsonProperty("communication_id") + @NotBlank + private String id; + + @Column(name = "communication_message_id") + @JsonProperty("communication_message_id") + @NotBlank + private String identifier; + + @Column(name = "communication_received_at") + @JsonProperty("communication_received_at") + @NotNull + private Instant receivedAt = now(); + + @Column(name = "communication_sent_at") + @JsonProperty("communication_sent_at") + @NotNull + private Instant sentAt = now(); + + @Column(name = "communication_subject") + @JsonProperty("communication_subject") + private String subject; + + @Column(name = "communication_content") + @JsonProperty("communication_content") + private String content; + + @Column(name = "communication_content_html") + @JsonProperty("communication_content_html") + private String contentHtml; + + @Type(StringArrayType.class) + @Column(name = "communication_attachments", columnDefinition = "text[]") + @JsonProperty("communication_attachments") + private String[] attachments; + + @ManyToOne(fetch = FetchType.LAZY) + @JoinColumn(name = "communication_inject") + @JsonSerialize(using = MonoIdDeserializer.class) + @JsonProperty("communication_inject") + private Inject inject; + + @ManyToMany(fetch = FetchType.LAZY) + @JoinTable( + name = "communications_users", + joinColumns = @JoinColumn(name = "communication_id"), + inverseJoinColumns = @JoinColumn(name = "user_id")) + @JsonSerialize(using = MultiIdListDeserializer.class) + @JsonProperty("communication_users") + private List users = new ArrayList<>(); + + @Column(name = "communication_ack") + @JsonProperty("communication_ack") + private Boolean ack = false; + + @Column(name = "communication_animation") + @JsonProperty("communication_animation") + private Boolean animation = false; + + @Column(name = "communication_from") + @JsonProperty("communication_from") + @NotBlank + private String from; + + @Column(name = "communication_to") + @JsonProperty("communication_to") + @NotBlank + private String to; + + @Override + public String getId() { + return id; + } public Instant getReceivedAt() { - return receivedAt; - } + return receivedAt; + } public Instant getSentAt() { - return sentAt; - } + return sentAt; + } public String getSubject() { - return subject; - } + return subject; + } public String getContent() { - return content; - } + return content; + } public String getContentHtml() { - return contentHtml; - } + return contentHtml; + } public Inject getInject() { - return inject; - } + return inject; + } public List getUsers() { - return users; - } + return users; + } public String getIdentifier() { - return identifier; - } + return identifier; + } public Boolean getAck() { - return ack; - } + return ack; + } public Boolean getAnimation() { - return animation; - } + return animation; + } public String getFrom() { - return from; - } + return from; + } public String getTo() { - return to; - } + return to; + } public String[] getAttachments() { - return attachments; - } + return attachments; + } @JsonProperty("communication_exercise") - public String getExercise() { - return this.inject.getExercise() != null ? this.inject.getExercise().getId() : StringUtils.EMPTY; - } - - @JsonIgnore - @Override - public boolean isUserHasAccess(User user) { - Inject inject = getInject(); - return user.isAdmin() || getUsers().contains(user) || (inject != null && inject.isUserHasAccess(user)); - } - - @Override - public boolean equals(Object o) { - if (this == o) return true; - if (o == null || !Base.class.isAssignableFrom(o.getClass())) return false; - Base base = (Base) o; - return id.equals(base.getId()); - } - - @Override - public int hashCode() { - return Objects.hash(id); - } + public String getExercise() { + return this.inject.getExercise() != null + ? this.inject.getExercise().getId() + : StringUtils.EMPTY; + } + + @JsonIgnore + @Override + public boolean isUserHasAccess(User user) { + Inject inject = getInject(); + return user.isAdmin() + || getUsers().contains(user) + || (inject != null && inject.isUserHasAccess(user)); + } + + @Override + public boolean equals(Object o) { + if (this == o) return true; + if (o == null || !Base.class.isAssignableFrom(o.getClass())) return false; + Base base = (Base) o; + return id.equals(base.getId()); + } + + @Override + public int hashCode() { + return Objects.hash(id); + } } diff --git a/openbas-model/src/main/java/io/openbas/database/model/DataAttachment.java b/openbas-model/src/main/java/io/openbas/database/model/DataAttachment.java index 09d3cd4016..45f6926dde 100644 --- a/openbas-model/src/main/java/io/openbas/database/model/DataAttachment.java +++ b/openbas-model/src/main/java/io/openbas/database/model/DataAttachment.java @@ -1,5 +1,5 @@ package io.openbas.database.model; public record DataAttachment(String id, String name, byte[] data, String contentType) { - // Nothing special + // Nothing special } diff --git a/openbas-model/src/main/java/io/openbas/database/model/DnsResolution.java b/openbas-model/src/main/java/io/openbas/database/model/DnsResolution.java index 1ea11f903e..a80bce9a67 100644 --- a/openbas-model/src/main/java/io/openbas/database/model/DnsResolution.java +++ b/openbas-model/src/main/java/io/openbas/database/model/DnsResolution.java @@ -29,9 +29,7 @@ public class DnsResolution extends Payload { @NotNull private String hostname; - public DnsResolution() { - - } + public DnsResolution() {} public DnsResolution(String id, String type, String name) { super(id, type, name); diff --git a/openbas-model/src/main/java/io/openbas/database/model/Document.java b/openbas-model/src/main/java/io/openbas/database/model/Document.java index d3cb947b35..a3b31f70b7 100644 --- a/openbas-model/src/main/java/io/openbas/database/model/Document.java +++ b/openbas-model/src/main/java/io/openbas/database/model/Document.java @@ -8,102 +8,103 @@ import io.openbas.helper.MultiIdSetDeserializer; import jakarta.persistence.*; import jakarta.validation.constraints.NotBlank; +import java.util.*; import lombok.Getter; import lombok.Setter; import org.hibernate.annotations.UuidGenerator; -import java.util.*; - @Setter @Getter @Entity @Table(name = "documents") @EntityListeners(ModelBaseListener.class) @NamedEntityGraphs({ - @NamedEntityGraph( - name = "Document.tags-scenarios-exercises", - attributeNodes = { - @NamedAttributeNode("tags"), - @NamedAttributeNode("scenarios"), - @NamedAttributeNode("exercises") - } - ) + @NamedEntityGraph( + name = "Document.tags-scenarios-exercises", + attributeNodes = { + @NamedAttributeNode("tags"), + @NamedAttributeNode("scenarios"), + @NamedAttributeNode("exercises") + }) }) public class Document implements Base { - @Id - @Column(name = "document_id") - @GeneratedValue(generator = "UUID") - @UuidGenerator - @JsonProperty("document_id") - @NotBlank - private String id; + @Id + @Column(name = "document_id") + @GeneratedValue(generator = "UUID") + @UuidGenerator + @JsonProperty("document_id") + @NotBlank + private String id; - @Column(name = "document_name") - @JsonProperty("document_name") - @Queryable(searchable = true, sortable = true) - @NotBlank - private String name; + @Column(name = "document_name") + @JsonProperty("document_name") + @Queryable(searchable = true, sortable = true) + @NotBlank + private String name; - @Column(name = "document_target") - @JsonProperty("document_target") - private String target; + @Column(name = "document_target") + @JsonProperty("document_target") + private String target; - @Column(name = "document_description") - @JsonProperty("document_description") - @Queryable(searchable = true, sortable = true) - private String description; + @Column(name = "document_description") + @JsonProperty("document_description") + @Queryable(searchable = true, sortable = true) + private String description; - @Column(name = "document_type") - @JsonProperty("document_type") - @Queryable(searchable = true, sortable = true) - @NotBlank - private String type; + @Column(name = "document_type") + @JsonProperty("document_type") + @Queryable(searchable = true, sortable = true) + @NotBlank + private String type; - @ManyToMany(fetch = FetchType.LAZY) - @JoinTable(name = "documents_tags", - joinColumns = @JoinColumn(name = "document_id"), - inverseJoinColumns = @JoinColumn(name = "tag_id")) - @JsonSerialize(using = MultiIdSetDeserializer.class) - @JsonProperty("document_tags") - @Queryable(sortable = true) - private Set tags = new HashSet<>(); + @ManyToMany(fetch = FetchType.LAZY) + @JoinTable( + name = "documents_tags", + joinColumns = @JoinColumn(name = "document_id"), + inverseJoinColumns = @JoinColumn(name = "tag_id")) + @JsonSerialize(using = MultiIdSetDeserializer.class) + @JsonProperty("document_tags") + @Queryable(sortable = true) + private Set tags = new HashSet<>(); - @ManyToMany(fetch = FetchType.LAZY) - @JoinTable(name = "exercises_documents", - joinColumns = @JoinColumn(name = "document_id"), - inverseJoinColumns = @JoinColumn(name = "exercise_id")) - @JsonSerialize(using = MultiIdSetDeserializer.class) - @JsonProperty("document_exercises") - private Set exercises = new HashSet<>(); + @ManyToMany(fetch = FetchType.LAZY) + @JoinTable( + name = "exercises_documents", + joinColumns = @JoinColumn(name = "document_id"), + inverseJoinColumns = @JoinColumn(name = "exercise_id")) + @JsonSerialize(using = MultiIdSetDeserializer.class) + @JsonProperty("document_exercises") + private Set exercises = new HashSet<>(); - @ManyToMany(fetch = FetchType.LAZY) - @JoinTable(name = "scenarios_documents", - joinColumns = @JoinColumn(name = "document_id"), - inverseJoinColumns = @JoinColumn(name = "scenario_id")) - @JsonSerialize(using = MultiIdSetDeserializer.class) - @JsonProperty("document_scenarios") - private Set scenarios = new HashSet<>(); + @ManyToMany(fetch = FetchType.LAZY) + @JoinTable( + name = "scenarios_documents", + joinColumns = @JoinColumn(name = "document_id"), + inverseJoinColumns = @JoinColumn(name = "scenario_id")) + @JsonSerialize(using = MultiIdSetDeserializer.class) + @JsonProperty("document_scenarios") + private Set scenarios = new HashSet<>(); - @OneToMany(mappedBy = "document", fetch = FetchType.LAZY) - @JsonIgnore - private List injectDocuments = new ArrayList<>(); + @OneToMany(mappedBy = "document", fetch = FetchType.LAZY) + @JsonIgnore + private List injectDocuments = new ArrayList<>(); - @Override - public boolean isUserHasAccess(User user) { - return exercises.stream().anyMatch(exercise -> exercise.isUserHasAccess(user)); - } + @Override + public boolean isUserHasAccess(User user) { + return exercises.stream().anyMatch(exercise -> exercise.isUserHasAccess(user)); + } - @Override - public boolean equals(Object o) { - if (this == o) return true; - if (o == null || !Base.class.isAssignableFrom(o.getClass())) return false; - Base base = (Base) o; - return id.equals(base.getId()); - } + @Override + public boolean equals(Object o) { + if (this == o) return true; + if (o == null || !Base.class.isAssignableFrom(o.getClass())) return false; + Base base = (Base) o; + return id.equals(base.getId()); + } - @Override - public int hashCode() { - return Objects.hash(id); - } + @Override + public int hashCode() { + return Objects.hash(id); + } } diff --git a/openbas-model/src/main/java/io/openbas/database/model/DryInject.java b/openbas-model/src/main/java/io/openbas/database/model/DryInject.java index 6d54f6acdc..b36a6e8a9f 100644 --- a/openbas-model/src/main/java/io/openbas/database/model/DryInject.java +++ b/openbas-model/src/main/java/io/openbas/database/model/DryInject.java @@ -1,22 +1,21 @@ package io.openbas.database.model; +import static java.util.Optional.of; +import static java.util.Optional.ofNullable; + import com.fasterxml.jackson.annotation.JsonProperty; import com.fasterxml.jackson.databind.annotation.JsonSerialize; import io.openbas.database.audit.ModelBaseListener; import io.openbas.helper.MonoIdDeserializer; import jakarta.persistence.*; import jakarta.validation.constraints.NotNull; -import lombok.Getter; -import lombok.Setter; -import org.hibernate.annotations.UuidGenerator; - import java.time.Instant; import java.util.Comparator; import java.util.Objects; import java.util.Optional; - -import static java.util.Optional.of; -import static java.util.Optional.ofNullable; +import lombok.Getter; +import lombok.Setter; +import org.hibernate.annotations.UuidGenerator; @Setter @Entity @@ -24,7 +23,8 @@ @EntityListeners(ModelBaseListener.class) public class DryInject implements Base, Injection { - public static final Comparator executionComparator = Comparator.comparing(o -> o.getDate().orElseThrow()); + public static final Comparator executionComparator = + Comparator.comparing(o -> o.getDate().orElseThrow()); @Getter @Id @@ -79,12 +79,12 @@ public boolean isUserHasAccess(User user) { @Override public boolean equals(Object o) { - if (this == o) { - return true; - } - if (o == null || !Base.class.isAssignableFrom(o.getClass())) { - return false; - } + if (this == o) { + return true; + } + if (o == null || !Base.class.isAssignableFrom(o.getClass())) { + return false; + } Base base = (Base) o; return id.equals(base.getId()); } diff --git a/openbas-model/src/main/java/io/openbas/database/model/DryInjectStatus.java b/openbas-model/src/main/java/io/openbas/database/model/DryInjectStatus.java index e9fa5f45fe..d6300beeda 100644 --- a/openbas-model/src/main/java/io/openbas/database/model/DryInjectStatus.java +++ b/openbas-model/src/main/java/io/openbas/database/model/DryInjectStatus.java @@ -4,110 +4,123 @@ import com.fasterxml.jackson.annotation.JsonProperty; import io.openbas.database.converter.InjectStatusExecutionConverter; import jakarta.persistence.*; -import lombok.Getter; -import lombok.Setter; -import org.hibernate.annotations.UuidGenerator; - import java.time.Duration; import java.time.Instant; import java.util.ArrayList; import java.util.List; import java.util.Objects; +import lombok.Getter; +import lombok.Setter; +import org.hibernate.annotations.UuidGenerator; @Setter @Getter @Entity @Table(name = "dryinjects_statuses") public class DryInjectStatus implements Base { - @Id - @Column(name = "status_id") - @GeneratedValue(generator = "UUID") - @UuidGenerator - @JsonProperty("status_id") - private String id; - - @Column(name = "status_name") - @JsonProperty("status_name") - @Enumerated(EnumType.STRING) - private ExecutionStatus name; - - // region dates tracking - @Column(name = "status_executions") - @Convert(converter = InjectStatusExecutionConverter.class) - @JsonProperty("status_traces") - private List traces = new ArrayList<>(); - - @Column(name = "tracking_sent_date") - @JsonProperty("tracking_sent_date") - private Instant trackingSentDate; // To Queue / processing engine - - @Column(name = "tracking_ack_date") - @JsonProperty("tracking_ack_date") - private Instant trackingAckDate; // Ack from remote injector - - @Column(name = "tracking_end_date") - @JsonProperty("tracking_end_date") - private Instant trackingEndDate; // Done task from injector - - @Column(name = "tracking_total_execution_time") - @JsonProperty("tracking_total_execution_time") - private Long trackingTotalExecutionTime; - // endregion - - // region count - @Column(name = "tracking_total_count") - @JsonProperty("tracking_total_count") - private Integer trackingTotalCount; - - @Column(name = "tracking_total_error") - @JsonProperty("tracking_total_error") - private Integer trackingTotalError; - - @Column(name = "tracking_total_success") - @JsonProperty("tracking_total_success") - private Integer trackingTotalSuccess; - // endregion - - @OneToOne - @JoinColumn(name = "status_dryinject") - @JsonIgnore - private DryInject dryInject; - - @Override - public boolean isUserHasAccess(User user) { - return dryInject.isUserHasAccess(user); - } - - public static DryInjectStatus fromExecution(Execution execution, DryInject executedInject) { - DryInjectStatus injectStatus = new DryInjectStatus(); - injectStatus.setDryInject(executedInject); - injectStatus.getTraces().addAll(execution.getTraces()); - int numberOfElements = execution.getTraces().size(); - int numberOfError = (int) execution.getTraces().stream().filter(ex -> ex.getStatus().equals(ExecutionStatus.ERROR)).count(); - int numberOfSuccess = (int) execution.getTraces().stream().filter(ex -> ex.getStatus().equals(ExecutionStatus.SUCCESS)).count(); - injectStatus.setTrackingTotalError(numberOfError); - injectStatus.setTrackingTotalSuccess(numberOfSuccess); - injectStatus.setTrackingTotalCount(numberOfElements); - injectStatus.setTrackingEndDate(Instant.now()); - ExecutionStatus globalStatus = numberOfSuccess > 0 ? ExecutionStatus.SUCCESS : ExecutionStatus.ERROR; - ExecutionStatus finalStatus = numberOfError > 0 && numberOfSuccess > 0 ? ExecutionStatus.PARTIAL : globalStatus; - injectStatus.setName(finalStatus); - if (injectStatus.getTrackingSentDate() != null && injectStatus.getTrackingEndDate() != null) { - injectStatus.setTrackingTotalExecutionTime(Duration.between(injectStatus.getTrackingSentDate(), injectStatus.getTrackingEndDate()).getSeconds()); - } - return injectStatus; - } - - @Override - public boolean equals(Object o) { - if (this == o) return true; - if (o == null || !Base.class.isAssignableFrom(o.getClass())) return false; - Base base = (Base) o; - return id.equals(base.getId()); - } - - @Override - public int hashCode() { - return Objects.hash(id); + @Id + @Column(name = "status_id") + @GeneratedValue(generator = "UUID") + @UuidGenerator + @JsonProperty("status_id") + private String id; + + @Column(name = "status_name") + @JsonProperty("status_name") + @Enumerated(EnumType.STRING) + private ExecutionStatus name; + + // region dates tracking + @Column(name = "status_executions") + @Convert(converter = InjectStatusExecutionConverter.class) + @JsonProperty("status_traces") + private List traces = new ArrayList<>(); + + @Column(name = "tracking_sent_date") + @JsonProperty("tracking_sent_date") + private Instant trackingSentDate; // To Queue / processing engine + + @Column(name = "tracking_ack_date") + @JsonProperty("tracking_ack_date") + private Instant trackingAckDate; // Ack from remote injector + + @Column(name = "tracking_end_date") + @JsonProperty("tracking_end_date") + private Instant trackingEndDate; // Done task from injector + + @Column(name = "tracking_total_execution_time") + @JsonProperty("tracking_total_execution_time") + private Long trackingTotalExecutionTime; + + // endregion + + // region count + @Column(name = "tracking_total_count") + @JsonProperty("tracking_total_count") + private Integer trackingTotalCount; + + @Column(name = "tracking_total_error") + @JsonProperty("tracking_total_error") + private Integer trackingTotalError; + + @Column(name = "tracking_total_success") + @JsonProperty("tracking_total_success") + private Integer trackingTotalSuccess; + + // endregion + + @OneToOne + @JoinColumn(name = "status_dryinject") + @JsonIgnore + private DryInject dryInject; + + @Override + public boolean isUserHasAccess(User user) { + return dryInject.isUserHasAccess(user); + } + + public static DryInjectStatus fromExecution(Execution execution, DryInject executedInject) { + DryInjectStatus injectStatus = new DryInjectStatus(); + injectStatus.setDryInject(executedInject); + injectStatus.getTraces().addAll(execution.getTraces()); + int numberOfElements = execution.getTraces().size(); + int numberOfError = + (int) + execution.getTraces().stream() + .filter(ex -> ex.getStatus().equals(ExecutionStatus.ERROR)) + .count(); + int numberOfSuccess = + (int) + execution.getTraces().stream() + .filter(ex -> ex.getStatus().equals(ExecutionStatus.SUCCESS)) + .count(); + injectStatus.setTrackingTotalError(numberOfError); + injectStatus.setTrackingTotalSuccess(numberOfSuccess); + injectStatus.setTrackingTotalCount(numberOfElements); + injectStatus.setTrackingEndDate(Instant.now()); + ExecutionStatus globalStatus = + numberOfSuccess > 0 ? ExecutionStatus.SUCCESS : ExecutionStatus.ERROR; + ExecutionStatus finalStatus = + numberOfError > 0 && numberOfSuccess > 0 ? ExecutionStatus.PARTIAL : globalStatus; + injectStatus.setName(finalStatus); + if (injectStatus.getTrackingSentDate() != null && injectStatus.getTrackingEndDate() != null) { + injectStatus.setTrackingTotalExecutionTime( + Duration.between(injectStatus.getTrackingSentDate(), injectStatus.getTrackingEndDate()) + .getSeconds()); } + return injectStatus; + } + + @Override + public boolean equals(Object o) { + if (this == o) return true; + if (o == null || !Base.class.isAssignableFrom(o.getClass())) return false; + Base base = (Base) o; + return id.equals(base.getId()); + } + + @Override + public int hashCode() { + return Objects.hash(id); + } } diff --git a/openbas-model/src/main/java/io/openbas/database/model/Dryrun.java b/openbas-model/src/main/java/io/openbas/database/model/Dryrun.java index e218a99b16..1bb2696f18 100644 --- a/openbas-model/src/main/java/io/openbas/database/model/Dryrun.java +++ b/openbas-model/src/main/java/io/openbas/database/model/Dryrun.java @@ -6,18 +6,17 @@ import io.openbas.database.audit.ModelBaseListener; import io.openbas.helper.MonoIdDeserializer; import io.openbas.helper.MultiIdListDeserializer; +import jakarta.persistence.*; import jakarta.validation.constraints.NotBlank; import jakarta.validation.constraints.NotNull; -import lombok.Getter; -import lombok.Setter; -import org.hibernate.annotations.UuidGenerator; - -import jakarta.persistence.*; import java.time.Instant; import java.util.ArrayList; import java.util.List; import java.util.Objects; import java.util.Optional; +import lombok.Getter; +import lombok.Setter; +import org.hibernate.annotations.UuidGenerator; @Setter @Getter @@ -26,83 +25,85 @@ @EntityListeners(ModelBaseListener.class) public class Dryrun implements Base { - @Id - @Column(name = "dryrun_id") - @GeneratedValue(generator = "UUID") - @UuidGenerator - @JsonProperty("dryrun_id") - @NotBlank - private String id; - - @Column(name = "dryrun_name") - @JsonProperty("dryrun_name") - private String name; - - @Column(name = "dryrun_speed") - @JsonProperty("dryrun_speed") - private int speed; - - @Column(name = "dryrun_date") - @JsonProperty("dryrun_date") - @NotNull - private Instant date; - - @ManyToOne(fetch = FetchType.LAZY) - @JoinColumn(name = "dryrun_exercise") - @JsonSerialize(using = MonoIdDeserializer.class) - @JsonProperty("dryrun_exercise") - private Exercise exercise; - - @OneToMany(mappedBy = "run", fetch = FetchType.LAZY) - @JsonIgnore - private List injects = new ArrayList<>(); - - @ManyToMany(fetch = FetchType.LAZY) - @JoinTable(name = "dryruns_users", - joinColumns = @JoinColumn(name = "dryrun_id"), - inverseJoinColumns = @JoinColumn(name = "user_id")) - @JsonSerialize(using = MultiIdListDeserializer.class) - @JsonProperty("dryrun_users") - private List users = new ArrayList<>(); - - // region transient - @JsonProperty("dryrun_finished") - public boolean isFinished() { - List injects = getInjects(); - return injects.stream().allMatch(dryInject -> dryInject.getStatus() != null); - } - - @JsonProperty("dryrun_users_number") - public long getUsersNumber() { - return getUsers().size(); - } - - @JsonProperty("dryrun_start_date") - public Optional getRunStart() { - return getInjects().stream().min(DryInject.executionComparator).flatMap(DryInject::getDate); - } - - @JsonProperty("dryrun_end_date") - public Optional getRunEnd() { - return getInjects().stream().max(DryInject.executionComparator).flatMap(DryInject::getDate); - } - // endregion + @Id + @Column(name = "dryrun_id") + @GeneratedValue(generator = "UUID") + @UuidGenerator + @JsonProperty("dryrun_id") + @NotBlank + private String id; + + @Column(name = "dryrun_name") + @JsonProperty("dryrun_name") + private String name; + + @Column(name = "dryrun_speed") + @JsonProperty("dryrun_speed") + private int speed; + + @Column(name = "dryrun_date") + @JsonProperty("dryrun_date") + @NotNull + private Instant date; + + @ManyToOne(fetch = FetchType.LAZY) + @JoinColumn(name = "dryrun_exercise") + @JsonSerialize(using = MonoIdDeserializer.class) + @JsonProperty("dryrun_exercise") + private Exercise exercise; + + @OneToMany(mappedBy = "run", fetch = FetchType.LAZY) + @JsonIgnore + private List injects = new ArrayList<>(); + + @ManyToMany(fetch = FetchType.LAZY) + @JoinTable( + name = "dryruns_users", + joinColumns = @JoinColumn(name = "dryrun_id"), + inverseJoinColumns = @JoinColumn(name = "user_id")) + @JsonSerialize(using = MultiIdListDeserializer.class) + @JsonProperty("dryrun_users") + private List users = new ArrayList<>(); + + // region transient + @JsonProperty("dryrun_finished") + public boolean isFinished() { + List injects = getInjects(); + return injects.stream().allMatch(dryInject -> dryInject.getStatus() != null); + } + + @JsonProperty("dryrun_users_number") + public long getUsersNumber() { + return getUsers().size(); + } + + @JsonProperty("dryrun_start_date") + public Optional getRunStart() { + return getInjects().stream().min(DryInject.executionComparator).flatMap(DryInject::getDate); + } + + @JsonProperty("dryrun_end_date") + public Optional getRunEnd() { + return getInjects().stream().max(DryInject.executionComparator).flatMap(DryInject::getDate); + } + + // endregion + + @Override + public boolean isUserHasAccess(User user) { + return exercise.isUserHasAccess(user); + } @Override - public boolean isUserHasAccess(User user) { - return exercise.isUserHasAccess(user); - } + public boolean equals(Object o) { + if (this == o) return true; + if (o == null || !Base.class.isAssignableFrom(o.getClass())) return false; + Base base = (Base) o; + return id.equals(base.getId()); + } @Override - public boolean equals(Object o) { - if (this == o) return true; - if (o == null || !Base.class.isAssignableFrom(o.getClass())) return false; - Base base = (Base) o; - return id.equals(base.getId()); - } - - @Override - public int hashCode() { - return Objects.hash(id); - } + public int hashCode() { + return Objects.hash(id); + } } diff --git a/openbas-model/src/main/java/io/openbas/database/model/Endpoint.java b/openbas-model/src/main/java/io/openbas/database/model/Endpoint.java index 6fb96e738f..f11f3ba660 100644 --- a/openbas-model/src/main/java/io/openbas/database/model/Endpoint.java +++ b/openbas-model/src/main/java/io/openbas/database/model/Endpoint.java @@ -86,9 +86,7 @@ public enum PLATFORM_TYPE { @JsonProperty("endpoint_mac_addresses") private String[] macAddresses; - public Endpoint() { - - } + public Endpoint() {} public Endpoint(String id, String type, String name, PLATFORM_TYPE platform) { super(id, type, name); diff --git a/openbas-model/src/main/java/io/openbas/database/model/Evaluation.java b/openbas-model/src/main/java/io/openbas/database/model/Evaluation.java index 6026178f06..ad6af1c6cc 100644 --- a/openbas-model/src/main/java/io/openbas/database/model/Evaluation.java +++ b/openbas-model/src/main/java/io/openbas/database/model/Evaluation.java @@ -1,21 +1,20 @@ package io.openbas.database.model; +import static java.time.Instant.now; + import com.fasterxml.jackson.annotation.JsonProperty; import com.fasterxml.jackson.databind.annotation.JsonSerialize; import io.openbas.database.audit.ModelBaseListener; import io.openbas.helper.MonoIdDeserializer; +import jakarta.persistence.*; import jakarta.validation.constraints.NotBlank; import jakarta.validation.constraints.NotNull; +import java.time.Instant; +import java.util.Objects; import lombok.Getter; import lombok.Setter; import org.hibernate.annotations.UuidGenerator; -import jakarta.persistence.*; -import java.time.Instant; -import java.util.Objects; - -import static java.time.Instant.now; - @Setter @Getter @Entity @@ -23,57 +22,57 @@ @EntityListeners(ModelBaseListener.class) public class Evaluation implements Base { - @Id - @Column(name = "evaluation_id") - @GeneratedValue(generator = "UUID") - @UuidGenerator - @JsonProperty("evaluation_id") - @NotBlank - private String id; + @Id + @Column(name = "evaluation_id") + @GeneratedValue(generator = "UUID") + @UuidGenerator + @JsonProperty("evaluation_id") + @NotBlank + private String id; - @ManyToOne(fetch = FetchType.LAZY) - @JoinColumn(name = "evaluation_objective") - @JsonSerialize(using = MonoIdDeserializer.class) - @JsonProperty("evaluation_objective") - @NotNull - private Objective objective; + @ManyToOne(fetch = FetchType.LAZY) + @JoinColumn(name = "evaluation_objective") + @JsonSerialize(using = MonoIdDeserializer.class) + @JsonProperty("evaluation_objective") + @NotNull + private Objective objective; - @ManyToOne(fetch = FetchType.LAZY) - @JoinColumn(name = "evaluation_user") - @JsonSerialize(using = MonoIdDeserializer.class) - @JsonProperty("evaluation_user") - @NotNull - private User user; + @ManyToOne(fetch = FetchType.LAZY) + @JoinColumn(name = "evaluation_user") + @JsonSerialize(using = MonoIdDeserializer.class) + @JsonProperty("evaluation_user") + @NotNull + private User user; - @Column(name = "evaluation_score") - @JsonProperty("evaluation_score") - private Long score; + @Column(name = "evaluation_score") + @JsonProperty("evaluation_score") + private Long score; - @Column(name = "evaluation_created_at") - @JsonProperty("evaluation_created_at") - @NotNull - private Instant created = now(); + @Column(name = "evaluation_created_at") + @JsonProperty("evaluation_created_at") + @NotNull + private Instant created = now(); - @Column(name = "evaluation_updated_at") - @JsonProperty("evaluation_updated_at") - @NotNull - private Instant updated = now(); + @Column(name = "evaluation_updated_at") + @JsonProperty("evaluation_updated_at") + @NotNull + private Instant updated = now(); - @Override - public boolean isUserHasAccess(User user) { - return getObjective().isUserHasAccess(user); - } + @Override + public boolean isUserHasAccess(User user) { + return getObjective().isUserHasAccess(user); + } - @Override - public boolean equals(Object o) { - if (this == o) return true; - if (o == null || !Base.class.isAssignableFrom(o.getClass())) return false; - Base base = (Base) o; - return id.equals(base.getId()); - } + @Override + public boolean equals(Object o) { + if (this == o) return true; + if (o == null || !Base.class.isAssignableFrom(o.getClass())) return false; + Base base = (Base) o; + return id.equals(base.getId()); + } - @Override - public int hashCode() { - return Objects.hash(id); - } + @Override + public int hashCode() { + return Objects.hash(id); + } } diff --git a/openbas-model/src/main/java/io/openbas/database/model/Executable.java b/openbas-model/src/main/java/io/openbas/database/model/Executable.java index 69c0e7d51c..6bfe98faed 100644 --- a/openbas-model/src/main/java/io/openbas/database/model/Executable.java +++ b/openbas-model/src/main/java/io/openbas/database/model/Executable.java @@ -35,9 +35,7 @@ public class Executable extends Payload { @NotNull private Endpoint.PLATFORM_ARCH executableArch; - public Executable() { - - } + public Executable() {} public Executable(String id, String type, String name) { super(id, type, name); diff --git a/openbas-model/src/main/java/io/openbas/database/model/Execution.java b/openbas-model/src/main/java/io/openbas/database/model/Execution.java index dd9ecc505c..d5c465a070 100644 --- a/openbas-model/src/main/java/io/openbas/database/model/Execution.java +++ b/openbas-model/src/main/java/io/openbas/database/model/Execution.java @@ -1,105 +1,106 @@ package io.openbas.database.model; -import com.fasterxml.jackson.annotation.JsonProperty; -import lombok.Getter; -import lombok.Setter; +import static java.time.Instant.now; +import com.fasterxml.jackson.annotation.JsonProperty; import java.time.Instant; import java.util.ArrayList; import java.util.List; import java.util.Objects; import java.util.logging.Level; import java.util.logging.Logger; - -import static java.time.Instant.now; +import lombok.Getter; +import lombok.Setter; public class Execution { - private static final Logger LOGGER = Logger.getLogger(Execution.class.getName()); - - @Getter - @JsonProperty("execution_runtime") - private boolean runtime; - - @Getter - @Setter - @JsonProperty("execution_async") - private boolean async; - - @Getter - @Setter - @JsonProperty("execution_expected_count") - private Integer expectedCount; - - @Getter - @JsonProperty("execution_start") - private Instant startTime; - - @JsonProperty("execution_stop") - private Instant stopTime; - - @Getter - @Setter - @JsonProperty("execution_traces") - private List traces = new ArrayList<>(); - - public Execution() { - // Default constructor for serialization + private static final Logger LOGGER = Logger.getLogger(Execution.class.getName()); + + @Getter + @JsonProperty("execution_runtime") + private boolean runtime; + + @Getter + @Setter + @JsonProperty("execution_async") + private boolean async; + + @Getter + @Setter + @JsonProperty("execution_expected_count") + private Integer expectedCount; + + @Getter + @JsonProperty("execution_start") + private Instant startTime; + + @JsonProperty("execution_stop") + private Instant stopTime; + + @Getter + @Setter + @JsonProperty("execution_traces") + private List traces = new ArrayList<>(); + + public Execution() { + // Default constructor for serialization + } + + public Execution(boolean runtime) { + this.runtime = runtime; + this.startTime = now(); + } + + @SuppressWarnings("unused") + public void setRuntime(boolean runtime) { + this.runtime = runtime; + } + + public void stop() { + this.stopTime = now(); + } + + public void addTrace(InjectStatusExecution context) { + ExecutionStatus status = context.getStatus(); + if (status.equals(ExecutionStatus.SUCCESS) || status.equals(ExecutionStatus.INFO)) { + LOGGER.log(Level.INFO, context.getMessage()); + } else { + LOGGER.log(Level.SEVERE, context.getMessage()); } - - public Execution(boolean runtime) { - this.runtime = runtime; - this.startTime = now(); - } - - @SuppressWarnings("unused") - public void setRuntime(boolean runtime) { - this.runtime = runtime; - } - - public void stop() { - this.stopTime = now(); - } - - public void addTrace(InjectStatusExecution context) { - ExecutionStatus status = context.getStatus(); - if (status.equals(ExecutionStatus.SUCCESS) || status.equals(ExecutionStatus.INFO)) { - LOGGER.log(Level.INFO, context.getMessage()); - } else { - LOGGER.log(Level.SEVERE, context.getMessage()); - } - this.traces.add(context); - } - - @JsonProperty("execution_time") - public int getExecutionTime() { - return (int) (this.stopTime.toEpochMilli() - this.startTime.toEpochMilli()); - } - - public ExecutionStatus getStatus() { - boolean hasSuccess = traces.stream().anyMatch(context -> context.getStatus().equals(ExecutionStatus.SUCCESS)); - boolean hasError = traces.stream().anyMatch(context -> context.getStatus().equals(ExecutionStatus.ERROR)); - if (!hasSuccess && !hasError) { - return ExecutionStatus.PENDING; - } else if (hasSuccess && hasError) { - return ExecutionStatus.PARTIAL; - } else { - return hasSuccess ? ExecutionStatus.SUCCESS : ExecutionStatus.ERROR; - } - } - - @Override - public boolean equals(Object o) { - if (this == o) return true; - if (o == null || getClass() != o.getClass()) return false; - Execution execution = (Execution) o; - return Objects.equals(stopTime, execution.stopTime) - && startTime.equals(execution.startTime) - && Objects.equals(traces, execution.traces); - } - - @Override - public int hashCode() { - return Objects.hash(stopTime, startTime, traces); + this.traces.add(context); + } + + @JsonProperty("execution_time") + public int getExecutionTime() { + return (int) (this.stopTime.toEpochMilli() - this.startTime.toEpochMilli()); + } + + public ExecutionStatus getStatus() { + boolean hasSuccess = + traces.stream().anyMatch(context -> context.getStatus().equals(ExecutionStatus.SUCCESS)); + boolean hasError = + traces.stream().anyMatch(context -> context.getStatus().equals(ExecutionStatus.ERROR)); + if (!hasSuccess && !hasError) { + return ExecutionStatus.PENDING; + } else if (hasSuccess && hasError) { + return ExecutionStatus.PARTIAL; + } else { + return hasSuccess ? ExecutionStatus.SUCCESS : ExecutionStatus.ERROR; } + } + + @Override + public boolean equals(Object o) { + if (this == o) return true; + if (o == null || getClass() != o.getClass()) return false; + Execution execution = (Execution) o; + return Objects.equals(stopTime, execution.stopTime) + && startTime.equals(execution.startTime) + && Objects.equals(traces, execution.traces); + } + + @Override + public int hashCode() { + return Objects.hash(stopTime, startTime, traces); + } } diff --git a/openbas-model/src/main/java/io/openbas/database/model/ExecutionStatus.java b/openbas-model/src/main/java/io/openbas/database/model/ExecutionStatus.java index b7b24cecfc..7c4d6a33c0 100644 --- a/openbas-model/src/main/java/io/openbas/database/model/ExecutionStatus.java +++ b/openbas-model/src/main/java/io/openbas/database/model/ExecutionStatus.java @@ -1,14 +1,14 @@ package io.openbas.database.model; public enum ExecutionStatus { - DRAFT, - INFO, - QUEUING, - EXECUTING, - PENDING, - PARTIAL, - ERROR, - MAYBE_PARTIAL_PREVENTED, - MAYBE_PREVENTED, - SUCCESS + DRAFT, + INFO, + QUEUING, + EXECUTING, + PENDING, + PARTIAL, + ERROR, + MAYBE_PARTIAL_PREVENTED, + MAYBE_PREVENTED, + SUCCESS } diff --git a/openbas-model/src/main/java/io/openbas/database/model/Executor.java b/openbas-model/src/main/java/io/openbas/database/model/Executor.java index 32a7924d50..396a7ee20c 100644 --- a/openbas-model/src/main/java/io/openbas/database/model/Executor.java +++ b/openbas-model/src/main/java/io/openbas/database/model/Executor.java @@ -1,5 +1,7 @@ package io.openbas.database.model; +import static java.time.Instant.now; + import com.fasterxml.jackson.annotation.JsonIgnore; import com.fasterxml.jackson.annotation.JsonProperty; import io.hypersistence.utils.hibernate.type.array.StringArrayType; @@ -7,15 +9,12 @@ import jakarta.persistence.*; import jakarta.validation.constraints.NotBlank; import jakarta.validation.constraints.NotNull; +import java.time.Instant; +import java.util.Objects; import lombok.Getter; import lombok.Setter; import org.hibernate.annotations.Type; -import java.time.Instant; -import java.util.Objects; - -import static java.time.Instant.now; - @Getter @Setter @Entity @@ -23,62 +22,62 @@ @EntityListeners(ModelBaseListener.class) public class Executor implements Base { - @Id - @Column(name = "executor_id") - @JsonProperty("executor_id") - @NotBlank - private String id; + @Id + @Column(name = "executor_id") + @JsonProperty("executor_id") + @NotBlank + private String id; - @Column(name = "executor_name") - @JsonProperty("executor_name") - @NotBlank - private String name; + @Column(name = "executor_name") + @JsonProperty("executor_name") + @NotBlank + private String name; - @Column(name = "executor_type") - @JsonProperty("executor_type") - @NotBlank - private String type; + @Column(name = "executor_type") + @JsonProperty("executor_type") + @NotBlank + private String type; - @Type(StringArrayType.class) - @Column(name = "executor_platforms", columnDefinition = "text[]") - @JsonProperty("executor_platforms") - private String[] platforms = new String[0]; + @Type(StringArrayType.class) + @Column(name = "executor_platforms", columnDefinition = "text[]") + @JsonProperty("executor_platforms") + private String[] platforms = new String[0]; - @Column(name = "executor_doc") - @JsonProperty("executor_doc") - private String doc; + @Column(name = "executor_doc") + @JsonProperty("executor_doc") + private String doc; - @Column(name = "executor_created_at") - @JsonProperty("executor_created_at") - @NotNull - private Instant createdAt = now(); + @Column(name = "executor_created_at") + @JsonProperty("executor_created_at") + @NotNull + private Instant createdAt = now(); - @Column(name = "executor_updated_at") - @JsonProperty("executor_updated_at") - @NotNull - private Instant updatedAt = now(); + @Column(name = "executor_updated_at") + @JsonProperty("executor_updated_at") + @NotNull + private Instant updatedAt = now(); - @JsonIgnore - @Override - public boolean isUserHasAccess(User user) { - return user.isAdmin(); - } + @JsonIgnore + @Override + public boolean isUserHasAccess(User user) { + return user.isAdmin(); + } - @Override - public String toString() { - return name; - } + @Override + public String toString() { + return name; + } - @Override - public boolean equals(Object o) { - if (this == o) return true; - if (o == null || !Base.class.isAssignableFrom(o.getClass())) return false; - Base base = (Base) o; - return id.equals(base.getId()); - } + @Override + public boolean equals(Object o) { + if (this == o) return true; + if (o == null || !Base.class.isAssignableFrom(o.getClass())) return false; + Base base = (Base) o; + return id.equals(base.getId()); + } - @Override - public int hashCode() { - return Objects.hash(id); - } + @Override + public int hashCode() { + return Objects.hash(id); + } } diff --git a/openbas-model/src/main/java/io/openbas/database/model/Exercise.java b/openbas-model/src/main/java/io/openbas/database/model/Exercise.java index 0f79a31898..b880646e5a 100644 --- a/openbas-model/src/main/java/io/openbas/database/model/Exercise.java +++ b/openbas-model/src/main/java/io/openbas/database/model/Exercise.java @@ -1,5 +1,11 @@ package io.openbas.database.model; +import static io.openbas.database.model.Grant.GRANT_TYPE.OBSERVER; +import static io.openbas.database.model.Grant.GRANT_TYPE.PLANNER; +import static io.openbas.helper.UserHelper.getUsersByType; +import static java.time.Instant.now; +import static java.util.Optional.ofNullable; + import com.fasterxml.jackson.annotation.JsonIgnore; import com.fasterxml.jackson.annotation.JsonProperty; import com.fasterxml.jackson.databind.annotation.JsonSerialize; @@ -12,19 +18,12 @@ import jakarta.validation.constraints.Email; import jakarta.validation.constraints.NotBlank; import jakarta.validation.constraints.NotNull; -import lombok.Getter; -import lombok.Setter; -import org.hibernate.annotations.UuidGenerator; - import java.time.Instant; import java.util.*; import java.util.stream.Collectors; - -import static io.openbas.database.model.Grant.GRANT_TYPE.OBSERVER; -import static io.openbas.database.model.Grant.GRANT_TYPE.PLANNER; -import static io.openbas.helper.UserHelper.getUsersByType; -import static java.time.Instant.now; -import static java.util.Optional.ofNullable; +import lombok.Getter; +import lombok.Setter; +import org.hibernate.annotations.UuidGenerator; @Setter @Entity @@ -114,7 +113,9 @@ public class Exercise implements Base { @Getter @ElementCollection(fetch = FetchType.EAGER) - @CollectionTable(name = "exercise_mails_reply_to", joinColumns = @JoinColumn(name = "exercise_id")) + @CollectionTable( + name = "exercise_mails_reply_to", + joinColumns = @JoinColumn(name = "exercise_id")) @Column(name = "exercise_reply_to", nullable = false) @JsonProperty("exercise_mails_reply_to") private List replyTos = new ArrayList<>(); @@ -142,7 +143,8 @@ public class Exercise implements Base { @Getter @ManyToOne(fetch = FetchType.LAZY) - @JoinTable(name = "scenarios_exercises", + @JoinTable( + name = "scenarios_exercises", joinColumns = @JoinColumn(name = "exercise_id"), inverseJoinColumns = @JoinColumn(name = "scenario_id")) @JsonSerialize(using = MonoIdDeserializer.class) @@ -179,7 +181,8 @@ public class Exercise implements Base { @Getter @ManyToMany(fetch = FetchType.LAZY) - @JoinTable(name = "exercises_teams", + @JoinTable( + name = "exercises_teams", joinColumns = @JoinColumn(name = "exercise_id"), inverseJoinColumns = @JoinColumn(name = "team_id")) @JsonSerialize(using = MultiIdListDeserializer.class) @@ -187,7 +190,11 @@ public class Exercise implements Base { private List teams = new ArrayList<>(); @Getter - @OneToMany(mappedBy = "exercise", fetch = FetchType.LAZY, cascade = CascadeType.ALL, orphanRemoval = true) + @OneToMany( + mappedBy = "exercise", + fetch = FetchType.LAZY, + cascade = CascadeType.ALL, + orphanRemoval = true) @JsonProperty("exercise_teams_users") @JsonSerialize(using = MultiModelDeserializer.class) private List teamUsers = new ArrayList<>(); @@ -210,7 +217,8 @@ public class Exercise implements Base { @Getter @ManyToMany(fetch = FetchType.LAZY) - @JoinTable(name = "exercises_tags", + @JoinTable( + name = "exercises_tags", joinColumns = @JoinColumn(name = "exercise_id"), inverseJoinColumns = @JoinColumn(name = "tag_id")) @JsonSerialize(using = MultiIdSetDeserializer.class) @@ -220,7 +228,8 @@ public class Exercise implements Base { @Getter @ManyToMany(fetch = FetchType.LAZY) - @JoinTable(name = "exercises_documents", + @JoinTable( + name = "exercises_documents", joinColumns = @JoinColumn(name = "exercise_id"), inverseJoinColumns = @JoinColumn(name = "document_id")) @JsonSerialize(using = MultiIdListDeserializer.class) @@ -247,8 +256,12 @@ public Map getInjectStatistics() { @JsonProperty("exercise_lessons_answers_number") public Long getLessonsAnswersNumbers() { - return getLessonsCategories().stream().flatMap(lessonsCategory -> lessonsCategory.getQuestions() - .stream().flatMap(lessonsQuestion -> lessonsQuestion.getAnswers().stream())).count(); + return getLessonsCategories().stream() + .flatMap( + lessonsCategory -> + lessonsCategory.getQuestions().stream() + .flatMap(lessonsQuestion -> lessonsQuestion.getAnswers().stream())) + .count(); } @JsonProperty("exercise_planners") @@ -269,7 +282,8 @@ public Optional getNextInjectExecution() { .filter(inject -> inject.getStatus().isEmpty()) .filter(inject -> inject.getDate().isPresent()) .filter(inject -> inject.getDate().get().isAfter(now())) - .findFirst().flatMap(Inject::getDate); + .findFirst() + .flatMap(Inject::getDate); } @JsonIgnore @@ -296,8 +310,8 @@ public List getUsers() { @JsonProperty("exercise_score") public Double getEvaluationAverage() { - double evaluationAverage = getObjectives().stream().mapToDouble(Objective::getEvaluationAverage).average() - .orElse(0D); + double evaluationAverage = + getObjectives().stream().mapToDouble(Objective::getEvaluationAverage).average().orElse(0D); return Math.round(evaluationAverage * 100.0) / 100.0; } @@ -315,24 +329,27 @@ public long getCommunicationsNumber() { @JsonProperty("exercise_platforms") public List getPlatforms() { return getInjects().stream() - .flatMap(inject -> inject.getInjectorContract() - .map(InjectorContract::getPlatforms) - .stream() - .flatMap(Arrays::stream)) + .flatMap( + inject -> + inject.getInjectorContract().map(InjectorContract::getPlatforms).stream() + .flatMap(Arrays::stream)) .distinct() .toList(); } // -- KILL CHAIN PHASES -- @JsonProperty("exercise_kill_chain_phases") - @Queryable(filterable = true, dynamicValues = true, path = "injects.injectorContract.attackPatterns.killChainPhases.id") + @Queryable( + filterable = true, + dynamicValues = true, + path = "injects.injectorContract.attackPatterns.killChainPhases.id") public List getKillChainPhases() { return getInjects().stream() - .flatMap(inject -> inject.getInjectorContract() - .map(InjectorContract::getAttackPatterns) - .stream() - .flatMap(Collection::stream) - .flatMap(attackPattern -> attackPattern.getKillChainPhases().stream())) + .flatMap( + inject -> + inject.getInjectorContract().map(InjectorContract::getAttackPatterns).stream() + .flatMap(Collection::stream) + .flatMap(attackPattern -> attackPattern.getKillChainPhases().stream())) .distinct() .toList(); } @@ -356,6 +373,7 @@ public List nextPossibleStatus() { } return List.of(); } + // endregion public Optional getStart() { @@ -371,7 +389,9 @@ public Optional getCurrentPause() { } public List getInjects() { - return injects.stream().sorted(Inject.executionComparator).collect(Collectors.toList()); // Should be modifiable + return injects.stream() + .sorted(Inject.executionComparator) + .collect(Collectors.toList()); // Should be modifiable } public List
getArticlesForChannel(Channel channel) { diff --git a/openbas-model/src/main/java/io/openbas/database/model/ExerciseStatus.java b/openbas-model/src/main/java/io/openbas/database/model/ExerciseStatus.java index f9bdc49d9a..4ef4509c60 100644 --- a/openbas-model/src/main/java/io/openbas/database/model/ExerciseStatus.java +++ b/openbas-model/src/main/java/io/openbas/database/model/ExerciseStatus.java @@ -1,9 +1,9 @@ package io.openbas.database.model; public enum ExerciseStatus { - SCHEDULED, - CANCELED, - RUNNING, - PAUSED, - FINISHED + SCHEDULED, + CANCELED, + RUNNING, + PAUSED, + FINISHED } diff --git a/openbas-model/src/main/java/io/openbas/database/model/ExerciseTeamUser.java b/openbas-model/src/main/java/io/openbas/database/model/ExerciseTeamUser.java index 6e1bc3113d..737aff7d0e 100644 --- a/openbas-model/src/main/java/io/openbas/database/model/ExerciseTeamUser.java +++ b/openbas-model/src/main/java/io/openbas/database/model/ExerciseTeamUser.java @@ -6,94 +6,91 @@ import io.openbas.database.raw.RawExerciseTeamUser; import io.openbas.helper.MonoIdDeserializer; import jakarta.persistence.*; - import java.util.Objects; @Entity @Table(name = "exercises_teams_users") public class ExerciseTeamUser { - @EmbeddedId - @JsonIgnore - private ExerciseTeamUserId compositeId = new ExerciseTeamUserId(); - - @ManyToOne(fetch = FetchType.LAZY) - @MapsId("exerciseId") - @JoinColumn(name = "exercise_id") - @JsonProperty("exercise_id") - @JsonSerialize(using = MonoIdDeserializer.class) - private Exercise exercise; - - @ManyToOne(fetch = FetchType.LAZY) - @MapsId("teamId") - @JoinColumn(name = "team_id") - @JsonProperty("team_id") - @JsonSerialize(using = MonoIdDeserializer.class) - private Team team; - - @ManyToOne(fetch = FetchType.LAZY) - @MapsId("userId") - @JoinColumn(name = "user_id") - @JsonProperty("user_id") - @JsonSerialize(using = MonoIdDeserializer.class) - private User user; - - public ExerciseTeamUserId getCompositeId() { - return compositeId; - } - - public void setCompositeId(ExerciseTeamUserId compositeId) { - this.compositeId = compositeId; - } - - public Exercise getExercise() { - return exercise; - } - - public void setExercise(Exercise exercise) { - this.exercise = exercise; - } - - public Team getTeam() { - return team; - } - - public void setTeam(Team team) { - this.team = team; - } - - public User getUser() { - return user; - } - - public void setUser(User user) { - this.user = user; - } - - @Override - public boolean equals(Object o) { - if (this == o) return true; - if (o == null || getClass() != o.getClass()) return false; - ExerciseTeamUser that = (ExerciseTeamUser) o; - return compositeId.equals(that.compositeId); - } - - @Override - public int hashCode() { - return Objects.hash(compositeId); - } - - public static ExerciseTeamUser fromRawExerciseTeamUser(RawExerciseTeamUser rawExerciseTeamUser) { - ExerciseTeamUser exerciseTeamUser = new ExerciseTeamUser(); - exerciseTeamUser.setTeam(new Team()); - exerciseTeamUser.getTeam().setId(rawExerciseTeamUser.getTeam_id()); - exerciseTeamUser.setExercise(new Exercise()); - exerciseTeamUser.getExercise().setId(rawExerciseTeamUser.getExercise_id()); - exerciseTeamUser.setUser(new User()); - exerciseTeamUser.getUser().setId(rawExerciseTeamUser.getUser_id()); - exerciseTeamUser.setCompositeId(new ExerciseTeamUserId()); - exerciseTeamUser.getCompositeId().setExerciseId(rawExerciseTeamUser.getExercise_id()); - exerciseTeamUser.getCompositeId().setTeamId(rawExerciseTeamUser.getTeam_id()); - exerciseTeamUser.getCompositeId().setUserId(rawExerciseTeamUser.getUser_id()); - return exerciseTeamUser; - } + @EmbeddedId @JsonIgnore private ExerciseTeamUserId compositeId = new ExerciseTeamUserId(); + + @ManyToOne(fetch = FetchType.LAZY) + @MapsId("exerciseId") + @JoinColumn(name = "exercise_id") + @JsonProperty("exercise_id") + @JsonSerialize(using = MonoIdDeserializer.class) + private Exercise exercise; + + @ManyToOne(fetch = FetchType.LAZY) + @MapsId("teamId") + @JoinColumn(name = "team_id") + @JsonProperty("team_id") + @JsonSerialize(using = MonoIdDeserializer.class) + private Team team; + + @ManyToOne(fetch = FetchType.LAZY) + @MapsId("userId") + @JoinColumn(name = "user_id") + @JsonProperty("user_id") + @JsonSerialize(using = MonoIdDeserializer.class) + private User user; + + public ExerciseTeamUserId getCompositeId() { + return compositeId; + } + + public void setCompositeId(ExerciseTeamUserId compositeId) { + this.compositeId = compositeId; + } + + public Exercise getExercise() { + return exercise; + } + + public void setExercise(Exercise exercise) { + this.exercise = exercise; + } + + public Team getTeam() { + return team; + } + + public void setTeam(Team team) { + this.team = team; + } + + public User getUser() { + return user; + } + + public void setUser(User user) { + this.user = user; + } + + @Override + public boolean equals(Object o) { + if (this == o) return true; + if (o == null || getClass() != o.getClass()) return false; + ExerciseTeamUser that = (ExerciseTeamUser) o; + return compositeId.equals(that.compositeId); + } + + @Override + public int hashCode() { + return Objects.hash(compositeId); + } + + public static ExerciseTeamUser fromRawExerciseTeamUser(RawExerciseTeamUser rawExerciseTeamUser) { + ExerciseTeamUser exerciseTeamUser = new ExerciseTeamUser(); + exerciseTeamUser.setTeam(new Team()); + exerciseTeamUser.getTeam().setId(rawExerciseTeamUser.getTeam_id()); + exerciseTeamUser.setExercise(new Exercise()); + exerciseTeamUser.getExercise().setId(rawExerciseTeamUser.getExercise_id()); + exerciseTeamUser.setUser(new User()); + exerciseTeamUser.getUser().setId(rawExerciseTeamUser.getUser_id()); + exerciseTeamUser.setCompositeId(new ExerciseTeamUserId()); + exerciseTeamUser.getCompositeId().setExerciseId(rawExerciseTeamUser.getExercise_id()); + exerciseTeamUser.getCompositeId().setTeamId(rawExerciseTeamUser.getTeam_id()); + exerciseTeamUser.getCompositeId().setUserId(rawExerciseTeamUser.getUser_id()); + return exerciseTeamUser; + } } diff --git a/openbas-model/src/main/java/io/openbas/database/model/ExerciseTeamUserId.java b/openbas-model/src/main/java/io/openbas/database/model/ExerciseTeamUserId.java index 55e7f36a5c..6471add7c0 100644 --- a/openbas-model/src/main/java/io/openbas/database/model/ExerciseTeamUserId.java +++ b/openbas-model/src/main/java/io/openbas/database/model/ExerciseTeamUserId.java @@ -1,7 +1,6 @@ package io.openbas.database.model; import jakarta.persistence.Embeddable; - import java.io.Serial; import java.io.Serializable; import java.util.Objects; @@ -9,51 +8,52 @@ @Embeddable public class ExerciseTeamUserId implements Serializable { - @Serial - private static final long serialVersionUID = 1L; - - private String exerciseId; - private String teamId; - private String userId; - - public ExerciseTeamUserId() { - // Default constructor - } - - public String getExerciseId() { - return exerciseId; - } - - public void setExerciseId(String exerciseId) { - this.exerciseId = exerciseId; - } - - public String getTeamId() { - return teamId; - } - - public void setTeamId(String teamId) { - this.teamId = teamId; - } - - public String getUserId() { - return userId; - } - - public void setUserId(String userId) { - this.userId = userId; - } - - @Override - public boolean equals(Object o) { - if (this == o) return true; - if (o == null || getClass() != o.getClass()) return false; - ExerciseTeamUserId that = (ExerciseTeamUserId) o; - return exerciseId.equals(that.exerciseId) && teamId.equals(that.teamId) && userId.equals(that.userId); - } - - @Override - public int hashCode() { - return Objects.hash(exerciseId, teamId, userId); - } + @Serial private static final long serialVersionUID = 1L; + + private String exerciseId; + private String teamId; + private String userId; + + public ExerciseTeamUserId() { + // Default constructor + } + + public String getExerciseId() { + return exerciseId; + } + + public void setExerciseId(String exerciseId) { + this.exerciseId = exerciseId; + } + + public String getTeamId() { + return teamId; + } + + public void setTeamId(String teamId) { + this.teamId = teamId; + } + + public String getUserId() { + return userId; + } + + public void setUserId(String userId) { + this.userId = userId; + } + + @Override + public boolean equals(Object o) { + if (this == o) return true; + if (o == null || getClass() != o.getClass()) return false; + ExerciseTeamUserId that = (ExerciseTeamUserId) o; + return exerciseId.equals(that.exerciseId) + && teamId.equals(that.teamId) + && userId.equals(that.userId); + } + + @Override + public int hashCode() { + return Objects.hash(exerciseId, teamId, userId); + } } diff --git a/openbas-model/src/main/java/io/openbas/database/model/FileDrop.java b/openbas-model/src/main/java/io/openbas/database/model/FileDrop.java index dde965fad7..d136fbe706 100644 --- a/openbas-model/src/main/java/io/openbas/database/model/FileDrop.java +++ b/openbas-model/src/main/java/io/openbas/database/model/FileDrop.java @@ -26,9 +26,7 @@ public class FileDrop extends Payload { @JsonProperty("file_drop_file") private Document fileDropFile; - public FileDrop() { - - } + public FileDrop() {} public FileDrop(String id, String type, String name) { super(id, type, name); diff --git a/openbas-model/src/main/java/io/openbas/database/model/Filters.java b/openbas-model/src/main/java/io/openbas/database/model/Filters.java index 2b1a23753d..31e266a4a0 100644 --- a/openbas-model/src/main/java/io/openbas/database/model/Filters.java +++ b/openbas-model/src/main/java/io/openbas/database/model/Filters.java @@ -2,11 +2,10 @@ import jakarta.validation.constraints.NotBlank; import jakarta.validation.constraints.NotNull; -import lombok.Data; - -import javax.annotation.Nullable; import java.util.List; import java.util.Optional; +import javax.annotation.Nullable; +import lombok.Data; public class Filters { @@ -33,8 +32,7 @@ public enum FilterOperator { @Data public static class FilterGroup { - @NotNull - private FilterMode mode; // Between filters + @NotNull private FilterMode mode; // Between filters private List filters; // -- UTILS -- @@ -44,8 +42,7 @@ public Optional findByKey(@NotBlank final String filterKey) { return Optional.empty(); } - return this.getFilters() - .stream() + return this.getFilters().stream() .filter(filter -> filter.getKey().equals(filterKey)) .findFirst(); } @@ -55,27 +52,24 @@ public void removeByKey(@NotBlank final String filterKey) { return; } - List newFilters = this.getFilters() - .stream() - .filter(filter -> !filter.getKey().equals(filterKey)) - .toList(); + List newFilters = + this.getFilters().stream().filter(filter -> !filter.getKey().equals(filterKey)).toList(); this.setFilters(newFilters); } - } @Data public static class Filter { - @NotNull - private String key; + @NotNull private String key; private FilterMode mode; // Between values: name = name1 OR name = name2 private List values; private FilterOperator operator; } public static boolean isEmptyFilterGroup(@Nullable final FilterGroup filterGroup) { - return filterGroup == null || filterGroup.getFilters() == null || filterGroup.getFilters().isEmpty(); + return filterGroup == null + || filterGroup.getFilters() == null + || filterGroup.getFilters().isEmpty(); } - } diff --git a/openbas-model/src/main/java/io/openbas/database/model/Grant.java b/openbas-model/src/main/java/io/openbas/database/model/Grant.java index 5eea6a9e51..0c1682d2e3 100644 --- a/openbas-model/src/main/java/io/openbas/database/model/Grant.java +++ b/openbas-model/src/main/java/io/openbas/database/model/Grant.java @@ -3,73 +3,72 @@ import com.fasterxml.jackson.annotation.JsonProperty; import com.fasterxml.jackson.databind.annotation.JsonSerialize; import io.openbas.helper.MonoIdDeserializer; +import jakarta.persistence.*; import jakarta.validation.constraints.NotBlank; import jakarta.validation.constraints.NotNull; +import java.util.Objects; import lombok.Getter; import lombok.Setter; import org.hibernate.annotations.UuidGenerator; -import jakarta.persistence.*; -import java.util.Objects; - @Setter @Getter @Entity @Table(name = "grants") public class Grant implements Base { - public enum GRANT_TYPE { - OBSERVER, - PLANNER - } + public enum GRANT_TYPE { + OBSERVER, + PLANNER + } - @Id - @Column(name = "grant_id") - @GeneratedValue(generator = "UUID") - @UuidGenerator - @JsonProperty("grant_id") - @NotBlank - private String id; + @Id + @Column(name = "grant_id") + @GeneratedValue(generator = "UUID") + @UuidGenerator + @JsonProperty("grant_id") + @NotBlank + private String id; - @Column(name = "grant_name") - @JsonProperty("grant_name") - @Enumerated(EnumType.STRING) - @NotNull - private GRANT_TYPE name; + @Column(name = "grant_name") + @JsonProperty("grant_name") + @Enumerated(EnumType.STRING) + @NotNull + private GRANT_TYPE name; - @ManyToOne(fetch = FetchType.LAZY) - @JoinColumn(name = "grant_group") - @JsonSerialize(using = MonoIdDeserializer.class) - @JsonProperty("grant_group") - private Group group; + @ManyToOne(fetch = FetchType.LAZY) + @JoinColumn(name = "grant_group") + @JsonSerialize(using = MonoIdDeserializer.class) + @JsonProperty("grant_group") + private Group group; - @ManyToOne(fetch = FetchType.LAZY) - @JoinColumn(name = "grant_exercise") - @JsonSerialize(using = MonoIdDeserializer.class) - @JsonProperty("grant_exercise") - private Exercise exercise; + @ManyToOne(fetch = FetchType.LAZY) + @JoinColumn(name = "grant_exercise") + @JsonSerialize(using = MonoIdDeserializer.class) + @JsonProperty("grant_exercise") + private Exercise exercise; - @ManyToOne(fetch = FetchType.LAZY) - @JoinColumn(name = "grant_scenario") - @JsonSerialize(using = MonoIdDeserializer.class) - @JsonProperty("grant_scenario") - private Scenario scenario; + @ManyToOne(fetch = FetchType.LAZY) + @JoinColumn(name = "grant_scenario") + @JsonSerialize(using = MonoIdDeserializer.class) + @JsonProperty("grant_scenario") + private Scenario scenario; - @Override - public boolean isUserHasAccess(User user) { - return user.isAdmin(); - } + @Override + public boolean isUserHasAccess(User user) { + return user.isAdmin(); + } - @Override - public boolean equals(Object o) { - if (this == o) return true; - if (o == null || !Base.class.isAssignableFrom(o.getClass())) return false; - Base base = (Base) o; - return id.equals(base.getId()); - } + @Override + public boolean equals(Object o) { + if (this == o) return true; + if (o == null || !Base.class.isAssignableFrom(o.getClass())) return false; + Base base = (Base) o; + return id.equals(base.getId()); + } - @Override - public int hashCode() { - return Objects.hash(id); - } + @Override + public int hashCode() { + return Objects.hash(id); + } } diff --git a/openbas-model/src/main/java/io/openbas/database/model/Group.java b/openbas-model/src/main/java/io/openbas/database/model/Group.java index 49f09ba61c..7ceba4c739 100644 --- a/openbas-model/src/main/java/io/openbas/database/model/Group.java +++ b/openbas-model/src/main/java/io/openbas/database/model/Group.java @@ -6,18 +6,17 @@ import io.openbas.database.audit.ModelBaseListener; import io.openbas.helper.MultiIdListDeserializer; import io.openbas.helper.MultiModelDeserializer; +import jakarta.persistence.*; import jakarta.validation.constraints.NotBlank; +import java.util.ArrayList; +import java.util.List; +import java.util.Objects; import lombok.Getter; import lombok.Setter; import org.hibernate.annotations.Fetch; import org.hibernate.annotations.FetchMode; import org.hibernate.annotations.UuidGenerator; -import jakarta.persistence.*; -import java.util.ArrayList; -import java.util.List; -import java.util.Objects; - @Setter @Getter @Entity @@ -25,103 +24,108 @@ @EntityListeners(ModelBaseListener.class) public class Group implements Base { - @Id - @Column(name = "group_id") - @GeneratedValue(generator = "UUID") - @UuidGenerator - @JsonProperty("group_id") - @NotBlank - private String id; - - @Queryable(sortable = true) - @Column(name = "group_name") - @JsonProperty("group_name") - @NotBlank - private String name; - - @Column(name = "group_description") - @JsonProperty("group_description") - private String description; - - @Queryable(sortable = true) - @Column(name = "group_default_user_assign") - @JsonProperty("group_default_user_assign") - private boolean defaultUserAssignation; - - @JsonProperty("group_default_exercise_assign") - @Enumerated(EnumType.STRING) - @ElementCollection - @CollectionTable(name = "groups_exercises_default_grants", - joinColumns = @JoinColumn(name = "group_id")) - private List exercisesDefaultGrants = new ArrayList<>(); - - @JsonProperty("group_default_scenario_assign") - @Enumerated(EnumType.STRING) - @ElementCollection - @CollectionTable(name = "groups_scenarios_default_grants", - joinColumns = @JoinColumn(name = "group_id")) - private List scenariosDefaultGrants = new ArrayList<>(); - - @OneToMany(mappedBy = "group", fetch = FetchType.EAGER) - @JsonProperty("group_grants") - @JsonSerialize(using = MultiModelDeserializer.class) - @Fetch(value = FetchMode.SUBSELECT) - private List grants = new ArrayList<>(); - - @ManyToMany(fetch = FetchType.EAGER) - @JoinTable(name = "users_groups", - joinColumns = @JoinColumn(name = "group_id"), - inverseJoinColumns = @JoinColumn(name = "user_id")) - @JsonSerialize(using = MultiIdListDeserializer.class) - @JsonProperty("group_users") - @Fetch(value = FetchMode.SUBSELECT) - private List users = new ArrayList<>(); - - @ManyToMany(fetch = FetchType.LAZY) - @JoinTable(name = "groups_organizations", - joinColumns = @JoinColumn(name = "group_id"), - inverseJoinColumns = @JoinColumn(name = "organization_id")) - @JsonSerialize(using = MultiIdListDeserializer.class) - @JsonProperty("group_organizations") - private List organizations = new ArrayList<>(); - - // region transient - @JsonProperty("group_default_exercise_planner") - public boolean isDefaultExercisePlanner() { - return exercisesDefaultGrants.contains(Grant.GRANT_TYPE.PLANNER); - } - - @JsonProperty("group_default_exercise_observer") - public boolean isDefaultExerciseObserver() { - return exercisesDefaultGrants.contains(Grant.GRANT_TYPE.OBSERVER); - } - - @JsonProperty("group_default_scenario_planner") - public boolean isDefaultScenarioPlanner() { - return scenariosDefaultGrants.contains(Grant.GRANT_TYPE.PLANNER); - } - - @JsonProperty("group_default_scenario_observer") - public boolean isDefaultScenarioObserver() { - return scenariosDefaultGrants.contains(Grant.GRANT_TYPE.OBSERVER); - } - // endregion - - @Override - public boolean isUserHasAccess(User user) { - return users.contains(user); - } - - @Override - public boolean equals(Object o) { - if (this == o) return true; - if (o == null || !Base.class.isAssignableFrom(o.getClass())) return false; - Base base = (Base) o; - return id.equals(base.getId()); - } - - @Override - public int hashCode() { - return Objects.hash(id); - } + @Id + @Column(name = "group_id") + @GeneratedValue(generator = "UUID") + @UuidGenerator + @JsonProperty("group_id") + @NotBlank + private String id; + + @Queryable(sortable = true) + @Column(name = "group_name") + @JsonProperty("group_name") + @NotBlank + private String name; + + @Column(name = "group_description") + @JsonProperty("group_description") + private String description; + + @Queryable(sortable = true) + @Column(name = "group_default_user_assign") + @JsonProperty("group_default_user_assign") + private boolean defaultUserAssignation; + + @JsonProperty("group_default_exercise_assign") + @Enumerated(EnumType.STRING) + @ElementCollection + @CollectionTable( + name = "groups_exercises_default_grants", + joinColumns = @JoinColumn(name = "group_id")) + private List exercisesDefaultGrants = new ArrayList<>(); + + @JsonProperty("group_default_scenario_assign") + @Enumerated(EnumType.STRING) + @ElementCollection + @CollectionTable( + name = "groups_scenarios_default_grants", + joinColumns = @JoinColumn(name = "group_id")) + private List scenariosDefaultGrants = new ArrayList<>(); + + @OneToMany(mappedBy = "group", fetch = FetchType.EAGER) + @JsonProperty("group_grants") + @JsonSerialize(using = MultiModelDeserializer.class) + @Fetch(value = FetchMode.SUBSELECT) + private List grants = new ArrayList<>(); + + @ManyToMany(fetch = FetchType.EAGER) + @JoinTable( + name = "users_groups", + joinColumns = @JoinColumn(name = "group_id"), + inverseJoinColumns = @JoinColumn(name = "user_id")) + @JsonSerialize(using = MultiIdListDeserializer.class) + @JsonProperty("group_users") + @Fetch(value = FetchMode.SUBSELECT) + private List users = new ArrayList<>(); + + @ManyToMany(fetch = FetchType.LAZY) + @JoinTable( + name = "groups_organizations", + joinColumns = @JoinColumn(name = "group_id"), + inverseJoinColumns = @JoinColumn(name = "organization_id")) + @JsonSerialize(using = MultiIdListDeserializer.class) + @JsonProperty("group_organizations") + private List organizations = new ArrayList<>(); + + // region transient + @JsonProperty("group_default_exercise_planner") + public boolean isDefaultExercisePlanner() { + return exercisesDefaultGrants.contains(Grant.GRANT_TYPE.PLANNER); + } + + @JsonProperty("group_default_exercise_observer") + public boolean isDefaultExerciseObserver() { + return exercisesDefaultGrants.contains(Grant.GRANT_TYPE.OBSERVER); + } + + @JsonProperty("group_default_scenario_planner") + public boolean isDefaultScenarioPlanner() { + return scenariosDefaultGrants.contains(Grant.GRANT_TYPE.PLANNER); + } + + @JsonProperty("group_default_scenario_observer") + public boolean isDefaultScenarioObserver() { + return scenariosDefaultGrants.contains(Grant.GRANT_TYPE.OBSERVER); + } + + // endregion + + @Override + public boolean isUserHasAccess(User user) { + return users.contains(user); + } + + @Override + public boolean equals(Object o) { + if (this == o) return true; + if (o == null || !Base.class.isAssignableFrom(o.getClass())) return false; + Base base = (Base) o; + return id.equals(base.getId()); + } + + @Override + public int hashCode() { + return Objects.hash(id); + } } diff --git a/openbas-model/src/main/java/io/openbas/database/model/ImportMapper.java b/openbas-model/src/main/java/io/openbas/database/model/ImportMapper.java index e6660f27b1..8d83a89f21 100644 --- a/openbas-model/src/main/java/io/openbas/database/model/ImportMapper.java +++ b/openbas-model/src/main/java/io/openbas/database/model/ImportMapper.java @@ -6,16 +6,15 @@ import jakarta.persistence.*; import jakarta.validation.constraints.NotBlank; import jakarta.validation.constraints.NotNull; -import lombok.Data; -import org.hibernate.annotations.CreationTimestamp; -import org.hibernate.annotations.UpdateTimestamp; -import org.hibernate.annotations.UuidGenerator; - import java.time.Instant; import java.util.ArrayList; import java.util.List; import java.util.Objects; import java.util.UUID; +import lombok.Data; +import org.hibernate.annotations.CreationTimestamp; +import org.hibernate.annotations.UpdateTimestamp; +import org.hibernate.annotations.UuidGenerator; @Data @Entity @@ -59,12 +58,12 @@ public class ImportMapper implements Base { @Override public boolean equals(Object o) { - if (this == o) { - return true; - } - if (o == null || !Base.class.isAssignableFrom(o.getClass())) { - return false; - } + if (this == o) { + return true; + } + if (o == null || !Base.class.isAssignableFrom(o.getClass())) { + return false; + } Base base = (Base) o; return id.equals(base.getId()); } diff --git a/openbas-model/src/main/java/io/openbas/database/model/Inject.java b/openbas-model/src/main/java/io/openbas/database/model/Inject.java index 88c3df75bc..b036c1e45a 100644 --- a/openbas-model/src/main/java/io/openbas/database/model/Inject.java +++ b/openbas-model/src/main/java/io/openbas/database/model/Inject.java @@ -1,5 +1,10 @@ package io.openbas.database.model; +import static io.openbas.database.model.Endpoint.ENDPOINT_TYPE; +import static io.openbas.database.specification.InjectSpecification.VALID_TESTABLE_TYPES; +import static java.time.Instant.now; +import static java.util.Optional.ofNullable; + import com.fasterxml.jackson.annotation.JsonIgnore; import com.fasterxml.jackson.annotation.JsonProperty; import com.fasterxml.jackson.databind.annotation.JsonSerialize; @@ -13,20 +18,14 @@ import jakarta.validation.constraints.Min; import jakarta.validation.constraints.NotBlank; import jakarta.validation.constraints.NotNull; +import java.time.Instant; +import java.util.*; +import java.util.stream.Collectors; import lombok.Getter; import lombok.Setter; import lombok.extern.java.Log; import org.hibernate.annotations.UuidGenerator; -import java.time.Instant; -import java.util.*; -import java.util.stream.Collectors; - -import static io.openbas.database.model.Endpoint.ENDPOINT_TYPE; -import static io.openbas.database.specification.InjectSpecification.VALID_TESTABLE_TYPES; -import static java.time.Instant.now; -import static java.util.Optional.ofNullable; - @Setter @Entity @Table(name = "injects") @@ -36,12 +35,13 @@ public class Inject implements Base, Injection { public static final int SPEED_STANDARD = 1; // Standard speed define by the user. - public static final Comparator executionComparator = (o1, o2) -> { - if (o1.getDate().isPresent() && o2.getDate().isPresent()) { - return o1.getDate().get().compareTo(o2.getDate().get()); - } - return o1.getId().compareTo(o2.getId()); - }; + public static final Comparator executionComparator = + (o1, o2) -> { + if (o1.getDate().isPresent() && o2.getDate().isPresent()) { + return o1.getDate().get().compareTo(o2.getDate().get()); + } + return o1.getId().compareTo(o2.getId()); + }; @Getter @Id @@ -158,7 +158,8 @@ public class Inject implements Base, Injection { @Getter @ManyToMany(fetch = FetchType.LAZY) - @JoinTable(name = "injects_tags", + @JoinTable( + name = "injects_tags", joinColumns = @JoinColumn(name = "inject_id"), inverseJoinColumns = @JoinColumn(name = "tag_id")) @JsonSerialize(using = MultiIdSetDeserializer.class) @@ -168,7 +169,8 @@ public class Inject implements Base, Injection { @Getter @ManyToMany(fetch = FetchType.EAGER) - @JoinTable(name = "injects_teams", + @JoinTable( + name = "injects_teams", joinColumns = @JoinColumn(name = "inject_id"), inverseJoinColumns = @JoinColumn(name = "team_id")) @JsonSerialize(using = MultiIdListDeserializer.class) @@ -177,7 +179,8 @@ public class Inject implements Base, Injection { @Getter @ManyToMany(fetch = FetchType.EAGER) - @JoinTable(name = "injects_assets", + @JoinTable( + name = "injects_assets", joinColumns = @JoinColumn(name = "inject_id"), inverseJoinColumns = @JoinColumn(name = "asset_id")) @JsonSerialize(using = MultiIdListDeserializer.class) @@ -186,7 +189,8 @@ public class Inject implements Base, Injection { @Getter @ManyToMany(fetch = FetchType.EAGER) - @JoinTable(name = "injects_asset_groups", + @JoinTable( + name = "injects_asset_groups", joinColumns = @JoinColumn(name = "inject_id"), inverseJoinColumns = @JoinColumn(name = "asset_group_id")) @JsonSerialize(using = MultiIdListDeserializer.class) @@ -195,7 +199,8 @@ public class Inject implements Base, Injection { @Getter @ManyToMany(fetch = FetchType.EAGER) - @JoinTable(name = "injects_payloads", + @JoinTable( + name = "injects_payloads", joinColumns = @JoinColumn(name = "inject_id"), inverseJoinColumns = @JoinColumn(name = "payload_id")) @JsonSerialize(using = MultiIdListDeserializer.class) @@ -204,29 +209,38 @@ public class Inject implements Base, Injection { // CascadeType.ALL is required here because of complex relationships @Getter - @OneToMany(mappedBy = "inject", fetch = FetchType.EAGER, cascade = CascadeType.ALL, orphanRemoval = true) + @OneToMany( + mappedBy = "inject", + fetch = FetchType.EAGER, + cascade = CascadeType.ALL, + orphanRemoval = true) @JsonProperty("inject_documents") @JsonSerialize(using = MultiModelDeserializer.class) private List documents = new ArrayList<>(); // CascadeType.ALL is required here because communications are embedded @Getter - @OneToMany(mappedBy = "inject", fetch = FetchType.EAGER, cascade = CascadeType.ALL, orphanRemoval = true) + @OneToMany( + mappedBy = "inject", + fetch = FetchType.EAGER, + cascade = CascadeType.ALL, + orphanRemoval = true) @JsonProperty("inject_communications") @JsonSerialize(using = MultiModelDeserializer.class) private List communications = new ArrayList<>(); // CascadeType.ALL is required here because expectations are embedded @Getter - @OneToMany(mappedBy = "inject", fetch = FetchType.EAGER, cascade = CascadeType.ALL, orphanRemoval = true) + @OneToMany( + mappedBy = "inject", + fetch = FetchType.EAGER, + cascade = CascadeType.ALL, + orphanRemoval = true) @JsonProperty("inject_expectations") @JsonSerialize(using = MultiModelDeserializer.class) private List expectations = new ArrayList<>(); - @Getter - @Setter - @Transient - private boolean isListened = true; + @Getter @Setter @Transient private boolean isListened = true; // region transient @Transient @@ -262,7 +276,8 @@ public long getNumberOfTargetUsers() { } return getTeams().stream() .map(team -> team.getUsersNumberInExercise(getExercise().getId())) - .reduce(Long::sum).orElse(0L); + .reduce(Long::sum) + .orElse(0L); } @JsonProperty("inject_ready") @@ -273,25 +288,29 @@ public boolean isReady() { isAllTeams(), getTeams().stream().map(Team::getId).collect(Collectors.toList()), getAssets().stream().map(Asset::getId).collect(Collectors.toList()), - getAssetGroups().stream().map(AssetGroup::getId).collect(Collectors.toList()) - ); + getAssetGroups().stream().map(AssetGroup::getId).collect(Collectors.toList())); } @JsonIgnore public Instant computeInjectDate(Instant source, int speed) { - return InjectModelHelper.computeInjectDate(source, speed, getDependsOn(), getDependsDuration(), getExercise()); + return InjectModelHelper.computeInjectDate( + source, speed, getDependsOn(), getDependsDuration(), getExercise()); } @JsonProperty("inject_date") public Optional getDate() { - // If a trigger now was executed for this inject linked to an exercise, we ignore pauses and we set inject inside of a range of execution - if(getExercise() != null && triggerNowDate != null ) { + // If a trigger now was executed for this inject linked to an exercise, we ignore pauses and we + // set inject inside of a range of execution + if (getExercise() != null && triggerNowDate != null) { Optional exerciseStartOpt = getExercise().getStart(); - if (exerciseStartOpt.isPresent() && (exerciseStartOpt.get().equals(triggerNowDate) || exerciseStartOpt.get().isBefore(triggerNowDate))) { + if (exerciseStartOpt.isPresent() + && (exerciseStartOpt.get().equals(triggerNowDate) + || exerciseStartOpt.get().isBefore(triggerNowDate))) { return Optional.of(now().minusSeconds(60)); } } - return InjectModelHelper.getDate(getExercise(), getScenario(), getDependsOn(), getDependsDuration()); + return InjectModelHelper.getDate( + getExercise(), getScenario(), getDependsOn(), getDependsDuration()); } @JsonIgnore @@ -313,6 +332,7 @@ public boolean isPastInject() { public boolean isFutureInject() { return this.getDate().map(date -> date.isAfter(now())).orElse(false); } + // endregion public Optional getInjectorContract() { @@ -327,8 +347,12 @@ public List getUserExpectationsForArticle(User user, Article return this.expectations.stream() .filter(execution -> execution.getType().equals(InjectExpectation.EXPECTATION_TYPE.ARTICLE)) .filter(execution -> execution.getArticle().equals(article)) - .filter(execution -> execution.getUser() != null) //We include only the expectations from players, because the validation link is always from a player - .filter(execution -> execution.getUser().equals(user)) + .filter( + execution -> + execution.getUser() + != null) // We include only the expectations from players, because the + // validation link is always from a player + .filter(execution -> execution.getUser().equals(user)) .toList(); } @@ -348,7 +372,9 @@ public long getCommunicationsNumber() { @JsonProperty("inject_communications_not_ack_number") public long getCommunicationsNotAckNumber() { - return this.getCommunications().stream().filter(communication -> !communication.getAck()).count(); + return this.getCommunications().stream() + .filter(communication -> !communication.getAck()) + .count(); } @JsonProperty("inject_sent_at") @@ -357,25 +383,24 @@ public Instant getSentAt() { } @JsonProperty("inject_kill_chain_phases") - @Queryable(filterable = true, dynamicValues = true, path = "injectorContract.attackPatterns.killChainPhases.id") + @Queryable( + filterable = true, + dynamicValues = true, + path = "injectorContract.attackPatterns.killChainPhases.id") public List getKillChainPhases() { return getInjectorContract() - .map(injectorContract -> - injectorContract.getAttackPatterns() - .stream() - .flatMap(attackPattern -> attackPattern.getKillChainPhases().stream()) - .distinct() - .collect(Collectors.toList() - ) - ) + .map( + injectorContract -> + injectorContract.getAttackPatterns().stream() + .flatMap(attackPattern -> attackPattern.getKillChainPhases().stream()) + .distinct() + .collect(Collectors.toList())) .orElseGet(ArrayList::new); } @JsonProperty("inject_attack_patterns") public List getAttackPatterns() { - return getInjectorContract() - .map(InjectorContract::getAttackPatterns) - .orElseGet(ArrayList::new); + return getInjectorContract().map(InjectorContract::getAttackPatterns).orElseGet(ArrayList::new); } @JsonProperty("inject_type") @@ -426,15 +451,18 @@ public int hashCode() { /** * Creates an Inject from a Raw Inject * - * @param rawInject the raw inject to convert - * @param rawTeams the map of the teams containing at least the ones linked to this inject - * @param rawInjectExpectationMap the map of the expectations containing at least the ones linked to this inject - * @param mapOfAssetGroups the map of the asset groups containing at least the ones linked to this inject - * @param mapOfAsset the map of the asset containing at least the ones linked to this inject and the - * asset groups linked to it + * @param rawInject the raw inject to convert + * @param rawTeams the map of the teams containing at least the ones linked to this inject + * @param rawInjectExpectationMap the map of the expectations containing at least the ones linked + * to this inject + * @param mapOfAssetGroups the map of the asset groups containing at least the ones linked to this + * inject + * @param mapOfAsset the map of the asset containing at least the ones linked to this inject and + * the asset groups linked to it * @return an Inject */ - public static Inject fromRawInject(RawInject rawInject, + public static Inject fromRawInject( + RawInject rawInject, Map rawTeams, Map rawInjectExpectationMap, Map mapOfAssetGroups, @@ -452,10 +480,11 @@ public static Inject fromRawInject(RawInject rawInject, InjectExpectation expectation = new InjectExpectation(); expectation.setId(rawInjectExpectation.getInject_expectation_id()); expectation.setType( - InjectExpectation.EXPECTATION_TYPE.valueOf(rawInjectExpectation.getInject_expectation_type())); + InjectExpectation.EXPECTATION_TYPE.valueOf( + rawInjectExpectation.getInject_expectation_type())); expectation.setScore(rawInjectExpectation.getInject_expectation_score()); expectation.setExpectedScore(rawInjectExpectation.getInject_expectation_expected_score()); - expectation.setExpectationGroup(rawInjectExpectation.getInject_expectation_group()); + expectation.setExpectationGroup(rawInjectExpectation.getInject_expectation_group()); // Add the team of the expectation if (rawInjectExpectation.getTeam_id() != null) { @@ -470,7 +499,8 @@ public static Inject fromRawInject(RawInject rawInject, // Add the asset group of the expectation if (rawInjectExpectation.getAsset_group_id() != null) { - RawAssetGroup rawAssetGroup = mapOfAssetGroups.get(rawInjectExpectation.getAsset_group_id()); + RawAssetGroup rawAssetGroup = + mapOfAssetGroups.get(rawInjectExpectation.getAsset_group_id()); if (rawAssetGroup != null) { AssetGroup assetGroup = new AssetGroup(); assetGroup.setId(rawAssetGroup.getAsset_group_id()); @@ -482,15 +512,19 @@ public static Inject fromRawInject(RawInject rawInject, RawAsset rawAsset = mapOfAsset.get(assetId); if (rawAsset != null) { if (rawAsset.getAsset_type().equals(ENDPOINT_TYPE)) { - Endpoint endpoint = new Endpoint(rawAsset.getAsset_id(), - rawAsset.getAsset_type(), - rawAsset.getAsset_name(), - Endpoint.PLATFORM_TYPE.valueOf(rawAsset.getEndpoint_platform())); + Endpoint endpoint = + new Endpoint( + rawAsset.getAsset_id(), + rawAsset.getAsset_type(), + rawAsset.getAsset_name(), + Endpoint.PLATFORM_TYPE.valueOf(rawAsset.getEndpoint_platform())); assetGroup.getAssets().add(endpoint); } else { - Asset asset = new Asset(rawAsset.getAsset_id(), - rawAsset.getAsset_type(), - rawAsset.getAsset_name()); + Asset asset = + new Asset( + rawAsset.getAsset_id(), + rawAsset.getAsset_type(), + rawAsset.getAsset_name()); assetGroup.getAssets().add(asset); } } @@ -504,17 +538,17 @@ public static Inject fromRawInject(RawInject rawInject, RawAsset rawAsset = mapOfAsset.get(rawInjectExpectation.getAsset_id()); if (rawAsset != null) { if (rawAsset.getAsset_type().equals(ENDPOINT_TYPE)) { - Endpoint endpoint = new Endpoint(rawAsset.getAsset_id(), - rawAsset.getAsset_type(), - rawAsset.getAsset_name(), - Endpoint.PLATFORM_TYPE.valueOf(rawAsset.getEndpoint_platform())); + Endpoint endpoint = + new Endpoint( + rawAsset.getAsset_id(), + rawAsset.getAsset_type(), + rawAsset.getAsset_name(), + Endpoint.PLATFORM_TYPE.valueOf(rawAsset.getEndpoint_platform())); expectation.setAsset(endpoint); } else { - Asset asset = new Asset( - rawAsset.getAsset_id(), - rawAsset.getAsset_type(), - rawAsset.getAsset_name() - ); + Asset asset = + new Asset( + rawAsset.getAsset_id(), rawAsset.getAsset_type(), rawAsset.getAsset_name()); expectation.setAsset(asset); } } @@ -543,19 +577,16 @@ public static Inject fromRawInject(RawInject rawInject, } if ("Endpoint".equals(rawAsset.getAsset_type())) { - Endpoint endpoint = new Endpoint( - rawAsset.getAsset_id(), - rawAsset.getAsset_type(), - rawAsset.getAsset_name(), - Endpoint.PLATFORM_TYPE.valueOf(rawAsset.getEndpoint_platform()) - ); + Endpoint endpoint = + new Endpoint( + rawAsset.getAsset_id(), + rawAsset.getAsset_type(), + rawAsset.getAsset_name(), + Endpoint.PLATFORM_TYPE.valueOf(rawAsset.getEndpoint_platform())); injectAssets.add(endpoint); } else { - Asset newAsset = new Asset( - rawAsset.getAsset_id(), - rawAsset.getAsset_type(), - rawAsset.getAsset_name() - ); + Asset newAsset = + new Asset(rawAsset.getAsset_id(), rawAsset.getAsset_type(), rawAsset.getAsset_name()); injectAssets.add(newAsset); } } @@ -564,32 +595,41 @@ public static Inject fromRawInject(RawInject rawInject, // Add the asset groups to the inject ArrayList injectAssetGroups = new ArrayList(); for (String injectAssetGroupId : rawInject.getInject_asset_groups()) { - Optional rawAssetGroup = Optional.ofNullable(mapOfAssetGroups.get(injectAssetGroupId)); - rawAssetGroup.ifPresent(rag -> { - AssetGroup assetGroup = new AssetGroup(); - assetGroup.setName(rag.getAsset_group_name()); - assetGroup.setId(rag.getAsset_group_id()); - - // We add the assets linked to the asset group - assetGroup.setAssets(rag.getAsset_ids().stream() - .map(assetId -> { - RawAsset rawAsset = mapOfAsset.get(assetId); - if (rawAsset == null) { - return null; - } - - if ("Endpoint".equals(rawAsset.getAsset_type())) { - return new Endpoint(rawAsset.getAsset_id(), rawAsset.getAsset_type(), rawAsset.getAsset_name(), - Endpoint.PLATFORM_TYPE.valueOf(rawAsset.getEndpoint_platform())); - } else { - return new Asset(rawAsset.getAsset_id(), rawAsset.getAsset_type(), rawAsset.getAsset_name()); - } - }) - .filter(Objects::nonNull) - .toList() - ); - injectAssetGroups.add(assetGroup); - }); + Optional rawAssetGroup = + Optional.ofNullable(mapOfAssetGroups.get(injectAssetGroupId)); + rawAssetGroup.ifPresent( + rag -> { + AssetGroup assetGroup = new AssetGroup(); + assetGroup.setName(rag.getAsset_group_name()); + assetGroup.setId(rag.getAsset_group_id()); + + // We add the assets linked to the asset group + assetGroup.setAssets( + rag.getAsset_ids().stream() + .map( + assetId -> { + RawAsset rawAsset = mapOfAsset.get(assetId); + if (rawAsset == null) { + return null; + } + + if ("Endpoint".equals(rawAsset.getAsset_type())) { + return new Endpoint( + rawAsset.getAsset_id(), + rawAsset.getAsset_type(), + rawAsset.getAsset_name(), + Endpoint.PLATFORM_TYPE.valueOf(rawAsset.getEndpoint_platform())); + } else { + return new Asset( + rawAsset.getAsset_id(), + rawAsset.getAsset_type(), + rawAsset.getAsset_name()); + } + }) + .filter(Objects::nonNull) + .toList()); + injectAssetGroups.add(assetGroup); + }); } inject.setAssetGroups(injectAssetGroups); @@ -597,4 +637,3 @@ public static Inject fromRawInject(RawInject rawInject, return inject; } } - diff --git a/openbas-model/src/main/java/io/openbas/database/model/InjectDocument.java b/openbas-model/src/main/java/io/openbas/database/model/InjectDocument.java index 11629c795c..5f7217fb12 100644 --- a/openbas-model/src/main/java/io/openbas/database/model/InjectDocument.java +++ b/openbas-model/src/main/java/io/openbas/database/model/InjectDocument.java @@ -4,56 +4,52 @@ import com.fasterxml.jackson.annotation.JsonProperty; import com.fasterxml.jackson.databind.annotation.JsonSerialize; import io.openbas.helper.MonoIdDeserializer; - import jakarta.persistence.*; +import java.util.Objects; import lombok.Getter; import lombok.Setter; -import java.util.Objects; - @Setter @Getter @Entity @Table(name = "injects_documents") public class InjectDocument { - @EmbeddedId - @JsonIgnore - private InjectDocumentId compositeId = new InjectDocumentId(); - - @ManyToOne(fetch = FetchType.EAGER) - @MapsId("injectId") - @JoinColumn(name = "inject_id") - @JsonProperty("inject_id") - @JsonSerialize(using = MonoIdDeserializer.class) - private Inject inject; - - @ManyToOne(fetch = FetchType.EAGER) - @MapsId("documentId") - @JoinColumn(name = "document_id") - @JsonProperty("document_id") - @JsonSerialize(using = MonoIdDeserializer.class) - private Document document; - - @Column(name = "document_attached") - @JsonProperty("document_attached") - private boolean attached = true; - - @JsonProperty("document_name") - public String getDocumentName() { - return this.document.getName(); - } - - @Override - public boolean equals(Object o) { - if (this == o) return true; - if (o == null || getClass() != o.getClass()) return false; - InjectDocument that = (InjectDocument) o; - return compositeId.equals(that.compositeId); - } - - @Override - public int hashCode() { - return Objects.hash(compositeId); - } + @EmbeddedId @JsonIgnore private InjectDocumentId compositeId = new InjectDocumentId(); + + @ManyToOne(fetch = FetchType.EAGER) + @MapsId("injectId") + @JoinColumn(name = "inject_id") + @JsonProperty("inject_id") + @JsonSerialize(using = MonoIdDeserializer.class) + private Inject inject; + + @ManyToOne(fetch = FetchType.EAGER) + @MapsId("documentId") + @JoinColumn(name = "document_id") + @JsonProperty("document_id") + @JsonSerialize(using = MonoIdDeserializer.class) + private Document document; + + @Column(name = "document_attached") + @JsonProperty("document_attached") + private boolean attached = true; + + @JsonProperty("document_name") + public String getDocumentName() { + return this.document.getName(); + } + + @Override + public boolean equals(Object o) { + if (this == o) return true; + if (o == null || getClass() != o.getClass()) return false; + InjectDocument that = (InjectDocument) o; + return compositeId.equals(that.compositeId); + } + + @Override + public int hashCode() { + return Objects.hash(compositeId); + } } diff --git a/openbas-model/src/main/java/io/openbas/database/model/InjectDocumentId.java b/openbas-model/src/main/java/io/openbas/database/model/InjectDocumentId.java index 4264975fb4..02cd4bbb35 100644 --- a/openbas-model/src/main/java/io/openbas/database/model/InjectDocumentId.java +++ b/openbas-model/src/main/java/io/openbas/database/model/InjectDocumentId.java @@ -8,42 +8,41 @@ @Embeddable public class InjectDocumentId implements Serializable { - @Serial - private static final long serialVersionUID = 1L; - - private String injectId; - private String documentId; - - public InjectDocumentId() { - // Default constructor - } - - public String getInjectId() { - return injectId; - } - - public void setInjectId(String injectId) { - this.injectId = injectId; - } - - public String getDocumentId() { - return documentId; - } - - public void setDocumentId(String documentId) { - this.documentId = documentId; - } - - @Override - public boolean equals(Object o) { - if (this == o) return true; - if (o == null || getClass() != o.getClass()) return false; - InjectDocumentId that = (InjectDocumentId) o; - return injectId.equals(that.injectId) && documentId.equals(that.documentId); - } - - @Override - public int hashCode() { - return Objects.hash(injectId, documentId); - } + @Serial private static final long serialVersionUID = 1L; + + private String injectId; + private String documentId; + + public InjectDocumentId() { + // Default constructor + } + + public String getInjectId() { + return injectId; + } + + public void setInjectId(String injectId) { + this.injectId = injectId; + } + + public String getDocumentId() { + return documentId; + } + + public void setDocumentId(String documentId) { + this.documentId = documentId; + } + + @Override + public boolean equals(Object o) { + if (this == o) return true; + if (o == null || getClass() != o.getClass()) return false; + InjectDocumentId that = (InjectDocumentId) o; + return injectId.equals(that.injectId) && documentId.equals(that.documentId); + } + + @Override + public int hashCode() { + return Objects.hash(injectId, documentId); + } } diff --git a/openbas-model/src/main/java/io/openbas/database/model/InjectExpectation.java b/openbas-model/src/main/java/io/openbas/database/model/InjectExpectation.java index db56ace78d..48a2961854 100644 --- a/openbas-model/src/main/java/io/openbas/database/model/InjectExpectation.java +++ b/openbas-model/src/main/java/io/openbas/database/model/InjectExpectation.java @@ -1,5 +1,7 @@ package io.openbas.database.model; +import static java.time.Instant.now; + import com.fasterxml.jackson.annotation.JsonIgnore; import com.fasterxml.jackson.annotation.JsonProperty; import com.fasterxml.jackson.databind.annotation.JsonSerialize; @@ -9,17 +11,14 @@ import jakarta.persistence.*; import jakarta.validation.constraints.NotBlank; import jakarta.validation.constraints.NotNull; -import lombok.Getter; -import lombok.Setter; -import org.hibernate.annotations.Type; -import org.hibernate.annotations.UuidGenerator; - import java.time.Instant; import java.util.ArrayList; import java.util.List; import java.util.Objects; - -import static java.time.Instant.now; +import lombok.Getter; +import lombok.Setter; +import org.hibernate.annotations.Type; +import org.hibernate.annotations.UuidGenerator; @Getter @Entity @@ -126,9 +125,7 @@ public EXPECTATION_STATUS getExpectationStatus() { @NotNull private Double expectedScore; - /** - * Expiration time in seconds - */ + /** Expiration time in seconds */ @Setter @Column(name = "inject_expiration_time") @JsonProperty("inject_expiration_time") @@ -149,6 +146,7 @@ public EXPECTATION_STATUS getExpectationStatus() { @Column(name = "inject_expectation_group") @JsonProperty("inject_expectation_group") private boolean expectationGroup; + // endregion // region contextual relations @@ -193,6 +191,7 @@ public EXPECTATION_STATUS getExpectationStatus() { @JsonSerialize(using = MonoIdDeserializer.class) @JsonProperty("inject_expectation_asset_group") private AssetGroup assetGroup; + // endregion @ManyToOne(fetch = FetchType.LAZY) @@ -217,25 +216,19 @@ public void setChallenge(Challenge challenge) { this.challenge = challenge; } - public void setManual( - @NotNull final Asset asset, - @NotNull final AssetGroup assetGroup) { + public void setManual(@NotNull final Asset asset, @NotNull final AssetGroup assetGroup) { this.type = EXPECTATION_TYPE.MANUAL; this.asset = asset; this.assetGroup = assetGroup; } - public void setPrevention( - @NotNull final Asset asset, - @NotNull final AssetGroup assetGroup) { + public void setPrevention(@NotNull final Asset asset, @NotNull final AssetGroup assetGroup) { this.type = EXPECTATION_TYPE.PREVENTION; this.asset = asset; this.assetGroup = assetGroup; } - public void setDetection( - @NotNull final Asset asset, - @NotNull final AssetGroup assetGroup) { + public void setDetection(@NotNull final Asset asset, @NotNull final AssetGroup assetGroup) { this.type = EXPECTATION_TYPE.DETECTION; this.asset = asset; this.assetGroup = assetGroup; diff --git a/openbas-model/src/main/java/io/openbas/database/model/InjectExpectationResult.java b/openbas-model/src/main/java/io/openbas/database/model/InjectExpectationResult.java index ec5765b77b..58df1204f1 100644 --- a/openbas-model/src/main/java/io/openbas/database/model/InjectExpectationResult.java +++ b/openbas-model/src/main/java/io/openbas/database/model/InjectExpectationResult.java @@ -18,6 +18,5 @@ public class InjectExpectationResult { private Double score; - @NotBlank - private String result; + @NotBlank private String result; } diff --git a/openbas-model/src/main/java/io/openbas/database/model/InjectExpectationSignature.java b/openbas-model/src/main/java/io/openbas/database/model/InjectExpectationSignature.java index ce8f40a9ea..2f33fcc7c9 100644 --- a/openbas-model/src/main/java/io/openbas/database/model/InjectExpectationSignature.java +++ b/openbas-model/src/main/java/io/openbas/database/model/InjectExpectationSignature.java @@ -1,6 +1,5 @@ package io.openbas.database.model; -import jakarta.validation.constraints.NotBlank; import lombok.Builder; import lombok.Data; import lombok.Setter; diff --git a/openbas-model/src/main/java/io/openbas/database/model/InjectImporter.java b/openbas-model/src/main/java/io/openbas/database/model/InjectImporter.java index 6d7f59eca9..e6355e9b9a 100644 --- a/openbas-model/src/main/java/io/openbas/database/model/InjectImporter.java +++ b/openbas-model/src/main/java/io/openbas/database/model/InjectImporter.java @@ -7,16 +7,15 @@ import jakarta.persistence.*; import jakarta.validation.constraints.NotBlank; import jakarta.validation.constraints.NotNull; -import lombok.Data; -import org.hibernate.annotations.CreationTimestamp; -import org.hibernate.annotations.UpdateTimestamp; -import org.hibernate.annotations.UuidGenerator; - import java.time.Instant; import java.util.ArrayList; import java.util.List; import java.util.Objects; import java.util.UUID; +import lombok.Data; +import org.hibernate.annotations.CreationTimestamp; +import org.hibernate.annotations.UpdateTimestamp; +import org.hibernate.annotations.UuidGenerator; @Data @Entity @@ -24,61 +23,61 @@ @EntityListeners(ModelBaseListener.class) public class InjectImporter implements Base { - @Id - @Column(name = "importer_id") - @JsonProperty("inject_importer_id") - @GeneratedValue - @UuidGenerator - @NotNull - private UUID id; + @Id + @Column(name = "importer_id") + @JsonProperty("inject_importer_id") + @GeneratedValue + @UuidGenerator + @NotNull + private UUID id; - @Column(name = "importer_import_type_value") - @JsonProperty("inject_importer_type_value") - @NotBlank - private String importTypeValue; + @Column(name = "importer_import_type_value") + @JsonProperty("inject_importer_type_value") + @NotBlank + private String importTypeValue; - @OneToOne(cascade = CascadeType.ALL, orphanRemoval = true) - @JoinColumn(name = "importer_injector_contract_id") - @JsonProperty("inject_importer_injector_contract") - @JsonSerialize(using = MonoIdDeserializer.class) - @NotNull - private InjectorContract injectorContract; + @OneToOne(cascade = CascadeType.ALL, orphanRemoval = true) + @JoinColumn(name = "importer_injector_contract_id") + @JsonProperty("inject_importer_injector_contract") + @JsonSerialize(using = MonoIdDeserializer.class) + @NotNull + private InjectorContract injectorContract; - @OneToMany(cascade = CascadeType.ALL, orphanRemoval = true, fetch = FetchType.EAGER) - @JoinColumn(name = "attribute_inject_importer_id", nullable = false) - @JsonProperty("inject_importer_rule_attributes") - private List ruleAttributes = new ArrayList<>(); + @OneToMany(cascade = CascadeType.ALL, orphanRemoval = true, fetch = FetchType.EAGER) + @JoinColumn(name = "attribute_inject_importer_id", nullable = false) + @JsonProperty("inject_importer_rule_attributes") + private List ruleAttributes = new ArrayList<>(); - @CreationTimestamp - @Column(name="importer_created_at") - @JsonProperty("inject_importer_created_at") - private Instant creationDate; + @CreationTimestamp + @Column(name = "importer_created_at") + @JsonProperty("inject_importer_created_at") + private Instant creationDate; - @UpdateTimestamp - @Column(name= "importer_updated_at") - @JsonProperty("inject_importer_updated_at") - private Instant updateDate; + @UpdateTimestamp + @Column(name = "importer_updated_at") + @JsonProperty("inject_importer_updated_at") + private Instant updateDate; - @Override - public boolean equals(Object o) { - if (this == o) return true; - if (o == null || !Base.class.isAssignableFrom(o.getClass())) return false; - Base base = (Base) o; - return id.equals(base.getId()); - } + @Override + public boolean equals(Object o) { + if (this == o) return true; + if (o == null || !Base.class.isAssignableFrom(o.getClass())) return false; + Base base = (Base) o; + return id.equals(base.getId()); + } - @Override - public int hashCode() { - return Objects.hash(id); - } + @Override + public int hashCode() { + return Objects.hash(id); + } - @Override - public String getId() { - return this.id != null ? this.id.toString(): ""; - } + @Override + public String getId() { + return this.id != null ? this.id.toString() : ""; + } - @Override - public void setId(String id) { - this.id = UUID.fromString(id); - } + @Override + public void setId(String id) { + this.id = UUID.fromString(id); + } } diff --git a/openbas-model/src/main/java/io/openbas/database/model/InjectStatus.java b/openbas-model/src/main/java/io/openbas/database/model/InjectStatus.java index 77b087498f..a10b1ed80b 100644 --- a/openbas-model/src/main/java/io/openbas/database/model/InjectStatus.java +++ b/openbas-model/src/main/java/io/openbas/database/model/InjectStatus.java @@ -3,11 +3,10 @@ import com.fasterxml.jackson.annotation.JsonProperty; import io.openbas.database.converter.InjectStatusCommandLineConverter; import jakarta.persistence.*; -import lombok.Getter; -import lombok.Setter; - import java.time.Duration; import java.time.Instant; +import lombok.Getter; +import lombok.Setter; @Setter @Getter @@ -27,20 +26,29 @@ public static InjectStatus fromExecution(Execution execution, Inject executedInj injectStatus.setInject(executedInject); injectStatus.getTraces().addAll(execution.getTraces()); int numberOfElements = execution.getTraces().size(); - int numberOfError = (int) execution.getTraces().stream().filter(ex -> ex.getStatus().equals(ExecutionStatus.ERROR)) - .count(); - int numberOfSuccess = (int) execution.getTraces().stream() - .filter(ex -> ex.getStatus().equals(ExecutionStatus.SUCCESS)).count(); + int numberOfError = + (int) + execution.getTraces().stream() + .filter(ex -> ex.getStatus().equals(ExecutionStatus.ERROR)) + .count(); + int numberOfSuccess = + (int) + execution.getTraces().stream() + .filter(ex -> ex.getStatus().equals(ExecutionStatus.SUCCESS)) + .count(); injectStatus.setTrackingTotalError(numberOfError); injectStatus.setTrackingTotalSuccess(numberOfSuccess); injectStatus.setTrackingTotalCount( execution.getExpectedCount() != null ? execution.getExpectedCount() : numberOfElements); - ExecutionStatus globalStatus = numberOfSuccess > 0 ? ExecutionStatus.SUCCESS : ExecutionStatus.ERROR; - ExecutionStatus finalStatus = numberOfError > 0 && numberOfSuccess > 0 ? ExecutionStatus.PARTIAL : globalStatus; + ExecutionStatus globalStatus = + numberOfSuccess > 0 ? ExecutionStatus.SUCCESS : ExecutionStatus.ERROR; + ExecutionStatus finalStatus = + numberOfError > 0 && numberOfSuccess > 0 ? ExecutionStatus.PARTIAL : globalStatus; injectStatus.setName(execution.isAsync() ? ExecutionStatus.PENDING : finalStatus); injectStatus.setTrackingEndDate(Instant.now()); injectStatus.setTrackingTotalExecutionTime( - Duration.between(injectStatus.getTrackingSentDate(), injectStatus.getTrackingEndDate()).getSeconds()); + Duration.between(injectStatus.getTrackingSentDate(), injectStatus.getTrackingEndDate()) + .getSeconds()); return injectStatus; } diff --git a/openbas-model/src/main/java/io/openbas/database/model/InjectStatusCommandLine.java b/openbas-model/src/main/java/io/openbas/database/model/InjectStatusCommandLine.java index ffe7728d98..6c910b736e 100644 --- a/openbas-model/src/main/java/io/openbas/database/model/InjectStatusCommandLine.java +++ b/openbas-model/src/main/java/io/openbas/database/model/InjectStatusCommandLine.java @@ -1,50 +1,50 @@ package io.openbas.database.model; import com.fasterxml.jackson.annotation.JsonProperty; -import lombok.Getter; -import lombok.Setter; - import java.util.List; import java.util.Objects; +import lombok.Getter; +import lombok.Setter; @Getter @Setter public class InjectStatusCommandLine { - @JsonProperty("content") - private List content; - - @JsonProperty("cleanup_command") - private List cleanupCommand; - - @JsonProperty("external_id") - private String externalId; - - public InjectStatusCommandLine() { - // Default constructor - } - - public InjectStatusCommandLine(List content, List cleanupCommand, String externalId) { - this.content = content; - this.cleanupCommand = cleanupCommand; - this.externalId = externalId; - } - - @Override - public boolean equals(Object o) { - if (this == o) return true; - if (o == null || getClass() != o.getClass()) return false; - InjectStatusCommandLine that = (InjectStatusCommandLine) o; - return Objects.equals(externalId, that.externalId); - } - - @Override - public int hashCode() { - return Objects.hash(content, cleanupCommand, externalId); - } - - @Override - public String toString() { - return externalId + ": " + content + "\n" + cleanupCommand; - } + @JsonProperty("content") + private List content; + + @JsonProperty("cleanup_command") + private List cleanupCommand; + + @JsonProperty("external_id") + private String externalId; + + public InjectStatusCommandLine() { + // Default constructor + } + + public InjectStatusCommandLine( + List content, List cleanupCommand, String externalId) { + this.content = content; + this.cleanupCommand = cleanupCommand; + this.externalId = externalId; + } + + @Override + public boolean equals(Object o) { + if (this == o) return true; + if (o == null || getClass() != o.getClass()) return false; + InjectStatusCommandLine that = (InjectStatusCommandLine) o; + return Objects.equals(externalId, that.externalId); + } + + @Override + public int hashCode() { + return Objects.hash(content, cleanupCommand, externalId); + } + + @Override + public String toString() { + return externalId + ": " + content + "\n" + cleanupCommand; + } } diff --git a/openbas-model/src/main/java/io/openbas/database/model/InjectStatusExecution.java b/openbas-model/src/main/java/io/openbas/database/model/InjectStatusExecution.java index 7190c48a51..9a5b509410 100644 --- a/openbas-model/src/main/java/io/openbas/database/model/InjectStatusExecution.java +++ b/openbas-model/src/main/java/io/openbas/database/model/InjectStatusExecution.java @@ -1,96 +1,100 @@ package io.openbas.database.model; import com.fasterxml.jackson.annotation.JsonProperty; -import lombok.Getter; -import lombok.Setter; - import java.time.Instant; import java.util.ArrayList; import java.util.List; import java.util.Objects; +import lombok.Getter; +import lombok.Setter; @Getter @Setter public class InjectStatusExecution { - public static final String EXECUTION_TYPE_STANDARD = "standard"; - public static final String EXECUTION_TYPE_COMMAND = "command_line"; - - @JsonProperty("execution_time") - private Instant time; - - @JsonProperty("execution_duration") - private int duration; - - @JsonProperty("execution_message") - private String message; - - @JsonProperty("execution_category") - private String category = "standard"; // standard / command_line / ?? - - @JsonProperty("execution_status") - private ExecutionStatus status; - - @JsonProperty("execution_context_identifiers") - private List identifiers = new ArrayList<>(); - - public InjectStatusExecution() { - // Default constructor - } - - public InjectStatusExecution(ExecutionStatus status, List identifiers, String message, String category) { - this.status = status; - this.identifiers = identifiers; - this.message = message; - this.time = Instant.now(); - this.category = category; - } - - public static InjectStatusExecution traceInfo(String message) { - return new InjectStatusExecution(ExecutionStatus.INFO, List.of(), message, EXECUTION_TYPE_STANDARD); - } - - public static InjectStatusExecution traceInfo(String category, String message) { - return new InjectStatusExecution(ExecutionStatus.INFO, List.of(), message, category); - } - - public static InjectStatusExecution traceInfo(String message, List identifiers) { - return new InjectStatusExecution(ExecutionStatus.INFO, identifiers, message, EXECUTION_TYPE_STANDARD); - } - - public static InjectStatusExecution traceSuccess(String message) { - return new InjectStatusExecution(ExecutionStatus.SUCCESS, List.of(), message, EXECUTION_TYPE_STANDARD); - } - - public static InjectStatusExecution traceSuccess(String message, List userIds) { - return new InjectStatusExecution(ExecutionStatus.SUCCESS, userIds, message, EXECUTION_TYPE_STANDARD); - } - - public static InjectStatusExecution traceError(String message) { - return new InjectStatusExecution(ExecutionStatus.ERROR, List.of(), message, EXECUTION_TYPE_STANDARD); - } - - public static InjectStatusExecution traceMaybePrevented(String message) { - return new InjectStatusExecution(ExecutionStatus.MAYBE_PREVENTED, List.of(), message, EXECUTION_TYPE_STANDARD); - } - - - @Override - public boolean equals(Object o) { - if (this == o) return true; - if (o == null || getClass() != o.getClass()) return false; - InjectStatusExecution that = (InjectStatusExecution) o; - return message.equals(that.message) - && status == that.status && time.equals(that.time); - } - - @Override - public int hashCode() { - return Objects.hash(message, status, time); - } - - @Override - public String toString() { - return message + ": " + status; - } + public static final String EXECUTION_TYPE_STANDARD = "standard"; + public static final String EXECUTION_TYPE_COMMAND = "command_line"; + + @JsonProperty("execution_time") + private Instant time; + + @JsonProperty("execution_duration") + private int duration; + + @JsonProperty("execution_message") + private String message; + + @JsonProperty("execution_category") + private String category = "standard"; // standard / command_line / ?? + + @JsonProperty("execution_status") + private ExecutionStatus status; + + @JsonProperty("execution_context_identifiers") + private List identifiers = new ArrayList<>(); + + public InjectStatusExecution() { + // Default constructor + } + + public InjectStatusExecution( + ExecutionStatus status, List identifiers, String message, String category) { + this.status = status; + this.identifiers = identifiers; + this.message = message; + this.time = Instant.now(); + this.category = category; + } + + public static InjectStatusExecution traceInfo(String message) { + return new InjectStatusExecution( + ExecutionStatus.INFO, List.of(), message, EXECUTION_TYPE_STANDARD); + } + + public static InjectStatusExecution traceInfo(String category, String message) { + return new InjectStatusExecution(ExecutionStatus.INFO, List.of(), message, category); + } + + public static InjectStatusExecution traceInfo(String message, List identifiers) { + return new InjectStatusExecution( + ExecutionStatus.INFO, identifiers, message, EXECUTION_TYPE_STANDARD); + } + + public static InjectStatusExecution traceSuccess(String message) { + return new InjectStatusExecution( + ExecutionStatus.SUCCESS, List.of(), message, EXECUTION_TYPE_STANDARD); + } + + public static InjectStatusExecution traceSuccess(String message, List userIds) { + return new InjectStatusExecution( + ExecutionStatus.SUCCESS, userIds, message, EXECUTION_TYPE_STANDARD); + } + + public static InjectStatusExecution traceError(String message) { + return new InjectStatusExecution( + ExecutionStatus.ERROR, List.of(), message, EXECUTION_TYPE_STANDARD); + } + + public static InjectStatusExecution traceMaybePrevented(String message) { + return new InjectStatusExecution( + ExecutionStatus.MAYBE_PREVENTED, List.of(), message, EXECUTION_TYPE_STANDARD); + } + + @Override + public boolean equals(Object o) { + if (this == o) return true; + if (o == null || getClass() != o.getClass()) return false; + InjectStatusExecution that = (InjectStatusExecution) o; + return message.equals(that.message) && status == that.status && time.equals(that.time); + } + + @Override + public int hashCode() { + return Objects.hash(message, status, time); + } + + @Override + public String toString() { + return message + ": " + status; + } } diff --git a/openbas-model/src/main/java/io/openbas/database/model/InjectTestStatus.java b/openbas-model/src/main/java/io/openbas/database/model/InjectTestStatus.java index 5c9acb0c1d..c053123f5e 100644 --- a/openbas-model/src/main/java/io/openbas/database/model/InjectTestStatus.java +++ b/openbas-model/src/main/java/io/openbas/database/model/InjectTestStatus.java @@ -2,15 +2,14 @@ import com.fasterxml.jackson.annotation.JsonProperty; import jakarta.persistence.*; +import java.time.Duration; +import java.time.Instant; +import java.util.Optional; import lombok.Getter; import lombok.Setter; import org.hibernate.annotations.CreationTimestamp; import org.hibernate.annotations.UpdateTimestamp; -import java.time.Instant; -import java.time.Duration; -import java.util.Optional; - @Setter @Getter @Entity @@ -34,7 +33,8 @@ public Optional getInjectContract() { @JsonProperty("inject_type") private String getType() { - return inject.getInjectorContract() + return inject + .getInjectorContract() .map(InjectorContract::getInjector) .map(Injector::getType) .orElse(null); @@ -55,22 +55,30 @@ public static InjectTestStatus fromExecutionTest(Execution execution) { injectTestStatus.setTrackingSentDate(Instant.now()); injectTestStatus.getTraces().addAll(execution.getTraces()); int numberOfElements = execution.getTraces().size(); - int numberOfError = (int) execution.getTraces().stream().filter(ex -> ex.getStatus().equals(ExecutionStatus.ERROR)) - .count(); - int numberOfSuccess = (int) execution.getTraces().stream() - .filter(ex -> ex.getStatus().equals(ExecutionStatus.SUCCESS)).count(); + int numberOfError = + (int) + execution.getTraces().stream() + .filter(ex -> ex.getStatus().equals(ExecutionStatus.ERROR)) + .count(); + int numberOfSuccess = + (int) + execution.getTraces().stream() + .filter(ex -> ex.getStatus().equals(ExecutionStatus.SUCCESS)) + .count(); injectTestStatus.setTrackingTotalError(numberOfError); injectTestStatus.setTrackingTotalSuccess(numberOfSuccess); injectTestStatus.setTrackingTotalCount( execution.getExpectedCount() != null ? execution.getExpectedCount() : numberOfElements); - ExecutionStatus globalStatus = numberOfSuccess > 0 ? ExecutionStatus.SUCCESS : ExecutionStatus.ERROR; - ExecutionStatus finalStatus = numberOfError > 0 && numberOfSuccess > 0 ? ExecutionStatus.PARTIAL : globalStatus; + ExecutionStatus globalStatus = + numberOfSuccess > 0 ? ExecutionStatus.SUCCESS : ExecutionStatus.ERROR; + ExecutionStatus finalStatus = + numberOfError > 0 && numberOfSuccess > 0 ? ExecutionStatus.PARTIAL : globalStatus; injectTestStatus.setName(execution.isAsync() ? ExecutionStatus.PENDING : finalStatus); injectTestStatus.setTrackingEndDate(Instant.now()); injectTestStatus.setTrackingTotalExecutionTime( - Duration.between(injectTestStatus.getTrackingSentDate(), injectTestStatus.getTrackingEndDate()).getSeconds()); + Duration.between( + injectTestStatus.getTrackingSentDate(), injectTestStatus.getTrackingEndDate()) + .getSeconds()); return injectTestStatus; } - - } diff --git a/openbas-model/src/main/java/io/openbas/database/model/Injection.java b/openbas-model/src/main/java/io/openbas/database/model/Injection.java index 890cb3af27..b68dded978 100644 --- a/openbas-model/src/main/java/io/openbas/database/model/Injection.java +++ b/openbas-model/src/main/java/io/openbas/database/model/Injection.java @@ -1,15 +1,14 @@ package io.openbas.database.model; import java.time.Instant; -import java.util.List; import java.util.Optional; public interface Injection { - String getId(); + String getId(); - Exercise getExercise(); + Exercise getExercise(); - Optional getDate(); + Optional getDate(); - Inject getInject(); + Inject getInject(); } diff --git a/openbas-model/src/main/java/io/openbas/database/model/Injector.java b/openbas-model/src/main/java/io/openbas/database/model/Injector.java index 3610eeb439..e70cf34a66 100644 --- a/openbas-model/src/main/java/io/openbas/database/model/Injector.java +++ b/openbas-model/src/main/java/io/openbas/database/model/Injector.java @@ -1,5 +1,7 @@ package io.openbas.database.model; +import static java.time.Instant.now; + import com.fasterxml.jackson.annotation.JsonIgnore; import com.fasterxml.jackson.annotation.JsonProperty; import io.hypersistence.utils.hibernate.type.basic.PostgreSQLHStoreType; @@ -7,15 +9,12 @@ import jakarta.persistence.*; import jakarta.validation.constraints.NotBlank; import jakarta.validation.constraints.NotNull; +import java.time.Instant; +import java.util.*; import lombok.Getter; import lombok.Setter; import org.hibernate.annotations.Type; -import java.time.Instant; -import java.util.*; - -import static java.time.Instant.now; - @Getter @Setter @Entity @@ -23,83 +22,83 @@ @EntityListeners(ModelBaseListener.class) public class Injector implements Base { - @Id - @Column(name = "injector_id") - @JsonProperty("injector_id") - @NotBlank - private String id; - - @Column(name = "injector_name") - @JsonProperty("injector_name") - @NotBlank - private String name; - - @Column(name = "injector_type") - @JsonProperty("injector_type") - @NotBlank - private String type; - - @Column(name = "injector_category") - @JsonProperty("injector_category") - private String category; - - @Column(name = "injector_external") - @JsonProperty("injector_external") - private boolean external = false; - - @Column(name = "injector_custom_contracts") - @JsonProperty("injector_custom_contracts") - private boolean customContracts = false; - - @Column(name = "injector_executor_commands") - @JsonProperty("injector_executor_commands") - @Type(PostgreSQLHStoreType.class) - private Map executorCommands = new HashMap<>(); - - @Column(name = "injector_executor_clear_commands") - @JsonProperty("injector_executor_clear_commands") - @Type(PostgreSQLHStoreType.class) - private Map executorClearCommands = new HashMap<>(); - - @Column(name = "injector_payloads") - @JsonProperty("injector_payloads") - private boolean payloads = false; - - @Column(name = "injector_created_at") - @JsonProperty("injector_created_at") - @NotNull - private Instant createdAt = now(); - - @Column(name = "injector_updated_at") - @JsonProperty("injector_updated_at") - @NotNull - private Instant updatedAt = now(); - - @OneToMany(mappedBy = "injector", fetch = FetchType.LAZY) - @JsonIgnore - private List contracts = new ArrayList<>(); - - @JsonIgnore - @Override - public boolean isUserHasAccess(User user) { - return user.isAdmin(); - } - - @Override - public String toString() { - return name; - } - - @Override - public boolean equals(Object o) { - if (this == o) return true; - if (o == null || !Base.class.isAssignableFrom(o.getClass())) return false; - Base base = (Base) o; - return id.equals(base.getId()); - } - - @Override - public int hashCode() { - return Objects.hash(id); - } + @Id + @Column(name = "injector_id") + @JsonProperty("injector_id") + @NotBlank + private String id; + + @Column(name = "injector_name") + @JsonProperty("injector_name") + @NotBlank + private String name; + + @Column(name = "injector_type") + @JsonProperty("injector_type") + @NotBlank + private String type; + + @Column(name = "injector_category") + @JsonProperty("injector_category") + private String category; + + @Column(name = "injector_external") + @JsonProperty("injector_external") + private boolean external = false; + + @Column(name = "injector_custom_contracts") + @JsonProperty("injector_custom_contracts") + private boolean customContracts = false; + + @Column(name = "injector_executor_commands") + @JsonProperty("injector_executor_commands") + @Type(PostgreSQLHStoreType.class) + private Map executorCommands = new HashMap<>(); + + @Column(name = "injector_executor_clear_commands") + @JsonProperty("injector_executor_clear_commands") + @Type(PostgreSQLHStoreType.class) + private Map executorClearCommands = new HashMap<>(); + + @Column(name = "injector_payloads") + @JsonProperty("injector_payloads") + private boolean payloads = false; + + @Column(name = "injector_created_at") + @JsonProperty("injector_created_at") + @NotNull + private Instant createdAt = now(); + + @Column(name = "injector_updated_at") + @JsonProperty("injector_updated_at") + @NotNull + private Instant updatedAt = now(); + + @OneToMany(mappedBy = "injector", fetch = FetchType.LAZY) + @JsonIgnore + private List contracts = new ArrayList<>(); + + @JsonIgnore + @Override + public boolean isUserHasAccess(User user) { + return user.isAdmin(); + } + + @Override + public String toString() { + return name; + } + + @Override + public boolean equals(Object o) { + if (this == o) return true; + if (o == null || !Base.class.isAssignableFrom(o.getClass())) return false; + Base base = (Base) o; + return id.equals(base.getId()); + } + + @Override + public int hashCode() { + return Objects.hash(id); + } } diff --git a/openbas-model/src/main/java/io/openbas/database/model/InjectorContract.java b/openbas-model/src/main/java/io/openbas/database/model/InjectorContract.java index d19c648ad3..a098c31b66 100644 --- a/openbas-model/src/main/java/io/openbas/database/model/InjectorContract.java +++ b/openbas-model/src/main/java/io/openbas/database/model/InjectorContract.java @@ -1,5 +1,7 @@ package io.openbas.database.model; +import static java.time.Instant.now; + import com.fasterxml.jackson.annotation.JsonIgnore; import com.fasterxml.jackson.annotation.JsonProperty; import com.fasterxml.jackson.databind.annotation.JsonSerialize; @@ -14,15 +16,12 @@ import jakarta.persistence.*; import jakarta.validation.constraints.NotBlank; import jakarta.validation.constraints.NotNull; +import java.time.Instant; +import java.util.*; import lombok.Getter; import lombok.Setter; import org.hibernate.annotations.Type; -import java.time.Instant; -import java.util.*; - -import static java.time.Instant.now; - @Getter @Setter @Entity @@ -30,131 +29,132 @@ @EntityListeners(ModelBaseListener.class) public class InjectorContract implements Base { - @Id - @Column(name = "injector_contract_id") - @JsonProperty("injector_contract_id") - @NotBlank - private String id; - - @Column(name = "injector_contract_labels") - @JsonProperty("injector_contract_labels") - @Type(PostgreSQLHStoreType.class) - @Queryable(searchable = true, filterable = true, sortable = true) - private Map labels = new HashMap<>(); - - @Column(name = "injector_contract_manual") - @JsonProperty("injector_contract_manual") - private Boolean manual; - - @Column(name = "injector_contract_content") - @JsonProperty("injector_contract_content") - @NotBlank - private String content; - - @Column(name = "injector_contract_content", insertable=false, updatable=false) - @Convert(converter = ContentConverter.class) - private ObjectNode convertedContent; - - @Column(name = "injector_contract_custom") - @JsonProperty("injector_contract_custom") - private Boolean custom = false; - - @Column(name = "injector_contract_needs_executor") - @JsonProperty("injector_contract_needs_executor") - private Boolean needsExecutor = false; - - @Type(StringArrayType.class) - @Enumerated(EnumType.STRING) - @Column(name = "injector_contract_platforms", columnDefinition = "text[]") - @JsonProperty("injector_contract_platforms") - @Queryable(filterable = true) - private Endpoint.PLATFORM_TYPE[] platforms = new Endpoint.PLATFORM_TYPE[0]; - - @Queryable(filterable = true, dynamicValues = true, path="payload.executableArch") - @JsonProperty("injector_contract_arch") - @Enumerated(EnumType.STRING) - public Endpoint.PLATFORM_ARCH getArch() { - return Optional.ofNullable(getPayload()) - .filter(payload -> payload instanceof Executable) - .map(payload -> ((Executable) payload).getExecutableArch()) - .orElse(null); - }; - - @ManyToOne(fetch = FetchType.EAGER) - @JoinColumn(name = "injector_contract_payload") - @JsonProperty("injector_contract_payload") - private Payload payload; - - @Column(name = "injector_contract_created_at") - @JsonProperty("injector_contract_created_at") - @NotNull - private Instant createdAt = now(); - - @Column(name = "injector_contract_updated_at") - @JsonProperty("injector_contract_updated_at") - @NotNull - private Instant updatedAt = now(); - - @ManyToOne(fetch = FetchType.EAGER) - @JoinColumn(name = "injector_id") - @JsonSerialize(using = MonoIdDeserializer.class) - @JsonProperty("injector_contract_injector") - @Queryable(filterable = true, dynamicValues = true) - @NotNull - private Injector injector; - - @Setter - @ManyToMany(fetch = FetchType.EAGER) - @JoinTable(name = "injectors_contracts_attack_patterns", - joinColumns = @JoinColumn(name = "injector_contract_id"), - inverseJoinColumns = @JoinColumn(name = "attack_pattern_id")) - @JsonSerialize(using = MultiIdListDeserializer.class) - @JsonProperty("injector_contract_attack_patterns") - @Queryable(searchable = true, filterable = true, path = "attackPatterns.externalId") - private List attackPatterns = new ArrayList<>(); - - @Column(name = "injector_contract_atomic_testing") - @JsonProperty("injector_contract_atomic_testing") - @Queryable(filterable = true) - private boolean isAtomicTesting; - - @Column(name = "injector_contract_import_available") - @JsonProperty("injector_contract_import_available") - @Queryable(filterable = true) - private boolean isImportAvailable; - - @JsonProperty("injector_contract_injector_type") - private String getInjectorType() { - return this.getInjector() != null ? this.getInjector().getType() : null; - } - - @JsonIgnore - @JsonProperty("injector_contract_kill_chain_phases") - @Queryable(filterable = true, dynamicValues = true, path = "attackPatterns.killChainPhases.id") - public List getKillChainPhases() { - return getAttackPatterns() - .stream() - .flatMap(attackPattern -> attackPattern.getKillChainPhases().stream()) - .distinct() - .toList(); - } - - @JsonIgnore - @Override - public boolean isUserHasAccess(User user) { - return user.isAdmin(); - } - - @Override - public boolean equals(Object o) { - if (this == o) return true; - if (o == null || !Base.class.isAssignableFrom(o.getClass())) return false; - Base base = (Base) o; - return id.equals(base.getId()); - } - - @Override - public int hashCode() { - return Objects.hash(id); - } + @Id + @Column(name = "injector_contract_id") + @JsonProperty("injector_contract_id") + @NotBlank + private String id; + + @Column(name = "injector_contract_labels") + @JsonProperty("injector_contract_labels") + @Type(PostgreSQLHStoreType.class) + @Queryable(searchable = true, filterable = true, sortable = true) + private Map labels = new HashMap<>(); + + @Column(name = "injector_contract_manual") + @JsonProperty("injector_contract_manual") + private Boolean manual; + + @Column(name = "injector_contract_content") + @JsonProperty("injector_contract_content") + @NotBlank + private String content; + + @Column(name = "injector_contract_content", insertable = false, updatable = false) + @Convert(converter = ContentConverter.class) + private ObjectNode convertedContent; + + @Column(name = "injector_contract_custom") + @JsonProperty("injector_contract_custom") + private Boolean custom = false; + + @Column(name = "injector_contract_needs_executor") + @JsonProperty("injector_contract_needs_executor") + private Boolean needsExecutor = false; + + @Type(StringArrayType.class) + @Enumerated(EnumType.STRING) + @Column(name = "injector_contract_platforms", columnDefinition = "text[]") + @JsonProperty("injector_contract_platforms") + @Queryable(filterable = true) + private Endpoint.PLATFORM_TYPE[] platforms = new Endpoint.PLATFORM_TYPE[0]; + + @Queryable(filterable = true, dynamicValues = true, path = "payload.executableArch") + @JsonProperty("injector_contract_arch") + @Enumerated(EnumType.STRING) + public Endpoint.PLATFORM_ARCH getArch() { + return Optional.ofNullable(getPayload()) + .filter(payload -> payload instanceof Executable) + .map(payload -> ((Executable) payload).getExecutableArch()) + .orElse(null); + } + ; + + @ManyToOne(fetch = FetchType.EAGER) + @JoinColumn(name = "injector_contract_payload") + @JsonProperty("injector_contract_payload") + private Payload payload; + + @Column(name = "injector_contract_created_at") + @JsonProperty("injector_contract_created_at") + @NotNull + private Instant createdAt = now(); + + @Column(name = "injector_contract_updated_at") + @JsonProperty("injector_contract_updated_at") + @NotNull + private Instant updatedAt = now(); + + @ManyToOne(fetch = FetchType.EAGER) + @JoinColumn(name = "injector_id") + @JsonSerialize(using = MonoIdDeserializer.class) + @JsonProperty("injector_contract_injector") + @Queryable(filterable = true, dynamicValues = true) + @NotNull + private Injector injector; + + @Setter + @ManyToMany(fetch = FetchType.EAGER) + @JoinTable( + name = "injectors_contracts_attack_patterns", + joinColumns = @JoinColumn(name = "injector_contract_id"), + inverseJoinColumns = @JoinColumn(name = "attack_pattern_id")) + @JsonSerialize(using = MultiIdListDeserializer.class) + @JsonProperty("injector_contract_attack_patterns") + @Queryable(searchable = true, filterable = true, path = "attackPatterns.externalId") + private List attackPatterns = new ArrayList<>(); + + @Column(name = "injector_contract_atomic_testing") + @JsonProperty("injector_contract_atomic_testing") + @Queryable(filterable = true) + private boolean isAtomicTesting; + + @Column(name = "injector_contract_import_available") + @JsonProperty("injector_contract_import_available") + @Queryable(filterable = true) + private boolean isImportAvailable; + + @JsonProperty("injector_contract_injector_type") + private String getInjectorType() { + return this.getInjector() != null ? this.getInjector().getType() : null; + } + + @JsonIgnore + @JsonProperty("injector_contract_kill_chain_phases") + @Queryable(filterable = true, dynamicValues = true, path = "attackPatterns.killChainPhases.id") + public List getKillChainPhases() { + return getAttackPatterns().stream() + .flatMap(attackPattern -> attackPattern.getKillChainPhases().stream()) + .distinct() + .toList(); + } + + @JsonIgnore + @Override + public boolean isUserHasAccess(User user) { + return user.isAdmin(); + } + + @Override + public boolean equals(Object o) { + if (this == o) return true; + if (o == null || !Base.class.isAssignableFrom(o.getClass())) return false; + Base base = (Base) o; + return id.equals(base.getId()); + } + + @Override + public int hashCode() { + return Objects.hash(id); + } } diff --git a/openbas-model/src/main/java/io/openbas/database/model/KillChainPhase.java b/openbas-model/src/main/java/io/openbas/database/model/KillChainPhase.java index e8fa686f03..5e74ebd669 100644 --- a/openbas-model/src/main/java/io/openbas/database/model/KillChainPhase.java +++ b/openbas-model/src/main/java/io/openbas/database/model/KillChainPhase.java @@ -1,18 +1,17 @@ package io.openbas.database.model; +import static java.time.Instant.now; + import com.fasterxml.jackson.annotation.JsonProperty; import io.openbas.annotation.Queryable; import io.openbas.database.audit.ModelBaseListener; import jakarta.persistence.*; import jakarta.validation.constraints.NotBlank; import jakarta.validation.constraints.NotNull; +import java.time.Instant; import lombok.Data; import org.hibernate.annotations.UuidGenerator; -import java.time.Instant; - -import static java.time.Instant.now; - @Data @Entity @Table(name = "kill_chain_phases") @@ -72,5 +71,4 @@ public class KillChainPhase implements Base { @JsonProperty("phase_updated_at") @NotNull private Instant updatedAt = now(); - } diff --git a/openbas-model/src/main/java/io/openbas/database/model/LessonsAnswer.java b/openbas-model/src/main/java/io/openbas/database/model/LessonsAnswer.java index a4090956c9..ff622844f4 100644 --- a/openbas-model/src/main/java/io/openbas/database/model/LessonsAnswer.java +++ b/openbas-model/src/main/java/io/openbas/database/model/LessonsAnswer.java @@ -1,5 +1,7 @@ package io.openbas.database.model; +import static java.time.Instant.now; + import com.fasterxml.jackson.annotation.JsonProperty; import com.fasterxml.jackson.databind.annotation.JsonSerialize; import io.openbas.database.audit.ModelBaseListener; @@ -7,15 +9,12 @@ import jakarta.persistence.*; import jakarta.validation.constraints.NotBlank; import jakarta.validation.constraints.NotNull; +import java.time.Instant; +import java.util.Objects; import lombok.Getter; import lombok.Setter; import org.hibernate.annotations.UuidGenerator; -import java.time.Instant; -import java.util.Objects; - -import static java.time.Instant.now; - @Getter @Setter @Entity @@ -23,73 +22,73 @@ @EntityListeners(ModelBaseListener.class) public class LessonsAnswer implements Base { - @Id - @Column(name = "lessons_answer_id") - @GeneratedValue(generator = "UUID") - @UuidGenerator - @JsonProperty("lessonsanswer_id") - @NotBlank - private String id; - - @ManyToOne(fetch = FetchType.LAZY) - @JoinColumn(name = "lessons_answer_question") - @JsonSerialize(using = MonoIdDeserializer.class) - @JsonProperty("lessons_answer_question") - @NotNull - private LessonsQuestion question; - - @ManyToOne(fetch = FetchType.LAZY) - @JoinColumn(name = "lessons_answer_user") - @JsonSerialize(using = MonoIdDeserializer.class) - @JsonProperty("lessons_answer_user") - private User user; - - @Column(name = "lessons_answer_created_at") - @JsonProperty("lessons_answer_created_at") - @NotNull - private Instant created = now(); - - @Column(name = "lessons_answer_updated_at") - @JsonProperty("lessons_answer_updated_at") - @NotNull - private Instant updated = now(); - - @Column(name = "lessons_answer_positive") - @JsonProperty("lessons_answer_positive") - private String positive; - - @Column(name = "lessons_answer_negative") - @JsonProperty("lessons_answer_negative") - private String negative; - - @Column(name = "lessons_answer_score") - @JsonProperty("lessons_answer_score") - @NotNull - private Integer score; - - // region transient - @JsonProperty("lessons_answer_exercise") - public String getExercise() { - return getQuestion().getCategory().getExercise().getId(); - } - // endregion - - @Override - public boolean isUserHasAccess(User user) { - return getQuestion().getCategory().getExercise().isUserHasAccess(user); - } - - @Override - public boolean equals(Object o) { - if (this == o) return true; - if (o == null || !Base.class.isAssignableFrom(o.getClass())) return false; - Base base = (Base) o; - return id.equals(base.getId()); - } - - @Override - public int hashCode() { - return Objects.hash(id); - } - + @Id + @Column(name = "lessons_answer_id") + @GeneratedValue(generator = "UUID") + @UuidGenerator + @JsonProperty("lessonsanswer_id") + @NotBlank + private String id; + + @ManyToOne(fetch = FetchType.LAZY) + @JoinColumn(name = "lessons_answer_question") + @JsonSerialize(using = MonoIdDeserializer.class) + @JsonProperty("lessons_answer_question") + @NotNull + private LessonsQuestion question; + + @ManyToOne(fetch = FetchType.LAZY) + @JoinColumn(name = "lessons_answer_user") + @JsonSerialize(using = MonoIdDeserializer.class) + @JsonProperty("lessons_answer_user") + private User user; + + @Column(name = "lessons_answer_created_at") + @JsonProperty("lessons_answer_created_at") + @NotNull + private Instant created = now(); + + @Column(name = "lessons_answer_updated_at") + @JsonProperty("lessons_answer_updated_at") + @NotNull + private Instant updated = now(); + + @Column(name = "lessons_answer_positive") + @JsonProperty("lessons_answer_positive") + private String positive; + + @Column(name = "lessons_answer_negative") + @JsonProperty("lessons_answer_negative") + private String negative; + + @Column(name = "lessons_answer_score") + @JsonProperty("lessons_answer_score") + @NotNull + private Integer score; + + // region transient + @JsonProperty("lessons_answer_exercise") + public String getExercise() { + return getQuestion().getCategory().getExercise().getId(); + } + + // endregion + + @Override + public boolean isUserHasAccess(User user) { + return getQuestion().getCategory().getExercise().isUserHasAccess(user); + } + + @Override + public boolean equals(Object o) { + if (this == o) return true; + if (o == null || !Base.class.isAssignableFrom(o.getClass())) return false; + Base base = (Base) o; + return id.equals(base.getId()); + } + + @Override + public int hashCode() { + return Objects.hash(id); + } } diff --git a/openbas-model/src/main/java/io/openbas/database/model/LessonsCategory.java b/openbas-model/src/main/java/io/openbas/database/model/LessonsCategory.java index 6c72704c42..9363b8ff6e 100644 --- a/openbas-model/src/main/java/io/openbas/database/model/LessonsCategory.java +++ b/openbas-model/src/main/java/io/openbas/database/model/LessonsCategory.java @@ -1,23 +1,22 @@ package io.openbas.database.model; +import static java.time.Instant.now; + import com.fasterxml.jackson.annotation.JsonProperty; import com.fasterxml.jackson.databind.annotation.JsonSerialize; import io.openbas.database.audit.ModelBaseListener; import io.openbas.helper.MonoIdDeserializer; import io.openbas.helper.MultiIdListDeserializer; +import jakarta.persistence.*; import jakarta.validation.constraints.NotBlank; import jakarta.validation.constraints.NotNull; -import lombok.Getter; -import lombok.Setter; -import org.hibernate.annotations.UuidGenerator; - -import jakarta.persistence.*; import java.time.Instant; import java.util.ArrayList; import java.util.List; import java.util.Objects; - -import static java.time.Instant.now; +import lombok.Getter; +import lombok.Setter; +import org.hibernate.annotations.UuidGenerator; @Getter @Setter @@ -26,84 +25,86 @@ @EntityListeners(ModelBaseListener.class) public class LessonsCategory implements Base { - @Id - @Column(name = "lessons_category_id") - @GeneratedValue(generator = "UUID") - @UuidGenerator - @JsonProperty("lessonscategory_id") - @NotBlank - private String id; - - @ManyToOne(fetch = FetchType.LAZY) - @JoinColumn(name = "lessons_category_exercise") - @JsonSerialize(using = MonoIdDeserializer.class) - @JsonProperty("lessons_category_exercise") - private Exercise exercise; - - @ManyToOne(fetch = FetchType.LAZY) - @JoinColumn(name = "lessons_category_scenario") - @JsonSerialize(using = MonoIdDeserializer.class) - @JsonProperty("lessons_category_scenario") - private Scenario scenario; - - @Column(name = "lessons_category_created_at") - @JsonProperty("lessons_category_created_at") - @NotNull - private Instant created = now(); - - @Column(name = "lessons_category_updated_at") - @JsonProperty("lessons_category_updated_at") - @NotNull - private Instant updated = now(); - - @Column(name = "lessons_category_name") - @JsonProperty("lessons_category_name") - @NotBlank - private String name; - - @Column(name = "lessons_category_description") - @JsonProperty("lessons_category_description") - private String description; - - @Column(name = "lessons_category_order") - @JsonProperty("lessons_category_order") - private int order; - - @ManyToMany(fetch = FetchType.LAZY) - @JoinTable(name = "lessons_categories_teams", - joinColumns = @JoinColumn(name = "lessons_category_id"), - inverseJoinColumns = @JoinColumn(name = "team_id")) - @JsonSerialize(using = MultiIdListDeserializer.class) - @JsonProperty("lessons_category_teams") - private List teams = new ArrayList<>(); - - @OneToMany(mappedBy = "category", fetch = FetchType.LAZY, cascade = CascadeType.ALL) - @JsonProperty("lessons_category_questions") - @JsonSerialize(using = MultiIdListDeserializer.class) - private List questions = new ArrayList<>(); - - // region transient - @JsonProperty("lessons_category_users") - public List getUsers() { - return getTeams().stream().flatMap(team -> team.getUsers().stream().map(User::getId)).toList(); - } - // endregion - - @Override - public boolean isUserHasAccess(User user) { - return getExercise().isUserHasAccess(user); - } - - @Override - public boolean equals(Object o) { - if (this == o) return true; - if (o == null || !Base.class.isAssignableFrom(o.getClass())) return false; - Base base = (Base) o; - return id.equals(base.getId()); - } - - @Override - public int hashCode() { - return Objects.hash(id); - } + @Id + @Column(name = "lessons_category_id") + @GeneratedValue(generator = "UUID") + @UuidGenerator + @JsonProperty("lessonscategory_id") + @NotBlank + private String id; + + @ManyToOne(fetch = FetchType.LAZY) + @JoinColumn(name = "lessons_category_exercise") + @JsonSerialize(using = MonoIdDeserializer.class) + @JsonProperty("lessons_category_exercise") + private Exercise exercise; + + @ManyToOne(fetch = FetchType.LAZY) + @JoinColumn(name = "lessons_category_scenario") + @JsonSerialize(using = MonoIdDeserializer.class) + @JsonProperty("lessons_category_scenario") + private Scenario scenario; + + @Column(name = "lessons_category_created_at") + @JsonProperty("lessons_category_created_at") + @NotNull + private Instant created = now(); + + @Column(name = "lessons_category_updated_at") + @JsonProperty("lessons_category_updated_at") + @NotNull + private Instant updated = now(); + + @Column(name = "lessons_category_name") + @JsonProperty("lessons_category_name") + @NotBlank + private String name; + + @Column(name = "lessons_category_description") + @JsonProperty("lessons_category_description") + private String description; + + @Column(name = "lessons_category_order") + @JsonProperty("lessons_category_order") + private int order; + + @ManyToMany(fetch = FetchType.LAZY) + @JoinTable( + name = "lessons_categories_teams", + joinColumns = @JoinColumn(name = "lessons_category_id"), + inverseJoinColumns = @JoinColumn(name = "team_id")) + @JsonSerialize(using = MultiIdListDeserializer.class) + @JsonProperty("lessons_category_teams") + private List teams = new ArrayList<>(); + + @OneToMany(mappedBy = "category", fetch = FetchType.LAZY, cascade = CascadeType.ALL) + @JsonProperty("lessons_category_questions") + @JsonSerialize(using = MultiIdListDeserializer.class) + private List questions = new ArrayList<>(); + + // region transient + @JsonProperty("lessons_category_users") + public List getUsers() { + return getTeams().stream().flatMap(team -> team.getUsers().stream().map(User::getId)).toList(); + } + + // endregion + + @Override + public boolean isUserHasAccess(User user) { + return getExercise().isUserHasAccess(user); + } + + @Override + public boolean equals(Object o) { + if (this == o) return true; + if (o == null || !Base.class.isAssignableFrom(o.getClass())) return false; + Base base = (Base) o; + return id.equals(base.getId()); + } + + @Override + public int hashCode() { + return Objects.hash(id); + } } diff --git a/openbas-model/src/main/java/io/openbas/database/model/LessonsQuestion.java b/openbas-model/src/main/java/io/openbas/database/model/LessonsQuestion.java index ce1d29762f..b638a20e0f 100644 --- a/openbas-model/src/main/java/io/openbas/database/model/LessonsQuestion.java +++ b/openbas-model/src/main/java/io/openbas/database/model/LessonsQuestion.java @@ -1,5 +1,7 @@ package io.openbas.database.model; +import static java.time.Instant.now; + import com.fasterxml.jackson.annotation.JsonProperty; import com.fasterxml.jackson.databind.annotation.JsonSerialize; import io.openbas.database.audit.ModelBaseListener; @@ -8,17 +10,14 @@ import jakarta.persistence.*; import jakarta.validation.constraints.NotBlank; import jakarta.validation.constraints.NotNull; -import lombok.Getter; -import lombok.Setter; -import org.hibernate.annotations.UuidGenerator; - import java.time.Instant; import java.util.ArrayList; import java.util.List; import java.util.Objects; import java.util.Optional; - -import static java.time.Instant.now; +import lombok.Getter; +import lombok.Setter; +import org.hibernate.annotations.UuidGenerator; @Getter @Setter @@ -27,76 +26,77 @@ @EntityListeners(ModelBaseListener.class) public class LessonsQuestion implements Base { - @Id - @Column(name = "lessons_question_id") - @GeneratedValue(generator = "UUID") - @UuidGenerator - @JsonProperty("lessonsquestion_id") - @NotBlank - private String id; - - @ManyToOne(fetch = FetchType.LAZY) - @JoinColumn(name = "lessons_question_category") - @JsonSerialize(using = MonoIdDeserializer.class) - @JsonProperty("lessons_question_category") - @NotNull - private LessonsCategory category; - - @Column(name = "lessons_question_created_at") - @JsonProperty("lessons_question_created_at") - @NotNull - private Instant created = now(); - - @Column(name = "lessons_question_updated_at") - @JsonProperty("lessons_question_updated_at") - @NotNull - private Instant updated = now(); - - @Column(name = "lessons_question_content") - @JsonProperty("lessons_question_content") - @NotBlank - private String content; - - @Column(name = "lessons_question_explanation") - @JsonProperty("lessons_question_explanation") - private String explanation; - - @Column(name = "lessons_question_order") - @JsonProperty("lessons_question_order") - private int order; - - @OneToMany(mappedBy = "question", fetch = FetchType.LAZY, cascade = CascadeType.ALL) - @JsonProperty("lessons_question_answers") - @JsonSerialize(using = MultiIdListDeserializer.class) - private List answers = new ArrayList<>(); - - // region transient - @JsonProperty("lessons_question_exercise") - public String getExercise() { - return Optional.ofNullable(getCategory().getExercise()).map(Exercise::getId).orElse(null); - } - - @JsonProperty("lessons_question_scenario") - public String getScenario() { - return Optional.ofNullable(getCategory().getScenario()).map(Scenario::getId).orElse(null); - } - // endregion - - @Override - public boolean isUserHasAccess(User user) { - return getCategory().getExercise().isUserHasAccess(user); - } - - @Override - public boolean equals(Object o) { - if (this == o) return true; - if (o == null || !Base.class.isAssignableFrom(o.getClass())) return false; - Base base = (Base) o; - return id.equals(base.getId()); - } - - @Override - public int hashCode() { - return Objects.hash(id); - } + @Id + @Column(name = "lessons_question_id") + @GeneratedValue(generator = "UUID") + @UuidGenerator + @JsonProperty("lessonsquestion_id") + @NotBlank + private String id; + + @ManyToOne(fetch = FetchType.LAZY) + @JoinColumn(name = "lessons_question_category") + @JsonSerialize(using = MonoIdDeserializer.class) + @JsonProperty("lessons_question_category") + @NotNull + private LessonsCategory category; + + @Column(name = "lessons_question_created_at") + @JsonProperty("lessons_question_created_at") + @NotNull + private Instant created = now(); + + @Column(name = "lessons_question_updated_at") + @JsonProperty("lessons_question_updated_at") + @NotNull + private Instant updated = now(); + + @Column(name = "lessons_question_content") + @JsonProperty("lessons_question_content") + @NotBlank + private String content; + + @Column(name = "lessons_question_explanation") + @JsonProperty("lessons_question_explanation") + private String explanation; + + @Column(name = "lessons_question_order") + @JsonProperty("lessons_question_order") + private int order; + + @OneToMany(mappedBy = "question", fetch = FetchType.LAZY, cascade = CascadeType.ALL) + @JsonProperty("lessons_question_answers") + @JsonSerialize(using = MultiIdListDeserializer.class) + private List answers = new ArrayList<>(); + + // region transient + @JsonProperty("lessons_question_exercise") + public String getExercise() { + return Optional.ofNullable(getCategory().getExercise()).map(Exercise::getId).orElse(null); + } + + @JsonProperty("lessons_question_scenario") + public String getScenario() { + return Optional.ofNullable(getCategory().getScenario()).map(Scenario::getId).orElse(null); + } + + // endregion + + @Override + public boolean isUserHasAccess(User user) { + return getCategory().getExercise().isUserHasAccess(user); + } + + @Override + public boolean equals(Object o) { + if (this == o) return true; + if (o == null || !Base.class.isAssignableFrom(o.getClass())) return false; + Base base = (Base) o; + return id.equals(base.getId()); + } + + @Override + public int hashCode() { + return Objects.hash(id); + } } diff --git a/openbas-model/src/main/java/io/openbas/database/model/LessonsTemplate.java b/openbas-model/src/main/java/io/openbas/database/model/LessonsTemplate.java index cee8c77c30..ee4e9dc53a 100644 --- a/openbas-model/src/main/java/io/openbas/database/model/LessonsTemplate.java +++ b/openbas-model/src/main/java/io/openbas/database/model/LessonsTemplate.java @@ -1,5 +1,7 @@ package io.openbas.database.model; +import static java.time.Instant.now; + import com.fasterxml.jackson.annotation.JsonIgnore; import com.fasterxml.jackson.annotation.JsonProperty; import io.openbas.annotation.Queryable; @@ -7,14 +9,11 @@ import jakarta.persistence.*; import jakarta.validation.constraints.NotBlank; import jakarta.validation.constraints.NotNull; -import lombok.Data; -import org.hibernate.annotations.UuidGenerator; - import java.time.Instant; import java.util.ArrayList; import java.util.List; - -import static java.time.Instant.now; +import lombok.Data; +import org.hibernate.annotations.UuidGenerator; @Entity @Table(name = "lessons_templates") @@ -22,42 +21,41 @@ @Data public class LessonsTemplate implements Base { - @Id - @Column(name = "lessons_template_id") - @GeneratedValue(generator = "UUID") - @UuidGenerator - @JsonProperty("lessonstemplate_id") - @NotBlank - private String id; - - @Column(name = "lessons_template_created_at") - @JsonProperty("lessons_template_created_at") - @NotNull - private Instant created = now(); - - @Column(name = "lessons_template_updated_at") - @JsonProperty("lessons_template_updated_at") - @NotNull - private Instant updated = now(); - - @Queryable(sortable = true) - @Column(name = "lessons_template_name") - @JsonProperty("lessons_template_name") - @NotBlank - private String name; - - @Queryable(sortable = true) - @Column(name = "lessons_template_description") - @JsonProperty("lessons_template_description") - private String description; - - @OneToMany(mappedBy = "template", fetch = FetchType.LAZY) - @JsonIgnore - private List categories = new ArrayList<>(); - - @Override - public boolean isUserHasAccess(User user) { - return user.isAdmin(); - } - + @Id + @Column(name = "lessons_template_id") + @GeneratedValue(generator = "UUID") + @UuidGenerator + @JsonProperty("lessonstemplate_id") + @NotBlank + private String id; + + @Column(name = "lessons_template_created_at") + @JsonProperty("lessons_template_created_at") + @NotNull + private Instant created = now(); + + @Column(name = "lessons_template_updated_at") + @JsonProperty("lessons_template_updated_at") + @NotNull + private Instant updated = now(); + + @Queryable(sortable = true) + @Column(name = "lessons_template_name") + @JsonProperty("lessons_template_name") + @NotBlank + private String name; + + @Queryable(sortable = true) + @Column(name = "lessons_template_description") + @JsonProperty("lessons_template_description") + private String description; + + @OneToMany(mappedBy = "template", fetch = FetchType.LAZY) + @JsonIgnore + private List categories = new ArrayList<>(); + + @Override + public boolean isUserHasAccess(User user) { + return user.isAdmin(); + } } diff --git a/openbas-model/src/main/java/io/openbas/database/model/LessonsTemplateCategory.java b/openbas-model/src/main/java/io/openbas/database/model/LessonsTemplateCategory.java index 4c2f987272..5ab00af641 100644 --- a/openbas-model/src/main/java/io/openbas/database/model/LessonsTemplateCategory.java +++ b/openbas-model/src/main/java/io/openbas/database/model/LessonsTemplateCategory.java @@ -1,5 +1,7 @@ package io.openbas.database.model; +import static java.time.Instant.now; + import com.fasterxml.jackson.annotation.JsonProperty; import com.fasterxml.jackson.databind.annotation.JsonSerialize; import io.openbas.database.audit.ModelBaseListener; @@ -8,66 +10,62 @@ import jakarta.persistence.*; import jakarta.validation.constraints.NotBlank; import jakarta.validation.constraints.NotNull; -import lombok.Data; -import org.hibernate.annotations.UuidGenerator; - import java.time.Instant; import java.util.ArrayList; import java.util.List; - -import static java.time.Instant.now; +import lombok.Data; +import org.hibernate.annotations.UuidGenerator; @Entity @Table(name = "lessons_template_categories") @EntityListeners(ModelBaseListener.class) @Data public class LessonsTemplateCategory implements Base { - @Id - @Column(name = "lessons_template_category_id") - @GeneratedValue(generator = "UUID") - @UuidGenerator - @JsonProperty("lessonstemplatecategory_id") - @NotBlank - private String id; - - @ManyToOne(fetch = FetchType.LAZY) - @JoinColumn(name = "lessons_template_category_template") - @JsonSerialize(using = MonoIdDeserializer.class) - @JsonProperty("lessons_template_category_template") - private LessonsTemplate template; + @Id + @Column(name = "lessons_template_category_id") + @GeneratedValue(generator = "UUID") + @UuidGenerator + @JsonProperty("lessonstemplatecategory_id") + @NotBlank + private String id; - @Column(name = "lessons_template_category_created_at") - @JsonProperty("lessons_template_category_created_at") - @NotNull - private Instant created = now(); + @ManyToOne(fetch = FetchType.LAZY) + @JoinColumn(name = "lessons_template_category_template") + @JsonSerialize(using = MonoIdDeserializer.class) + @JsonProperty("lessons_template_category_template") + private LessonsTemplate template; - @Column(name = "lessons_template_category_updated_at") - @JsonProperty("lessons_template_category_updated_at") - @NotNull - private Instant updated = now(); + @Column(name = "lessons_template_category_created_at") + @JsonProperty("lessons_template_category_created_at") + @NotNull + private Instant created = now(); - @Column(name = "lessons_template_category_name") - @JsonProperty("lessons_template_category_name") - @NotBlank - private String name; + @Column(name = "lessons_template_category_updated_at") + @JsonProperty("lessons_template_category_updated_at") + @NotNull + private Instant updated = now(); - @Column(name = "lessons_template_category_description") - @JsonProperty("lessons_template_category_description") - private String description; + @Column(name = "lessons_template_category_name") + @JsonProperty("lessons_template_category_name") + @NotBlank + private String name; - @Column(name = "lessons_template_category_order") - @JsonProperty("lessons_template_category_order") - @NotNull - private int order; + @Column(name = "lessons_template_category_description") + @JsonProperty("lessons_template_category_description") + private String description; - @OneToMany(mappedBy = "category", fetch = FetchType.EAGER) - @JsonProperty("lessons_template_category_questions") - @JsonSerialize(using = MultiIdListDeserializer.class) - private List questions = new ArrayList<>(); + @Column(name = "lessons_template_category_order") + @JsonProperty("lessons_template_category_order") + @NotNull + private int order; - @Override - public boolean isUserHasAccess(User user) { - return template.isUserHasAccess(user); - } + @OneToMany(mappedBy = "category", fetch = FetchType.EAGER) + @JsonProperty("lessons_template_category_questions") + @JsonSerialize(using = MultiIdListDeserializer.class) + private List questions = new ArrayList<>(); + @Override + public boolean isUserHasAccess(User user) { + return template.isUserHasAccess(user); + } } diff --git a/openbas-model/src/main/java/io/openbas/database/model/LessonsTemplateQuestion.java b/openbas-model/src/main/java/io/openbas/database/model/LessonsTemplateQuestion.java index eb7eecd314..8cabbce943 100644 --- a/openbas-model/src/main/java/io/openbas/database/model/LessonsTemplateQuestion.java +++ b/openbas-model/src/main/java/io/openbas/database/model/LessonsTemplateQuestion.java @@ -1,5 +1,7 @@ package io.openbas.database.model; +import static java.time.Instant.now; + import com.fasterxml.jackson.annotation.JsonProperty; import com.fasterxml.jackson.databind.annotation.JsonSerialize; import io.openbas.database.audit.ModelBaseListener; @@ -7,59 +9,55 @@ import jakarta.persistence.*; import jakarta.validation.constraints.NotBlank; import jakarta.validation.constraints.NotNull; +import java.time.Instant; import lombok.Data; import org.hibernate.annotations.UuidGenerator; -import java.time.Instant; - -import static java.time.Instant.now; - @Entity @Table(name = "lessons_template_questions") @EntityListeners(ModelBaseListener.class) @Data public class LessonsTemplateQuestion implements Base { - @Id - @Column(name = "lessons_template_question_id") - @GeneratedValue(generator = "UUID") - @UuidGenerator - @JsonProperty("lessonstemplatequestion_id") - @NotBlank - private String id; - - @ManyToOne(fetch = FetchType.LAZY) - @JoinColumn(name = "lessons_template_question_category") - @JsonSerialize(using = MonoIdDeserializer.class) - @JsonProperty("lessons_template_question_category") - private LessonsTemplateCategory category; - - @Column(name = "lessons_template_question_created_at") - @JsonProperty("lessons_template_question_created_at") - @NotNull - private Instant created = now(); - - @Column(name = "lessons_template_question_updated_at") - @JsonProperty("lessons_template_question_updated_at") - @NotNull - private Instant updated = now(); - - @Column(name = "lessons_template_question_content") - @JsonProperty("lessons_template_question_content") - @NotBlank - private String content; - - @Column(name = "lessons_template_question_explanation") - @JsonProperty("lessons_template_question_explanation") - private String explanation; - - @Column(name = "lessons_template_question_order") - @JsonProperty("lessons_template_question_order") - @NotNull - private int order; - - @Override - public boolean isUserHasAccess(User user) { - return user.isAdmin(); - } - + @Id + @Column(name = "lessons_template_question_id") + @GeneratedValue(generator = "UUID") + @UuidGenerator + @JsonProperty("lessonstemplatequestion_id") + @NotBlank + private String id; + + @ManyToOne(fetch = FetchType.LAZY) + @JoinColumn(name = "lessons_template_question_category") + @JsonSerialize(using = MonoIdDeserializer.class) + @JsonProperty("lessons_template_question_category") + private LessonsTemplateCategory category; + + @Column(name = "lessons_template_question_created_at") + @JsonProperty("lessons_template_question_created_at") + @NotNull + private Instant created = now(); + + @Column(name = "lessons_template_question_updated_at") + @JsonProperty("lessons_template_question_updated_at") + @NotNull + private Instant updated = now(); + + @Column(name = "lessons_template_question_content") + @JsonProperty("lessons_template_question_content") + @NotBlank + private String content; + + @Column(name = "lessons_template_question_explanation") + @JsonProperty("lessons_template_question_explanation") + private String explanation; + + @Column(name = "lessons_template_question_order") + @JsonProperty("lessons_template_question_order") + @NotNull + private int order; + + @Override + public boolean isUserHasAccess(User user) { + return user.isAdmin(); + } } diff --git a/openbas-model/src/main/java/io/openbas/database/model/Log.java b/openbas-model/src/main/java/io/openbas/database/model/Log.java index 3eaaa494b2..202d32c60f 100644 --- a/openbas-model/src/main/java/io/openbas/database/model/Log.java +++ b/openbas-model/src/main/java/io/openbas/database/model/Log.java @@ -1,5 +1,7 @@ package io.openbas.database.model; +import static java.time.Instant.now; + import com.fasterxml.jackson.annotation.JsonProperty; import com.fasterxml.jackson.databind.annotation.JsonSerialize; import io.openbas.database.audit.ModelBaseListener; @@ -8,15 +10,12 @@ import jakarta.persistence.*; import jakarta.validation.constraints.NotBlank; import jakarta.validation.constraints.NotNull; -import lombok.Setter; -import org.hibernate.annotations.UuidGenerator; - import java.time.Instant; import java.util.HashSet; import java.util.Objects; import java.util.Set; - -import static java.time.Instant.now; +import lombok.Setter; +import org.hibernate.annotations.UuidGenerator; @Setter @Entity @@ -24,102 +23,103 @@ @EntityListeners(ModelBaseListener.class) public class Log implements Base { - @Id - @Column(name = "log_id") - @GeneratedValue(generator = "UUID") - @UuidGenerator - @JsonProperty("log_id") - @NotBlank - private String id; - - @ManyToOne(fetch = FetchType.LAZY) - @JoinColumn(name = "log_exercise") - @JsonSerialize(using = MonoIdDeserializer.class) - @JsonProperty("log_exercise") - private Exercise exercise; - - @ManyToOne(fetch = FetchType.LAZY) - @JoinColumn(name = "log_user") - @JsonSerialize(using = MonoIdDeserializer.class) - @JsonProperty("log_user") - private User user; - - @Column(name = "log_title") - @JsonProperty("log_title") - @NotBlank - private String title; - - @Column(name = "log_content") - @JsonProperty("log_content") - @NotBlank - private String content; - - @Column(name = "log_created_at") - @JsonProperty("log_created_at") - @NotNull - private Instant created = now(); - - @Column(name = "log_updated_at") - @JsonProperty("log_updated_at") - @NotNull - private Instant updated = now(); - - @ManyToMany(fetch = FetchType.LAZY) - @JoinTable(name = "logs_tags", - joinColumns = @JoinColumn(name = "log_id"), - inverseJoinColumns = @JoinColumn(name = "tag_id")) - @JsonSerialize(using = MultiIdSetDeserializer.class) - @JsonProperty("log_tags") - private Set tags = new HashSet<>(); - - @Override - public String getId() { - return id; - } - - @Override - public boolean isUserHasAccess(User user) { - return exercise.isUserHasAccess(user); - } + @Id + @Column(name = "log_id") + @GeneratedValue(generator = "UUID") + @UuidGenerator + @JsonProperty("log_id") + @NotBlank + private String id; + + @ManyToOne(fetch = FetchType.LAZY) + @JoinColumn(name = "log_exercise") + @JsonSerialize(using = MonoIdDeserializer.class) + @JsonProperty("log_exercise") + private Exercise exercise; + + @ManyToOne(fetch = FetchType.LAZY) + @JoinColumn(name = "log_user") + @JsonSerialize(using = MonoIdDeserializer.class) + @JsonProperty("log_user") + private User user; + + @Column(name = "log_title") + @JsonProperty("log_title") + @NotBlank + private String title; + + @Column(name = "log_content") + @JsonProperty("log_content") + @NotBlank + private String content; + + @Column(name = "log_created_at") + @JsonProperty("log_created_at") + @NotNull + private Instant created = now(); + + @Column(name = "log_updated_at") + @JsonProperty("log_updated_at") + @NotNull + private Instant updated = now(); + + @ManyToMany(fetch = FetchType.LAZY) + @JoinTable( + name = "logs_tags", + joinColumns = @JoinColumn(name = "log_id"), + inverseJoinColumns = @JoinColumn(name = "tag_id")) + @JsonSerialize(using = MultiIdSetDeserializer.class) + @JsonProperty("log_tags") + private Set tags = new HashSet<>(); + + @Override + public String getId() { + return id; + } + + @Override + public boolean isUserHasAccess(User user) { + return exercise.isUserHasAccess(user); + } public Exercise getExercise() { - return exercise; - } + return exercise; + } public User getUser() { - return user; - } + return user; + } public String getTitle() { - return title; - } + return title; + } public String getContent() { - return content; - } + return content; + } public Set getTags() { - return tags; - } + return tags; + } public Instant getCreated() { - return created; - } + return created; + } public Instant getUpdated() { - return updated; - } + return updated; + } + + @Override + public boolean equals(Object o) { + if (this == o) return true; + if (o == null || !Base.class.isAssignableFrom(o.getClass())) return false; + Base base = (Base) o; + return id.equals(base.getId()); + } @Override - public boolean equals(Object o) { - if (this == o) return true; - if (o == null || !Base.class.isAssignableFrom(o.getClass())) return false; - Base base = (Base) o; - return id.equals(base.getId()); - } - - @Override - public int hashCode() { - return Objects.hash(id); - } + public int hashCode() { + return Objects.hash(id); + } } diff --git a/openbas-model/src/main/java/io/openbas/database/model/Mitigation.java b/openbas-model/src/main/java/io/openbas/database/model/Mitigation.java index fb51e4ddf7..850c0589b7 100644 --- a/openbas-model/src/main/java/io/openbas/database/model/Mitigation.java +++ b/openbas-model/src/main/java/io/openbas/database/model/Mitigation.java @@ -1,5 +1,7 @@ package io.openbas.database.model; +import static java.time.Instant.now; + import com.fasterxml.jackson.annotation.JsonProperty; import com.fasterxml.jackson.databind.annotation.JsonSerialize; import io.hypersistence.utils.hibernate.type.array.StringArrayType; @@ -9,15 +11,12 @@ import jakarta.persistence.*; import jakarta.validation.constraints.NotBlank; import jakarta.validation.constraints.NotNull; -import lombok.Data; -import org.hibernate.annotations.Type; -import org.hibernate.annotations.UuidGenerator; - import java.time.Instant; import java.util.ArrayList; import java.util.List; - -import static java.time.Instant.now; +import lombok.Data; +import org.hibernate.annotations.Type; +import org.hibernate.annotations.UuidGenerator; @Data @Entity @@ -77,11 +76,11 @@ public class Mitigation implements Base { private Instant updatedAt = now(); @ManyToMany(fetch = FetchType.LAZY) - @JoinTable(name = "mitigations_attack_patterns", + @JoinTable( + name = "mitigations_attack_patterns", joinColumns = @JoinColumn(name = "mitigation_id"), inverseJoinColumns = @JoinColumn(name = "attack_pattern_id")) @JsonSerialize(using = MultiIdListDeserializer.class) @JsonProperty("mitigation_attack_patterns") private List attackPatterns = new ArrayList<>(); - } diff --git a/openbas-model/src/main/java/io/openbas/database/model/NetworkTraffic.java b/openbas-model/src/main/java/io/openbas/database/model/NetworkTraffic.java index 4af2f0a64e..c5c40075f9 100644 --- a/openbas-model/src/main/java/io/openbas/database/model/NetworkTraffic.java +++ b/openbas-model/src/main/java/io/openbas/database/model/NetworkTraffic.java @@ -53,9 +53,7 @@ public class NetworkTraffic extends Payload { @NotNull private String protocol; - public NetworkTraffic() { - - } + public NetworkTraffic() {} public NetworkTraffic(String id, String type, String name) { super(id, type, name); diff --git a/openbas-model/src/main/java/io/openbas/database/model/Objective.java b/openbas-model/src/main/java/io/openbas/database/model/Objective.java index fffb578fad..a98369da29 100644 --- a/openbas-model/src/main/java/io/openbas/database/model/Objective.java +++ b/openbas-model/src/main/java/io/openbas/database/model/Objective.java @@ -1,5 +1,7 @@ package io.openbas.database.model; +import static java.time.Instant.now; + import com.fasterxml.jackson.annotation.JsonProperty; import com.fasterxml.jackson.databind.annotation.JsonSerialize; import io.openbas.database.audit.ModelBaseListener; @@ -8,16 +10,13 @@ import jakarta.persistence.*; import jakarta.validation.constraints.NotBlank; import jakarta.validation.constraints.NotNull; -import lombok.Getter; -import lombok.Setter; -import org.hibernate.annotations.UuidGenerator; - import java.time.Instant; import java.util.ArrayList; import java.util.List; import java.util.Objects; - -import static java.time.Instant.now; +import lombok.Getter; +import lombok.Setter; +import org.hibernate.annotations.UuidGenerator; @Getter @Setter @@ -26,75 +25,76 @@ @EntityListeners(ModelBaseListener.class) public class Objective implements Base { - @Id - @Column(name = "objective_id") - @GeneratedValue(generator = "UUID") - @UuidGenerator - @JsonProperty("objective_id") - @NotBlank - private String id; - - @ManyToOne(fetch = FetchType.LAZY) - @JoinColumn(name = "objective_exercise") - @JsonSerialize(using = MonoIdDeserializer.class) - @JsonProperty("objective_exercise") - private Exercise exercise; - - @ManyToOne(fetch = FetchType.LAZY) - @JoinColumn(name = "objective_scenario") - @JsonSerialize(using = MonoIdDeserializer.class) - @JsonProperty("objective_scenario") - private Scenario scenario; - - @Column(name = "objective_title") - @JsonProperty("objective_title") - private String title; - - @Column(name = "objective_description") - @JsonProperty("objective_description") - private String description; - - @Column(name = "objective_priority") - @JsonProperty("objective_priority") - private Short priority; - - @Column(name = "objective_created_at") - @JsonProperty("objective_created_at") - @NotNull - private Instant createdAt = now(); - - @Column(name = "objective_updated_at") - @JsonProperty("objective_updated_at") - @NotNull - private Instant updatedAt = now(); - - @OneToMany(mappedBy = "objective", fetch = FetchType.LAZY, cascade = CascadeType.ALL) - @JsonSerialize(using = MultiIdListDeserializer.class) - @JsonProperty("objective_evaluations") - private List evaluations = new ArrayList<>(); - - // region transient - @JsonProperty("objective_score") - public Double getEvaluationAverage() { - return getEvaluations().stream().mapToDouble(Evaluation::getScore).average().orElse(0D); - } - // endregion - - @Override - public boolean isUserHasAccess(User user) { - return getExercise().isUserHasAccess(user); - } - - @Override - public boolean equals(Object o) { - if (this == o) return true; - if (o == null || !Base.class.isAssignableFrom(o.getClass())) return false; - Base base = (Base) o; - return id.equals(base.getId()); - } - - @Override - public int hashCode() { - return Objects.hash(id); - } + @Id + @Column(name = "objective_id") + @GeneratedValue(generator = "UUID") + @UuidGenerator + @JsonProperty("objective_id") + @NotBlank + private String id; + + @ManyToOne(fetch = FetchType.LAZY) + @JoinColumn(name = "objective_exercise") + @JsonSerialize(using = MonoIdDeserializer.class) + @JsonProperty("objective_exercise") + private Exercise exercise; + + @ManyToOne(fetch = FetchType.LAZY) + @JoinColumn(name = "objective_scenario") + @JsonSerialize(using = MonoIdDeserializer.class) + @JsonProperty("objective_scenario") + private Scenario scenario; + + @Column(name = "objective_title") + @JsonProperty("objective_title") + private String title; + + @Column(name = "objective_description") + @JsonProperty("objective_description") + private String description; + + @Column(name = "objective_priority") + @JsonProperty("objective_priority") + private Short priority; + + @Column(name = "objective_created_at") + @JsonProperty("objective_created_at") + @NotNull + private Instant createdAt = now(); + + @Column(name = "objective_updated_at") + @JsonProperty("objective_updated_at") + @NotNull + private Instant updatedAt = now(); + + @OneToMany(mappedBy = "objective", fetch = FetchType.LAZY, cascade = CascadeType.ALL) + @JsonSerialize(using = MultiIdListDeserializer.class) + @JsonProperty("objective_evaluations") + private List evaluations = new ArrayList<>(); + + // region transient + @JsonProperty("objective_score") + public Double getEvaluationAverage() { + return getEvaluations().stream().mapToDouble(Evaluation::getScore).average().orElse(0D); + } + + // endregion + + @Override + public boolean isUserHasAccess(User user) { + return getExercise().isUserHasAccess(user); + } + + @Override + public boolean equals(Object o) { + if (this == o) return true; + if (o == null || !Base.class.isAssignableFrom(o.getClass())) return false; + Base base = (Base) o; + return id.equals(base.getId()); + } + + @Override + public int hashCode() { + return Objects.hash(id); + } } diff --git a/openbas-model/src/main/java/io/openbas/database/model/Organization.java b/openbas-model/src/main/java/io/openbas/database/model/Organization.java index 72522959f3..7f6d070a5f 100644 --- a/openbas-model/src/main/java/io/openbas/database/model/Organization.java +++ b/openbas-model/src/main/java/io/openbas/database/model/Organization.java @@ -1,5 +1,8 @@ package io.openbas.database.model; +import static java.time.Instant.now; +import static java.util.stream.StreamSupport.stream; + import com.fasterxml.jackson.annotation.JsonIgnore; import com.fasterxml.jackson.annotation.JsonProperty; import com.fasterxml.jackson.databind.annotation.JsonSerialize; @@ -10,150 +13,156 @@ import jakarta.persistence.*; import jakarta.validation.constraints.NotBlank; import jakarta.validation.constraints.NotNull; -import lombok.Getter; -import lombok.Setter; -import org.hibernate.annotations.UuidGenerator; - import java.time.Instant; import java.util.*; import java.util.stream.Collectors; - -import static java.time.Instant.now; -import static java.util.stream.StreamSupport.stream; +import lombok.Getter; +import lombok.Setter; +import org.hibernate.annotations.UuidGenerator; @Entity @Table(name = "organizations") @EntityListeners(ModelBaseListener.class) public class Organization implements Base { - @Id - @Column(name = "organization_id") - @GeneratedValue(generator = "UUID") - @UuidGenerator - @JsonProperty("organization_id") - @NotBlank - private String id; - - @Column(name = "organization_name") - @JsonProperty("organization_name") - @Queryable(searchable = true) - @NotBlank - private String name; - - @Column(name = "organization_description") - @JsonProperty("organization_description") - private String description; - - @Column(name = "organization_created_at") - @JsonProperty("organization_created_at") - @NotNull - private Instant createdAt = now(); - - @Column(name = "organization_updated_at") - @JsonProperty("organization_updated_at") - @NotNull - private Instant updatedAt = now(); - - @OneToMany(mappedBy = "organization", fetch = FetchType.LAZY) - @JsonIgnore - private List users = new ArrayList<>(); - - @Setter - @Getter - @ManyToMany(fetch = FetchType.LAZY) - @JoinTable(name = "organizations_tags", - joinColumns = @JoinColumn(name = "organization_id"), - inverseJoinColumns = @JoinColumn(name = "tag_id")) - @JsonSerialize(using = MultiIdSetDeserializer.class) - @JsonProperty("organization_tags") - private Set tags = new HashSet<>(); - - // region transient - private transient List injects = new ArrayList<>(); - public void resolveInjects(Iterable injects) { - this.injects = stream(injects.spliterator(), false) - .filter(inject -> inject.isAllTeams() || inject.getTeams().stream() - .anyMatch(team -> getUsers().stream() - .flatMap(user -> user.getTeams().stream()).toList() - .contains(team))) - .collect(Collectors.toList()); - } - - @JsonProperty("organization_injects") - @JsonSerialize(using = MultiIdListDeserializer.class) - public List getOrganizationInject() { - return injects; - } - - @JsonProperty("organization_injects_number") - public long getOrganizationInjectsNumber() { - return injects.size(); - } - // endregion - - public String getId() { - return id; - } - - @Override - public boolean isUserHasAccess(User user) { - return user.isAdmin(); - } - - public void setId(String id) { - this.id = id; - } - - public String getName() { - return name; - } - - public void setName(String name) { - this.name = name; - } - - public String getDescription() { - return description; - } - - public void setDescription(String description) { - this.description = description; - } - - public Instant getCreatedAt() { - return createdAt; - } - - public void setCreatedAt(Instant createdAt) { - this.createdAt = createdAt; - } - - public Instant getUpdatedAt() { - return updatedAt; - } - - public void setUpdatedAt(Instant updatedAt) { - this.updatedAt = updatedAt; - } + @Id + @Column(name = "organization_id") + @GeneratedValue(generator = "UUID") + @UuidGenerator + @JsonProperty("organization_id") + @NotBlank + private String id; + + @Column(name = "organization_name") + @JsonProperty("organization_name") + @Queryable(searchable = true) + @NotBlank + private String name; + + @Column(name = "organization_description") + @JsonProperty("organization_description") + private String description; + + @Column(name = "organization_created_at") + @JsonProperty("organization_created_at") + @NotNull + private Instant createdAt = now(); + + @Column(name = "organization_updated_at") + @JsonProperty("organization_updated_at") + @NotNull + private Instant updatedAt = now(); + + @OneToMany(mappedBy = "organization", fetch = FetchType.LAZY) + @JsonIgnore + private List users = new ArrayList<>(); + + @Setter + @Getter + @ManyToMany(fetch = FetchType.LAZY) + @JoinTable( + name = "organizations_tags", + joinColumns = @JoinColumn(name = "organization_id"), + inverseJoinColumns = @JoinColumn(name = "tag_id")) + @JsonSerialize(using = MultiIdSetDeserializer.class) + @JsonProperty("organization_tags") + private Set tags = new HashSet<>(); + + // region transient + private transient List injects = new ArrayList<>(); + + public void resolveInjects(Iterable injects) { + this.injects = + stream(injects.spliterator(), false) + .filter( + inject -> + inject.isAllTeams() + || inject.getTeams().stream() + .anyMatch( + team -> + getUsers().stream() + .flatMap(user -> user.getTeams().stream()) + .toList() + .contains(team))) + .collect(Collectors.toList()); + } + + @JsonProperty("organization_injects") + @JsonSerialize(using = MultiIdListDeserializer.class) + public List getOrganizationInject() { + return injects; + } + + @JsonProperty("organization_injects_number") + public long getOrganizationInjectsNumber() { + return injects.size(); + } + + // endregion + + public String getId() { + return id; + } + + @Override + public boolean isUserHasAccess(User user) { + return user.isAdmin(); + } + + public void setId(String id) { + this.id = id; + } + + public String getName() { + return name; + } + + public void setName(String name) { + this.name = name; + } + + public String getDescription() { + return description; + } + + public void setDescription(String description) { + this.description = description; + } + + public Instant getCreatedAt() { + return createdAt; + } + + public void setCreatedAt(Instant createdAt) { + this.createdAt = createdAt; + } + + public Instant getUpdatedAt() { + return updatedAt; + } + + public void setUpdatedAt(Instant updatedAt) { + this.updatedAt = updatedAt; + } public List getUsers() { - return users; - } - - public void setUsers(List users) { - this.users = users; - } - - @Override - public boolean equals(Object o) { - if (this == o) return true; - if (o == null || !Base.class.isAssignableFrom(o.getClass())) return false; - Base base = (Base) o; - return id.equals(base.getId()); - } - - @Override - public int hashCode() { - return Objects.hash(id); - } + return users; + } + + public void setUsers(List users) { + this.users = users; + } + + @Override + public boolean equals(Object o) { + if (this == o) return true; + if (o == null || !Base.class.isAssignableFrom(o.getClass())) return false; + Base base = (Base) o; + return id.equals(base.getId()); + } + + @Override + public int hashCode() { + return Objects.hash(id); + } } diff --git a/openbas-model/src/main/java/io/openbas/database/model/Pause.java b/openbas-model/src/main/java/io/openbas/database/model/Pause.java index c09d6cf609..cd56d89d6d 100644 --- a/openbas-model/src/main/java/io/openbas/database/model/Pause.java +++ b/openbas-model/src/main/java/io/openbas/database/model/Pause.java @@ -3,85 +3,84 @@ import com.fasterxml.jackson.annotation.JsonProperty; import com.fasterxml.jackson.databind.annotation.JsonSerialize; import io.openbas.helper.MonoIdDeserializer; -import org.hibernate.annotations.UuidGenerator; - import jakarta.persistence.*; import java.time.Instant; import java.util.Objects; import java.util.Optional; +import org.hibernate.annotations.UuidGenerator; @Entity @Table(name = "pauses") public class Pause implements Base { - @Id - @Column(name = "pause_id") - @GeneratedValue(generator = "UUID") - @UuidGenerator - @JsonProperty("log_id") - private String id; - - @Column(name = "pause_date") - @JsonProperty("pause_date") - private Instant date; - - @Column(name = "pause_duration") - @JsonProperty("pause_duration") - private Long duration = 0L; - - @ManyToOne(fetch = FetchType.LAZY) - @JoinColumn(name = "pause_exercise") - @JsonSerialize(using = MonoIdDeserializer.class) - @JsonProperty("pause_exercise") - private Exercise exercise; - - @Override - public String getId() { - return id; - } - - @Override - public boolean isUserHasAccess(User user) { - return exercise.isUserHasAccess(user); - } - - public void setId(String id) { - this.id = id; - } - - public Instant getDate() { - return date; - } - - public void setDate(Instant date) { - this.date = date; - } - - public Optional getDuration() { - return Optional.ofNullable(duration); - } - - public void setDuration(Long duration) { - this.duration = duration; - } - - public Exercise getExercise() { - return exercise; - } - - public void setExercise(Exercise exercise) { - this.exercise = exercise; - } - - @Override - public boolean equals(Object o) { - if (this == o) return true; - if (o == null || !Base.class.isAssignableFrom(o.getClass())) return false; - Base base = (Base) o; - return id.equals(base.getId()); - } - - @Override - public int hashCode() { - return Objects.hash(id); - } + @Id + @Column(name = "pause_id") + @GeneratedValue(generator = "UUID") + @UuidGenerator + @JsonProperty("log_id") + private String id; + + @Column(name = "pause_date") + @JsonProperty("pause_date") + private Instant date; + + @Column(name = "pause_duration") + @JsonProperty("pause_duration") + private Long duration = 0L; + + @ManyToOne(fetch = FetchType.LAZY) + @JoinColumn(name = "pause_exercise") + @JsonSerialize(using = MonoIdDeserializer.class) + @JsonProperty("pause_exercise") + private Exercise exercise; + + @Override + public String getId() { + return id; + } + + @Override + public boolean isUserHasAccess(User user) { + return exercise.isUserHasAccess(user); + } + + public void setId(String id) { + this.id = id; + } + + public Instant getDate() { + return date; + } + + public void setDate(Instant date) { + this.date = date; + } + + public Optional getDuration() { + return Optional.ofNullable(duration); + } + + public void setDuration(Long duration) { + this.duration = duration; + } + + public Exercise getExercise() { + return exercise; + } + + public void setExercise(Exercise exercise) { + this.exercise = exercise; + } + + @Override + public boolean equals(Object o) { + if (this == o) return true; + if (o == null || !Base.class.isAssignableFrom(o.getClass())) return false; + Base base = (Base) o; + return id.equals(base.getId()); + } + + @Override + public int hashCode() { + return Objects.hash(id); + } } diff --git a/openbas-model/src/main/java/io/openbas/database/model/Payload.java b/openbas-model/src/main/java/io/openbas/database/model/Payload.java index f4747bc1f2..20c46265d0 100644 --- a/openbas-model/src/main/java/io/openbas/database/model/Payload.java +++ b/openbas-model/src/main/java/io/openbas/database/model/Payload.java @@ -1,5 +1,9 @@ package io.openbas.database.model; +import static jakarta.persistence.DiscriminatorType.STRING; +import static java.time.Instant.now; +import static lombok.AccessLevel.NONE; + import com.fasterxml.jackson.annotation.JsonProperty; import com.fasterxml.jackson.databind.annotation.JsonSerialize; import io.hypersistence.utils.hibernate.type.array.StringArrayType; @@ -13,19 +17,14 @@ import jakarta.persistence.*; import jakarta.validation.constraints.NotBlank; import jakarta.validation.constraints.NotNull; +import java.time.Instant; +import java.util.*; import lombok.Data; import lombok.Getter; import lombok.Setter; import org.hibernate.annotations.Type; import org.hibernate.annotations.UuidGenerator; -import java.time.Instant; -import java.util.*; - -import static jakarta.persistence.DiscriminatorType.STRING; -import static java.time.Instant.now; -import static lombok.AccessLevel.NONE; - @Data @Entity @Table(name = "payloads") @@ -77,9 +76,10 @@ public enum PAYLOAD_STATUS { @Setter @ManyToMany(fetch = FetchType.EAGER) - @JoinTable(name = "payloads_attack_patterns", - joinColumns = @JoinColumn(name = "payload_id"), - inverseJoinColumns = @JoinColumn(name = "attack_pattern_id")) + @JoinTable( + name = "payloads_attack_patterns", + joinColumns = @JoinColumn(name = "payload_id"), + inverseJoinColumns = @JoinColumn(name = "attack_pattern_id")) @JsonSerialize(using = MultiIdListDeserializer.class) @JsonProperty("payload_attack_patterns") @Queryable(filterable = true, searchable = true, dynamicValues = true, path = "attackPatterns.id") @@ -145,7 +145,8 @@ public enum PAYLOAD_STATUS { @Queryable(filterable = true, dynamicValues = true) @ManyToMany(fetch = FetchType.LAZY) - @JoinTable(name = "payloads_tags", + @JoinTable( + name = "payloads_tags", joinColumns = @JoinColumn(name = "payload_id"), inverseJoinColumns = @JoinColumn(name = "tag_id")) @JsonSerialize(using = MultiIdSetDeserializer.class) @@ -175,9 +176,7 @@ public int hashCode() { return Objects.hash(id); } - public Payload() { - - } + public Payload() {} public Payload(String id, String type, String name) { this.name = name; diff --git a/openbas-model/src/main/java/io/openbas/database/model/PayloadPrerequisite.java b/openbas-model/src/main/java/io/openbas/database/model/PayloadPrerequisite.java index eeec4264af..95a4114f63 100644 --- a/openbas-model/src/main/java/io/openbas/database/model/PayloadPrerequisite.java +++ b/openbas-model/src/main/java/io/openbas/database/model/PayloadPrerequisite.java @@ -2,7 +2,6 @@ import com.fasterxml.jackson.annotation.JsonProperty; import jakarta.validation.constraints.NotBlank; -import lombok.Builder; import lombok.Data; import lombok.Getter; import lombok.Setter; @@ -25,5 +24,4 @@ public class PayloadPrerequisite { @JsonProperty("description") private String description; - } diff --git a/openbas-model/src/main/java/io/openbas/database/model/PayloadType.java b/openbas-model/src/main/java/io/openbas/database/model/PayloadType.java index a4c3300fc7..56228c3831 100644 --- a/openbas-model/src/main/java/io/openbas/database/model/PayloadType.java +++ b/openbas-model/src/main/java/io/openbas/database/model/PayloadType.java @@ -1,24 +1,24 @@ package io.openbas.database.model; public enum PayloadType { - COMMAND("Command"), - EXECUTABLE("Executable"), - FILE_DROP("FileDrop"), - DNS_RESOLUTION("DnsResolution"), - NETWORK_TRAFFIC("NetworkTraffic"); + COMMAND("Command"), + EXECUTABLE("Executable"), + FILE_DROP("FileDrop"), + DNS_RESOLUTION("DnsResolution"), + NETWORK_TRAFFIC("NetworkTraffic"); - public final String key; + public final String key; - PayloadType(String key) { - this.key = key; - } + PayloadType(String key) { + this.key = key; + } - public static PayloadType fromString(String key) { - for (PayloadType type : PayloadType.values()) { - if (type.key.equalsIgnoreCase(key)) { - return type; - } - } - throw new IllegalArgumentException("No PayloadType found for key: " + key); + public static PayloadType fromString(String key) { + for (PayloadType type : PayloadType.values()) { + if (type.key.equalsIgnoreCase(key)) { + return type; + } } + throw new IllegalArgumentException("No PayloadType found for key: " + key); + } } diff --git a/openbas-model/src/main/java/io/openbas/database/model/Report.java b/openbas-model/src/main/java/io/openbas/database/model/Report.java index ccebabcb5d..97ae6689da 100644 --- a/openbas-model/src/main/java/io/openbas/database/model/Report.java +++ b/openbas-model/src/main/java/io/openbas/database/model/Report.java @@ -1,90 +1,97 @@ package io.openbas.database.model; +import static java.time.Instant.now; + import com.fasterxml.jackson.annotation.JsonProperty; import com.fasterxml.jackson.databind.annotation.JsonSerialize; import io.openbas.database.audit.ModelBaseListener; import io.openbas.helper.MonoIdDeserializer; import io.openbas.helper.MultiModelDeserializer; +import jakarta.persistence.*; import jakarta.validation.constraints.NotBlank; import jakarta.validation.constraints.NotNull; +import java.time.Instant; +import java.util.*; import lombok.Data; import org.hibernate.annotations.CreationTimestamp; import org.hibernate.annotations.UpdateTimestamp; import org.hibernate.annotations.UuidGenerator; -import jakarta.persistence.*; -import java.time.Instant; -import java.util.*; - -import static java.time.Instant.now; - @Data @Entity @Table(name = "reports") @EntityListeners(ModelBaseListener.class) public class Report implements Base { - @Id - @Column(name = "report_id") - @JsonProperty("report_id") - @GeneratedValue - @UuidGenerator - @NotNull - private UUID id; - - @Column(name = "report_name") - @JsonProperty("report_name") - @NotBlank - private String name; - - @Column(name = "report_global_observation") - @JsonProperty("report_global_observation") - private String globalObservation; - - @CreationTimestamp - @Column(name = "report_created_at") - @JsonProperty("report_created_at") - @NotNull - private Instant creationDate = now(); - - @UpdateTimestamp - @Column(name = "report_updated_at") - @JsonProperty("report_updated_at") - @NotNull - private Instant updateDate = now(); - - @OneToMany(mappedBy = "report", cascade = CascadeType.ALL, orphanRemoval = true, fetch = FetchType.EAGER) - @JsonProperty("report_informations") - private List reportInformations = new ArrayList<>(); - - @ManyToOne(fetch = FetchType.LAZY) - @JoinTable(name = "reports_exercises", - joinColumns = @JoinColumn(name = "report_id"), - inverseJoinColumns = @JoinColumn(name = "exercise_id")) - @JsonProperty("report_exercise") - @JsonSerialize(using = MonoIdDeserializer.class) - private Exercise exercise; - - @OneToMany(mappedBy = "report", cascade = CascadeType.ALL, orphanRemoval = true, fetch = FetchType.EAGER) - @JsonProperty("report_injects_comments") - @JsonSerialize(using = MultiModelDeserializer.class) - private List reportInjectsComments = new ArrayList<>(); - - @Override - public String getId() { - return this.id != null ? this.id.toString() : ""; - } - - @Override - public void setId(String id) { - this.id = UUID.fromString(id); - } - - @Override - public String toString() { - return name; - } - - @Transient - private boolean isListened = false; + @Id + @Column(name = "report_id") + @JsonProperty("report_id") + @GeneratedValue + @UuidGenerator + @NotNull + private UUID id; + + @Column(name = "report_name") + @JsonProperty("report_name") + @NotBlank + private String name; + + @Column(name = "report_global_observation") + @JsonProperty("report_global_observation") + private String globalObservation; + + @CreationTimestamp + @Column(name = "report_created_at") + @JsonProperty("report_created_at") + @NotNull + private Instant creationDate = now(); + + @UpdateTimestamp + @Column(name = "report_updated_at") + @JsonProperty("report_updated_at") + @NotNull + private Instant updateDate = now(); + + @OneToMany( + mappedBy = "report", + cascade = CascadeType.ALL, + orphanRemoval = true, + fetch = FetchType.EAGER) + @JsonProperty("report_informations") + private List reportInformations = new ArrayList<>(); + + @ManyToOne(fetch = FetchType.LAZY) + @JoinTable( + name = "reports_exercises", + joinColumns = @JoinColumn(name = "report_id"), + inverseJoinColumns = @JoinColumn(name = "exercise_id")) + @JsonProperty("report_exercise") + @JsonSerialize(using = MonoIdDeserializer.class) + private Exercise exercise; + + @OneToMany( + mappedBy = "report", + cascade = CascadeType.ALL, + orphanRemoval = true, + fetch = FetchType.EAGER) + @JsonProperty("report_injects_comments") + @JsonSerialize(using = MultiModelDeserializer.class) + private List reportInjectsComments = new ArrayList<>(); + + @Override + public String getId() { + return this.id != null ? this.id.toString() : ""; + } + + @Override + public void setId(String id) { + this.id = UUID.fromString(id); + } + + @Override + public String toString() { + return name; + } + + @Transient private boolean isListened = false; } diff --git a/openbas-model/src/main/java/io/openbas/database/model/ReportInformation.java b/openbas-model/src/main/java/io/openbas/database/model/ReportInformation.java index 14e73b7868..404d59914b 100644 --- a/openbas-model/src/main/java/io/openbas/database/model/ReportInformation.java +++ b/openbas-model/src/main/java/io/openbas/database/model/ReportInformation.java @@ -3,54 +3,54 @@ import com.fasterxml.jackson.annotation.JsonProperty; import com.fasterxml.jackson.databind.annotation.JsonSerialize; import io.openbas.helper.MonoIdDeserializer; -import lombok.Data; -import org.hibernate.annotations.UuidGenerator; - import jakarta.persistence.*; import jakarta.validation.constraints.NotNull; import java.util.Objects; import java.util.UUID; - +import lombok.Data; +import org.hibernate.annotations.UuidGenerator; @Data @Entity -@Table(name = "report_informations", uniqueConstraints = { - @UniqueConstraint(columnNames = {"report_id", "report_informations_type"}) -}) +@Table( + name = "report_informations", + uniqueConstraints = { + @UniqueConstraint(columnNames = {"report_id", "report_informations_type"}) + }) public class ReportInformation implements Base { - @Id - @Column(name = "report_informations_id") - @GeneratedValue - @UuidGenerator - @NotNull - private UUID id; - - @ManyToOne(fetch = FetchType.LAZY) - @JoinColumn(name = "report_id") - @JsonSerialize(using = MonoIdDeserializer.class) - @NotNull - private Report report; - - @Enumerated(EnumType.STRING) - @JsonProperty("report_informations_type") - @Column(name = "report_informations_type", nullable = false) - @NotNull - private ReportInformationsType reportInformationsType; - - @Column(name = "report_informations_display") - @JsonProperty("report_informations_display") - private Boolean reportInformationsDisplay = false; - - @Override - public int hashCode() { - return Objects.hash(id); - } - - public String getId() { - return this.id != null ? this.id.toString() : ""; - } - - public void setId(String id) { - this.id = UUID.fromString(id); - } + @Id + @Column(name = "report_informations_id") + @GeneratedValue + @UuidGenerator + @NotNull + private UUID id; + + @ManyToOne(fetch = FetchType.LAZY) + @JoinColumn(name = "report_id") + @JsonSerialize(using = MonoIdDeserializer.class) + @NotNull + private Report report; + + @Enumerated(EnumType.STRING) + @JsonProperty("report_informations_type") + @Column(name = "report_informations_type", nullable = false) + @NotNull + private ReportInformationsType reportInformationsType; + + @Column(name = "report_informations_display") + @JsonProperty("report_informations_display") + private Boolean reportInformationsDisplay = false; + + @Override + public int hashCode() { + return Objects.hash(id); + } + + public String getId() { + return this.id != null ? this.id.toString() : ""; + } + + public void setId(String id) { + this.id = UUID.fromString(id); + } } diff --git a/openbas-model/src/main/java/io/openbas/database/model/ReportInformationsType.java b/openbas-model/src/main/java/io/openbas/database/model/ReportInformationsType.java index 12ceabb36f..d820b7a4ad 100644 --- a/openbas-model/src/main/java/io/openbas/database/model/ReportInformationsType.java +++ b/openbas-model/src/main/java/io/openbas/database/model/ReportInformationsType.java @@ -1,10 +1,10 @@ package io.openbas.database.model; -public enum ReportInformationsType { - MAIN_INFORMATION, - SCORE_DETAILS, - INJECT_RESULT, - GLOBAL_OBSERVATION, - PLAYER_SURVEYS, - EXERCISE_DETAILS -} \ No newline at end of file +public enum ReportInformationsType { + MAIN_INFORMATION, + SCORE_DETAILS, + INJECT_RESULT, + GLOBAL_OBSERVATION, + PLAYER_SURVEYS, + EXERCISE_DETAILS +} diff --git a/openbas-model/src/main/java/io/openbas/database/model/ReportInjectComment.java b/openbas-model/src/main/java/io/openbas/database/model/ReportInjectComment.java index 3b88de68cb..b5b7f1486f 100644 --- a/openbas-model/src/main/java/io/openbas/database/model/ReportInjectComment.java +++ b/openbas-model/src/main/java/io/openbas/database/model/ReportInjectComment.java @@ -12,37 +12,35 @@ @Entity @Table(name = "report_inject_comment") public class ReportInjectComment { - @EmbeddedId - @JsonIgnore - private ReportInjectCommentId compositeId = new ReportInjectCommentId(); + @EmbeddedId @JsonIgnore private ReportInjectCommentId compositeId = new ReportInjectCommentId(); - @ManyToOne(fetch = FetchType.LAZY) - @MapsId("injectId") - @JoinColumn(name = "inject_id") - @JsonIgnore // Ignore Inject object in JSON - @JsonSerialize(using = MonoIdDeserializer.class) - @NotNull - private Inject inject; + @ManyToOne(fetch = FetchType.LAZY) + @MapsId("injectId") + @JoinColumn(name = "inject_id") + @JsonIgnore // Ignore Inject object in JSON + @JsonSerialize(using = MonoIdDeserializer.class) + @NotNull + private Inject inject; - @ManyToOne(fetch = FetchType.LAZY) - @MapsId("reportId") - @JoinColumn(name = "report_id") - @JsonIgnore // Ignore Inject object in JSON - @JsonSerialize(using = MonoIdDeserializer.class) - @NotNull - private Report report; + @ManyToOne(fetch = FetchType.LAZY) + @MapsId("reportId") + @JoinColumn(name = "report_id") + @JsonIgnore // Ignore Inject object in JSON + @JsonSerialize(using = MonoIdDeserializer.class) + @NotNull + private Report report; - @Column(name = "comment") - @JsonProperty("report_inject_comment") - private String comment; + @Column(name = "comment") + @JsonProperty("report_inject_comment") + private String comment; - @JsonProperty("inject_id") - public String getInjectId() { - return inject != null ? inject.getId() : null; // Customize serialization to return ID - } + @JsonProperty("inject_id") + public String getInjectId() { + return inject != null ? inject.getId() : null; // Customize serialization to return ID + } - @JsonProperty("report_id") - public String getReportId() { - return report != null ? report.getId() : null; // Customize serialization to return ID - } + @JsonProperty("report_id") + public String getReportId() { + return report != null ? report.getId() : null; // Customize serialization to return ID + } } diff --git a/openbas-model/src/main/java/io/openbas/database/model/ReportInjectCommentId.java b/openbas-model/src/main/java/io/openbas/database/model/ReportInjectCommentId.java index 6ad2630bab..7e0884b47b 100644 --- a/openbas-model/src/main/java/io/openbas/database/model/ReportInjectCommentId.java +++ b/openbas-model/src/main/java/io/openbas/database/model/ReportInjectCommentId.java @@ -6,13 +6,12 @@ public class ReportInjectCommentId implements Serializable { - @Serial - private static final long serialVersionUID = 1L; + @Serial private static final long serialVersionUID = 1L; - private String injectId; - private UUID reportId; + private String injectId; + private UUID reportId; - public ReportInjectCommentId() { - // Default constructor - } + public ReportInjectCommentId() { + // Default constructor + } } diff --git a/openbas-model/src/main/java/io/openbas/database/model/RuleAttribute.java b/openbas-model/src/main/java/io/openbas/database/model/RuleAttribute.java index 2dcbb2a4e7..8ac900f595 100644 --- a/openbas-model/src/main/java/io/openbas/database/model/RuleAttribute.java +++ b/openbas-model/src/main/java/io/openbas/database/model/RuleAttribute.java @@ -6,79 +6,78 @@ import jakarta.persistence.*; import jakarta.validation.constraints.NotBlank; import jakarta.validation.constraints.NotNull; +import java.time.Instant; +import java.util.Map; +import java.util.Objects; +import java.util.UUID; import lombok.Data; import org.hibernate.annotations.CreationTimestamp; import org.hibernate.annotations.Type; import org.hibernate.annotations.UpdateTimestamp; import org.hibernate.annotations.UuidGenerator; -import java.time.Instant; -import java.util.Map; -import java.util.Objects; -import java.util.UUID; - @Data @Entity @Table(name = "rule_attributes") @EntityListeners(ModelBaseListener.class) public class RuleAttribute implements Base { - @Id - @Column(name = "attribute_id") - @JsonProperty("rule_attribute_id") - @GeneratedValue - @UuidGenerator - @NotNull - private UUID id; + @Id + @Column(name = "attribute_id") + @JsonProperty("rule_attribute_id") + @GeneratedValue + @UuidGenerator + @NotNull + private UUID id; - @Column(name = "attribute_name") - @JsonProperty("rule_attribute_name") - @NotBlank - private String name; + @Column(name = "attribute_name") + @JsonProperty("rule_attribute_name") + @NotBlank + private String name; - @Column(name = "attribute_columns") - @JsonProperty("rule_attribute_columns") - private String columns; + @Column(name = "attribute_columns") + @JsonProperty("rule_attribute_columns") + private String columns; - @Column(name = "attribute_default_value") - @JsonProperty("rule_attribute_default_value") - private String defaultValue; + @Column(name = "attribute_default_value") + @JsonProperty("rule_attribute_default_value") + private String defaultValue; - @Type(PostgreSQLHStoreType.class) - @Column(name = "attribute_additional_config") - @JsonProperty("rule_attribute_additional_config") - private Map additionalConfig; + @Type(PostgreSQLHStoreType.class) + @Column(name = "attribute_additional_config") + @JsonProperty("rule_attribute_additional_config") + private Map additionalConfig; - @CreationTimestamp - @Column(name="attribute_created_at") - @JsonProperty("rule_attribute_created_at") - private Instant creationDate; + @CreationTimestamp + @Column(name = "attribute_created_at") + @JsonProperty("rule_attribute_created_at") + private Instant creationDate; - @UpdateTimestamp - @Column(name= "attribute_updated_at") - @JsonProperty("rule_attribute_updated_at") - private Instant updateDate; + @UpdateTimestamp + @Column(name = "attribute_updated_at") + @JsonProperty("rule_attribute_updated_at") + private Instant updateDate; - @Override - public boolean equals(Object o) { - if (this == o) return true; - if (o == null || !Base.class.isAssignableFrom(o.getClass())) return false; - Base base = (Base) o; - return id.equals(base.getId()); - } + @Override + public boolean equals(Object o) { + if (this == o) return true; + if (o == null || !Base.class.isAssignableFrom(o.getClass())) return false; + Base base = (Base) o; + return id.equals(base.getId()); + } - @Override - public int hashCode() { - return Objects.hash(id); - } + @Override + public int hashCode() { + return Objects.hash(id); + } - @Override - public String getId() { - return this.id != null ? this.id.toString(): ""; - } + @Override + public String getId() { + return this.id != null ? this.id.toString() : ""; + } - @Override - public void setId(String id) { - this.id = UUID.fromString(id); - } + @Override + public void setId(String id) { + this.id = UUID.fromString(id); + } } diff --git a/openbas-model/src/main/java/io/openbas/database/model/Scenario.java b/openbas-model/src/main/java/io/openbas/database/model/Scenario.java index 2ac7402a24..b19e131d63 100644 --- a/openbas-model/src/main/java/io/openbas/database/model/Scenario.java +++ b/openbas-model/src/main/java/io/openbas/database/model/Scenario.java @@ -1,5 +1,11 @@ package io.openbas.database.model; +import static io.openbas.database.model.Grant.GRANT_TYPE.OBSERVER; +import static io.openbas.database.model.Grant.GRANT_TYPE.PLANNER; +import static io.openbas.helper.UserHelper.getUsersByType; +import static java.time.Instant.now; +import static lombok.AccessLevel.NONE; + import com.fasterxml.jackson.annotation.JsonIgnore; import com.fasterxml.jackson.annotation.JsonProperty; import com.fasterxml.jackson.databind.annotation.JsonSerialize; @@ -14,31 +20,20 @@ import jakarta.validation.constraints.Email; import jakarta.validation.constraints.NotBlank; import jakarta.validation.constraints.NotNull; +import java.time.Instant; +import java.util.*; import lombok.Data; import lombok.Getter; import org.hibernate.annotations.UuidGenerator; -import java.time.Instant; -import java.util.*; - -import static io.openbas.database.model.Grant.GRANT_TYPE.OBSERVER; -import static io.openbas.database.model.Grant.GRANT_TYPE.PLANNER; -import static io.openbas.helper.UserHelper.getUsersByType; -import static java.time.Instant.now; -import static lombok.AccessLevel.NONE; - @Data @Entity @Table(name = "scenarios") @EntityListeners(ModelBaseListener.class) @NamedEntityGraphs({ - @NamedEntityGraph( - name = "Scenario.tags-injects", - attributeNodes = { - @NamedAttributeNode("tags"), - @NamedAttributeNode("injects") - } - ) + @NamedEntityGraph( + name = "Scenario.tags-injects", + attributeNodes = {@NamedAttributeNode("tags"), @NamedAttributeNode("injects")}) }) public class Scenario implements Base { @@ -129,7 +124,9 @@ public enum SEVERITY { private String from; @ElementCollection(fetch = FetchType.EAGER) - @CollectionTable(name = "scenario_mails_reply_to", joinColumns = @JoinColumn(name = "scenario_id")) + @CollectionTable( + name = "scenario_mails_reply_to", + joinColumns = @JoinColumn(name = "scenario_id")) @Column(name = "scenario_reply_to", nullable = false) @JsonProperty("scenario_mails_reply_to") private List replyTos = new ArrayList<>(); @@ -160,14 +157,19 @@ public enum SEVERITY { private Set injects = new HashSet<>(); @ManyToMany(fetch = FetchType.LAZY) - @JoinTable(name = "scenarios_teams", + @JoinTable( + name = "scenarios_teams", joinColumns = @JoinColumn(name = "scenario_id"), inverseJoinColumns = @JoinColumn(name = "team_id")) @JsonSerialize(using = MultiIdListDeserializer.class) @JsonProperty("scenario_teams") private List teams = new ArrayList<>(); - @OneToMany(mappedBy = "scenario", fetch = FetchType.LAZY, cascade = CascadeType.ALL, orphanRemoval = true) + @OneToMany( + mappedBy = "scenario", + fetch = FetchType.LAZY, + cascade = CascadeType.ALL, + orphanRemoval = true) @JsonProperty("scenario_teams_users") @JsonSerialize(using = MultiModelDeserializer.class) private List teamUsers = new ArrayList<>(); @@ -177,7 +179,8 @@ public enum SEVERITY { private List objectives = new ArrayList<>(); @ManyToMany(fetch = FetchType.LAZY) - @JoinTable(name = "scenarios_tags", + @JoinTable( + name = "scenarios_tags", joinColumns = @JoinColumn(name = "scenario_id"), inverseJoinColumns = @JoinColumn(name = "tag_id")) @JsonSerialize(using = MultiIdSetDeserializer.class) @@ -186,7 +189,8 @@ public enum SEVERITY { private Set tags = new HashSet<>(); @ManyToMany(fetch = FetchType.LAZY) - @JoinTable(name = "scenarios_documents", + @JoinTable( + name = "scenarios_documents", joinColumns = @JoinColumn(name = "scenario_id"), inverseJoinColumns = @JoinColumn(name = "document_id")) @JsonSerialize(using = MultiIdListDeserializer.class) @@ -204,7 +208,8 @@ public enum SEVERITY { private List lessonsCategories = new ArrayList<>(); @OneToMany(fetch = FetchType.LAZY) - @JoinTable(name = "scenarios_exercises", + @JoinTable( + name = "scenarios_exercises", joinColumns = @JoinColumn(name = "scenario_id"), inverseJoinColumns = @JoinColumn(name = "exercise_id")) @JsonSerialize(using = MultiIdListDeserializer.class) @@ -256,10 +261,7 @@ public long usersNumber() { @JsonProperty("scenario_users") @JsonSerialize(using = MultiIdListDeserializer.class) public List getUsers() { - return getTeamUsers().stream() - .map(ScenarioTeamUser::getUser) - .distinct() - .toList(); + return getTeamUsers().stream().map(ScenarioTeamUser::getUser).distinct().toList(); } @JsonProperty("scenario_communications_number") @@ -270,9 +272,7 @@ public long getCommunicationsNumber() { // -- CHANNELS -- public List
getArticlesForChannel(Channel channel) { - return this.articles.stream() - .filter(article -> article.getChannel().equals(channel)) - .toList(); + return this.articles.stream().filter(article -> article.getChannel().equals(channel)).toList(); } // -- PLATFORMS -- @@ -280,9 +280,8 @@ public List
getArticlesForChannel(Channel channel) { @Queryable(filterable = true, path = "injects.injectorContract.platforms", clazz = String[].class) public List getPlatforms() { return getInjects().stream() - .flatMap(inject -> inject.getInjectorContract() - .map(InjectorContract::getPlatforms) - .stream()) + .flatMap( + inject -> inject.getInjectorContract().map(InjectorContract::getPlatforms).stream()) .flatMap(Arrays::stream) .filter(Objects::nonNull) .distinct() @@ -291,14 +290,17 @@ public List getPlatforms() { // -- KILL CHAIN PHASES -- @JsonProperty("scenario_kill_chain_phases") - @Queryable(filterable = true, dynamicValues = true, path = "injects.injectorContract.attackPatterns.killChainPhases.id") + @Queryable( + filterable = true, + dynamicValues = true, + path = "injects.injectorContract.attackPatterns.killChainPhases.id") public List getKillChainPhases() { return getInjects().stream() - .flatMap(inject -> inject.getInjectorContract() - .map(InjectorContract::getAttackPatterns) - .stream() - .flatMap(Collection::stream) - .flatMap(attackPattern -> attackPattern.getKillChainPhases().stream())) + .flatMap( + inject -> + inject.getInjectorContract().map(InjectorContract::getAttackPatterns).stream() + .flatMap(Collection::stream) + .flatMap(attackPattern -> attackPattern.getKillChainPhases().stream())) .distinct() .toList(); } diff --git a/openbas-model/src/main/java/io/openbas/database/model/ScenarioTeamUser.java b/openbas-model/src/main/java/io/openbas/database/model/ScenarioTeamUser.java index eb3fdeecf5..cb8991c92c 100644 --- a/openbas-model/src/main/java/io/openbas/database/model/ScenarioTeamUser.java +++ b/openbas-model/src/main/java/io/openbas/database/model/ScenarioTeamUser.java @@ -12,9 +12,7 @@ @Table(name = "scenarios_teams_users") public class ScenarioTeamUser { - @EmbeddedId - @JsonIgnore - private ScenarioTeamUserId compositeId = new ScenarioTeamUserId(); + @EmbeddedId @JsonIgnore private ScenarioTeamUserId compositeId = new ScenarioTeamUserId(); @ManyToOne(fetch = FetchType.LAZY) @MapsId("scenarioId") @@ -36,5 +34,4 @@ public class ScenarioTeamUser { @JsonProperty("user_id") @JsonSerialize(using = MonoIdDeserializer.class) private User user; - } diff --git a/openbas-model/src/main/java/io/openbas/database/model/ScenarioTeamUserId.java b/openbas-model/src/main/java/io/openbas/database/model/ScenarioTeamUserId.java index c480d342e4..4cdd6bfd4b 100644 --- a/openbas-model/src/main/java/io/openbas/database/model/ScenarioTeamUserId.java +++ b/openbas-model/src/main/java/io/openbas/database/model/ScenarioTeamUserId.java @@ -1,24 +1,21 @@ package io.openbas.database.model; import jakarta.persistence.Embeddable; -import lombok.Data; - import java.io.Serial; import java.io.Serializable; +import lombok.Data; @Data @Embeddable public class ScenarioTeamUserId implements Serializable { - @Serial - private static final long serialVersionUID = 1L; - - private String scenarioId; - private String teamId; - private String userId; + @Serial private static final long serialVersionUID = 1L; - public ScenarioTeamUserId() { - // Default constructor - } + private String scenarioId; + private String teamId; + private String userId; + public ScenarioTeamUserId() { + // Default constructor + } } diff --git a/openbas-model/src/main/java/io/openbas/database/model/SecurityPlatform.java b/openbas-model/src/main/java/io/openbas/database/model/SecurityPlatform.java index d5c1d40aed..b6cbbafc49 100644 --- a/openbas-model/src/main/java/io/openbas/database/model/SecurityPlatform.java +++ b/openbas-model/src/main/java/io/openbas/database/model/SecurityPlatform.java @@ -53,11 +53,10 @@ public enum SECURITY_PLATFORM_TYPE { @JsonProperty("security_platform_logo_dark") private Document logoDark; - public SecurityPlatform() { + public SecurityPlatform() {} - } - - public SecurityPlatform(String id, String type, String name, SECURITY_PLATFORM_TYPE securityPlatformType) { + public SecurityPlatform( + String id, String type, String name, SECURITY_PLATFORM_TYPE securityPlatformType) { super(id, type, name); this.securityPlatformType = securityPlatformType; } diff --git a/openbas-model/src/main/java/io/openbas/database/model/Setting.java b/openbas-model/src/main/java/io/openbas/database/model/Setting.java index 642560ddcf..cd58dd720c 100644 --- a/openbas-model/src/main/java/io/openbas/database/model/Setting.java +++ b/openbas-model/src/main/java/io/openbas/database/model/Setting.java @@ -2,13 +2,12 @@ import com.fasterxml.jackson.annotation.JsonProperty; import io.openbas.database.audit.ModelBaseListener; +import jakarta.persistence.*; +import java.util.Objects; import lombok.Data; import lombok.NoArgsConstructor; import org.hibernate.annotations.UuidGenerator; -import jakarta.persistence.*; -import java.util.Objects; - @Data @Entity @Table(name = "parameters") @@ -16,41 +15,41 @@ @NoArgsConstructor public class Setting implements Base { - @Id - @Column(name = "parameter_id") - @GeneratedValue(generator = "UUID") - @UuidGenerator - @JsonProperty("setting_id") - private String id; - - @Column(name = "parameter_key") - @JsonProperty("setting_key") - private String key; - - @Column(name = "parameter_value") - @JsonProperty("setting_value") - private String value; - - public Setting(String key, String value) { - this.key = key; - this.value = value; - } - - @Override - public boolean isUserHasAccess(User user) { - return user.isAdmin(); - } - - @Override - public boolean equals(Object o) { - if (this == o) return true; - if (o == null || !Base.class.isAssignableFrom(o.getClass())) return false; - Base base = (Base) o; - return id.equals(base.getId()); - } - - @Override - public int hashCode() { - return Objects.hash(id); - } + @Id + @Column(name = "parameter_id") + @GeneratedValue(generator = "UUID") + @UuidGenerator + @JsonProperty("setting_id") + private String id; + + @Column(name = "parameter_key") + @JsonProperty("setting_key") + private String key; + + @Column(name = "parameter_value") + @JsonProperty("setting_value") + private String value; + + public Setting(String key, String value) { + this.key = key; + this.value = value; + } + + @Override + public boolean isUserHasAccess(User user) { + return user.isAdmin(); + } + + @Override + public boolean equals(Object o) { + if (this == o) return true; + if (o == null || !Base.class.isAssignableFrom(o.getClass())) return false; + Base base = (Base) o; + return id.equals(base.getId()); + } + + @Override + public int hashCode() { + return Objects.hash(id); + } } diff --git a/openbas-model/src/main/java/io/openbas/database/model/SettingKeys.java b/openbas-model/src/main/java/io/openbas/database/model/SettingKeys.java index 1207322d8e..cdaa8a7179 100644 --- a/openbas-model/src/main/java/io/openbas/database/model/SettingKeys.java +++ b/openbas-model/src/main/java/io/openbas/database/model/SettingKeys.java @@ -1,16 +1,17 @@ package io.openbas.database.model; public enum SettingKeys { - DEFAULT_THEME("platform_theme", "dark"), - DEFAULT_LANG( "platform_lang", "auto"), + DEFAULT_LANG("platform_lang", "auto"), PLATFORM_CONSENT_MESSAGE("platform_consent_message", ""), - PLATFORM_CONSENT_CONFIRM_TEXT( "platform_consent_confirm_text", ""), - PLATFORM_ENTERPRISE_EDITION( "platform_enterprise_edition", "false"), - PLATFORM_LOGIN_MESSAGE( "platform_login_message", "This platform is dedicated to Filigran team testing. **Sandbox running the latest rolling release.**"), - PLATFORM_WHITEMARK( "platform_whitemark", "false"), - PLATFORM_NAME( "platform_name", "OpenBAS - Breach and Attack Simulation Platform"), - PLATFORM_BANNER( "platform_banner", ""); + PLATFORM_CONSENT_CONFIRM_TEXT("platform_consent_confirm_text", ""), + PLATFORM_ENTERPRISE_EDITION("platform_enterprise_edition", "false"), + PLATFORM_LOGIN_MESSAGE( + "platform_login_message", + "This platform is dedicated to Filigran team testing. **Sandbox running the latest rolling release.**"), + PLATFORM_WHITEMARK("platform_whitemark", "false"), + PLATFORM_NAME("platform_name", "OpenBAS - Breach and Attack Simulation Platform"), + PLATFORM_BANNER("platform_banner", ""); private final String key; private final String defaultValue; diff --git a/openbas-model/src/main/java/io/openbas/database/model/Tag.java b/openbas-model/src/main/java/io/openbas/database/model/Tag.java index 0ad5db038d..302f5c4e3a 100644 --- a/openbas-model/src/main/java/io/openbas/database/model/Tag.java +++ b/openbas-model/src/main/java/io/openbas/database/model/Tag.java @@ -6,12 +6,11 @@ import io.openbas.database.audit.ModelBaseListener; import jakarta.persistence.*; import jakarta.validation.constraints.NotBlank; +import java.util.Objects; import lombok.Getter; import lombok.Setter; import org.hibernate.annotations.UuidGenerator; -import java.util.Objects; - @Entity @Table(name = "tags") @EntityListeners(ModelBaseListener.class) diff --git a/openbas-model/src/main/java/io/openbas/database/model/Team.java b/openbas-model/src/main/java/io/openbas/database/model/Team.java index e2239872ce..f79e0e78f1 100644 --- a/openbas-model/src/main/java/io/openbas/database/model/Team.java +++ b/openbas-model/src/main/java/io/openbas/database/model/Team.java @@ -1,5 +1,7 @@ package io.openbas.database.model; +import static java.time.Instant.now; + import com.fasterxml.jackson.annotation.JsonProperty; import com.fasterxml.jackson.databind.annotation.JsonSerialize; import io.openbas.annotation.Queryable; @@ -11,16 +13,13 @@ import jakarta.persistence.*; import jakarta.validation.constraints.NotBlank; import jakarta.validation.constraints.NotNull; -import lombok.Getter; -import lombok.Setter; -import org.hibernate.annotations.UuidGenerator; - import java.time.Instant; import java.util.*; import java.util.function.Predicate; import java.util.stream.Collectors; - -import static java.time.Instant.now; +import lombok.Getter; +import lombok.Setter; +import org.hibernate.annotations.UuidGenerator; @Setter @Getter @@ -28,190 +27,213 @@ @Table(name = "teams") @EntityListeners(ModelBaseListener.class) @NamedEntityGraphs({ - @NamedEntityGraph( - name = "Team.tags", - attributeNodes = @NamedAttributeNode("tags") - ) + @NamedEntityGraph(name = "Team.tags", attributeNodes = @NamedAttributeNode("tags")) }) public class Team implements Base { - @Id - @Column(name = "team_id") - @GeneratedValue(generator = "UUID") - @UuidGenerator - @JsonProperty("team_id") - @NotBlank - private String id; - - @Column(name = "team_name") - @JsonProperty("team_name") - @Queryable(searchable = true, sortable = true) - @NotBlank - private String name; - - @Queryable(searchable = true, sortable = true) - @Column(name = "team_description") - @JsonProperty("team_description") - private String description; - - @Column(name = "team_created_at") - @JsonProperty("team_created_at") - @NotNull - private Instant createdAt = now(); - - @Queryable(sortable = true) - @Column(name = "team_updated_at") - @JsonProperty("team_updated_at") - @NotNull - private Instant updatedAt = now(); - - @Queryable(filterable = true, dynamicValues = true, path = "tags.id") - @ManyToMany(fetch = FetchType.LAZY) - @JoinTable(name = "teams_tags", - joinColumns = @JoinColumn(name = "team_id"), - inverseJoinColumns = @JoinColumn(name = "tag_id")) - @JsonSerialize(using = MultiIdSetDeserializer.class) - @JsonProperty("team_tags") - private Set tags = new HashSet<>(); - - @ManyToOne(fetch = FetchType.LAZY) - @JoinColumn(name = "team_organization") - @JsonSerialize(using = MonoIdDeserializer.class) - @JsonProperty("team_organization") - private Organization organization; - - @ManyToMany(fetch = FetchType.LAZY) - @JoinTable(name = "users_teams", - joinColumns = @JoinColumn(name = "team_id"), - inverseJoinColumns = @JoinColumn(name = "user_id")) - @JsonSerialize(using = MultiIdListDeserializer.class) - @JsonProperty("team_users") - private List users = new ArrayList<>(); - - @ManyToMany(fetch = FetchType.LAZY) - @JoinTable(name = "exercises_teams", - joinColumns = @JoinColumn(name = "team_id"), - inverseJoinColumns = @JoinColumn(name = "exercise_id")) - @JsonSerialize(using = MultiIdListDeserializer.class) - @JsonProperty("team_exercises") - private List exercises = new ArrayList<>(); - - @ManyToMany(fetch = FetchType.LAZY) - @JoinTable(name = "scenarios_teams", - joinColumns = @JoinColumn(name = "team_id"), - inverseJoinColumns = @JoinColumn(name = "scenario_id")) - @JsonSerialize(using = MultiIdListDeserializer.class) - @JsonProperty("team_scenarios") - private List scenarios = new ArrayList<>(); - - @Column(name = "team_contextual") - @JsonProperty("team_contextual") - private Boolean contextual = false; - - @OneToMany(mappedBy = "team", fetch = FetchType.LAZY, cascade = CascadeType.ALL, orphanRemoval = true) - @JsonProperty("team_exercises_users") - @JsonSerialize(using = MultiModelDeserializer.class) - private List exerciseTeamUsers = new ArrayList<>(); - - @JsonProperty("team_users_number") - public long getUsersNumber() { - return getUsers().size(); - } - - // region transient - @JsonProperty("team_exercise_injects") - @JsonSerialize(using = MultiIdListDeserializer.class) - public List getExercisesInjects() { - Predicate selectedInject = inject -> inject.isAllTeams() || inject.getTeams().contains(this); - return getExercises().stream().map(exercise -> exercise.getInjects().stream().filter(selectedInject).distinct().toList()).flatMap(List::stream).toList(); - } - - @JsonProperty("team_exercise_injects_number") - public long getExercisesInjectsNumber() { - return getExercisesInjects().size(); - } - - @JsonProperty("team_scenario_injects") - @JsonSerialize(using = MultiIdListDeserializer.class) - public List getScenariosInjects() { - Predicate selectedInject = inject -> inject.isAllTeams() || inject.getTeams().contains(this); - return getScenarios().stream().map(scenario -> scenario.getInjects().stream().filter(selectedInject).distinct().toList()).flatMap(List::stream).toList(); - } - - @JsonProperty("team_scenario_injects_number") - public long getScenariosInjectsNumber() { - return getScenariosInjects().size(); - } - - @OneToMany(mappedBy = "team", fetch = FetchType.LAZY) - @JsonSerialize(using = MultiIdListDeserializer.class) - @JsonProperty("team_inject_expectations") - private List injectExpectations = new ArrayList<>(); - - @JsonProperty("team_injects_expectations_number") - public long getInjectExceptationsNumber() { - return getInjectExpectations().size(); - } - - @JsonProperty("team_injects_expectations_total_score") - @NotNull - public double getInjectExceptationsTotalScore() { - return getInjectExpectations().stream() - .filter((inject) -> inject.getScore() != null) - .mapToDouble(InjectExpectation::getScore).sum(); - } - @JsonProperty("team_injects_expectations_total_score_by_exercise") - @NotNull - public Map getInjectExceptationsTotalScoreByExercise() { - return getInjectExpectations().stream() - .filter(expectation -> Objects.nonNull(expectation.getExercise()) && Objects.nonNull(expectation.getScore())) - .collect(Collectors.groupingBy(expectation -> expectation.getExercise().getId(), + @Id + @Column(name = "team_id") + @GeneratedValue(generator = "UUID") + @UuidGenerator + @JsonProperty("team_id") + @NotBlank + private String id; + + @Column(name = "team_name") + @JsonProperty("team_name") + @Queryable(searchable = true, sortable = true) + @NotBlank + private String name; + + @Queryable(searchable = true, sortable = true) + @Column(name = "team_description") + @JsonProperty("team_description") + private String description; + + @Column(name = "team_created_at") + @JsonProperty("team_created_at") + @NotNull + private Instant createdAt = now(); + + @Queryable(sortable = true) + @Column(name = "team_updated_at") + @JsonProperty("team_updated_at") + @NotNull + private Instant updatedAt = now(); + + @Queryable(filterable = true, dynamicValues = true, path = "tags.id") + @ManyToMany(fetch = FetchType.LAZY) + @JoinTable( + name = "teams_tags", + joinColumns = @JoinColumn(name = "team_id"), + inverseJoinColumns = @JoinColumn(name = "tag_id")) + @JsonSerialize(using = MultiIdSetDeserializer.class) + @JsonProperty("team_tags") + private Set tags = new HashSet<>(); + + @ManyToOne(fetch = FetchType.LAZY) + @JoinColumn(name = "team_organization") + @JsonSerialize(using = MonoIdDeserializer.class) + @JsonProperty("team_organization") + private Organization organization; + + @ManyToMany(fetch = FetchType.LAZY) + @JoinTable( + name = "users_teams", + joinColumns = @JoinColumn(name = "team_id"), + inverseJoinColumns = @JoinColumn(name = "user_id")) + @JsonSerialize(using = MultiIdListDeserializer.class) + @JsonProperty("team_users") + private List users = new ArrayList<>(); + + @ManyToMany(fetch = FetchType.LAZY) + @JoinTable( + name = "exercises_teams", + joinColumns = @JoinColumn(name = "team_id"), + inverseJoinColumns = @JoinColumn(name = "exercise_id")) + @JsonSerialize(using = MultiIdListDeserializer.class) + @JsonProperty("team_exercises") + private List exercises = new ArrayList<>(); + + @ManyToMany(fetch = FetchType.LAZY) + @JoinTable( + name = "scenarios_teams", + joinColumns = @JoinColumn(name = "team_id"), + inverseJoinColumns = @JoinColumn(name = "scenario_id")) + @JsonSerialize(using = MultiIdListDeserializer.class) + @JsonProperty("team_scenarios") + private List scenarios = new ArrayList<>(); + + @Column(name = "team_contextual") + @JsonProperty("team_contextual") + private Boolean contextual = false; + + @OneToMany( + mappedBy = "team", + fetch = FetchType.LAZY, + cascade = CascadeType.ALL, + orphanRemoval = true) + @JsonProperty("team_exercises_users") + @JsonSerialize(using = MultiModelDeserializer.class) + private List exerciseTeamUsers = new ArrayList<>(); + + @JsonProperty("team_users_number") + public long getUsersNumber() { + return getUsers().size(); + } + + // region transient + @JsonProperty("team_exercise_injects") + @JsonSerialize(using = MultiIdListDeserializer.class) + public List getExercisesInjects() { + Predicate selectedInject = + inject -> inject.isAllTeams() || inject.getTeams().contains(this); + return getExercises().stream() + .map(exercise -> exercise.getInjects().stream().filter(selectedInject).distinct().toList()) + .flatMap(List::stream) + .toList(); + } + + @JsonProperty("team_exercise_injects_number") + public long getExercisesInjectsNumber() { + return getExercisesInjects().size(); + } + + @JsonProperty("team_scenario_injects") + @JsonSerialize(using = MultiIdListDeserializer.class) + public List getScenariosInjects() { + Predicate selectedInject = + inject -> inject.isAllTeams() || inject.getTeams().contains(this); + return getScenarios().stream() + .map(scenario -> scenario.getInjects().stream().filter(selectedInject).distinct().toList()) + .flatMap(List::stream) + .toList(); + } + + @JsonProperty("team_scenario_injects_number") + public long getScenariosInjectsNumber() { + return getScenariosInjects().size(); + } + + @OneToMany(mappedBy = "team", fetch = FetchType.LAZY) + @JsonSerialize(using = MultiIdListDeserializer.class) + @JsonProperty("team_inject_expectations") + private List injectExpectations = new ArrayList<>(); + + @JsonProperty("team_injects_expectations_number") + public long getInjectExceptationsNumber() { + return getInjectExpectations().size(); + } + + @JsonProperty("team_injects_expectations_total_score") + @NotNull + public double getInjectExceptationsTotalScore() { + return getInjectExpectations().stream() + .filter((inject) -> inject.getScore() != null) + .mapToDouble(InjectExpectation::getScore) + .sum(); + } + + @JsonProperty("team_injects_expectations_total_score_by_exercise") + @NotNull + public Map getInjectExceptationsTotalScoreByExercise() { + return getInjectExpectations().stream() + .filter( + expectation -> + Objects.nonNull(expectation.getExercise()) + && Objects.nonNull(expectation.getScore())) + .collect( + Collectors.groupingBy( + expectation -> expectation.getExercise().getId(), Collectors.summingDouble(InjectExpectation::getScore))); - } - - @JsonProperty("team_injects_expectations_total_expected_score") - @NotNull - public double getInjectExceptationsTotalExpectedScore() { - return getInjectExpectations().stream().mapToDouble(InjectExpectation::getExpectedScore).sum(); - } - - @JsonProperty("team_injects_expectations_total_expected_score_by_exercise") - @NotNull - public Map getInjectExpectationsTotalExpectedScoreByExercise() { - return getInjectExpectations().stream() - .filter(expectation -> Objects.nonNull(expectation.getExercise())) - .collect(Collectors.groupingBy(expectation -> expectation.getExercise().getId(), + } + + @JsonProperty("team_injects_expectations_total_expected_score") + @NotNull + public double getInjectExceptationsTotalExpectedScore() { + return getInjectExpectations().stream().mapToDouble(InjectExpectation::getExpectedScore).sum(); + } + + @JsonProperty("team_injects_expectations_total_expected_score_by_exercise") + @NotNull + public Map getInjectExpectationsTotalExpectedScoreByExercise() { + return getInjectExpectations().stream() + .filter(expectation -> Objects.nonNull(expectation.getExercise())) + .collect( + Collectors.groupingBy( + expectation -> expectation.getExercise().getId(), Collectors.summingDouble(InjectExpectation::getExpectedScore))); - } - // endregion - - @JsonProperty("team_communications") - public List getCommunications() { - return getExercisesInjects().stream().flatMap(inject -> inject.getCommunications().stream()) - .distinct() - .toList(); - } - - public long getUsersNumberInExercise(String exerciseId) { - return exerciseId == null ? - 0: - getExerciseTeamUsers() - .stream() - .filter(exerciseTeamUser -> exerciseTeamUser.getExercise().getId().equals(exerciseId)) - .toList() - .size(); - } - - @Override - public boolean equals(Object o) { - if (this == o) return true; - if (o == null || !Base.class.isAssignableFrom(o.getClass())) return false; - Base base = (Base) o; - return id.equals(base.getId()); - } - - @Override - public int hashCode() { - return Objects.hash(id); - } + } + + // endregion + + @JsonProperty("team_communications") + public List getCommunications() { + return getExercisesInjects().stream() + .flatMap(inject -> inject.getCommunications().stream()) + .distinct() + .toList(); + } + + public long getUsersNumberInExercise(String exerciseId) { + return exerciseId == null + ? 0 + : getExerciseTeamUsers().stream() + .filter(exerciseTeamUser -> exerciseTeamUser.getExercise().getId().equals(exerciseId)) + .toList() + .size(); + } + + @Override + public boolean equals(Object o) { + if (this == o) return true; + if (o == null || !Base.class.isAssignableFrom(o.getClass())) return false; + Base base = (Base) o; + return id.equals(base.getId()); + } + + @Override + public int hashCode() { + return Objects.hash(id); + } } diff --git a/openbas-model/src/main/java/io/openbas/database/model/TeamSimple.java b/openbas-model/src/main/java/io/openbas/database/model/TeamSimple.java index 1da1ed59c1..6cd53e5bcd 100644 --- a/openbas-model/src/main/java/io/openbas/database/model/TeamSimple.java +++ b/openbas-model/src/main/java/io/openbas/database/model/TeamSimple.java @@ -1,159 +1,173 @@ package io.openbas.database.model; +import static java.time.Instant.now; + import com.fasterxml.jackson.annotation.JsonIgnore; import com.fasterxml.jackson.annotation.JsonProperty; import io.openbas.annotation.Queryable; import io.openbas.database.raw.RawTeam; import jakarta.validation.constraints.NotBlank; import jakarta.validation.constraints.NotNull; -import lombok.Getter; -import lombok.Setter; - import java.time.Instant; import java.util.*; import java.util.stream.Collectors; - -import static java.time.Instant.now; +import lombok.Getter; +import lombok.Setter; @Setter @Getter public class TeamSimple { - @JsonProperty("team_id") - @NotBlank - private String id; - - @NotBlank - @JsonProperty("team_name") - @Queryable(searchable = true) - private String name; - - @JsonProperty("team_description") - private String description; - - @JsonProperty("team_created_at") - private Instant createdAt = now(); - - @JsonProperty("team_updated_at") - private Instant updatedAt = now(); - - @JsonProperty("team_tags") - private Set tags = new HashSet<>(); - - @JsonProperty("team_organization") - private String organization; - - @JsonProperty("team_users") - private Set users = new HashSet<>(); - - @JsonProperty("team_exercises") - private Set exercises = new HashSet<>(); - - @JsonProperty("team_scenarios") - private Set scenarios = new HashSet<>(); - - @JsonProperty("team_contextual") - private Boolean contextual = false; - - @JsonProperty("team_exercises_users") - private Set exerciseTeamUsers = new HashSet<>(); - - @JsonProperty("team_users_number") - public long getUsersNumber() { - return this.users.size(); - } - - // region transient - @JsonProperty("team_exercise_injects") - private Set exercisesInjects = new HashSet<>(); - - @JsonProperty("team_exercise_injects_number") - public long getExercisesInjectsNumber() { - return this.exercisesInjects.size(); - } - - @JsonProperty("team_scenario_injects") - Set scenariosInjects = new HashSet<>(); - - @JsonProperty("team_scenario_injects_number") - public long getScenariosInjectsNumber() { - return this.scenariosInjects.size(); - } - - @JsonIgnore - private List injectExpectations = new ArrayList<>(); - - @JsonProperty("team_inject_expectations") - private Set getInjectExpectationsAsStringList() { - return getInjectExpectations().stream().map(InjectExpectation::getId).collect(Collectors.toSet()); - } - - @JsonProperty("team_injects_expectations_number") - public long getInjectExceptationsNumber() { - return getInjectExpectations().size(); - } - - @JsonProperty("team_injects_expectations_total_score") - @NotNull - public double getInjectExceptationsTotalScore() { - return getInjectExpectations().stream() - .filter((inject) -> inject.getScore() != null) - .mapToDouble(InjectExpectation::getScore).sum(); - } - @JsonProperty("team_injects_expectations_total_score_by_exercise") - @NotNull - public Map getInjectExceptationsTotalScoreByExercise() { - return getInjectExpectations().stream() - .filter(expectation -> Objects.nonNull(expectation.getExercise()) && Objects.nonNull(expectation.getScore())) - .collect(Collectors.groupingBy(expectation -> expectation.getExercise().getId(), + @JsonProperty("team_id") + @NotBlank + private String id; + + @NotBlank + @JsonProperty("team_name") + @Queryable(searchable = true) + private String name; + + @JsonProperty("team_description") + private String description; + + @JsonProperty("team_created_at") + private Instant createdAt = now(); + + @JsonProperty("team_updated_at") + private Instant updatedAt = now(); + + @JsonProperty("team_tags") + private Set tags = new HashSet<>(); + + @JsonProperty("team_organization") + private String organization; + + @JsonProperty("team_users") + private Set users = new HashSet<>(); + + @JsonProperty("team_exercises") + private Set exercises = new HashSet<>(); + + @JsonProperty("team_scenarios") + private Set scenarios = new HashSet<>(); + + @JsonProperty("team_contextual") + private Boolean contextual = false; + + @JsonProperty("team_exercises_users") + private Set exerciseTeamUsers = new HashSet<>(); + + @JsonProperty("team_users_number") + public long getUsersNumber() { + return this.users.size(); + } + + // region transient + @JsonProperty("team_exercise_injects") + private Set exercisesInjects = new HashSet<>(); + + @JsonProperty("team_exercise_injects_number") + public long getExercisesInjectsNumber() { + return this.exercisesInjects.size(); + } + + @JsonProperty("team_scenario_injects") + Set scenariosInjects = new HashSet<>(); + + @JsonProperty("team_scenario_injects_number") + public long getScenariosInjectsNumber() { + return this.scenariosInjects.size(); + } + + @JsonIgnore private List injectExpectations = new ArrayList<>(); + + @JsonProperty("team_inject_expectations") + private Set getInjectExpectationsAsStringList() { + return getInjectExpectations().stream() + .map(InjectExpectation::getId) + .collect(Collectors.toSet()); + } + + @JsonProperty("team_injects_expectations_number") + public long getInjectExceptationsNumber() { + return getInjectExpectations().size(); + } + + @JsonProperty("team_injects_expectations_total_score") + @NotNull + public double getInjectExceptationsTotalScore() { + return getInjectExpectations().stream() + .filter((inject) -> inject.getScore() != null) + .mapToDouble(InjectExpectation::getScore) + .sum(); + } + + @JsonProperty("team_injects_expectations_total_score_by_exercise") + @NotNull + public Map getInjectExceptationsTotalScoreByExercise() { + return getInjectExpectations().stream() + .filter( + expectation -> + Objects.nonNull(expectation.getExercise()) + && Objects.nonNull(expectation.getScore())) + .collect( + Collectors.groupingBy( + expectation -> expectation.getExercise().getId(), Collectors.summingDouble(InjectExpectation::getScore))); - } - - @JsonProperty("team_injects_expectations_total_expected_score") - @NotNull - public double getInjectExceptationsTotalExpectedScore() { - return getInjectExpectations().stream() .filter(expectation -> Objects.nonNull(expectation.getExpectedScore())).mapToDouble(InjectExpectation::getExpectedScore).sum(); - } - - @JsonProperty("team_injects_expectations_total_expected_score_by_exercise") - @NotNull - public Map getInjectExpectationsTotalExpectedScoreByExercise() { - Map result = getInjectExpectations().stream() - .filter(expectation -> Objects.nonNull(expectation.getExercise())) - .collect(Collectors.groupingBy(expectation -> expectation.getExercise().getId(), - Collectors.summingDouble(InjectExpectation::getExpectedScore))); - return result; - } - // endregion - - @JsonProperty("team_communications") - List communications = new ArrayList<>(); - - public TeamSimple(RawTeam raw) { - super(); - this.id = raw.getTeam_id(); - this.scenarios = raw.getTeam_scenarios(); - this.exercisesInjects = raw.getTeam_exercise_injects(); - this.contextual = raw.getTeam_contextual(); - this.exercises = raw.getTeam_exercises(); - this.createdAt = raw.getTeam_created_at(); - this.description = raw.getTeam_description(); - this.updatedAt = raw.getTeam_updated_at(); - this.name = raw.getTeam_name(); - this.organization = raw.getTeam_organization(); - this.users = raw.getTeam_users(); - this.tags = raw.getTeam_tags(); - } - - @Override - public boolean equals(Object o) { - if (this == o) return true; - if (o == null || !Base.class.isAssignableFrom(o.getClass())) return false; - Base base = (Base) o; - return id.equals(base.getId()); - } - - @Override - public int hashCode() { - return Objects.hash(id); - } + } + + @JsonProperty("team_injects_expectations_total_expected_score") + @NotNull + public double getInjectExceptationsTotalExpectedScore() { + return getInjectExpectations().stream() + .filter(expectation -> Objects.nonNull(expectation.getExpectedScore())) + .mapToDouble(InjectExpectation::getExpectedScore) + .sum(); + } + + @JsonProperty("team_injects_expectations_total_expected_score_by_exercise") + @NotNull + public Map getInjectExpectationsTotalExpectedScoreByExercise() { + Map result = + getInjectExpectations().stream() + .filter(expectation -> Objects.nonNull(expectation.getExercise())) + .collect( + Collectors.groupingBy( + expectation -> expectation.getExercise().getId(), + Collectors.summingDouble(InjectExpectation::getExpectedScore))); + return result; + } + + // endregion + + @JsonProperty("team_communications") + List communications = new ArrayList<>(); + + public TeamSimple(RawTeam raw) { + super(); + this.id = raw.getTeam_id(); + this.scenarios = raw.getTeam_scenarios(); + this.exercisesInjects = raw.getTeam_exercise_injects(); + this.contextual = raw.getTeam_contextual(); + this.exercises = raw.getTeam_exercises(); + this.createdAt = raw.getTeam_created_at(); + this.description = raw.getTeam_description(); + this.updatedAt = raw.getTeam_updated_at(); + this.name = raw.getTeam_name(); + this.organization = raw.getTeam_organization(); + this.users = raw.getTeam_users(); + this.tags = raw.getTeam_tags(); + } + + @Override + public boolean equals(Object o) { + if (this == o) return true; + if (o == null || !Base.class.isAssignableFrom(o.getClass())) return false; + Base base = (Base) o; + return id.equals(base.getId()); + } + + @Override + public int hashCode() { + return Objects.hash(id); + } } diff --git a/openbas-model/src/main/java/io/openbas/database/model/Theme.java b/openbas-model/src/main/java/io/openbas/database/model/Theme.java index 02e2dec586..bb191718ea 100644 --- a/openbas-model/src/main/java/io/openbas/database/model/Theme.java +++ b/openbas-model/src/main/java/io/openbas/database/model/Theme.java @@ -1,17 +1,10 @@ package io.openbas.database.model; import com.fasterxml.jackson.annotation.JsonProperty; -import io.openbas.database.audit.ModelBaseListener; import jakarta.persistence.*; import lombok.Data; -import lombok.EqualsAndHashCode; -import lombok.Getter; -import lombok.Setter; import org.hibernate.annotations.UuidGenerator; -import java.util.Objects; - - @Data public class Theme implements Base { @@ -54,12 +47,10 @@ public Theme() { @JsonProperty("theme_id") private String id; - @Column(name = "personalized_theme_key") @JsonProperty("theme_key") private String key; - @Column(name = "personalized_theme_value") @JsonProperty("theme_value") private String value; @@ -68,5 +59,4 @@ public Theme() { public boolean isUserHasAccess(User user) { return user.isAdmin(); } - } diff --git a/openbas-model/src/main/java/io/openbas/database/model/Token.java b/openbas-model/src/main/java/io/openbas/database/model/Token.java index 44e501e333..f5d69eaf1e 100644 --- a/openbas-model/src/main/java/io/openbas/database/model/Token.java +++ b/openbas-model/src/main/java/io/openbas/database/model/Token.java @@ -3,63 +3,62 @@ import com.fasterxml.jackson.annotation.JsonProperty; import com.fasterxml.jackson.databind.annotation.JsonSerialize; import io.openbas.helper.MonoIdDeserializer; +import jakarta.persistence.*; import jakarta.validation.constraints.NotBlank; import jakarta.validation.constraints.NotNull; +import java.time.Instant; +import java.util.Objects; import lombok.Getter; import lombok.Setter; import org.hibernate.annotations.UuidGenerator; -import jakarta.persistence.*; -import java.time.Instant; -import java.util.Objects; - @Setter @Getter @Entity @Table(name = "tokens") public class Token implements Base { - public static final String ADMIN_TOKEN_UUID = "0d17ce9a-f3a8-4c6d-9721-c98dc3dc023f"; + public static final String ADMIN_TOKEN_UUID = "0d17ce9a-f3a8-4c6d-9721-c98dc3dc023f"; - @Id - @Column(name = "token_id") - @GeneratedValue(generator = "UUID") - @UuidGenerator - @JsonProperty("token_id") - @NotBlank - private String id; + @Id + @Column(name = "token_id") + @GeneratedValue(generator = "UUID") + @UuidGenerator + @JsonProperty("token_id") + @NotBlank + private String id; - @ManyToOne(fetch = FetchType.EAGER) - @JoinColumn(name = "token_user") - @JsonSerialize(using = MonoIdDeserializer.class) - @JsonProperty("token_user") - private User user; + @ManyToOne(fetch = FetchType.EAGER) + @JoinColumn(name = "token_user") + @JsonSerialize(using = MonoIdDeserializer.class) + @JsonProperty("token_user") + private User user; - @Column(name = "token_value") - @JsonProperty("token_value") - @NotBlank - private String value; + @Column(name = "token_value") + @JsonProperty("token_value") + @NotBlank + private String value; - @Column(name = "token_created_at") - @JsonProperty("token_created_at") - @NotNull - private Instant created; + @Column(name = "token_created_at") + @JsonProperty("token_created_at") + @NotNull + private Instant created; - @Override - public boolean isUserHasAccess(User user) { - return this.user.equals(user); - } + @Override + public boolean isUserHasAccess(User user) { + return this.user.equals(user); + } - @Override - public boolean equals(Object o) { - if (this == o) return true; - if (o == null || !Base.class.isAssignableFrom(o.getClass())) return false; - Base base = (Base) o; - return id.equals(base.getId()); - } + @Override + public boolean equals(Object o) { + if (this == o) return true; + if (o == null || !Base.class.isAssignableFrom(o.getClass())) return false; + Base base = (Base) o; + return id.equals(base.getId()); + } - @Override - public int hashCode() { - return Objects.hash(id); - } + @Override + public int hashCode() { + return Objects.hash(id); + } } diff --git a/openbas-model/src/main/java/io/openbas/database/model/User.java b/openbas-model/src/main/java/io/openbas/database/model/User.java index 709b2e27c3..962367f223 100644 --- a/openbas-model/src/main/java/io/openbas/database/model/User.java +++ b/openbas-model/src/main/java/io/openbas/database/model/User.java @@ -1,5 +1,10 @@ package io.openbas.database.model; +import static java.time.Instant.now; +import static java.util.Optional.ofNullable; +import static java.util.stream.StreamSupport.stream; +import static lombok.AccessLevel.NONE; + import com.fasterxml.jackson.annotation.JsonIgnore; import com.fasterxml.jackson.annotation.JsonProperty; import com.fasterxml.jackson.databind.annotation.JsonSerialize; @@ -12,31 +17,21 @@ import jakarta.persistence.*; import jakarta.validation.constraints.NotBlank; import jakarta.validation.constraints.NotNull; -import lombok.Getter; -import lombok.Setter; -import org.hibernate.annotations.UuidGenerator; - import java.time.Instant; import java.util.*; import java.util.stream.Collectors; - -import static java.time.Instant.now; -import static java.util.Optional.ofNullable; -import static java.util.stream.StreamSupport.stream; -import static lombok.AccessLevel.NONE; +import lombok.Getter; +import lombok.Setter; +import org.hibernate.annotations.UuidGenerator; @Getter @Entity @Table(name = "users") @EntityListeners(ModelBaseListener.class) @NamedEntityGraphs({ - @NamedEntityGraph( - name = "Player.tags-organization", - attributeNodes = { - @NamedAttributeNode("tags"), - @NamedAttributeNode("organization") - } - ) + @NamedEntityGraph( + name = "Player.tags-organization", + attributeNodes = {@NamedAttributeNode("tags"), @NamedAttributeNode("organization")}) }) public class User implements Base { @@ -153,7 +148,8 @@ public class User implements Base { @Setter // @ManyToMany(fetch = FetchType.LAZY) @ManyToMany(fetch = FetchType.EAGER) - @JoinTable(name = "users_groups", + @JoinTable( + name = "users_groups", joinColumns = @JoinColumn(name = "user_id"), inverseJoinColumns = @JoinColumn(name = "group_id")) @JsonSerialize(using = MultiIdListDeserializer.class) @@ -162,7 +158,8 @@ public class User implements Base { @Setter @ManyToMany(fetch = FetchType.LAZY) - @JoinTable(name = "users_teams", + @JoinTable( + name = "users_teams", joinColumns = @JoinColumn(name = "user_id"), inverseJoinColumns = @JoinColumn(name = "team_id")) @JsonSerialize(using = MultiIdListDeserializer.class) @@ -171,7 +168,8 @@ public class User implements Base { @Setter @ManyToMany(fetch = FetchType.LAZY) - @JoinTable(name = "users_tags", + @JoinTable( + name = "users_tags", joinColumns = @JoinColumn(name = "user_id"), inverseJoinColumns = @JoinColumn(name = "tag_id")) @JsonSerialize(using = MultiIdSetDeserializer.class) @@ -181,7 +179,8 @@ public class User implements Base { @Setter @ManyToMany(fetch = FetchType.LAZY) - @JoinTable(name = "communications_users", + @JoinTable( + name = "communications_users", joinColumns = @JoinColumn(name = "user_id"), inverseJoinColumns = @JoinColumn(name = "communication_id")) @JsonSerialize(using = MultiIdListDeserializer.class) @@ -211,17 +210,22 @@ public String getEmail() { } public void setEmail(final String email) { - this.email = ofNullable(email).map(String::toLowerCase).orElseThrow(() -> new IllegalArgumentException("Email can't be null")); + this.email = + ofNullable(email) + .map(String::toLowerCase) + .orElseThrow(() -> new IllegalArgumentException("Email can't be null")); } - @Transient - private List injects = new ArrayList<>(); + @Transient private List injects = new ArrayList<>(); public void resolveInjects(Iterable injects) { - this.injects = stream(injects.spliterator(), false) - .filter(inject -> inject.isAllTeams() || inject.getTeams().stream() - .anyMatch(team -> getTeams().contains(team))) - .collect(Collectors.toList()); + this.injects = + stream(injects.spliterator(), false) + .filter( + inject -> + inject.isAllTeams() + || inject.getTeams().stream().anyMatch(team -> getTeams().contains(team))) + .collect(Collectors.toList()); } @JsonProperty("user_injects") @@ -242,15 +246,15 @@ public String getGravatar() { @JsonProperty("user_is_planner") public boolean isPlanner() { - return isAdmin() || getGroups().stream() - .flatMap(group -> group.getGrants().stream()) - .anyMatch(grant -> Grant.GRANT_TYPE.PLANNER.equals(grant.getName())); + return isAdmin() + || getGroups().stream() + .flatMap(group -> group.getGrants().stream()) + .anyMatch(grant -> Grant.GRANT_TYPE.PLANNER.equals(grant.getName())); } @JsonProperty("user_is_observer") public boolean isObserver() { - return isAdmin() || getGroups().stream() - .mapToLong(group -> group.getGrants().size()).sum() > 0; + return isAdmin() || getGroups().stream().mapToLong(group -> group.getGrants().size()).sum() > 0; } @JsonProperty("user_is_manager") diff --git a/openbas-model/src/main/java/io/openbas/database/model/Variable.java b/openbas-model/src/main/java/io/openbas/database/model/Variable.java index 2459858d14..6b05b0bed4 100644 --- a/openbas-model/src/main/java/io/openbas/database/model/Variable.java +++ b/openbas-model/src/main/java/io/openbas/database/model/Variable.java @@ -1,19 +1,18 @@ package io.openbas.database.model; +import static java.time.Instant.now; + import com.fasterxml.jackson.annotation.JsonProperty; import com.fasterxml.jackson.databind.annotation.JsonSerialize; import io.openbas.database.audit.ModelBaseListener; import io.openbas.helper.MonoIdDeserializer; -import lombok.Data; -import org.hibernate.annotations.UuidGenerator; - import jakarta.persistence.*; import jakarta.validation.constraints.NotBlank; import jakarta.validation.constraints.NotNull; import jakarta.validation.constraints.Pattern; import java.time.Instant; - -import static java.time.Instant.now; +import lombok.Data; +import org.hibernate.annotations.UuidGenerator; @Data @Entity @@ -40,7 +39,7 @@ public enum VariableType { @Column(name = "variable_key") @JsonProperty("variable_key") @NotBlank - @Pattern(regexp="^[a-z_]+$") + @Pattern(regexp = "^[a-z_]+$") private String key; @Column(name = "variable_value") @@ -80,5 +79,4 @@ public enum VariableType { @JsonProperty("variable_updated_at") @NotNull private Instant updatedAt = now(); - } diff --git a/openbas-model/src/main/java/io/openbas/database/raw/RawAssetGroup.java b/openbas-model/src/main/java/io/openbas/database/raw/RawAssetGroup.java index 3e1c255530..dfc44aeafa 100644 --- a/openbas-model/src/main/java/io/openbas/database/raw/RawAssetGroup.java +++ b/openbas-model/src/main/java/io/openbas/database/raw/RawAssetGroup.java @@ -3,7 +3,6 @@ import com.fasterxml.jackson.core.JsonProcessingException; import com.fasterxml.jackson.databind.ObjectMapper; import io.openbas.database.model.Filters; - import java.util.List; public interface RawAssetGroup { @@ -22,7 +21,6 @@ default Filters.FilterGroup getAssetGroupDynamicFilter() { String getAsset_group_name(); List getAsset_ids(); - - String getAsset_group_dynamic_filter(); + String getAsset_group_dynamic_filter(); } diff --git a/openbas-model/src/main/java/io/openbas/database/raw/RawAttackPattern.java b/openbas-model/src/main/java/io/openbas/database/raw/RawAttackPattern.java index efc77e4025..ba153314bb 100644 --- a/openbas-model/src/main/java/io/openbas/database/raw/RawAttackPattern.java +++ b/openbas-model/src/main/java/io/openbas/database/raw/RawAttackPattern.java @@ -4,15 +4,25 @@ @SuppressWarnings("unused") public interface RawAttackPattern { - String getAttack_pattern_id(); - String getAttack_pattern_stix_id(); - String getAttack_pattern_name(); - String getAttack_pattern_description(); - String getAttack_pattern_external_id(); - List getAttack_pattern_platforms(); - List getAttack_pattern_permissions_required(); - String getAttack_pattern_created_at(); - String getAttack_pattern_updated_at(); - String getAttack_pattern_parent(); - List getAttack_pattern_kill_chain_phases(); + String getAttack_pattern_id(); + + String getAttack_pattern_stix_id(); + + String getAttack_pattern_name(); + + String getAttack_pattern_description(); + + String getAttack_pattern_external_id(); + + List getAttack_pattern_platforms(); + + List getAttack_pattern_permissions_required(); + + String getAttack_pattern_created_at(); + + String getAttack_pattern_updated_at(); + + String getAttack_pattern_parent(); + + List getAttack_pattern_kill_chain_phases(); } diff --git a/openbas-model/src/main/java/io/openbas/database/raw/RawCommunication.java b/openbas-model/src/main/java/io/openbas/database/raw/RawCommunication.java index 6fc4aeb65f..050dae2eef 100644 --- a/openbas-model/src/main/java/io/openbas/database/raw/RawCommunication.java +++ b/openbas-model/src/main/java/io/openbas/database/raw/RawCommunication.java @@ -5,27 +5,27 @@ public interface RawCommunication { - public String getCommunication_id(); + public String getCommunication_id(); - public String getCommunication_message_id(); + public String getCommunication_message_id(); - public Instant getCommunication_received_at(); + public Instant getCommunication_received_at(); - public Instant getCommunication_sent_at(); + public Instant getCommunication_sent_at(); - public String getCommunication_subject(); + public String getCommunication_subject(); - public String getCommunication_inject(); + public String getCommunication_inject(); - public Set getCommunication_users(); + public Set getCommunication_users(); - public boolean getCommunication_ack(); + public boolean getCommunication_ack(); - public boolean getCommunication_animation(); + public boolean getCommunication_animation(); - public String getCommunication_from(); + public String getCommunication_from(); - public String getCommunication_to(); + public String getCommunication_to(); - public String getCommunication_exercise(); + public String getCommunication_exercise(); } diff --git a/openbas-model/src/main/java/io/openbas/database/raw/RawDocument.java b/openbas-model/src/main/java/io/openbas/database/raw/RawDocument.java index d0edfb14f9..f0d15b9f2c 100644 --- a/openbas-model/src/main/java/io/openbas/database/raw/RawDocument.java +++ b/openbas-model/src/main/java/io/openbas/database/raw/RawDocument.java @@ -4,12 +4,19 @@ public interface RawDocument { - String getDocument_id(); - String getDocument_name(); - String getDocument_description(); - String getDocument_type(); - String getDocument_target(); - List getDocument_tags(); - List getDocument_exercises(); - List getDocument_scenarios(); + String getDocument_id(); + + String getDocument_name(); + + String getDocument_description(); + + String getDocument_type(); + + String getDocument_target(); + + List getDocument_tags(); + + List getDocument_exercises(); + + List getDocument_scenarios(); } diff --git a/openbas-model/src/main/java/io/openbas/database/raw/RawEvaluation.java b/openbas-model/src/main/java/io/openbas/database/raw/RawEvaluation.java index e29fd532a2..6dd7b3ce18 100644 --- a/openbas-model/src/main/java/io/openbas/database/raw/RawEvaluation.java +++ b/openbas-model/src/main/java/io/openbas/database/raw/RawEvaluation.java @@ -1,7 +1,9 @@ package io.openbas.database.raw; public interface RawEvaluation { - String getEvaluation_id(); - long getEvaluation_score(); - String getEvaluation_objective(); + String getEvaluation_id(); + + long getEvaluation_score(); + + String getEvaluation_objective(); } diff --git a/openbas-model/src/main/java/io/openbas/database/raw/RawExercise.java b/openbas-model/src/main/java/io/openbas/database/raw/RawExercise.java index 7040c6a817..be00ad4bce 100644 --- a/openbas-model/src/main/java/io/openbas/database/raw/RawExercise.java +++ b/openbas-model/src/main/java/io/openbas/database/raw/RawExercise.java @@ -5,50 +5,71 @@ import java.util.Set; public interface RawExercise { - String getExercise_category(); + String getExercise_category(); - String getExercise_id(); + String getExercise_id(); - String getExercise_status(); + String getExercise_status(); - Instant getExercise_start_date(); + Instant getExercise_start_date(); - Instant getExercise_end_date(); + Instant getExercise_end_date(); - String getExercise_name(); + String getExercise_name(); - String getExercise_description(); + String getExercise_description(); - String getExercise_main_focus(); + String getExercise_main_focus(); - String getExercise_severity(); + String getExercise_severity(); - String getExercise_subtitle(); + String getExercise_subtitle(); - List getExercise_tags(); + List getExercise_tags(); - List getInject_ids(); + List getInject_ids(); - String getExercise_message_header(); - String getExercise_message_footer(); - String getExercise_mail_from(); - Set getExercise_reply_to(); - String getExercise_logo_dark(); - String getExercise_logo_light(); - boolean getExercise_lessons_anonymized(); - String getScenario_id(); - Instant getExercise_created_at(); - Instant getExercise_updated_at(); - Set getExercise_injects(); - Set getExercise_teams(); - Set getExercise_pauses(); - Instant getExercise_pause_date(); - Set getExercise_documents(); - Set getExercise_articles(); - Set getExercise_lessons_categories(); - Set getExercise_lessons_users(); - Set getExercise_users(); - Set getLessons_answers(); - Set getUsers(); - Set getLogs(); + String getExercise_message_header(); + + String getExercise_message_footer(); + + String getExercise_mail_from(); + + Set getExercise_reply_to(); + + String getExercise_logo_dark(); + + String getExercise_logo_light(); + + boolean getExercise_lessons_anonymized(); + + String getScenario_id(); + + Instant getExercise_created_at(); + + Instant getExercise_updated_at(); + + Set getExercise_injects(); + + Set getExercise_teams(); + + Set getExercise_pauses(); + + Instant getExercise_pause_date(); + + Set getExercise_documents(); + + Set getExercise_articles(); + + Set getExercise_lessons_categories(); + + Set getExercise_lessons_users(); + + Set getExercise_users(); + + Set getLessons_answers(); + + Set getUsers(); + + Set getLogs(); } diff --git a/openbas-model/src/main/java/io/openbas/database/raw/RawExerciseSimple.java b/openbas-model/src/main/java/io/openbas/database/raw/RawExerciseSimple.java index 34373298fb..78da223ec3 100644 --- a/openbas-model/src/main/java/io/openbas/database/raw/RawExerciseSimple.java +++ b/openbas-model/src/main/java/io/openbas/database/raw/RawExerciseSimple.java @@ -5,23 +5,23 @@ public interface RawExerciseSimple { - String getExercise_id(); + String getExercise_id(); - String getExercise_status(); + String getExercise_status(); - Instant getExercise_start_date(); + Instant getExercise_start_date(); - Instant getExercise_updated_at(); + Instant getExercise_updated_at(); - Instant getExercise_end_date(); + Instant getExercise_end_date(); - String getExercise_name(); + String getExercise_name(); - String getExercise_category(); + String getExercise_category(); - String getExercise_subtitle(); + String getExercise_subtitle(); - List getExercise_tags(); + List getExercise_tags(); - List getInject_ids(); + List getInject_ids(); } diff --git a/openbas-model/src/main/java/io/openbas/database/raw/RawExerciseTeamUser.java b/openbas-model/src/main/java/io/openbas/database/raw/RawExerciseTeamUser.java index 5d02089c47..a6639e11d4 100644 --- a/openbas-model/src/main/java/io/openbas/database/raw/RawExerciseTeamUser.java +++ b/openbas-model/src/main/java/io/openbas/database/raw/RawExerciseTeamUser.java @@ -2,9 +2,9 @@ public interface RawExerciseTeamUser { - public String getExercise_id(); + public String getExercise_id(); - public String getTeam_id(); + public String getTeam_id(); - public String getUser_id(); + public String getUser_id(); } diff --git a/openbas-model/src/main/java/io/openbas/database/raw/RawGlobalInjectExpectation.java b/openbas-model/src/main/java/io/openbas/database/raw/RawGlobalInjectExpectation.java index bdf025bbdb..f8f6881342 100644 --- a/openbas-model/src/main/java/io/openbas/database/raw/RawGlobalInjectExpectation.java +++ b/openbas-model/src/main/java/io/openbas/database/raw/RawGlobalInjectExpectation.java @@ -2,14 +2,13 @@ public interface RawGlobalInjectExpectation { - String getInject_expectation_type(); + String getInject_expectation_type(); - Double getInject_expectation_score(); + Double getInject_expectation_score(); - Double getInject_expectation_expected_score(); + Double getInject_expectation_expected_score(); - String getInject_title(); - - String getAttack_pattern_id(); + String getInject_title(); + String getAttack_pattern_id(); } diff --git a/openbas-model/src/main/java/io/openbas/database/raw/RawGrant.java b/openbas-model/src/main/java/io/openbas/database/raw/RawGrant.java index 3af48cd2e9..a80b4b2304 100644 --- a/openbas-model/src/main/java/io/openbas/database/raw/RawGrant.java +++ b/openbas-model/src/main/java/io/openbas/database/raw/RawGrant.java @@ -1,7 +1,9 @@ package io.openbas.database.raw; public interface RawGrant { - String getGrant_id(); - String getGrant_name(); - String getUser_id(); + String getGrant_id(); + + String getGrant_name(); + + String getUser_id(); } diff --git a/openbas-model/src/main/java/io/openbas/database/raw/RawInject.java b/openbas-model/src/main/java/io/openbas/database/raw/RawInject.java index 29be14297b..c5f67c2dfe 100644 --- a/openbas-model/src/main/java/io/openbas/database/raw/RawInject.java +++ b/openbas-model/src/main/java/io/openbas/database/raw/RawInject.java @@ -5,26 +5,25 @@ public interface RawInject { - String getInject_id(); + String getInject_id(); - String getAsset_group_id(); + String getAsset_group_id(); - List getInject_teams(); + List getInject_teams(); - List getInject_assets(); + List getInject_assets(); - List getInject_asset_groups(); + List getInject_asset_groups(); - List getInject_expectations(); + List getInject_expectations(); - Set getInject_communications(); + Set getInject_communications(); - Set getInject_platforms(); + Set getInject_platforms(); - Set getInject_kill_chain_phases(); + Set getInject_kill_chain_phases(); - String getStatus_name(); - - String getInject_scenario(); + String getStatus_name(); + String getInject_scenario(); } diff --git a/openbas-model/src/main/java/io/openbas/database/raw/RawInjectExpectation.java b/openbas-model/src/main/java/io/openbas/database/raw/RawInjectExpectation.java index 0a4e76fa5c..bcf81422ff 100644 --- a/openbas-model/src/main/java/io/openbas/database/raw/RawInjectExpectation.java +++ b/openbas-model/src/main/java/io/openbas/database/raw/RawInjectExpectation.java @@ -23,5 +23,4 @@ public interface RawInjectExpectation { String getInject_id(); Boolean getInject_expectation_group(); - } diff --git a/openbas-model/src/main/java/io/openbas/database/raw/RawInjectorsContrats.java b/openbas-model/src/main/java/io/openbas/database/raw/RawInjectorsContrats.java index 72cbf8e82c..2406c2fd3a 100644 --- a/openbas-model/src/main/java/io/openbas/database/raw/RawInjectorsContrats.java +++ b/openbas-model/src/main/java/io/openbas/database/raw/RawInjectorsContrats.java @@ -3,6 +3,7 @@ import java.util.List; public interface RawInjectorsContrats { - String getInjector_contract_id(); - List getInjector_contract_attack_patterns_external_id(); + String getInjector_contract_id(); + + List getInjector_contract_attack_patterns_external_id(); } diff --git a/openbas-model/src/main/java/io/openbas/database/raw/RawObjective.java b/openbas-model/src/main/java/io/openbas/database/raw/RawObjective.java index 0f29efc158..9e31dc8fee 100644 --- a/openbas-model/src/main/java/io/openbas/database/raw/RawObjective.java +++ b/openbas-model/src/main/java/io/openbas/database/raw/RawObjective.java @@ -2,7 +2,7 @@ public interface RawObjective { - public String getObjective_id(); - public String getObjective_exercise(); + public String getObjective_id(); + public String getObjective_exercise(); } diff --git a/openbas-model/src/main/java/io/openbas/database/raw/RawOrganization.java b/openbas-model/src/main/java/io/openbas/database/raw/RawOrganization.java index a585bf7664..7c8eb12c7f 100644 --- a/openbas-model/src/main/java/io/openbas/database/raw/RawOrganization.java +++ b/openbas-model/src/main/java/io/openbas/database/raw/RawOrganization.java @@ -4,12 +4,19 @@ @SuppressWarnings("unused") public interface RawOrganization { - String getOrganization_id(); - String getOrganization_name(); - String getOrganization_description(); - String getOrganization_created_at(); - String getOrganization_updated_at(); - List getOrganization_tags(); - List getOrganization_injects(); - long getOrganization_injects_number(); + String getOrganization_id(); + + String getOrganization_name(); + + String getOrganization_description(); + + String getOrganization_created_at(); + + String getOrganization_updated_at(); + + List getOrganization_tags(); + + List getOrganization_injects(); + + long getOrganization_injects_number(); } diff --git a/openbas-model/src/main/java/io/openbas/database/raw/RawPaginationDocument.java b/openbas-model/src/main/java/io/openbas/database/raw/RawPaginationDocument.java index 92cdc8b63d..2b1b72c980 100644 --- a/openbas-model/src/main/java/io/openbas/database/raw/RawPaginationDocument.java +++ b/openbas-model/src/main/java/io/openbas/database/raw/RawPaginationDocument.java @@ -4,9 +4,8 @@ import io.openbas.database.model.Exercise; import io.openbas.database.model.Scenario; import io.openbas.database.model.Tag; -import lombok.Data; - import java.util.List; +import lombok.Data; @Data public class RawPaginationDocument { diff --git a/openbas-model/src/main/java/io/openbas/database/raw/RawPaginationImportMapper.java b/openbas-model/src/main/java/io/openbas/database/raw/RawPaginationImportMapper.java index ca8da14c36..738d017ca0 100644 --- a/openbas-model/src/main/java/io/openbas/database/raw/RawPaginationImportMapper.java +++ b/openbas-model/src/main/java/io/openbas/database/raw/RawPaginationImportMapper.java @@ -2,23 +2,21 @@ import io.openbas.database.model.ImportMapper; import jakarta.validation.constraints.NotBlank; -import lombok.Data; - import java.time.Instant; +import lombok.Data; @Data public class RawPaginationImportMapper { - @NotBlank - String import_mapper_id; - String import_mapper_name; - Instant import_mapper_created_at; - Instant import_mapper_updated_at; + @NotBlank String import_mapper_id; + String import_mapper_name; + Instant import_mapper_created_at; + Instant import_mapper_updated_at; - public RawPaginationImportMapper(final ImportMapper importMapper) { - this.import_mapper_id = importMapper.getId(); - this.import_mapper_name = importMapper.getName(); - this.import_mapper_created_at = importMapper.getCreationDate(); - this.import_mapper_updated_at = importMapper.getUpdateDate(); - } + public RawPaginationImportMapper(final ImportMapper importMapper) { + this.import_mapper_id = importMapper.getId(); + this.import_mapper_name = importMapper.getName(); + this.import_mapper_created_at = importMapper.getCreationDate(); + this.import_mapper_updated_at = importMapper.getUpdateDate(); + } } diff --git a/openbas-model/src/main/java/io/openbas/database/raw/RawPaginationPlayer.java b/openbas-model/src/main/java/io/openbas/database/raw/RawPaginationPlayer.java index c4867bbc8a..08e7c60192 100644 --- a/openbas-model/src/main/java/io/openbas/database/raw/RawPaginationPlayer.java +++ b/openbas-model/src/main/java/io/openbas/database/raw/RawPaginationPlayer.java @@ -1,13 +1,12 @@ package io.openbas.database.raw; +import static java.util.Optional.ofNullable; + import io.openbas.database.model.Organization; import io.openbas.database.model.Tag; import io.openbas.database.model.User; -import lombok.Data; - import java.util.List; - -import static java.util.Optional.ofNullable; +import lombok.Data; @Data public class RawPaginationPlayer { @@ -32,7 +31,8 @@ public RawPaginationPlayer(final User user) { this.user_phone2 = user.getPhone2(); this.user_country = user.getCountry(); this.user_pgp_key = user.getPgpKey(); - this.user_organization = ofNullable(user.getOrganization()).map(Organization::getId).orElse(null); + this.user_organization = + ofNullable(user.getOrganization()).map(Organization::getId).orElse(null); this.user_tags = user.getTags().stream().map(Tag::getId).toList(); } } diff --git a/openbas-model/src/main/java/io/openbas/database/raw/RawPaginationScenario.java b/openbas-model/src/main/java/io/openbas/database/raw/RawPaginationScenario.java index f23b6f6af4..01d60670a9 100644 --- a/openbas-model/src/main/java/io/openbas/database/raw/RawPaginationScenario.java +++ b/openbas-model/src/main/java/io/openbas/database/raw/RawPaginationScenario.java @@ -1,12 +1,11 @@ package io.openbas.database.raw; import io.openbas.database.model.Scenario.SEVERITY; -import lombok.Data; - import java.time.Instant; import java.util.Arrays; import java.util.HashSet; import java.util.Set; +import lombok.Data; @Data public class RawPaginationScenario { @@ -28,8 +27,7 @@ public RawPaginationScenario( String recurrence, Instant updatedAt, String[] tags, - String[] platforms - ) { + String[] platforms) { this.scenario_id = id; this.scenario_name = name; this.scenario_severity = severity; @@ -37,7 +35,7 @@ public RawPaginationScenario( this.scenario_recurrence = recurrence; this.scenario_updated_at = updatedAt; this.scenario_tags = tags != null ? new HashSet<>(Arrays.asList(tags)) : new HashSet<>(); - this.scenario_platforms = platforms != null ? new HashSet<>(Arrays.asList(platforms)) : new HashSet<>(); + this.scenario_platforms = + platforms != null ? new HashSet<>(Arrays.asList(platforms)) : new HashSet<>(); } - } diff --git a/openbas-model/src/main/java/io/openbas/database/raw/RawPause.java b/openbas-model/src/main/java/io/openbas/database/raw/RawPause.java index 4c5648f7e1..4abe10a145 100644 --- a/openbas-model/src/main/java/io/openbas/database/raw/RawPause.java +++ b/openbas-model/src/main/java/io/openbas/database/raw/RawPause.java @@ -3,8 +3,11 @@ import java.time.Instant; public interface RawPause { - String getPause_id(); - String getPause_exercise(); - Instant getPause_date(); - long getPause_duration(); + String getPause_id(); + + String getPause_exercise(); + + Instant getPause_date(); + + long getPause_duration(); } diff --git a/openbas-model/src/main/java/io/openbas/database/raw/RawPlayer.java b/openbas-model/src/main/java/io/openbas/database/raw/RawPlayer.java index 8b9f413da2..2045ec755a 100644 --- a/openbas-model/src/main/java/io/openbas/database/raw/RawPlayer.java +++ b/openbas-model/src/main/java/io/openbas/database/raw/RawPlayer.java @@ -1,24 +1,23 @@ package io.openbas.database.raw; import io.openbas.helper.UserHelper; - import java.util.List; public interface RawPlayer { - default String getUser_gravatar() { - return UserHelper.getGravatar(getUser_email()); - } + default String getUser_gravatar() { + return UserHelper.getGravatar(getUser_email()); + } - String getUser_id(); + String getUser_id(); - String getUser_firstname(); + String getUser_firstname(); - String getUser_lastname(); + String getUser_lastname(); - String getUser_email(); + String getUser_email(); - String getUser_organization(); + String getUser_organization(); - List getUser_tags(); + List getUser_tags(); } diff --git a/openbas-model/src/main/java/io/openbas/database/raw/RawScenario.java b/openbas-model/src/main/java/io/openbas/database/raw/RawScenario.java index b73a2e467e..f78e284035 100644 --- a/openbas-model/src/main/java/io/openbas/database/raw/RawScenario.java +++ b/openbas-model/src/main/java/io/openbas/database/raw/RawScenario.java @@ -4,10 +4,13 @@ public interface RawScenario { - public String getScenario_id(); - public String getScenario_name(); - public String getScenario_subtitle(); - public Set getScenario_tags(); - public Set getScenario_injects(); + public String getScenario_id(); + public String getScenario_name(); + + public String getScenario_subtitle(); + + public Set getScenario_tags(); + + public Set getScenario_injects(); } diff --git a/openbas-model/src/main/java/io/openbas/database/raw/impl/SimpleRawInjectExpectation.java b/openbas-model/src/main/java/io/openbas/database/raw/impl/SimpleRawInjectExpectation.java index 87c3aae581..45f8db7d89 100644 --- a/openbas-model/src/main/java/io/openbas/database/raw/impl/SimpleRawInjectExpectation.java +++ b/openbas-model/src/main/java/io/openbas/database/raw/impl/SimpleRawInjectExpectation.java @@ -1,33 +1,31 @@ package io.openbas.database.raw.impl; import io.openbas.database.raw.RawInjectExpectation; +import java.util.List; import lombok.Getter; import lombok.Setter; -import java.util.List; - @Getter @Setter public class SimpleRawInjectExpectation implements RawInjectExpectation { - private String inject_expectation_id; - private String inject_expectation_type; - private Double inject_expectation_score; - private Double inject_expectation_expected_score; - private String team_id; - private String team_name; - private String user_id; - private String user_firstname; - private String user_lastname; - private String asset_id; - private String asset_name; - private String asset_type; - private String endpoint_platform; - private String asset_group_id; - private String asset_group_name; - private List asset_ids; - private String exercise_id; - private String inject_id; - private Boolean inject_expectation_group; - + private String inject_expectation_id; + private String inject_expectation_type; + private Double inject_expectation_score; + private Double inject_expectation_expected_score; + private String team_id; + private String team_name; + private String user_id; + private String user_firstname; + private String user_lastname; + private String asset_id; + private String asset_name; + private String asset_type; + private String endpoint_platform; + private String asset_group_id; + private String asset_group_name; + private List asset_ids; + private String exercise_id; + private String inject_id; + private Boolean inject_expectation_group; } diff --git a/openbas-model/src/main/java/io/openbas/database/repository/ArticleRepository.java b/openbas-model/src/main/java/io/openbas/database/repository/ArticleRepository.java index 65145ed0f9..905fef779d 100644 --- a/openbas-model/src/main/java/io/openbas/database/repository/ArticleRepository.java +++ b/openbas-model/src/main/java/io/openbas/database/repository/ArticleRepository.java @@ -1,16 +1,16 @@ package io.openbas.database.repository; import io.openbas.database.model.Article; +import jakarta.validation.constraints.NotNull; +import java.util.Optional; import org.springframework.data.jpa.repository.JpaSpecificationExecutor; import org.springframework.data.repository.CrudRepository; import org.springframework.stereotype.Repository; -import jakarta.validation.constraints.NotNull; -import java.util.Optional; - @Repository -public interface ArticleRepository extends CrudRepository, JpaSpecificationExecutor
{ +public interface ArticleRepository + extends CrudRepository, JpaSpecificationExecutor
{ - @NotNull - Optional
findById(@NotNull String id); + @NotNull + Optional
findById(@NotNull String id); } diff --git a/openbas-model/src/main/java/io/openbas/database/repository/AssetAgentJobRepository.java b/openbas-model/src/main/java/io/openbas/database/repository/AssetAgentJobRepository.java index 38797c45d3..3595958e8a 100644 --- a/openbas-model/src/main/java/io/openbas/database/repository/AssetAgentJobRepository.java +++ b/openbas-model/src/main/java/io/openbas/database/repository/AssetAgentJobRepository.java @@ -2,15 +2,15 @@ import io.openbas.database.model.AssetAgentJob; import jakarta.validation.constraints.NotNull; +import java.util.Optional; import org.springframework.data.jpa.repository.JpaSpecificationExecutor; import org.springframework.data.repository.CrudRepository; import org.springframework.stereotype.Repository; -import java.util.Optional; - @Repository -public interface AssetAgentJobRepository extends CrudRepository, JpaSpecificationExecutor { +public interface AssetAgentJobRepository + extends CrudRepository, JpaSpecificationExecutor { - @NotNull - Optional findById(@NotNull String id); + @NotNull + Optional findById(@NotNull String id); } diff --git a/openbas-model/src/main/java/io/openbas/database/repository/AssetGroupRepository.java b/openbas-model/src/main/java/io/openbas/database/repository/AssetGroupRepository.java index b3c0e586fa..efdc450b7d 100644 --- a/openbas-model/src/main/java/io/openbas/database/repository/AssetGroupRepository.java +++ b/openbas-model/src/main/java/io/openbas/database/repository/AssetGroupRepository.java @@ -1,33 +1,34 @@ package io.openbas.database.repository; import io.openbas.database.model.AssetGroup; +import io.openbas.database.raw.RawAssetGroup; +import java.time.Instant; +import java.util.List; import org.jetbrains.annotations.NotNull; import org.springframework.data.domain.Page; import org.springframework.data.domain.Pageable; import org.springframework.data.jpa.domain.Specification; import org.springframework.data.jpa.repository.EntityGraph; -import io.openbas.database.raw.RawAssetGroup; import org.springframework.data.jpa.repository.JpaSpecificationExecutor; import org.springframework.data.jpa.repository.Query; import org.springframework.data.repository.CrudRepository; import org.springframework.data.repository.query.Param; import org.springframework.stereotype.Repository; -import java.time.Instant; -import java.util.List; - @Repository -public interface AssetGroupRepository extends CrudRepository, - StatisticRepository, - JpaSpecificationExecutor { +public interface AssetGroupRepository + extends CrudRepository, + StatisticRepository, + JpaSpecificationExecutor { @Override - @Query("select COUNT(DISTINCT ag) from Inject i " + - "join i.assetGroups as ag " + - "join i.exercise as e " + - "join e.grants as grant " + - "join grant.group.users as user " + - "where user.id = :userId and i.createdAt < :creationDate") + @Query( + "select COUNT(DISTINCT ag) from Inject i " + + "join i.assetGroups as ag " + + "join i.exercise as e " + + "join e.grants as grant " + + "join grant.group.users as user " + + "where user.id = :userId and i.createdAt < :creationDate") long userCount(@Param("userId") String userId, @Param("creationDate") Instant creationDate); @Override @@ -40,24 +41,30 @@ public interface AssetGroupRepository extends CrudRepository * @param ids a list of ids * @return the list of raw asset group */ - @Query(value = "SELECT ag.asset_group_id, ag.asset_group_name, CAST(ag.asset_group_dynamic_filter as text), " + - "coalesce(array_agg(aga.asset_id) FILTER ( WHERE aga.asset_id IS NOT NULL ), '{}') asset_ids " + - "FROM asset_groups ag " + - "LEFT JOIN asset_groups_assets aga ON ag.asset_group_id = aga.asset_group_id " + - "WHERE ag.asset_group_id IN :ids " + - "GROUP BY ag.asset_group_id;", nativeQuery = true) + @Query( + value = + "SELECT ag.asset_group_id, ag.asset_group_name, CAST(ag.asset_group_dynamic_filter as text), " + + "coalesce(array_agg(aga.asset_id) FILTER ( WHERE aga.asset_id IS NOT NULL ), '{}') asset_ids " + + "FROM asset_groups ag " + + "LEFT JOIN asset_groups_assets aga ON ag.asset_group_id = aga.asset_group_id " + + "WHERE ag.asset_group_id IN :ids " + + "GROUP BY ag.asset_group_id;", + nativeQuery = true) List rawAssetGroupByIds(@Param("ids") List ids); - - @Query(value = - "SELECT ag.asset_group_id, ag.asset_group_name, CAST(ag.asset_group_dynamic_filter as text), " + - "coalesce(array_agg(aga.asset_id) FILTER ( WHERE aga.asset_id IS NOT NULL ), '{}') asset_ids " + - "FROM asset_groups ag " + - "LEFT JOIN injects_asset_groups iat ON ag.asset_group_id = iat.asset_group_id " + - "LEFT JOIN asset_groups_assets aga ON aga.asset_group_id = ag.asset_group_id " + - "WHERE iat.asset_group_id IN (:assetGroupIds) OR iat.inject_id IN (:injectIds) " + - "GROUP BY ag.asset_group_id, ag.asset_group_name, CAST(ag.asset_group_dynamic_filter as text) ;", nativeQuery = true) - List rawByIdsOrInjectIds(@Param("assetGroupIds") List assetGroupIds, @Param("injectIds") List injectIds); + @Query( + value = + "SELECT ag.asset_group_id, ag.asset_group_name, CAST(ag.asset_group_dynamic_filter as text), " + + "coalesce(array_agg(aga.asset_id) FILTER ( WHERE aga.asset_id IS NOT NULL ), '{}') asset_ids " + + "FROM asset_groups ag " + + "LEFT JOIN injects_asset_groups iat ON ag.asset_group_id = iat.asset_group_id " + + "LEFT JOIN asset_groups_assets aga ON aga.asset_group_id = ag.asset_group_id " + + "WHERE iat.asset_group_id IN (:assetGroupIds) OR iat.inject_id IN (:injectIds) " + + "GROUP BY ag.asset_group_id, ag.asset_group_name, CAST(ag.asset_group_dynamic_filter as text) ;", + nativeQuery = true) + List rawByIdsOrInjectIds( + @Param("assetGroupIds") List assetGroupIds, + @Param("injectIds") List injectIds); // -- PAGINATION -- diff --git a/openbas-model/src/main/java/io/openbas/database/repository/AssetRepository.java b/openbas-model/src/main/java/io/openbas/database/repository/AssetRepository.java index 699b29f957..1ba027b27d 100644 --- a/openbas-model/src/main/java/io/openbas/database/repository/AssetRepository.java +++ b/openbas-model/src/main/java/io/openbas/database/repository/AssetRepository.java @@ -2,16 +2,16 @@ import io.openbas.database.model.Asset; import io.openbas.database.raw.RawAsset; +import java.util.List; import org.springframework.data.jpa.repository.JpaSpecificationExecutor; import org.springframework.data.jpa.repository.Query; import org.springframework.data.repository.CrudRepository; import org.springframework.data.repository.query.Param; import org.springframework.stereotype.Repository; -import java.util.List; - @Repository -public interface AssetRepository extends CrudRepository, JpaSpecificationExecutor { +public interface AssetRepository + extends CrudRepository, JpaSpecificationExecutor { @Query("select a from Asset a where a.type IN :types") List findByType(@Param("types") final List types); @@ -22,15 +22,21 @@ public interface AssetRepository extends CrudRepository, JpaSpeci * @param ids the ids * @return the list of raw assets */ - @Query(value = "SELECT asset_id, asset_name, asset_type, endpoint_platform " + - "FROM assets " + - "WHERE asset_id IN :ids ;", nativeQuery = true) + @Query( + value = + "SELECT asset_id, asset_name, asset_type, endpoint_platform " + + "FROM assets " + + "WHERE asset_id IN :ids ;", + nativeQuery = true) List rawByIds(@Param("ids") List ids); - @Query(value = "SELECT DISTINCT a.asset_id, a.asset_name, a.asset_type, a.endpoint_platform " + - "FROM assets a " + - "LEFT JOIN injects_assets ia ON a.asset_id = ia.asset_id " + - "WHERE a.asset_id IN (:assetIds) OR ia.inject_id IN (:injectIds) ;", nativeQuery = true) - List rawByIdsOrInjectIds(@Param("assetIds") List assetIds, @Param("injectIds") List injectIds); + @Query( + value = + "SELECT DISTINCT a.asset_id, a.asset_name, a.asset_type, a.endpoint_platform " + + "FROM assets a " + + "LEFT JOIN injects_assets ia ON a.asset_id = ia.asset_id " + + "WHERE a.asset_id IN (:assetIds) OR ia.inject_id IN (:injectIds) ;", + nativeQuery = true) + List rawByIdsOrInjectIds( + @Param("assetIds") List assetIds, @Param("injectIds") List injectIds); } - diff --git a/openbas-model/src/main/java/io/openbas/database/repository/AttackPatternRepository.java b/openbas-model/src/main/java/io/openbas/database/repository/AttackPatternRepository.java index 033bcf671e..67756c4adb 100644 --- a/openbas-model/src/main/java/io/openbas/database/repository/AttackPatternRepository.java +++ b/openbas-model/src/main/java/io/openbas/database/repository/AttackPatternRepository.java @@ -3,16 +3,16 @@ import io.openbas.database.model.AttackPattern; import io.openbas.database.raw.RawAttackPattern; import jakarta.validation.constraints.NotNull; +import java.util.List; +import java.util.Optional; import org.springframework.data.jpa.repository.JpaSpecificationExecutor; import org.springframework.data.jpa.repository.Query; import org.springframework.data.repository.CrudRepository; import org.springframework.stereotype.Repository; -import java.util.List; -import java.util.Optional; - @Repository -public interface AttackPatternRepository extends CrudRepository, JpaSpecificationExecutor { +public interface AttackPatternRepository + extends CrudRepository, JpaSpecificationExecutor { @NotNull Optional findById(@NotNull String id); @@ -23,7 +23,10 @@ public interface AttackPatternRepository extends CrudRepository findByStixId(@NotNull String stixId); - @Query(value = "select ap.*, array_remove(array_agg(apphase.phase_id), NULL) as attack_pattern_kill_chain_phases from attack_patterns ap " + - "left join attack_patterns_kill_chain_phases apphase ON ap.attack_pattern_id = apphase.attack_pattern_id GROUP BY ap.attack_pattern_id", nativeQuery = true) + @Query( + value = + "select ap.*, array_remove(array_agg(apphase.phase_id), NULL) as attack_pattern_kill_chain_phases from attack_patterns ap " + + "left join attack_patterns_kill_chain_phases apphase ON ap.attack_pattern_id = apphase.attack_pattern_id GROUP BY ap.attack_pattern_id", + nativeQuery = true) List rawAll(); } diff --git a/openbas-model/src/main/java/io/openbas/database/repository/ChallengeFlagRepository.java b/openbas-model/src/main/java/io/openbas/database/repository/ChallengeFlagRepository.java index 87cac1914e..cce069bdb8 100644 --- a/openbas-model/src/main/java/io/openbas/database/repository/ChallengeFlagRepository.java +++ b/openbas-model/src/main/java/io/openbas/database/repository/ChallengeFlagRepository.java @@ -1,16 +1,16 @@ package io.openbas.database.repository; import io.openbas.database.model.ChallengeFlag; +import jakarta.validation.constraints.NotNull; +import java.util.Optional; import org.springframework.data.jpa.repository.JpaSpecificationExecutor; import org.springframework.data.repository.CrudRepository; import org.springframework.stereotype.Repository; -import jakarta.validation.constraints.NotNull; -import java.util.Optional; - @Repository -public interface ChallengeFlagRepository extends CrudRepository, JpaSpecificationExecutor { +public interface ChallengeFlagRepository + extends CrudRepository, JpaSpecificationExecutor { - @NotNull - Optional findById(@NotNull String id); + @NotNull + Optional findById(@NotNull String id); } diff --git a/openbas-model/src/main/java/io/openbas/database/repository/ChallengeRepository.java b/openbas-model/src/main/java/io/openbas/database/repository/ChallengeRepository.java index b6150b155f..2b9bb3390e 100644 --- a/openbas-model/src/main/java/io/openbas/database/repository/ChallengeRepository.java +++ b/openbas-model/src/main/java/io/openbas/database/repository/ChallengeRepository.java @@ -1,16 +1,16 @@ package io.openbas.database.repository; import io.openbas.database.model.Challenge; +import java.util.List; +import java.util.Optional; import org.jetbrains.annotations.NotNull; import org.springframework.data.jpa.repository.JpaSpecificationExecutor; import org.springframework.data.repository.CrudRepository; import org.springframework.stereotype.Repository; -import java.util.List; -import java.util.Optional; - @Repository -public interface ChallengeRepository extends CrudRepository, JpaSpecificationExecutor { +public interface ChallengeRepository + extends CrudRepository, JpaSpecificationExecutor { @NotNull Optional findById(@NotNull final String id); diff --git a/openbas-model/src/main/java/io/openbas/database/repository/ChannelRepository.java b/openbas-model/src/main/java/io/openbas/database/repository/ChannelRepository.java index a7faaca660..b939c949e2 100644 --- a/openbas-model/src/main/java/io/openbas/database/repository/ChannelRepository.java +++ b/openbas-model/src/main/java/io/openbas/database/repository/ChannelRepository.java @@ -1,18 +1,19 @@ package io.openbas.database.repository; import io.openbas.database.model.Channel; -import org.springframework.data.jpa.repository.JpaSpecificationExecutor; -import org.springframework.data.repository.CrudRepository; -import org.springframework.stereotype.Repository; - import jakarta.validation.constraints.NotNull; import java.util.List; import java.util.Optional; +import org.springframework.data.jpa.repository.JpaSpecificationExecutor; +import org.springframework.data.repository.CrudRepository; +import org.springframework.stereotype.Repository; @Repository -public interface ChannelRepository extends CrudRepository, JpaSpecificationExecutor { +public interface ChannelRepository + extends CrudRepository, JpaSpecificationExecutor { - @NotNull Optional findById(@NotNull String id); + @NotNull + Optional findById(@NotNull String id); - List findByNameIgnoreCase(String name); + List findByNameIgnoreCase(String name); } diff --git a/openbas-model/src/main/java/io/openbas/database/repository/CollectorRepository.java b/openbas-model/src/main/java/io/openbas/database/repository/CollectorRepository.java index dc05853bd8..8ef2152905 100644 --- a/openbas-model/src/main/java/io/openbas/database/repository/CollectorRepository.java +++ b/openbas-model/src/main/java/io/openbas/database/repository/CollectorRepository.java @@ -2,17 +2,16 @@ import io.openbas.database.model.Collector; import jakarta.validation.constraints.NotNull; +import java.util.Optional; import org.springframework.data.repository.CrudRepository; import org.springframework.stereotype.Repository; -import java.util.Optional; - @Repository public interface CollectorRepository extends CrudRepository { - @NotNull - Optional findById(@NotNull String id); + @NotNull + Optional findById(@NotNull String id); - @NotNull - Optional findByType(@NotNull String type); + @NotNull + Optional findByType(@NotNull String type); } diff --git a/openbas-model/src/main/java/io/openbas/database/repository/ComcheckRepository.java b/openbas-model/src/main/java/io/openbas/database/repository/ComcheckRepository.java index 73d012053b..1128563a22 100644 --- a/openbas-model/src/main/java/io/openbas/database/repository/ComcheckRepository.java +++ b/openbas-model/src/main/java/io/openbas/database/repository/ComcheckRepository.java @@ -2,22 +2,22 @@ import io.openbas.database.model.Comcheck; import jakarta.validation.constraints.NotNull; +import java.time.Instant; +import java.util.List; +import java.util.Optional; import org.springframework.data.jpa.repository.JpaSpecificationExecutor; import org.springframework.data.jpa.repository.Query; import org.springframework.data.repository.CrudRepository; import org.springframework.data.repository.query.Param; import org.springframework.stereotype.Repository; -import java.time.Instant; -import java.util.List; -import java.util.Optional; - @Repository -public interface ComcheckRepository extends CrudRepository, JpaSpecificationExecutor { +public interface ComcheckRepository + extends CrudRepository, JpaSpecificationExecutor { - @NotNull - Optional findById(@NotNull String id); + @NotNull + Optional findById(@NotNull String id); - @Query(value = "select c from Comcheck c where c.state = 'RUNNING' and c.end <= :expirationDate") - List thatMustBeExpired(@Param("expirationDate") Instant expirationDate); + @Query(value = "select c from Comcheck c where c.state = 'RUNNING' and c.end <= :expirationDate") + List thatMustBeExpired(@Param("expirationDate") Instant expirationDate); } diff --git a/openbas-model/src/main/java/io/openbas/database/repository/ComcheckStatusRepository.java b/openbas-model/src/main/java/io/openbas/database/repository/ComcheckStatusRepository.java index 852648f026..e670532394 100644 --- a/openbas-model/src/main/java/io/openbas/database/repository/ComcheckStatusRepository.java +++ b/openbas-model/src/main/java/io/openbas/database/repository/ComcheckStatusRepository.java @@ -2,15 +2,15 @@ import io.openbas.database.model.ComcheckStatus; import jakarta.validation.constraints.NotNull; +import java.util.Optional; import org.springframework.data.jpa.repository.JpaSpecificationExecutor; import org.springframework.data.repository.CrudRepository; import org.springframework.stereotype.Repository; -import java.util.Optional; - @Repository -public interface ComcheckStatusRepository extends CrudRepository, JpaSpecificationExecutor { +public interface ComcheckStatusRepository + extends CrudRepository, JpaSpecificationExecutor { - @NotNull - Optional findById(@NotNull String id); + @NotNull + Optional findById(@NotNull String id); } diff --git a/openbas-model/src/main/java/io/openbas/database/repository/CommunicationRepository.java b/openbas-model/src/main/java/io/openbas/database/repository/CommunicationRepository.java index baac1e6e76..70c0322c8c 100644 --- a/openbas-model/src/main/java/io/openbas/database/repository/CommunicationRepository.java +++ b/openbas-model/src/main/java/io/openbas/database/repository/CommunicationRepository.java @@ -3,34 +3,38 @@ import io.openbas.database.model.Communication; import io.openbas.database.raw.RawCommunication; import jakarta.validation.constraints.NotNull; +import java.util.List; +import java.util.Optional; import org.springframework.data.jpa.repository.JpaSpecificationExecutor; import org.springframework.data.jpa.repository.Query; import org.springframework.data.repository.CrudRepository; import org.springframework.data.repository.query.Param; import org.springframework.stereotype.Repository; -import java.util.List; -import java.util.Optional; - @Repository -public interface CommunicationRepository extends CrudRepository, JpaSpecificationExecutor { - - @NotNull - Optional findById(@NotNull String id); - - List findByInjectId(@NotNull String injectId); - - @Query("select c from Communication c join c.users as user where user.id = :userId order by c.receivedAt desc") - List findByUser(@Param("userId") String userId); - - boolean existsByIdentifier(String identifier); - - @Query(value = "SELECT c.*, injects.inject_exercise as communication_exercise, " + - "coalesce(array_agg(DISTINCT cu.user_id) FILTER ( WHERE cu.user_id IS NOT NULL ), '{}') as communication_users " + - "FROM communications c " + - "LEFT JOIN communications_users cu ON cu.communication_id = c.communication_id " + - "LEFT JOIN injects ON injects.inject_id = c.communication_inject " + - "WHERE c.communication_id IN :ids " + - "GROUP BY c.communication_id, injects.inject_exercise ;", nativeQuery = true) - List rawByIds(@Param("ids")List ids); +public interface CommunicationRepository + extends CrudRepository, JpaSpecificationExecutor { + + @NotNull + Optional findById(@NotNull String id); + + List findByInjectId(@NotNull String injectId); + + @Query( + "select c from Communication c join c.users as user where user.id = :userId order by c.receivedAt desc") + List findByUser(@Param("userId") String userId); + + boolean existsByIdentifier(String identifier); + + @Query( + value = + "SELECT c.*, injects.inject_exercise as communication_exercise, " + + "coalesce(array_agg(DISTINCT cu.user_id) FILTER ( WHERE cu.user_id IS NOT NULL ), '{}') as communication_users " + + "FROM communications c " + + "LEFT JOIN communications_users cu ON cu.communication_id = c.communication_id " + + "LEFT JOIN injects ON injects.inject_id = c.communication_inject " + + "WHERE c.communication_id IN :ids " + + "GROUP BY c.communication_id, injects.inject_exercise ;", + nativeQuery = true) + List rawByIds(@Param("ids") List ids); } diff --git a/openbas-model/src/main/java/io/openbas/database/repository/DocumentRepository.java b/openbas-model/src/main/java/io/openbas/database/repository/DocumentRepository.java index d6d2832132..b84b844b67 100644 --- a/openbas-model/src/main/java/io/openbas/database/repository/DocumentRepository.java +++ b/openbas-model/src/main/java/io/openbas/database/repository/DocumentRepository.java @@ -2,6 +2,8 @@ import io.openbas.database.model.Document; import io.openbas.database.raw.RawDocument; +import java.util.List; +import java.util.Optional; import org.jetbrains.annotations.NotNull; import org.springframework.data.domain.Page; import org.springframework.data.domain.Pageable; @@ -13,66 +15,73 @@ import org.springframework.data.repository.query.Param; import org.springframework.stereotype.Repository; -import java.util.List; -import java.util.Optional; - @Repository -public interface DocumentRepository extends CrudRepository, JpaSpecificationExecutor { +public interface DocumentRepository + extends CrudRepository, JpaSpecificationExecutor { + + @NotNull + Optional findById(@NotNull String id); - @NotNull - Optional findById(@NotNull String id); - List removeById(@NotNull String id); + List removeById(@NotNull String id); - @NotNull - Optional findByTarget(@NotNull String target); + @NotNull + Optional findByTarget(@NotNull String target); - @NotNull - Optional findByName(@NotNull String name); + @NotNull + Optional findByName(@NotNull String name); - @Query("select d from Document d " + - "join d.exercises as exercise " + - "join exercise.grants as grant " + - "join grant.group as g " + - "join g.users as user " + - "where d.id = :id and user.id = :userId") - Optional findByIdGranted(@Param("id") String documentId, @Param("userId") String userId); + @Query( + "select d from Document d " + + "join d.exercises as exercise " + + "join exercise.grants as grant " + + "join grant.group as g " + + "join g.users as user " + + "where d.id = :id and user.id = :userId") + Optional findByIdGranted( + @Param("id") String documentId, @Param("userId") String userId); - @Query(value = "select d.*, " + - "array_remove(array_agg(tg.tag_id), NULL) as document_tags, " + - "array_remove(array_agg(ex.exercise_id), NULL) as document_exercises, " + - "array_remove(array_agg(sc.scenario_id), NULL) as document_scenarios " + - "from documents d left join exercises_documents exdoc on d.document_id = exdoc.document_id " + - "left join exercises ex on ex.exercise_id = exdoc.exercise_id " + - "left join scenarios_documents scdoc on d.document_id = scdoc.document_id " + - "left join scenarios sc on sc.scenario_id = scdoc.scenario_id " + - "left join documents_tags tagdoc on d.document_id = tagdoc.document_id " + - "left join tags tg on tg.tag_id = tagdoc.tag_id " + - "group by d.document_id " + - "order by document_id desc ", nativeQuery = true ) - List rawAllDocuments(); + @Query( + value = + "select d.*, " + + "array_remove(array_agg(tg.tag_id), NULL) as document_tags, " + + "array_remove(array_agg(ex.exercise_id), NULL) as document_exercises, " + + "array_remove(array_agg(sc.scenario_id), NULL) as document_scenarios " + + "from documents d left join exercises_documents exdoc on d.document_id = exdoc.document_id " + + "left join exercises ex on ex.exercise_id = exdoc.exercise_id " + + "left join scenarios_documents scdoc on d.document_id = scdoc.document_id " + + "left join scenarios sc on sc.scenario_id = scdoc.scenario_id " + + "left join documents_tags tagdoc on d.document_id = tagdoc.document_id " + + "left join tags tg on tg.tag_id = tagdoc.tag_id " + + "group by d.document_id " + + "order by document_id desc ", + nativeQuery = true) + List rawAllDocuments(); - @Query(value = "select d.*, " + - "array_remove(array_agg(tg.tag_id), NULL) as document_tags, " + - "array_remove(array_agg(ex.exercise_id), NULL) as document_exercises, " + - "array_remove(array_agg(sc.scenario_id), NULL) as document_scenarios " + - "from documents d left join exercises_documents exdoc on d.document_id = exdoc.document_id " + - "left join exercises ex on ex.exercise_id = exdoc.exercise_id " + - "left join scenarios_documents scdoc on d.document_id = scdoc.document_id " + - "left join scenarios sc on sc.scenario_id = scdoc.scenario_id " + - "left join documents_tags tagdoc on d.document_id = tagdoc.document_id " + - "left join tags tg on tg.tag_id = tagdoc.tag_id " + - "left join grants grt on grt.grant_exercise = exdoc.exercise_id " + - "left join groups grp on grt.grant_group = grp.group_id " + - "left join users_groups usgrp on grp.group_id = usgrp.group_id " + - "left outer join users u on usgrp.user_id = u.user_id " + - "where u.user_id = :userId " + - "group by d.document_id " + - "order by d.document_id desc ", nativeQuery = true) - List rawAllDocumentsByAccessLevel(@Param("userId") String userId); + @Query( + value = + "select d.*, " + + "array_remove(array_agg(tg.tag_id), NULL) as document_tags, " + + "array_remove(array_agg(ex.exercise_id), NULL) as document_exercises, " + + "array_remove(array_agg(sc.scenario_id), NULL) as document_scenarios " + + "from documents d left join exercises_documents exdoc on d.document_id = exdoc.document_id " + + "left join exercises ex on ex.exercise_id = exdoc.exercise_id " + + "left join scenarios_documents scdoc on d.document_id = scdoc.document_id " + + "left join scenarios sc on sc.scenario_id = scdoc.scenario_id " + + "left join documents_tags tagdoc on d.document_id = tagdoc.document_id " + + "left join tags tg on tg.tag_id = tagdoc.tag_id " + + "left join grants grt on grt.grant_exercise = exdoc.exercise_id " + + "left join groups grp on grt.grant_group = grp.group_id " + + "left join users_groups usgrp on grp.group_id = usgrp.group_id " + + "left outer join users u on usgrp.user_id = u.user_id " + + "where u.user_id = :userId " + + "group by d.document_id " + + "order by d.document_id desc ", + nativeQuery = true) + List rawAllDocumentsByAccessLevel(@Param("userId") String userId); - // -- PAGINATION -- + // -- PAGINATION -- - @NotNull - @EntityGraph(value = "Document.tags-scenarios-exercises", type = EntityGraph.EntityGraphType.LOAD) - Page findAll(@NotNull Specification spec, @NotNull Pageable pageable); + @NotNull + @EntityGraph(value = "Document.tags-scenarios-exercises", type = EntityGraph.EntityGraphType.LOAD) + Page findAll(@NotNull Specification spec, @NotNull Pageable pageable); } diff --git a/openbas-model/src/main/java/io/openbas/database/repository/DryInjectReportingRepository.java b/openbas-model/src/main/java/io/openbas/database/repository/DryInjectReportingRepository.java index 55b6ef82f3..9d0cf61ff9 100644 --- a/openbas-model/src/main/java/io/openbas/database/repository/DryInjectReportingRepository.java +++ b/openbas-model/src/main/java/io/openbas/database/repository/DryInjectReportingRepository.java @@ -2,14 +2,13 @@ import io.openbas.database.model.DryInjectStatus; import jakarta.validation.constraints.NotNull; +import java.util.Optional; import org.springframework.data.repository.CrudRepository; import org.springframework.stereotype.Repository; -import java.util.Optional; - @Repository public interface DryInjectReportingRepository extends CrudRepository { - @NotNull - Optional findById(@NotNull String id); + @NotNull + Optional findById(@NotNull String id); } diff --git a/openbas-model/src/main/java/io/openbas/database/repository/DryInjectRepository.java b/openbas-model/src/main/java/io/openbas/database/repository/DryInjectRepository.java index 0d3d021a8b..ddb25c98ce 100644 --- a/openbas-model/src/main/java/io/openbas/database/repository/DryInjectRepository.java +++ b/openbas-model/src/main/java/io/openbas/database/repository/DryInjectRepository.java @@ -1,16 +1,16 @@ package io.openbas.database.repository; import io.openbas.database.model.DryInject; +import jakarta.validation.constraints.NotNull; +import java.util.Optional; import org.springframework.data.jpa.repository.JpaSpecificationExecutor; import org.springframework.data.repository.CrudRepository; import org.springframework.stereotype.Repository; -import jakarta.validation.constraints.NotNull; -import java.util.Optional; - @Repository -public interface DryInjectRepository extends CrudRepository, JpaSpecificationExecutor { +public interface DryInjectRepository + extends CrudRepository, JpaSpecificationExecutor { - @NotNull - Optional findById(@NotNull String id); + @NotNull + Optional findById(@NotNull String id); } diff --git a/openbas-model/src/main/java/io/openbas/database/repository/DryInjectStatusRepository.java b/openbas-model/src/main/java/io/openbas/database/repository/DryInjectStatusRepository.java index 1fffae5b66..7d25247e53 100644 --- a/openbas-model/src/main/java/io/openbas/database/repository/DryInjectStatusRepository.java +++ b/openbas-model/src/main/java/io/openbas/database/repository/DryInjectStatusRepository.java @@ -2,15 +2,15 @@ import io.openbas.database.model.DryInjectStatus; import jakarta.validation.constraints.NotNull; +import java.util.Optional; import org.springframework.data.jpa.repository.JpaSpecificationExecutor; import org.springframework.data.repository.CrudRepository; import org.springframework.stereotype.Repository; -import java.util.Optional; - @Repository -public interface DryInjectStatusRepository extends CrudRepository, JpaSpecificationExecutor { +public interface DryInjectStatusRepository + extends CrudRepository, JpaSpecificationExecutor { - @NotNull - Optional findById(@NotNull String id); + @NotNull + Optional findById(@NotNull String id); } diff --git a/openbas-model/src/main/java/io/openbas/database/repository/DryRunRepository.java b/openbas-model/src/main/java/io/openbas/database/repository/DryRunRepository.java index ceaa05cde4..560d0613fa 100644 --- a/openbas-model/src/main/java/io/openbas/database/repository/DryRunRepository.java +++ b/openbas-model/src/main/java/io/openbas/database/repository/DryRunRepository.java @@ -2,15 +2,15 @@ import io.openbas.database.model.Dryrun; import jakarta.validation.constraints.NotNull; +import java.util.Optional; import org.springframework.data.jpa.repository.JpaSpecificationExecutor; import org.springframework.data.repository.CrudRepository; import org.springframework.stereotype.Repository; -import java.util.Optional; - @Repository -public interface DryRunRepository extends CrudRepository, JpaSpecificationExecutor { +public interface DryRunRepository + extends CrudRepository, JpaSpecificationExecutor { - @NotNull - Optional findById(@NotNull String id); + @NotNull + Optional findById(@NotNull String id); } diff --git a/openbas-model/src/main/java/io/openbas/database/repository/EndpointRepository.java b/openbas-model/src/main/java/io/openbas/database/repository/EndpointRepository.java index 6a3733bcac..24b5c010aa 100644 --- a/openbas-model/src/main/java/io/openbas/database/repository/EndpointRepository.java +++ b/openbas-model/src/main/java/io/openbas/database/repository/EndpointRepository.java @@ -2,43 +2,51 @@ import io.openbas.database.model.Endpoint; import jakarta.validation.constraints.NotBlank; +import java.time.Instant; +import java.util.List; +import java.util.Optional; import org.springframework.data.jpa.repository.JpaSpecificationExecutor; import org.springframework.data.jpa.repository.Query; import org.springframework.data.repository.CrudRepository; import org.springframework.data.repository.query.Param; import org.springframework.stereotype.Repository; -import java.time.Instant; -import java.util.List; -import java.util.Optional; - @Repository -public interface EndpointRepository extends CrudRepository, - StatisticRepository, - JpaSpecificationExecutor { - - @Query(value = "select e.* from assets e where e.endpoint_hostname = :hostname", nativeQuery = true) +public interface EndpointRepository + extends CrudRepository, + StatisticRepository, + JpaSpecificationExecutor { + + @Query( + value = "select e.* from assets e where e.endpoint_hostname = :hostname", + nativeQuery = true) List findByHostname(@NotBlank final @Param("hostname") String hostname); - @Query(value = "select e.* from assets e where e.asset_parent is null and e.asset_inject is null and e.endpoint_hostname = :hostname", nativeQuery = true) + @Query( + value = + "select e.* from assets e where e.asset_parent is null and e.asset_inject is null and e.endpoint_hostname = :hostname", + nativeQuery = true) List findForInjectionByHostname(@NotBlank final @Param("hostname") String hostname); - @Query(value = "select e.* from assets e where e.asset_parent is not null or e.asset_inject is not null and e.endpoint_hostname = :hostname", nativeQuery = true) + @Query( + value = + "select e.* from assets e where e.asset_parent is not null or e.asset_inject is not null and e.endpoint_hostname = :hostname", + nativeQuery = true) List findForExecutionByHostname(@NotBlank final @Param("hostname") String hostname); Optional findByExternalReference(@Param("externalReference") String externalReference); @Override - @Query("select COUNT(DISTINCT a) from Inject i " + - "join i.assets as a " + - "join i.exercise as e " + - "join e.grants as grant " + - "join grant.group.users as user " + - "where user.id = :userId and i.createdAt < :creationDate") + @Query( + "select COUNT(DISTINCT a) from Inject i " + + "join i.assets as a " + + "join i.exercise as e " + + "join e.grants as grant " + + "join grant.group.users as user " + + "where user.id = :userId and i.createdAt < :creationDate") long userCount(@Param("userId") String userId, @Param("creationDate") Instant creationDate); @Override @Query("select count(distinct e) from Endpoint e where e.createdAt < :creationDate") long globalCount(@Param("creationDate") Instant creationDate); - } diff --git a/openbas-model/src/main/java/io/openbas/database/repository/EvaluationRepository.java b/openbas-model/src/main/java/io/openbas/database/repository/EvaluationRepository.java index 76ef105734..72c1aab081 100644 --- a/openbas-model/src/main/java/io/openbas/database/repository/EvaluationRepository.java +++ b/openbas-model/src/main/java/io/openbas/database/repository/EvaluationRepository.java @@ -3,21 +3,23 @@ import io.openbas.database.model.Evaluation; import io.openbas.database.raw.RawEvaluation; import jakarta.validation.constraints.NotNull; +import java.util.List; +import java.util.Optional; import org.springframework.data.jpa.repository.JpaSpecificationExecutor; import org.springframework.data.jpa.repository.Query; import org.springframework.data.repository.CrudRepository; import org.springframework.data.repository.query.Param; import org.springframework.stereotype.Repository; -import java.util.List; -import java.util.Optional; - @Repository -public interface EvaluationRepository extends CrudRepository, JpaSpecificationExecutor { +public interface EvaluationRepository + extends CrudRepository, JpaSpecificationExecutor { - @NotNull - Optional findById(@NotNull String id); + @NotNull + Optional findById(@NotNull String id); - @Query(value="SELECT * FROM evaluations WHERE evaluation_objective IN :ids ;", nativeQuery = true) - List rawByObjectiveIds(@Param("ids") List ids); + @Query( + value = "SELECT * FROM evaluations WHERE evaluation_objective IN :ids ;", + nativeQuery = true) + List rawByObjectiveIds(@Param("ids") List ids); } diff --git a/openbas-model/src/main/java/io/openbas/database/repository/ExecutorRepository.java b/openbas-model/src/main/java/io/openbas/database/repository/ExecutorRepository.java index feba5ad329..477bae2437 100644 --- a/openbas-model/src/main/java/io/openbas/database/repository/ExecutorRepository.java +++ b/openbas-model/src/main/java/io/openbas/database/repository/ExecutorRepository.java @@ -2,17 +2,16 @@ import io.openbas.database.model.Executor; import jakarta.validation.constraints.NotNull; +import java.util.Optional; import org.springframework.data.repository.CrudRepository; import org.springframework.stereotype.Repository; -import java.util.Optional; - @Repository public interface ExecutorRepository extends CrudRepository { - @NotNull - Optional findById(@NotNull String id); + @NotNull + Optional findById(@NotNull String id); - @NotNull - Optional findByType(@NotNull String type); + @NotNull + Optional findByType(@NotNull String type); } diff --git a/openbas-model/src/main/java/io/openbas/database/repository/ExerciseRepository.java b/openbas-model/src/main/java/io/openbas/database/repository/ExerciseRepository.java index 66b7b23e43..fa7081aad4 100644 --- a/openbas-model/src/main/java/io/openbas/database/repository/ExerciseRepository.java +++ b/openbas-model/src/main/java/io/openbas/database/repository/ExerciseRepository.java @@ -6,20 +6,20 @@ import io.openbas.database.raw.RawGlobalInjectExpectation; import io.openbas.database.raw.RawInjectExpectation; import jakarta.validation.constraints.NotNull; +import java.time.Instant; +import java.util.List; +import java.util.Optional; import org.springframework.data.jpa.repository.JpaSpecificationExecutor; import org.springframework.data.jpa.repository.Query; import org.springframework.data.repository.CrudRepository; import org.springframework.data.repository.query.Param; import org.springframework.stereotype.Repository; -import java.time.Instant; -import java.util.List; -import java.util.Optional; - @Repository -public interface ExerciseRepository extends CrudRepository, - StatisticRepository, - JpaSpecificationExecutor { +public interface ExerciseRepository + extends CrudRepository, + StatisticRepository, + JpaSpecificationExecutor { @NotNull Optional findById(@NotNull String id); @@ -27,29 +27,33 @@ public interface ExerciseRepository extends CrudRepository, @Query(value = "select e from Exercise e where e.status = 'SCHEDULED' and e.start <= :start") List findAllShouldBeInRunningState(@Param("start") Instant start); - @Query("select distinct e from Exercise e " + - "join e.grants as grant " + - "join grant.group.users as user " + - "where user.id = :userId") + @Query( + "select distinct e from Exercise e " + + "join e.grants as grant " + + "join grant.group.users as user " + + "where user.id = :userId") List findAllGranted(@Param("userId") String userId); @Override - @Query("select count(distinct e) from Exercise e " + - "join e.grants as grant " + - "join grant.group.users as user " + - "where user.id = :userId and e.createdAt < :creationDate") + @Query( + "select count(distinct e) from Exercise e " + + "join e.grants as grant " + + "join grant.group.users as user " + + "where user.id = :userId and e.createdAt < :creationDate") long userCount(@Param("userId") String userId, @Param("creationDate") Instant creationDate); @Override @Query("select count(distinct e) from Exercise e where e.createdAt < :creationDate") long globalCount(@Param("creationDate") Instant creationDate); - @Query(value = "select e.*, se.scenario_id from exercises e " + - "left join injects as inject on e.exercise_id = inject.inject_exercise " + - "left join injects_statuses as status on inject.inject_id = status.status_inject and status.status_name != 'PENDING'" - + - "left join scenarios_exercises as se on e.exercise_id = se.exercise_id " + - "where e.exercise_status = 'RUNNING' group by e.exercise_id, se.scenario_id having count(status) = count(inject);", nativeQuery = true) + @Query( + value = + "select e.*, se.scenario_id from exercises e " + + "left join injects as inject on e.exercise_id = inject.inject_exercise " + + "left join injects_statuses as status on inject.inject_id = status.status_inject and status.status_name != 'PENDING'" + + "left join scenarios_exercises as se on e.exercise_id = se.exercise_id " + + "where e.exercise_status = 'RUNNING' group by e.exercise_id, se.scenario_id having count(status) = count(inject);", + nativeQuery = true) List thatMustBeFinished(); /** @@ -58,35 +62,38 @@ public interface ExerciseRepository extends CrudRepository, * @param from the max date of creation * @return the list of expectations */ - @Query(value = - "SELECT " - + "ie.inject_expectation_type, ie.inject_expectation_group, ie.inject_expectation_score, ie.inject_expectation_expected_score " - + "FROM injects_expectations ie " - + "INNER JOIN injects ON ie.inject_id = injects.inject_id " - + "INNER JOIN exercises ON injects.inject_exercise = exercises.exercise_id " - + "WHERE exercises.exercise_created_at < :from ;", nativeQuery = true) + @Query( + value = + "SELECT " + + "ie.inject_expectation_type, ie.inject_expectation_group, ie.inject_expectation_score, ie.inject_expectation_expected_score " + + "FROM injects_expectations ie " + + "INNER JOIN injects ON ie.inject_id = injects.inject_id " + + "INNER JOIN exercises ON injects.inject_exercise = exercises.exercise_id " + + "WHERE exercises.exercise_created_at < :from ;", + nativeQuery = true) List allInjectExpectationsFromDate(@Param("from") Instant from); /** * Get all the expectations a user can see that were created before a date * - * @param from the max date of creation + * @param from the max date of creation * @param userId the id of the user * @return the list of expectations */ - @Query(value = - "SELECT ie.inject_expectation_type, ie.inject_expectation_group, ie.inject_expectation_score, ie.inject_expectation_expected_score " - + - "FROM injects_expectations ie " + - "INNER JOIN injects ON ie.inject_id = injects.inject_id " + - "INNER JOIN exercises e ON injects.inject_exercise = e.exercise_id " + - "INNER join grants ON grants.grant_exercise = e.exercise_id " + - "INNER join groups ON grants.grant_group = groups.group_id " + - "INNER JOIN users_groups ON groups.group_id = users_groups.group_id " + - "WHERE e.exercise_created_at < :from " + - "AND users_groups.user_id = :userId ;", nativeQuery = true) - List allGrantedInjectExpectationsFromDate(@Param("from") Instant from, - @Param("userId") String userId); + @Query( + value = + "SELECT ie.inject_expectation_type, ie.inject_expectation_group, ie.inject_expectation_score, ie.inject_expectation_expected_score " + + "FROM injects_expectations ie " + + "INNER JOIN injects ON ie.inject_id = injects.inject_id " + + "INNER JOIN exercises e ON injects.inject_exercise = e.exercise_id " + + "INNER join grants ON grants.grant_exercise = e.exercise_id " + + "INNER join groups ON grants.grant_group = groups.group_id " + + "INNER JOIN users_groups ON groups.group_id = users_groups.group_id " + + "WHERE e.exercise_created_at < :from " + + "AND users_groups.user_id = :userId ;", + nativeQuery = true) + List allGrantedInjectExpectationsFromDate( + @Param("from") Instant from, @Param("userId") String userId); /** * Returns the global expectations that were created before a date @@ -94,62 +101,65 @@ List allGrantedInjectExpectationsFromDate(@Param("from") I * @param from the date max of creation * @return a list of expectations */ - @Query(value = - "SELECT ie.inject_expectation_type, ie.inject_expectation_score, ie.inject_expectation_expected_score, injects.inject_title, icap.attack_pattern_id " - + - "FROM exercises " + - "INNER JOIN injects ON exercises.exercise_id = injects.inject_exercise " + - "LEFT JOIN injects_expectations ie ON injects.inject_id = ie.exercise_id " + - "INNER JOIN injectors_contracts ic ON injects.inject_injector_contract = ic.injector_contract_id " + - "INNER JOIN injectors_contracts_attack_patterns icap ON ic.injector_contract_id = icap.injector_contract_id " - + - "WHERE exercises.exercise_created_at < :from ;", nativeQuery = true) - Iterable rawGlobalInjectExpectationResultsFromDate(@Param("from") Instant from); + @Query( + value = + "SELECT ie.inject_expectation_type, ie.inject_expectation_score, ie.inject_expectation_expected_score, injects.inject_title, icap.attack_pattern_id " + + "FROM exercises " + + "INNER JOIN injects ON exercises.exercise_id = injects.inject_exercise " + + "LEFT JOIN injects_expectations ie ON injects.inject_id = ie.exercise_id " + + "INNER JOIN injectors_contracts ic ON injects.inject_injector_contract = ic.injector_contract_id " + + "INNER JOIN injectors_contracts_attack_patterns icap ON ic.injector_contract_id = icap.injector_contract_id " + + "WHERE exercises.exercise_created_at < :from ;", + nativeQuery = true) + Iterable rawGlobalInjectExpectationResultsFromDate( + @Param("from") Instant from); /** * Returns the global expectations that were created before a date and that a user can see * - * @param from the date max of creation + * @param from the date max of creation * @param userId the id of the user * @return the list of global expectations */ - @Query(value = - "SELECT ie.inject_expectation_type, ie.inject_expectation_score, ie.inject_expectation_expected_score, injects.inject_title, icap.attack_pattern_id " - + - "FROM exercises " + - "INNER JOIN injects ON exercises.exercise_id = injects.inject_exercise " + - "LEFT JOIN injects_expectations ie ON exercises.exercise_id = ie.exercise_id " + - "INNER JOIN injectors_contracts ic ON injects.inject_injector_contract = ic.injector_contract_id " + - "INNER JOIN injectors_contracts_attack_patterns icap ON ic.injector_contract_id = icap.injector_contract_id " - + - "INNER join grants ON grants.grant_exercise = exercises.exercise_id " + - "INNER join groups ON grants.grant_group = groups.group_id " + - "INNER JOIN users_groups ON groups.group_id = users_groups.group_id " + - "WHERE exercises.exercise_created_at < :from " + - "AND users_groups.user_id = :userId ;", nativeQuery = true) - Iterable rawGrantedInjectExpectationResultsFromDate(@Param("from") Instant from, - @Param("userId") String userId); + @Query( + value = + "SELECT ie.inject_expectation_type, ie.inject_expectation_score, ie.inject_expectation_expected_score, injects.inject_title, icap.attack_pattern_id " + + "FROM exercises " + + "INNER JOIN injects ON exercises.exercise_id = injects.inject_exercise " + + "LEFT JOIN injects_expectations ie ON exercises.exercise_id = ie.exercise_id " + + "INNER JOIN injectors_contracts ic ON injects.inject_injector_contract = ic.injector_contract_id " + + "INNER JOIN injectors_contracts_attack_patterns icap ON ic.injector_contract_id = icap.injector_contract_id " + + "INNER join grants ON grants.grant_exercise = exercises.exercise_id " + + "INNER join groups ON grants.grant_group = groups.group_id " + + "INNER JOIN users_groups ON groups.group_id = users_groups.group_id " + + "WHERE exercises.exercise_created_at < :from " + + "AND users_groups.user_id = :userId ;", + nativeQuery = true) + Iterable rawGrantedInjectExpectationResultsFromDate( + @Param("from") Instant from, @Param("userId") String userId); /** * Get the raw version of the exercises * * @return the list of exercises */ - @Query(value = - " SELECT ex.exercise_id, " - + "ex.exercise_status, " - + "ex.exercise_start_date, " - + "ex.exercise_updated_at, " - + "ex.exercise_end_date, " - + "ex.exercise_name, " - + "ex.exercise_category, " - + "ex.exercise_subtitle, " - + " array_agg(distinct ie.inject_id) FILTER ( WHERE ie.inject_id IS NOT NULL ) as inject_ids, " - + " array_agg(distinct et.tag_id) FILTER ( WHERE et.tag_id IS NOT NULL ) as exercise_tags " - + "FROM exercises ex " - + "LEFT JOIN injects_expectations ie ON ex.exercise_id = ie.exercise_id " - + "LEFT JOIN exercises_tags et ON et.exercise_id = ex.exercise_id " - + "GROUP BY ex.exercise_id ;", nativeQuery = true) + @Query( + value = + " SELECT ex.exercise_id, " + + "ex.exercise_status, " + + "ex.exercise_start_date, " + + "ex.exercise_updated_at, " + + "ex.exercise_end_date, " + + "ex.exercise_name, " + + "ex.exercise_category, " + + "ex.exercise_subtitle, " + + " array_agg(distinct ie.inject_id) FILTER ( WHERE ie.inject_id IS NOT NULL ) as inject_ids, " + + " array_agg(distinct et.tag_id) FILTER ( WHERE et.tag_id IS NOT NULL ) as exercise_tags " + + "FROM exercises ex " + + "LEFT JOIN injects_expectations ie ON ex.exercise_id = ie.exercise_id " + + "LEFT JOIN exercises_tags et ON et.exercise_id = ex.exercise_id " + + "GROUP BY ex.exercise_id ;", + nativeQuery = true) List rawAll(); /** @@ -158,26 +168,28 @@ Iterable rawGrantedInjectExpectationResultsFromDate( * @param userId the id of the user * @return the list of exercises */ - @Query(value = - " SELECT ex.exercise_id, " - + "ex.exercise_status, " - + "ex.exercise_start_date, " - + "ex.exercise_updated_at, " - + "ex.exercise_end_date, " - + "ex.exercise_name, " - + "ex.exercise_category, " - + "ex.exercise_subtitle, " - + " array_agg(et.tag_id) FILTER ( WHERE et.tag_id IS NOT NULL ) as exercise_tags, " - + " array_agg(injects.inject_id) FILTER ( WHERE injects.inject_id IS NOT NULL ) as inject_ids " + - "FROM exercises ex " + - "LEFT JOIN injects_expectations ie ON ex.exercise_id = ie.exercise_id " + - "LEFT JOIN injects ON ie.inject_id = injects.inject_id " + - "LEFT JOIN exercises_tags et ON et.exercise_id = ex.exercise_id " + - "INNER join grants ON grants.grant_exercise = ex.exercise_id " + - "INNER join groups ON grants.grant_group = groups.group_id " + - "INNER JOIN users_groups ON groups.group_id = users_groups.group_id " + - "WHERE users_groups.user_id = :userId " + - "GROUP BY ex.exercise_id ;", nativeQuery = true) + @Query( + value = + " SELECT ex.exercise_id, " + + "ex.exercise_status, " + + "ex.exercise_start_date, " + + "ex.exercise_updated_at, " + + "ex.exercise_end_date, " + + "ex.exercise_name, " + + "ex.exercise_category, " + + "ex.exercise_subtitle, " + + " array_agg(et.tag_id) FILTER ( WHERE et.tag_id IS NOT NULL ) as exercise_tags, " + + " array_agg(injects.inject_id) FILTER ( WHERE injects.inject_id IS NOT NULL ) as inject_ids " + + "FROM exercises ex " + + "LEFT JOIN injects_expectations ie ON ex.exercise_id = ie.exercise_id " + + "LEFT JOIN injects ON ie.inject_id = injects.inject_id " + + "LEFT JOIN exercises_tags et ON et.exercise_id = ex.exercise_id " + + "INNER join grants ON grants.grant_exercise = ex.exercise_id " + + "INNER join groups ON grants.grant_group = groups.group_id " + + "INNER JOIN users_groups ON groups.group_id = users_groups.group_id " + + "WHERE users_groups.user_id = :userId " + + "GROUP BY ex.exercise_id ;", + nativeQuery = true) List rawAllGranted(@Param("userId") String userId); /** @@ -186,75 +198,73 @@ Iterable rawGrantedInjectExpectationResultsFromDate( * @param exerciseId the id of the user * @return the list of exercises */ - @Query(value = - " SELECT ex.exercise_category, ex.exercise_id, ex.exercise_status, ex.exercise_start_date, ex.exercise_name, " + - " ex.exercise_description, ex.exercise_main_focus, ex.exercise_severity, ex.exercise_start_date, " + - " ex.exercise_end_date, ex.exercise_message_header, ex.exercise_message_footer, ex.exercise_mail_from, " + - " ex.exercise_subtitle, ex.exercise_logo_dark, ex.exercise_logo_light, ex.exercise_lessons_anonymized, " + - " inj.inject_scenario, ex.exercise_created_at, ex.exercise_updated_at, se.scenario_id, ex.exercise_pause_date, " - + - " coalesce(array_agg(et.tag_id) FILTER ( WHERE et.tag_id IS NOT NULL ), '{}') as exercise_tags, " + - " coalesce(array_agg(ed.document_id) FILTER ( WHERE ed.document_id IS NOT NULL ), '{}') as exercise_documents, " - + - " coalesce(array_agg(inj.inject_id) FILTER ( WHERE inj.inject_id IS NOT NULL ), '{}') as inject_ids, " + - " coalesce(array_agg(ext.team_id) FILTER ( WHERE ext.team_id IS NOT NULL ), '{}') as exercise_teams, " + - " coalesce(array_agg(emrt.exercise_reply_to) FILTER ( WHERE emrt.exercise_reply_to IS NOT NULL ), '{}') as exercise_reply_to, " - + - " coalesce(array_agg(pauses.pause_id) FILTER ( WHERE pauses.pause_id IS NOT NULL ), '{}') as exercise_pauses, " - + - " coalesce(array_agg(art.article_id) FILTER ( WHERE art.article_id IS NOT NULL ), '{}') as exercise_articles, " - + - " coalesce(array_agg(lc.lessons_category_id) FILTER ( WHERE lc.lessons_category_id IS NOT NULL ), '{}') as exercise_lessons_categories, " - + - " coalesce(array_agg(ut.user_id) FILTER ( WHERE ut.user_id IS NOT NULL ), '{}') as exercise_users, " + - " coalesce(array_agg(la.lessons_answer_id) FILTER ( WHERE la.lessons_answer_id IS NOT NULL ), '{}') as lessons_answers, " - + - " coalesce(array_agg(ut.user_id) FILTER ( WHERE ut.user_id IS NOT NULL ), '{}') as users, " + - " coalesce(array_agg(logs.log_id) FILTER ( WHERE logs.log_id IS NOT NULL ), '{}') as logs " + - "FROM exercises ex " + - "LEFT JOIN injects_expectations ie ON ex.exercise_id = ie.exercise_id " + - "LEFT JOIN injects ON ie.inject_id = injects.inject_id " + - "LEFT JOIN injects inj ON ex.exercise_id = inj.inject_exercise " + - "LEFT JOIN exercises_tags et ON et.exercise_id = ex.exercise_id " + - "LEFT JOIN exercise_mails_reply_to emrt ON emrt.exercise_id = ex.exercise_id " + - "LEFT JOIN exercises_teams ext ON ext.exercise_id = ex.exercise_id " + - "LEFT JOIN pauses ON pauses.pause_exercise = ex.exercise_id " + - "LEFT JOIN exercises_documents ed ON ed.exercise_id = ex.exercise_id " + - "LEFT JOIN articles art ON art.article_exercise = ex.exercise_id " + - "LEFT JOIN lessons_categories lc ON lc.lessons_category_exercise = ex.exercise_id " + - "LEFT JOIN lessons_questions lq ON lq.lessons_question_category = lc.lessons_category_id " + - "LEFT JOIN lessons_answers la ON la.lessons_answer_question = lq.lessons_question_id " + - "LEFT JOIN scenarios_exercises se ON se.exercise_id = ex.exercise_id " + - "LEFT JOIN users_teams ut ON ext.team_id = ut.team_id " + - "LEFT JOIN logs ON logs.log_exercise = ex.exercise_id " + - "WHERE ex.exercise_id = :exerciseId " + - "GROUP BY ex.exercise_id, inj.inject_scenario, se.scenario_id ;", nativeQuery = true) + @Query( + value = + " SELECT ex.exercise_category, ex.exercise_id, ex.exercise_status, ex.exercise_start_date, ex.exercise_name, " + + " ex.exercise_description, ex.exercise_main_focus, ex.exercise_severity, ex.exercise_start_date, " + + " ex.exercise_end_date, ex.exercise_message_header, ex.exercise_message_footer, ex.exercise_mail_from, " + + " ex.exercise_subtitle, ex.exercise_logo_dark, ex.exercise_logo_light, ex.exercise_lessons_anonymized, " + + " inj.inject_scenario, ex.exercise_created_at, ex.exercise_updated_at, se.scenario_id, ex.exercise_pause_date, " + + " coalesce(array_agg(et.tag_id) FILTER ( WHERE et.tag_id IS NOT NULL ), '{}') as exercise_tags, " + + " coalesce(array_agg(ed.document_id) FILTER ( WHERE ed.document_id IS NOT NULL ), '{}') as exercise_documents, " + + " coalesce(array_agg(inj.inject_id) FILTER ( WHERE inj.inject_id IS NOT NULL ), '{}') as inject_ids, " + + " coalesce(array_agg(ext.team_id) FILTER ( WHERE ext.team_id IS NOT NULL ), '{}') as exercise_teams, " + + " coalesce(array_agg(emrt.exercise_reply_to) FILTER ( WHERE emrt.exercise_reply_to IS NOT NULL ), '{}') as exercise_reply_to, " + + " coalesce(array_agg(pauses.pause_id) FILTER ( WHERE pauses.pause_id IS NOT NULL ), '{}') as exercise_pauses, " + + " coalesce(array_agg(art.article_id) FILTER ( WHERE art.article_id IS NOT NULL ), '{}') as exercise_articles, " + + " coalesce(array_agg(lc.lessons_category_id) FILTER ( WHERE lc.lessons_category_id IS NOT NULL ), '{}') as exercise_lessons_categories, " + + " coalesce(array_agg(ut.user_id) FILTER ( WHERE ut.user_id IS NOT NULL ), '{}') as exercise_users, " + + " coalesce(array_agg(la.lessons_answer_id) FILTER ( WHERE la.lessons_answer_id IS NOT NULL ), '{}') as lessons_answers, " + + " coalesce(array_agg(ut.user_id) FILTER ( WHERE ut.user_id IS NOT NULL ), '{}') as users, " + + " coalesce(array_agg(logs.log_id) FILTER ( WHERE logs.log_id IS NOT NULL ), '{}') as logs " + + "FROM exercises ex " + + "LEFT JOIN injects_expectations ie ON ex.exercise_id = ie.exercise_id " + + "LEFT JOIN injects ON ie.inject_id = injects.inject_id " + + "LEFT JOIN injects inj ON ex.exercise_id = inj.inject_exercise " + + "LEFT JOIN exercises_tags et ON et.exercise_id = ex.exercise_id " + + "LEFT JOIN exercise_mails_reply_to emrt ON emrt.exercise_id = ex.exercise_id " + + "LEFT JOIN exercises_teams ext ON ext.exercise_id = ex.exercise_id " + + "LEFT JOIN pauses ON pauses.pause_exercise = ex.exercise_id " + + "LEFT JOIN exercises_documents ed ON ed.exercise_id = ex.exercise_id " + + "LEFT JOIN articles art ON art.article_exercise = ex.exercise_id " + + "LEFT JOIN lessons_categories lc ON lc.lessons_category_exercise = ex.exercise_id " + + "LEFT JOIN lessons_questions lq ON lq.lessons_question_category = lc.lessons_category_id " + + "LEFT JOIN lessons_answers la ON la.lessons_answer_question = lq.lessons_question_id " + + "LEFT JOIN scenarios_exercises se ON se.exercise_id = ex.exercise_id " + + "LEFT JOIN users_teams ut ON ext.team_id = ut.team_id " + + "LEFT JOIN logs ON logs.log_exercise = ex.exercise_id " + + "WHERE ex.exercise_id = :exerciseId " + + "GROUP BY ex.exercise_id, inj.inject_scenario, se.scenario_id ;", + nativeQuery = true) RawExercise rawDetailsById(@Param("exerciseId") String exerciseId); - @Query(value = - " SELECT DISTINCT (ie.inject_id) " - + "FROM exercises ex " - + "LEFT JOIN injects_expectations ie ON ex.exercise_id = ie.exercise_id " - + "WHERE ex.exercise_id = :exerciseId AND ie.inject_id IS NOT NULL;", nativeQuery = true) + @Query( + value = + " SELECT DISTINCT (ie.inject_id) " + + "FROM exercises ex " + + "LEFT JOIN injects_expectations ie ON ex.exercise_id = ie.exercise_id " + + "WHERE ex.exercise_id = :exerciseId AND ie.inject_id IS NOT NULL;", + nativeQuery = true) List findInjectsByExercise(@Param("exerciseId") String exerciseId); - @Query(value = - " SELECT ex.exercise_id, " - + "ex.exercise_status, " - + "ex.exercise_start_date, " - + "ex.exercise_updated_at, " - + "ex.exercise_end_date, " - + "ex.exercise_name, " - + "ex.exercise_category, " - + "ex.exercise_subtitle, " - + " array_agg(distinct ie.inject_id) FILTER ( WHERE ie.inject_id IS NOT NULL ) as inject_ids, " - + " array_agg(distinct et.tag_id) FILTER ( WHERE et.tag_id IS NOT NULL ) as exercise_tags " - + "FROM exercises ex " - + "LEFT JOIN scenarios_exercises s ON s.exercise_id = ex.exercise_id " - + "LEFT JOIN exercises_tags et ON et.exercise_id = ex.exercise_id " - + "LEFT JOIN injects_expectations ie ON ex.exercise_id = ie.exercise_id " - + "WHERE s.scenario_id IN (:scenarioIds) " - + "GROUP BY ex.exercise_id ;", nativeQuery = true) + @Query( + value = + " SELECT ex.exercise_id, " + + "ex.exercise_status, " + + "ex.exercise_start_date, " + + "ex.exercise_updated_at, " + + "ex.exercise_end_date, " + + "ex.exercise_name, " + + "ex.exercise_category, " + + "ex.exercise_subtitle, " + + " array_agg(distinct ie.inject_id) FILTER ( WHERE ie.inject_id IS NOT NULL ) as inject_ids, " + + " array_agg(distinct et.tag_id) FILTER ( WHERE et.tag_id IS NOT NULL ) as exercise_tags " + + "FROM exercises ex " + + "LEFT JOIN scenarios_exercises s ON s.exercise_id = ex.exercise_id " + + "LEFT JOIN exercises_tags et ON et.exercise_id = ex.exercise_id " + + "LEFT JOIN injects_expectations ie ON ex.exercise_id = ie.exercise_id " + + "WHERE s.scenario_id IN (:scenarioIds) " + + "GROUP BY ex.exercise_id ;", + nativeQuery = true) List rawAllByScenarioId(@Param("scenarioIds") List scenarioIds); - } diff --git a/openbas-model/src/main/java/io/openbas/database/repository/ExerciseTeamUserRepository.java b/openbas-model/src/main/java/io/openbas/database/repository/ExerciseTeamUserRepository.java index 6982c84d7a..b965873c27 100644 --- a/openbas-model/src/main/java/io/openbas/database/repository/ExerciseTeamUserRepository.java +++ b/openbas-model/src/main/java/io/openbas/database/repository/ExerciseTeamUserRepository.java @@ -4,6 +4,8 @@ import io.openbas.database.model.ExerciseTeamUserId; import io.openbas.database.raw.RawExerciseTeamUser; import jakarta.validation.constraints.NotNull; +import java.util.List; +import java.util.Optional; import org.springframework.data.jpa.repository.JpaSpecificationExecutor; import org.springframework.data.jpa.repository.Modifying; import org.springframework.data.jpa.repository.Query; @@ -11,33 +13,42 @@ import org.springframework.data.repository.query.Param; import org.springframework.stereotype.Repository; -import java.util.List; -import java.util.Optional; - @Repository -public interface ExerciseTeamUserRepository extends CrudRepository, JpaSpecificationExecutor { - - @NotNull - Optional findById(@NotNull ExerciseTeamUserId id); - - @Modifying - @Query(value = "delete from exercises_teams_users i where i.user_id = :userId", nativeQuery = true) - void deleteUserFromAllReferences(@Param("userId") String userId); - - @Modifying - @Query(value = "delete from exercises_teams_users i where i.team_id = :teamId", nativeQuery = true) - void deleteTeamFromAllReferences(@Param("teamId") String teamId); - - @Modifying - @Query(value = "insert into exercises_teams_users (exercise_id, team_id, user_id) " + - "values (:exerciseId, :teamId, :userId)", nativeQuery = true) - void addExerciseTeamUser(@Param("exerciseId") String exerciseId, - @Param("teamId") String teamId, - @Param("userId") String userId); - - @Query(value = "SELECT * FROM exercises_teams_users WHERE team_id IN :ids ;", nativeQuery = true) - List rawByTeamIds(@Param("ids") List ids); - - @Query(value = "SELECT * FROM exercises_teams_users WHERE exercise_id IN :ids ;", nativeQuery = true) - List rawByExerciseIds(@Param("ids") List ids); +public interface ExerciseTeamUserRepository + extends CrudRepository, + JpaSpecificationExecutor { + + @NotNull + Optional findById(@NotNull ExerciseTeamUserId id); + + @Modifying + @Query( + value = "delete from exercises_teams_users i where i.user_id = :userId", + nativeQuery = true) + void deleteUserFromAllReferences(@Param("userId") String userId); + + @Modifying + @Query( + value = "delete from exercises_teams_users i where i.team_id = :teamId", + nativeQuery = true) + void deleteTeamFromAllReferences(@Param("teamId") String teamId); + + @Modifying + @Query( + value = + "insert into exercises_teams_users (exercise_id, team_id, user_id) " + + "values (:exerciseId, :teamId, :userId)", + nativeQuery = true) + void addExerciseTeamUser( + @Param("exerciseId") String exerciseId, + @Param("teamId") String teamId, + @Param("userId") String userId); + + @Query(value = "SELECT * FROM exercises_teams_users WHERE team_id IN :ids ;", nativeQuery = true) + List rawByTeamIds(@Param("ids") List ids); + + @Query( + value = "SELECT * FROM exercises_teams_users WHERE exercise_id IN :ids ;", + nativeQuery = true) + List rawByExerciseIds(@Param("ids") List ids); } diff --git a/openbas-model/src/main/java/io/openbas/database/repository/GrantRepository.java b/openbas-model/src/main/java/io/openbas/database/repository/GrantRepository.java index 6a9c956f9c..e6fd96662d 100644 --- a/openbas-model/src/main/java/io/openbas/database/repository/GrantRepository.java +++ b/openbas-model/src/main/java/io/openbas/database/repository/GrantRepository.java @@ -3,25 +3,28 @@ import io.openbas.database.model.Grant; import io.openbas.database.raw.RawGrant; import jakarta.validation.constraints.NotNull; +import java.util.List; +import java.util.Optional; import org.springframework.data.jpa.repository.JpaSpecificationExecutor; import org.springframework.data.jpa.repository.Query; import org.springframework.data.repository.CrudRepository; import org.springframework.data.repository.query.Param; import org.springframework.stereotype.Repository; -import java.util.List; -import java.util.Optional; - @Repository -public interface GrantRepository extends CrudRepository, JpaSpecificationExecutor { +public interface GrantRepository + extends CrudRepository, JpaSpecificationExecutor { - @NotNull - Optional findById(@NotNull String id); + @NotNull + Optional findById(@NotNull String id); - @Query(value = "SELECT users_groups.user_id, grants.grant_name, grants.grant_id " + - "FROM grants " + - "LEFT JOIN groups ON grants.grant_group = groups.group_id " + - "LEFT JOIN users_groups ON groups.group_id = grants.grant_group " + - "WHERE grants.grant_exercise IN :ids ;", nativeQuery = true) - List rawByExerciseIds(@Param("ids") List ids); + @Query( + value = + "SELECT users_groups.user_id, grants.grant_name, grants.grant_id " + + "FROM grants " + + "LEFT JOIN groups ON grants.grant_group = groups.group_id " + + "LEFT JOIN users_groups ON groups.group_id = grants.grant_group " + + "WHERE grants.grant_exercise IN :ids ;", + nativeQuery = true) + List rawByExerciseIds(@Param("ids") List ids); } diff --git a/openbas-model/src/main/java/io/openbas/database/repository/GroupRepository.java b/openbas-model/src/main/java/io/openbas/database/repository/GroupRepository.java index ec6aba9b71..6e10529086 100644 --- a/openbas-model/src/main/java/io/openbas/database/repository/GroupRepository.java +++ b/openbas-model/src/main/java/io/openbas/database/repository/GroupRepository.java @@ -2,15 +2,15 @@ import io.openbas.database.model.Group; import jakarta.validation.constraints.NotNull; +import java.util.Optional; import org.springframework.data.jpa.repository.JpaSpecificationExecutor; import org.springframework.data.repository.CrudRepository; import org.springframework.stereotype.Repository; -import java.util.Optional; - @Repository -public interface GroupRepository extends CrudRepository, JpaSpecificationExecutor { +public interface GroupRepository + extends CrudRepository, JpaSpecificationExecutor { - @NotNull - Optional findById(@NotNull String id); + @NotNull + Optional findById(@NotNull String id); } diff --git a/openbas-model/src/main/java/io/openbas/database/repository/ImportMapperRepository.java b/openbas-model/src/main/java/io/openbas/database/repository/ImportMapperRepository.java index 7c4d95a50a..2fd300120a 100644 --- a/openbas-model/src/main/java/io/openbas/database/repository/ImportMapperRepository.java +++ b/openbas-model/src/main/java/io/openbas/database/repository/ImportMapperRepository.java @@ -1,6 +1,7 @@ package io.openbas.database.repository; import io.openbas.database.model.ImportMapper; +import java.util.UUID; import org.jetbrains.annotations.NotNull; import org.springframework.data.domain.Page; import org.springframework.data.domain.Pageable; @@ -8,11 +9,9 @@ import org.springframework.data.repository.CrudRepository; import org.springframework.stereotype.Repository; -import java.util.UUID; - @Repository public interface ImportMapperRepository extends CrudRepository { - @NotNull - Page findAll(@NotNull Specification spec, @NotNull Pageable pageable); + @NotNull + Page findAll(@NotNull Specification spec, @NotNull Pageable pageable); } diff --git a/openbas-model/src/main/java/io/openbas/database/repository/InjectDocumentRepository.java b/openbas-model/src/main/java/io/openbas/database/repository/InjectDocumentRepository.java index 3daea6e9e5..b5a3f5793b 100644 --- a/openbas-model/src/main/java/io/openbas/database/repository/InjectDocumentRepository.java +++ b/openbas-model/src/main/java/io/openbas/database/repository/InjectDocumentRepository.java @@ -2,6 +2,8 @@ import io.openbas.database.model.InjectDocument; import io.openbas.database.model.InjectDocumentId; +import jakarta.validation.constraints.NotNull; +import java.util.Optional; import org.springframework.data.jpa.repository.JpaSpecificationExecutor; import org.springframework.data.jpa.repository.Modifying; import org.springframework.data.jpa.repository.Query; @@ -9,27 +11,34 @@ import org.springframework.data.repository.query.Param; import org.springframework.stereotype.Repository; -import jakarta.validation.constraints.NotNull; -import java.util.Optional; - @Repository -public interface InjectDocumentRepository extends CrudRepository, JpaSpecificationExecutor { +public interface InjectDocumentRepository + extends CrudRepository, + JpaSpecificationExecutor { - @NotNull - Optional findById(@NotNull InjectDocumentId id); + @NotNull + Optional findById(@NotNull InjectDocumentId id); - @Modifying - @Query(value = "delete from injects_documents i where i.document_id = :documentId", nativeQuery = true) - void deleteDocumentFromAllReferences(@Param("documentId") String docId); + @Modifying + @Query( + value = "delete from injects_documents i where i.document_id = :documentId", + nativeQuery = true) + void deleteDocumentFromAllReferences(@Param("documentId") String docId); - @Modifying - @Query(value = "delete from injects_documents i where i.inject_id = :injectId", nativeQuery = true) - void deleteDocumentsFromInject(@Param("injectId") String injectId); + @Modifying + @Query( + value = "delete from injects_documents i where i.inject_id = :injectId", + nativeQuery = true) + void deleteDocumentsFromInject(@Param("injectId") String injectId); - @Modifying - @Query(value = "insert into injects_documents (inject_id, document_id, document_attached) " + - "values (:injectId, :documentId, :documentAttached)", nativeQuery = true) - void addInjectDoc(@Param("injectId") String injectId, - @Param("documentId") String docId, - @Param("documentAttached") boolean docAttached); + @Modifying + @Query( + value = + "insert into injects_documents (inject_id, document_id, document_attached) " + + "values (:injectId, :documentId, :documentAttached)", + nativeQuery = true) + void addInjectDoc( + @Param("injectId") String injectId, + @Param("documentId") String docId, + @Param("documentAttached") boolean docAttached); } diff --git a/openbas-model/src/main/java/io/openbas/database/repository/InjectExpectationRepository.java b/openbas-model/src/main/java/io/openbas/database/repository/InjectExpectationRepository.java index b2f9b9c455..25fb7463d3 100644 --- a/openbas-model/src/main/java/io/openbas/database/repository/InjectExpectationRepository.java +++ b/openbas-model/src/main/java/io/openbas/database/repository/InjectExpectationRepository.java @@ -4,18 +4,17 @@ import io.openbas.database.raw.RawInjectExpectation; import jakarta.validation.constraints.NotBlank; import jakarta.validation.constraints.NotNull; +import java.util.List; +import java.util.Optional; import org.springframework.data.jpa.repository.JpaSpecificationExecutor; import org.springframework.data.jpa.repository.Query; import org.springframework.data.repository.CrudRepository; import org.springframework.data.repository.query.Param; import org.springframework.stereotype.Repository; -import java.util.List; -import java.util.Optional; - @Repository -public interface InjectExpectationRepository extends CrudRepository, - JpaSpecificationExecutor { +public interface InjectExpectationRepository + extends CrudRepository, JpaSpecificationExecutor { @NotNull Optional findById(@NotNull String id); @@ -23,129 +22,162 @@ public interface InjectExpectationRepository extends CrudRepository findAllForExercise(@Param("exerciseId") String exerciseId); - @Query(value = "select i from InjectExpectation i where i.exercise.id = :exerciseId and i.inject.id = :injectId") + @Query( + value = + "select i from InjectExpectation i where i.exercise.id = :exerciseId and i.inject.id = :injectId") List findAllForExerciseAndInject( @Param("exerciseId") @NotBlank final String exerciseId, - @Param("injectId") @NotBlank final String injectId - ); - - @Query(value = "select i from InjectExpectation i where i.exercise.id = :exerciseId " + - "and i.type = 'CHALLENGE' and i.user.id = :userId ") - List findChallengeExpectationsByExerciseAndUser(@Param("exerciseId") String exerciseId, - @Param("userId") String userId); - - @Query(value = "select i from InjectExpectation i where i.exercise.id = :exerciseId " + - "and i.type = 'CHALLENGE' and i.challenge.id = :challengeId and i.team.id in (:teamIds)") - List findChallengeExpectations(@Param("exerciseId") String exerciseId, + @Param("injectId") @NotBlank final String injectId); + + @Query( + value = + "select i from InjectExpectation i where i.exercise.id = :exerciseId " + + "and i.type = 'CHALLENGE' and i.user.id = :userId ") + List findChallengeExpectationsByExerciseAndUser( + @Param("exerciseId") String exerciseId, @Param("userId") String userId); + + @Query( + value = + "select i from InjectExpectation i where i.exercise.id = :exerciseId " + + "and i.type = 'CHALLENGE' and i.challenge.id = :challengeId and i.team.id in (:teamIds)") + List findChallengeExpectations( + @Param("exerciseId") String exerciseId, @Param("teamIds") List teamIds, @Param("challengeId") String challengeId); - @Query(value = "select i from InjectExpectation i where i.user.id = :userId and i.exercise.id = :exerciseId " + - "and i.challenge.id = :challengeId and i.type = 'CHALLENGE' ") - List findByUserAndExerciseAndChallenge(@Param("userId") String userId, + @Query( + value = + "select i from InjectExpectation i where i.user.id = :userId and i.exercise.id = :exerciseId " + + "and i.challenge.id = :challengeId and i.type = 'CHALLENGE' ") + List findByUserAndExerciseAndChallenge( + @Param("userId") String userId, @Param("exerciseId") String exerciseId, @Param("challengeId") String challengeId); - @Query(value = "select i from InjectExpectation i where i.inject.id in (:injectIds) " + - "and i.article.id in (:articlesIds) and i.team.id in (:teamIds) and i.type = 'ARTICLE'") - List findChannelExpectations(@Param("injectIds") List injectIds, + @Query( + value = + "select i from InjectExpectation i where i.inject.id in (:injectIds) " + + "and i.article.id in (:articlesIds) and i.team.id in (:teamIds) and i.type = 'ARTICLE'") + List findChannelExpectations( + @Param("injectIds") List injectIds, @Param("teamIds") List teamIds, @Param("articlesIds") List articlesIds); + // -- PREVENTION -- - @Query(value = "select i from InjectExpectation i where i.type = 'PREVENTION' and i.inject.id = :injectId and i.asset.id = :assetId") - InjectExpectation findPreventionExpectationForAsset(@Param("injectId") String injectId, - @Param("assetId") String assetId); + @Query( + value = + "select i from InjectExpectation i where i.type = 'PREVENTION' and i.inject.id = :injectId and i.asset.id = :assetId") + InjectExpectation findPreventionExpectationForAsset( + @Param("injectId") String injectId, @Param("assetId") String assetId); - @Query(value = "select i from InjectExpectation i where i.type = 'PREVENTION' and i.inject.id = :injectId and i.assetGroup.id = :assetGroupId") - InjectExpectation findPreventionExpectationForAssetGroup(@Param("injectId") String injectId, - @Param("assetGroupId") String assetGroupId); + @Query( + value = + "select i from InjectExpectation i where i.type = 'PREVENTION' and i.inject.id = :injectId and i.assetGroup.id = :assetGroupId") + InjectExpectation findPreventionExpectationForAssetGroup( + @Param("injectId") String injectId, @Param("assetGroupId") String assetGroupId); // -- BY TARGET TYPE - @Query(value = "select i from InjectExpectation i where i.inject.id = :injectId and i.team.id = :teamId and i.user.id = :playerId") + @Query( + value = + "select i from InjectExpectation i where i.inject.id = :injectId and i.team.id = :teamId and i.user.id = :playerId") List findAllByInjectAndTeamAndPlayer( @Param("injectId") @NotBlank final String injectId, @Param("teamId") @NotBlank final String teamId, - @Param("playerId") @NotBlank final String playerId - ); - - @Query("select ie from InjectExpectation ie " + - "where ie.inject.id = :injectId " + - "and ie.team.id = :teamId " + - "and ie.name = :expectationName ") - List findAllByInjectAndTeamAndExpectationName(final String injectId, final String teamId, - final String expectationName); - - @Query("select ie from InjectExpectation ie " + - "where ie.inject.id = :injectId " + - "and ie.team.id = :teamId " + - "and ie.name = :expectationName " + - "and ie.user is not null") - List findAllByInjectAndTeamAndExpectationNameAndUserIsNotNull(final String injectId, - final String teamId, final String expectationName); + @Param("playerId") @NotBlank final String playerId); + + @Query( + "select ie from InjectExpectation ie " + + "where ie.inject.id = :injectId " + + "and ie.team.id = :teamId " + + "and ie.name = :expectationName ") + List findAllByInjectAndTeamAndExpectationName( + final String injectId, final String teamId, final String expectationName); + + @Query( + "select ie from InjectExpectation ie " + + "where ie.inject.id = :injectId " + + "and ie.team.id = :teamId " + + "and ie.name = :expectationName " + + "and ie.user is not null") + List findAllByInjectAndTeamAndExpectationNameAndUserIsNotNull( + final String injectId, final String teamId, final String expectationName); // -- RETRIEVE EXPECTATIONS FOR TEAM AND NOT FOR PLAYERS - @Query("select ie from InjectExpectation ie where ie.inject.id = :injectId and ie.team.id = :teamId and ie.name = :expectationName and ie.user is null") - Optional findByInjectAndTeamAndExpectationNameAndUserIsNull(String injectId, String teamId, - String expectationName); - - @Query(value = "select i from InjectExpectation i where i.inject.id = :injectId and i.team.id = :teamId and i.user is null") + @Query( + "select ie from InjectExpectation ie where ie.inject.id = :injectId and ie.team.id = :teamId and ie.name = :expectationName and ie.user is null") + Optional findByInjectAndTeamAndExpectationNameAndUserIsNull( + String injectId, String teamId, String expectationName); + + @Query( + value = + "select i from InjectExpectation i where i.inject.id = :injectId and i.team.id = :teamId and i.user is null") List findAllByInjectAndTeam( @Param("injectId") @NotBlank final String injectId, - @Param("teamId") @NotBlank final String teamId - ); + @Param("teamId") @NotBlank final String teamId); - @Query(value = "select i from InjectExpectation i where i.inject.id = :injectId and i.asset.id = :assetId") + @Query( + value = + "select i from InjectExpectation i where i.inject.id = :injectId and i.asset.id = :assetId") List findAllByInjectAndAsset( @Param("injectId") @NotBlank final String injectId, - @Param("assetId") @NotBlank final String assetId - ); + @Param("assetId") @NotBlank final String assetId); - @Query(value = "select i from InjectExpectation i where i.inject.id = :injectId and i.assetGroup.id = :assetGroupId") + @Query( + value = + "select i from InjectExpectation i where i.inject.id = :injectId and i.assetGroup.id = :assetGroupId") List findAllByInjectAndAssetGroup( @Param("injectId") @NotBlank final String injectId, - @Param("assetGroupId") @NotBlank final String assetGroupId - ); - - @Query(value = "SELECT " - + "team_id, asset_id, asset_group_id, inject_expectation_type, " - + "inject_expectation_score, inject_expectation_group, inject_expectation_expected_score, inject_expectation_id, exercise_id " - + "FROM injects_expectations i " - + "where i.inject_expectation_id IN :ids ;", + @Param("assetGroupId") @NotBlank final String assetGroupId); + + @Query( + value = + "SELECT " + + "team_id, asset_id, asset_group_id, inject_expectation_type, " + + "inject_expectation_score, inject_expectation_group, inject_expectation_expected_score, inject_expectation_id, exercise_id " + + "FROM injects_expectations i " + + "where i.inject_expectation_id IN :ids ;", nativeQuery = true) List rawByIds(@Param("ids") final List ids); - @Query(value = "SELECT " - + "i.inject_expectation_id AS inject_expectation_id, " - + "i.inject_id AS inject_id, " - + "i.exercise_id AS exercise_id, " - + "i.team_id AS team_id, " - + "i.asset_id AS asset_id, " - + "i.asset_group_id AS asset_group_id, " - + "i.inject_expectation_type AS inject_expectation_type, " - + "i.user_id AS user_id, " - + "i.inject_expectation_score AS inject_expectation_score, " - + "i.inject_expectation_expected_score AS inject_expectation_expected_score, " - + "i.inject_expectation_group AS inject_expectation_group " - + "FROM injects_expectations i " - + "WHERE i.inject_id IN (:injectIds) " - + "AND i.user_id is null ;", nativeQuery = true) //We don't include expectations for players, only for the team, if applicable + @Query( + value = + "SELECT " + + "i.inject_expectation_id AS inject_expectation_id, " + + "i.inject_id AS inject_id, " + + "i.exercise_id AS exercise_id, " + + "i.team_id AS team_id, " + + "i.asset_id AS asset_id, " + + "i.asset_group_id AS asset_group_id, " + + "i.inject_expectation_type AS inject_expectation_type, " + + "i.user_id AS user_id, " + + "i.inject_expectation_score AS inject_expectation_score, " + + "i.inject_expectation_expected_score AS inject_expectation_expected_score, " + + "i.inject_expectation_group AS inject_expectation_group " + + "FROM injects_expectations i " + + "WHERE i.inject_id IN (:injectIds) " + + "AND i.user_id is null ;", + nativeQuery = + true) // We don't include expectations for players, only for the team, if applicable List rawForComputeGlobalByIds(@Param("injectIds") List injectIds); - @Query(value = "SELECT " - + "i.inject_expectation_id AS inject_expectation_id, " - + "i.inject_id AS inject_id, " - + "i.exercise_id AS exercise_id, " - + "i.team_id AS team_id, " - + "i.asset_id AS asset_id, " - + "i.asset_group_id AS asset_group_id, " - + "i.inject_expectation_type AS inject_expectation_type, " - + "i.user_id AS user_id, " - + "i.inject_expectation_score AS inject_expectation_score, " - + "i.inject_expectation_expected_score AS inject_expectation_expected_score, " - + "i.inject_expectation_group AS inject_expectation_group " - + "FROM injects_expectations i " - + "WHERE i.inject_id IN (:injectIds) ; ", nativeQuery = true) + @Query( + value = + "SELECT " + + "i.inject_expectation_id AS inject_expectation_id, " + + "i.inject_id AS inject_id, " + + "i.exercise_id AS exercise_id, " + + "i.team_id AS team_id, " + + "i.asset_id AS asset_id, " + + "i.asset_group_id AS asset_group_id, " + + "i.inject_expectation_type AS inject_expectation_type, " + + "i.user_id AS user_id, " + + "i.inject_expectation_score AS inject_expectation_score, " + + "i.inject_expectation_expected_score AS inject_expectation_expected_score, " + + "i.inject_expectation_group AS inject_expectation_group " + + "FROM injects_expectations i " + + "WHERE i.inject_id IN (:injectIds) ; ", + nativeQuery = true) List rawByInjectId(@Param("injectIds") final List injectIds); } diff --git a/openbas-model/src/main/java/io/openbas/database/repository/InjectImporterRepository.java b/openbas-model/src/main/java/io/openbas/database/repository/InjectImporterRepository.java index 6db7fc68eb..d7042fd694 100644 --- a/openbas-model/src/main/java/io/openbas/database/repository/InjectImporterRepository.java +++ b/openbas-model/src/main/java/io/openbas/database/repository/InjectImporterRepository.java @@ -1,11 +1,9 @@ package io.openbas.database.repository; import io.openbas.database.model.InjectImporter; +import java.util.UUID; import org.springframework.data.repository.CrudRepository; import org.springframework.stereotype.Repository; -import java.util.UUID; - @Repository -public interface InjectImporterRepository extends CrudRepository { -} +public interface InjectImporterRepository extends CrudRepository {} diff --git a/openbas-model/src/main/java/io/openbas/database/repository/InjectReportingRepository.java b/openbas-model/src/main/java/io/openbas/database/repository/InjectReportingRepository.java index a54f8a8bce..304d1641b3 100644 --- a/openbas-model/src/main/java/io/openbas/database/repository/InjectReportingRepository.java +++ b/openbas-model/src/main/java/io/openbas/database/repository/InjectReportingRepository.java @@ -2,14 +2,13 @@ import io.openbas.database.model.InjectStatus; import jakarta.validation.constraints.NotNull; +import java.util.Optional; import org.springframework.data.repository.CrudRepository; import org.springframework.stereotype.Repository; -import java.util.Optional; - @Repository public interface InjectReportingRepository extends CrudRepository { - @NotNull - Optional findById(@NotNull String id); + @NotNull + Optional findById(@NotNull String id); } diff --git a/openbas-model/src/main/java/io/openbas/database/repository/InjectRepository.java b/openbas-model/src/main/java/io/openbas/database/repository/InjectRepository.java index 3a0861e0be..5d2a468e09 100644 --- a/openbas-model/src/main/java/io/openbas/database/repository/InjectRepository.java +++ b/openbas-model/src/main/java/io/openbas/database/repository/InjectRepository.java @@ -2,9 +2,11 @@ import io.openbas.database.model.Inject; import io.openbas.database.raw.RawInject; +import java.time.Instant; import java.util.Collection; +import java.util.List; +import java.util.Optional; import java.util.Set; - import org.jetbrains.annotations.NotNull; import org.springframework.data.jpa.repository.JpaSpecificationExecutor; import org.springframework.data.jpa.repository.Modifying; @@ -13,13 +15,9 @@ import org.springframework.data.repository.query.Param; import org.springframework.stereotype.Repository; -import java.time.Instant; -import java.util.List; -import java.util.Optional; - @Repository -public interface InjectRepository extends CrudRepository, JpaSpecificationExecutor, - StatisticRepository { +public interface InjectRepository + extends CrudRepository, JpaSpecificationExecutor, StatisticRepository { @NotNull Optional findById(@NotNull String id); @@ -31,28 +29,41 @@ public interface InjectRepository extends CrudRepository, JpaSpe @NotNull Optional findWithStatusById(@NotNull String id); - @Query(value = "select i.* from injects i where i.inject_injector_contract = '49229430-b5b5-431f-ba5b-f36f599b0233'" + - " and i.inject_content like :challengeId", nativeQuery = true) + @Query( + value = + "select i.* from injects i where i.inject_injector_contract = '49229430-b5b5-431f-ba5b-f36f599b0233'" + + " and i.inject_content like :challengeId", + nativeQuery = true) List findAllForChallengeId(@Param("challengeId") String challengeId); - @Query(value = "select i from Inject i " + - "join i.documents as doc_rel " + - "join doc_rel.document as doc " + - "where doc.id = :documentId and i.exercise.id = :exerciseId") - List findAllForExerciseAndDoc(@Param("exerciseId") String exerciseId, @Param("documentId") String documentId); - - @Query(value = "select i from Inject i " + - "join i.documents as doc_rel " + - "join doc_rel.document as doc " + - "where doc.id = :documentId and i.scenario.id = :scenarioId") - List findAllForScenarioAndDoc(@Param("scenarioId") String scenarioId, @Param("documentId") String documentId); + @Query( + value = + "select i from Inject i " + + "join i.documents as doc_rel " + + "join doc_rel.document as doc " + + "where doc.id = :documentId and i.exercise.id = :exerciseId") + List findAllForExerciseAndDoc( + @Param("exerciseId") String exerciseId, @Param("documentId") String documentId); + + @Query( + value = + "select i from Inject i " + + "join i.documents as doc_rel " + + "join doc_rel.document as doc " + + "where doc.id = :documentId and i.scenario.id = :scenarioId") + List findAllForScenarioAndDoc( + @Param("scenarioId") String scenarioId, @Param("documentId") String documentId); @Modifying - @Query(value = "insert into injects (inject_id, inject_title, inject_description, inject_country, inject_city," + - "inject_injector_contract, inject_all_teams, inject_enabled, inject_exercise, inject_depends_from_another, " + - "inject_depends_duration, inject_content) " + - "values (:id, :title, :description, :country, :city, :contract, :allTeams, :enabled, :exercise, :dependsOn, :dependsDuration, :content)", nativeQuery = true) - void importSaveForExercise(@Param("id") String id, + @Query( + value = + "insert into injects (inject_id, inject_title, inject_description, inject_country, inject_city," + + "inject_injector_contract, inject_all_teams, inject_enabled, inject_exercise, inject_depends_from_another, " + + "inject_depends_duration, inject_content) " + + "values (:id, :title, :description, :country, :city, :contract, :allTeams, :enabled, :exercise, :dependsOn, :dependsDuration, :content)", + nativeQuery = true) + void importSaveForExercise( + @Param("id") String id, @Param("title") String title, @Param("description") String description, @Param("country") String country, @@ -66,11 +77,15 @@ void importSaveForExercise(@Param("id") String id, @Param("content") String content); @Modifying - @Query(value = "insert into injects (inject_id, inject_title, inject_description, inject_country, inject_city," + - "inject_injector_contract, inject_all_teams, inject_enabled, inject_scenario, inject_depends_from_another, " + - "inject_depends_duration, inject_content) " + - "values (:id, :title, :description, :country, :city, :contract, :allTeams, :enabled, :scenario, :dependsOn, :dependsDuration, :content)", nativeQuery = true) - void importSaveForScenario(@Param("id") String id, + @Query( + value = + "insert into injects (inject_id, inject_title, inject_description, inject_country, inject_city," + + "inject_injector_contract, inject_all_teams, inject_enabled, inject_scenario, inject_depends_from_another, " + + "inject_depends_duration, inject_content) " + + "values (:id, :title, :description, :country, :city, :contract, :allTeams, :enabled, :scenario, :dependsOn, :dependsDuration, :content)", + nativeQuery = true) + void importSaveForScenario( + @Param("id") String id, @Param("title") String title, @Param("description") String description, @Param("country") String country, @@ -84,69 +99,82 @@ void importSaveForScenario(@Param("id") String id, @Param("content") String content); @Modifying - @Query(value = "insert into injects_tags (inject_id, tag_id) values (:injectId, :tagId)", nativeQuery = true) + @Query( + value = "insert into injects_tags (inject_id, tag_id) values (:injectId, :tagId)", + nativeQuery = true) void addTag(@Param("injectId") String injectId, @Param("tagId") String tagId); @Modifying - @Query(value = "insert into injects_teams (inject_id, team_id) values (:injectId, :teamId)", nativeQuery = true) + @Query( + value = "insert into injects_teams (inject_id, team_id) values (:injectId, :teamId)", + nativeQuery = true) void addTeam(@Param("injectId") String injectId, @Param("teamId") String teamId); @Override - @Query("select count(distinct i) from Inject i " + - "join i.exercise as e " + - "join e.grants as grant " + - "join grant.group.users as user " + - "where user.id = :userId and i.createdAt < :creationDate") + @Query( + "select count(distinct i) from Inject i " + + "join i.exercise as e " + + "join e.grants as grant " + + "join grant.group.users as user " + + "where user.id = :userId and i.createdAt < :creationDate") long userCount(@Param("userId") String userId, @Param("creationDate") Instant creationDate); @Override @Query("select count(distinct i) from Inject i where i.createdAt < :creationDate") long globalCount(@Param("creationDate") Instant creationDate); - @Query(value = " SELECT injects.inject_id, ins.status_name, injects.inject_scenario, " + - "coalesce(array_agg(it.team_id) FILTER ( WHERE it.team_id IS NOT NULL ), '{}') as inject_teams, " + - "coalesce(array_agg(assets.asset_id) FILTER ( WHERE assets.asset_id IS NOT NULL ), '{}') as inject_assets, " + - "coalesce(array_agg(iag.asset_group_id) FILTER ( WHERE iag.asset_group_id IS NOT NULL ), '{}') as inject_asset_groups, " + - "coalesce(array_agg(ie.inject_expectation_id) FILTER ( WHERE ie.inject_expectation_id IS NOT NULL ), '{}') as inject_expectations, " + - "coalesce(array_agg(com.communication_id) FILTER ( WHERE com.communication_id IS NOT NULL ), '{}') as inject_communications, " + - "coalesce(array_agg(apkcp.phase_id) FILTER ( WHERE apkcp.phase_id IS NOT NULL ), '{}') as inject_kill_chain_phases, " + - "coalesce(array_union_agg(injcon.injector_contract_platforms) FILTER ( WHERE injcon.injector_contract_platforms IS NOT NULL ), '{}') as inject_platforms " + - "FROM injects " + - "LEFT JOIN injects_teams it ON injects.inject_id = it.inject_id " + - "LEFT JOIN injects_assets ia ON injects.inject_id = ia.inject_id " + - "LEFT JOIN injects_asset_groups iag ON injects.inject_id = iag.inject_id " + - "LEFT JOIN asset_groups_assets aga ON aga.asset_group_id = iag.asset_group_id " + - "LEFT JOIN assets ON assets.asset_id = ia.asset_id OR aga.asset_id = assets.asset_id " + - "LEFT JOIN communications com ON com.communication_inject = injects.inject_id " + - "LEFT JOIN injects_expectations ie ON injects.inject_id = ie.inject_id " + - "LEFT JOIN injectors_contracts_attack_patterns icap ON icap.injector_contract_id = injects.inject_injector_contract " + - "LEFT JOIN injectors_contracts injcon ON injcon.injector_contract_id = injects.inject_injector_contract " + - "LEFT JOIN attack_patterns_kill_chain_phases apkcp ON apkcp.attack_pattern_id = icap.attack_pattern_id " + - "LEFT JOIN injects_statuses ins ON ins.status_inject = injects.inject_id " + - "WHERE injects.inject_id IN :ids " + - "GROUP BY injects.inject_id, ins.status_name;", nativeQuery = true) - List findRawByIds(@Param("ids")List ids); - - @Query(value = " SELECT injects.inject_id, " + - "coalesce(array_agg(it.team_id) FILTER ( WHERE it.team_id IS NOT NULL ), '{}') as inject_teams " + - "FROM injects " + - "LEFT JOIN injects_teams it ON injects.inject_id = it.inject_id " + - "WHERE injects.inject_id IN :ids AND it.team_id = :teamId " + - "GROUP BY injects.inject_id", nativeQuery = true) - Set findRawInjectTeams(@Param("ids") Collection ids, @Param("teamId") String teamId); - - @Query(value = - "SELECT org.*, " + - "array_agg(DISTINCT org_tags.tag_id) FILTER (WHERE org_tags.tag_id IS NOT NULL) AS organization_tags, " + - "array_agg(DISTINCT injects.inject_id) FILTER (WHERE injects.inject_id IS NOT NULL) AS organization_injects, " + - "coalesce(array_length(array_agg(DISTINCT injects.inject_id) FILTER (WHERE injects.inject_id IS NOT NULL), 1), 0) AS organization_injects_number " + - "FROM organizations org " + - "LEFT JOIN organizations_tags org_tags ON org.organization_id = org_tags.organization_id " + - "LEFT JOIN users ON users.user_organization = org.organization_id " + - "LEFT JOIN users_teams ON users.user_id = users_teams.user_id " + - "LEFT JOIN injects_teams ON injects_teams.team_id = users_teams.team_id " + - "LEFT JOIN injects ON injects.inject_id = injects_teams.inject_id OR injects.inject_all_teams " + - "GROUP BY org.organization_id", + @Query( + value = + " SELECT injects.inject_id, ins.status_name, injects.inject_scenario, " + + "coalesce(array_agg(it.team_id) FILTER ( WHERE it.team_id IS NOT NULL ), '{}') as inject_teams, " + + "coalesce(array_agg(assets.asset_id) FILTER ( WHERE assets.asset_id IS NOT NULL ), '{}') as inject_assets, " + + "coalesce(array_agg(iag.asset_group_id) FILTER ( WHERE iag.asset_group_id IS NOT NULL ), '{}') as inject_asset_groups, " + + "coalesce(array_agg(ie.inject_expectation_id) FILTER ( WHERE ie.inject_expectation_id IS NOT NULL ), '{}') as inject_expectations, " + + "coalesce(array_agg(com.communication_id) FILTER ( WHERE com.communication_id IS NOT NULL ), '{}') as inject_communications, " + + "coalesce(array_agg(apkcp.phase_id) FILTER ( WHERE apkcp.phase_id IS NOT NULL ), '{}') as inject_kill_chain_phases, " + + "coalesce(array_union_agg(injcon.injector_contract_platforms) FILTER ( WHERE injcon.injector_contract_platforms IS NOT NULL ), '{}') as inject_platforms " + + "FROM injects " + + "LEFT JOIN injects_teams it ON injects.inject_id = it.inject_id " + + "LEFT JOIN injects_assets ia ON injects.inject_id = ia.inject_id " + + "LEFT JOIN injects_asset_groups iag ON injects.inject_id = iag.inject_id " + + "LEFT JOIN asset_groups_assets aga ON aga.asset_group_id = iag.asset_group_id " + + "LEFT JOIN assets ON assets.asset_id = ia.asset_id OR aga.asset_id = assets.asset_id " + + "LEFT JOIN communications com ON com.communication_inject = injects.inject_id " + + "LEFT JOIN injects_expectations ie ON injects.inject_id = ie.inject_id " + + "LEFT JOIN injectors_contracts_attack_patterns icap ON icap.injector_contract_id = injects.inject_injector_contract " + + "LEFT JOIN injectors_contracts injcon ON injcon.injector_contract_id = injects.inject_injector_contract " + + "LEFT JOIN attack_patterns_kill_chain_phases apkcp ON apkcp.attack_pattern_id = icap.attack_pattern_id " + + "LEFT JOIN injects_statuses ins ON ins.status_inject = injects.inject_id " + + "WHERE injects.inject_id IN :ids " + + "GROUP BY injects.inject_id, ins.status_name;", + nativeQuery = true) + List findRawByIds(@Param("ids") List ids); + + @Query( + value = + " SELECT injects.inject_id, " + + "coalesce(array_agg(it.team_id) FILTER ( WHERE it.team_id IS NOT NULL ), '{}') as inject_teams " + + "FROM injects " + + "LEFT JOIN injects_teams it ON injects.inject_id = it.inject_id " + + "WHERE injects.inject_id IN :ids AND it.team_id = :teamId " + + "GROUP BY injects.inject_id", + nativeQuery = true) + Set findRawInjectTeams( + @Param("ids") Collection ids, @Param("teamId") String teamId); + + @Query( + value = + "SELECT org.*, " + + "array_agg(DISTINCT org_tags.tag_id) FILTER (WHERE org_tags.tag_id IS NOT NULL) AS organization_tags, " + + "array_agg(DISTINCT injects.inject_id) FILTER (WHERE injects.inject_id IS NOT NULL) AS organization_injects, " + + "coalesce(array_length(array_agg(DISTINCT injects.inject_id) FILTER (WHERE injects.inject_id IS NOT NULL), 1), 0) AS organization_injects_number " + + "FROM organizations org " + + "LEFT JOIN organizations_tags org_tags ON org.organization_id = org_tags.organization_id " + + "LEFT JOIN users ON users.user_organization = org.organization_id " + + "LEFT JOIN users_teams ON users.user_id = users_teams.user_id " + + "LEFT JOIN injects_teams ON injects_teams.team_id = users_teams.team_id " + + "LEFT JOIN injects ON injects.inject_id = injects_teams.inject_id OR injects.inject_all_teams " + + "GROUP BY org.organization_id", nativeQuery = true) List rawAll(); } diff --git a/openbas-model/src/main/java/io/openbas/database/repository/InjectStatusRepository.java b/openbas-model/src/main/java/io/openbas/database/repository/InjectStatusRepository.java index 25c443c158..1d599b81f9 100644 --- a/openbas-model/src/main/java/io/openbas/database/repository/InjectStatusRepository.java +++ b/openbas-model/src/main/java/io/openbas/database/repository/InjectStatusRepository.java @@ -2,24 +2,26 @@ import io.openbas.database.model.Inject; import io.openbas.database.model.InjectStatus; +import jakarta.validation.constraints.NotNull; +import java.util.List; +import java.util.Optional; import org.springframework.data.jpa.repository.JpaSpecificationExecutor; import org.springframework.data.jpa.repository.Query; import org.springframework.data.repository.CrudRepository; import org.springframework.data.repository.query.Param; import org.springframework.stereotype.Repository; -import jakarta.validation.constraints.NotNull; -import java.util.List; -import java.util.Optional; - @Repository -public interface InjectStatusRepository extends CrudRepository, JpaSpecificationExecutor { +public interface InjectStatusRepository + extends CrudRepository, JpaSpecificationExecutor { - @NotNull - Optional findById(@NotNull String id); + @NotNull + Optional findById(@NotNull String id); - @Query(value = "select c from InjectStatus c where c.name = 'PENDING' and c.inject.injectorContract.injector.type = :injectType") - List pendingForInjectType(@Param("injectType") String injectType); + @Query( + value = + "select c from InjectStatus c where c.name = 'PENDING' and c.inject.injectorContract.injector.type = :injectType") + List pendingForInjectType(@Param("injectType") String injectType); - Optional findByInject(@NotNull Inject inject); + Optional findByInject(@NotNull Inject inject); } diff --git a/openbas-model/src/main/java/io/openbas/database/repository/InjectTestStatusRepository.java b/openbas-model/src/main/java/io/openbas/database/repository/InjectTestStatusRepository.java index 1aad970a8a..1e9a7561ee 100644 --- a/openbas-model/src/main/java/io/openbas/database/repository/InjectTestStatusRepository.java +++ b/openbas-model/src/main/java/io/openbas/database/repository/InjectTestStatusRepository.java @@ -3,17 +3,15 @@ import io.openbas.database.model.Inject; import io.openbas.database.model.InjectTestStatus; import jakarta.validation.constraints.NotNull; +import java.util.Optional; import org.springframework.data.jpa.repository.JpaSpecificationExecutor; import org.springframework.data.repository.CrudRepository; -import java.util.Optional; - -public interface InjectTestStatusRepository extends CrudRepository, - JpaSpecificationExecutor { +public interface InjectTestStatusRepository + extends CrudRepository, JpaSpecificationExecutor { @NotNull Optional findById(@NotNull String id); Optional findByInject(@NotNull Inject inject); - } diff --git a/openbas-model/src/main/java/io/openbas/database/repository/InjectorContractRepository.java b/openbas-model/src/main/java/io/openbas/database/repository/InjectorContractRepository.java index 433b0c47e6..f375da77f1 100644 --- a/openbas-model/src/main/java/io/openbas/database/repository/InjectorContractRepository.java +++ b/openbas-model/src/main/java/io/openbas/database/repository/InjectorContractRepository.java @@ -5,25 +5,26 @@ import io.openbas.database.model.Payload; import io.openbas.database.raw.RawInjectorsContrats; import jakarta.validation.constraints.NotNull; +import java.util.List; +import java.util.Optional; import org.springframework.data.jpa.repository.JpaSpecificationExecutor; import org.springframework.data.jpa.repository.Query; import org.springframework.data.repository.CrudRepository; import org.springframework.stereotype.Repository; -import java.util.List; -import java.util.Optional; - @Repository -public interface InjectorContractRepository extends - CrudRepository, - JpaSpecificationExecutor { +public interface InjectorContractRepository + extends CrudRepository, JpaSpecificationExecutor { - @Query(value = "SELECT injcon.injector_contract_id, " + - "array_remove(array_agg(attpatt.attack_pattern_external_id), NULL) AS injector_contract_attack_patterns_external_id " + - "FROM injectors_contracts injcon " + - "LEFT JOIN injectors_contracts_attack_patterns injconatt ON injcon.injector_contract_id = injconatt.injector_contract_id " + - "LEFT JOIN attack_patterns attpatt ON injconatt.attack_pattern_id = attpatt.attack_pattern_id " + - "GROUP BY injcon.injector_contract_id", nativeQuery = true) + @Query( + value = + "SELECT injcon.injector_contract_id, " + + "array_remove(array_agg(attpatt.attack_pattern_external_id), NULL) AS injector_contract_attack_patterns_external_id " + + "FROM injectors_contracts injcon " + + "LEFT JOIN injectors_contracts_attack_patterns injconatt ON injcon.injector_contract_id = injconatt.injector_contract_id " + + "LEFT JOIN attack_patterns attpatt ON injconatt.attack_pattern_id = attpatt.attack_pattern_id " + + "GROUP BY injcon.injector_contract_id", + nativeQuery = true) List getAllRawInjectorsContracts(); @NotNull @@ -33,5 +34,6 @@ public interface InjectorContractRepository extends List findInjectorContractsByInjector(@NotNull Injector injector); @NotNull - Optional findInjectorContractByInjectorAndPayload(@NotNull Injector injector, @NotNull Payload payload); + Optional findInjectorContractByInjectorAndPayload( + @NotNull Injector injector, @NotNull Payload payload); } diff --git a/openbas-model/src/main/java/io/openbas/database/repository/InjectorRepository.java b/openbas-model/src/main/java/io/openbas/database/repository/InjectorRepository.java index 8c71aea0de..36f23d8d0d 100644 --- a/openbas-model/src/main/java/io/openbas/database/repository/InjectorRepository.java +++ b/openbas-model/src/main/java/io/openbas/database/repository/InjectorRepository.java @@ -2,21 +2,21 @@ import io.openbas.database.model.Injector; import jakarta.validation.constraints.NotNull; +import java.util.List; +import java.util.Optional; import org.springframework.data.jpa.repository.JpaSpecificationExecutor; import org.springframework.data.repository.CrudRepository; import org.springframework.stereotype.Repository; -import java.util.List; -import java.util.Optional; - @Repository -public interface InjectorRepository extends CrudRepository, JpaSpecificationExecutor { +public interface InjectorRepository + extends CrudRepository, JpaSpecificationExecutor { - @NotNull - Optional findById(@NotNull String id); + @NotNull + Optional findById(@NotNull String id); - @NotNull - Optional findByType(@NotNull String type); + @NotNull + Optional findByType(@NotNull String type); - List findAllByPayloads(@NotNull Boolean payloads); + List findAllByPayloads(@NotNull Boolean payloads); } diff --git a/openbas-model/src/main/java/io/openbas/database/repository/KillChainPhaseRepository.java b/openbas-model/src/main/java/io/openbas/database/repository/KillChainPhaseRepository.java index 06d47781f7..4e9a0d7f26 100644 --- a/openbas-model/src/main/java/io/openbas/database/repository/KillChainPhaseRepository.java +++ b/openbas-model/src/main/java/io/openbas/database/repository/KillChainPhaseRepository.java @@ -2,22 +2,23 @@ import io.openbas.database.model.KillChainPhase; import jakarta.validation.constraints.NotNull; +import java.util.List; +import java.util.Optional; import org.springframework.data.jpa.repository.JpaSpecificationExecutor; import org.springframework.data.jpa.repository.Query; import org.springframework.data.repository.CrudRepository; import org.springframework.stereotype.Repository; -import java.util.List; -import java.util.Optional; - @Repository -public interface KillChainPhaseRepository extends CrudRepository, JpaSpecificationExecutor { +public interface KillChainPhaseRepository + extends CrudRepository, JpaSpecificationExecutor { - @NotNull - Optional findById(@NotNull String id); + @NotNull + Optional findById(@NotNull String id); - @Query("SELECT k FROM KillChainPhase k WHERE k.shortName IN (:names)") - List findAllByShortName(@NotNull List names); + @Query("SELECT k FROM KillChainPhase k WHERE k.shortName IN (:names)") + List findAllByShortName(@NotNull List names); - Optional findByKillChainNameAndShortName(@NotNull String killChainName, @NotNull String shortName); + Optional findByKillChainNameAndShortName( + @NotNull String killChainName, @NotNull String shortName); } diff --git a/openbas-model/src/main/java/io/openbas/database/repository/LessonsAnswerRepository.java b/openbas-model/src/main/java/io/openbas/database/repository/LessonsAnswerRepository.java index 810b0da94e..ab60de84ce 100644 --- a/openbas-model/src/main/java/io/openbas/database/repository/LessonsAnswerRepository.java +++ b/openbas-model/src/main/java/io/openbas/database/repository/LessonsAnswerRepository.java @@ -2,18 +2,18 @@ import io.openbas.database.model.LessonsAnswer; import jakarta.validation.constraints.NotNull; +import java.util.Optional; import org.springframework.data.jpa.repository.JpaSpecificationExecutor; import org.springframework.data.repository.CrudRepository; import org.springframework.stereotype.Repository; -import java.util.Optional; - @Repository -public interface LessonsAnswerRepository extends CrudRepository, - JpaSpecificationExecutor { +public interface LessonsAnswerRepository + extends CrudRepository, JpaSpecificationExecutor { @NotNull Optional findById(@NotNull String id); - Optional findByUserIdAndQuestionId(@NotNull String userId, @NotNull String questionId); + Optional findByUserIdAndQuestionId( + @NotNull String userId, @NotNull String questionId); } diff --git a/openbas-model/src/main/java/io/openbas/database/repository/LessonsCategoryRepository.java b/openbas-model/src/main/java/io/openbas/database/repository/LessonsCategoryRepository.java index ede64bcfad..c31b523ca8 100644 --- a/openbas-model/src/main/java/io/openbas/database/repository/LessonsCategoryRepository.java +++ b/openbas-model/src/main/java/io/openbas/database/repository/LessonsCategoryRepository.java @@ -1,16 +1,16 @@ package io.openbas.database.repository; import io.openbas.database.model.LessonsCategory; +import jakarta.validation.constraints.NotNull; +import java.util.Optional; import org.springframework.data.jpa.repository.JpaSpecificationExecutor; import org.springframework.data.repository.CrudRepository; import org.springframework.stereotype.Repository; -import jakarta.validation.constraints.NotNull; -import java.util.Optional; - @Repository -public interface LessonsCategoryRepository extends CrudRepository, JpaSpecificationExecutor { +public interface LessonsCategoryRepository + extends CrudRepository, JpaSpecificationExecutor { - @NotNull - Optional findById(@NotNull String id); + @NotNull + Optional findById(@NotNull String id); } diff --git a/openbas-model/src/main/java/io/openbas/database/repository/LessonsQuestionRepository.java b/openbas-model/src/main/java/io/openbas/database/repository/LessonsQuestionRepository.java index eaeb6b2ccd..dcc6653685 100644 --- a/openbas-model/src/main/java/io/openbas/database/repository/LessonsQuestionRepository.java +++ b/openbas-model/src/main/java/io/openbas/database/repository/LessonsQuestionRepository.java @@ -1,16 +1,16 @@ package io.openbas.database.repository; import io.openbas.database.model.LessonsQuestion; +import jakarta.validation.constraints.NotNull; +import java.util.Optional; import org.springframework.data.jpa.repository.JpaSpecificationExecutor; import org.springframework.data.repository.CrudRepository; import org.springframework.stereotype.Repository; -import jakarta.validation.constraints.NotNull; -import java.util.Optional; - @Repository -public interface LessonsQuestionRepository extends CrudRepository, JpaSpecificationExecutor { +public interface LessonsQuestionRepository + extends CrudRepository, JpaSpecificationExecutor { - @NotNull - Optional findById(@NotNull String id); + @NotNull + Optional findById(@NotNull String id); } diff --git a/openbas-model/src/main/java/io/openbas/database/repository/LessonsTemplateCategoryRepository.java b/openbas-model/src/main/java/io/openbas/database/repository/LessonsTemplateCategoryRepository.java index 519c0394a9..840f01e11b 100644 --- a/openbas-model/src/main/java/io/openbas/database/repository/LessonsTemplateCategoryRepository.java +++ b/openbas-model/src/main/java/io/openbas/database/repository/LessonsTemplateCategoryRepository.java @@ -1,16 +1,17 @@ package io.openbas.database.repository; import io.openbas.database.model.LessonsTemplateCategory; +import jakarta.validation.constraints.NotNull; +import java.util.Optional; import org.springframework.data.jpa.repository.JpaSpecificationExecutor; import org.springframework.data.repository.CrudRepository; import org.springframework.stereotype.Repository; -import jakarta.validation.constraints.NotNull; -import java.util.Optional; - @Repository -public interface LessonsTemplateCategoryRepository extends CrudRepository, JpaSpecificationExecutor { +public interface LessonsTemplateCategoryRepository + extends CrudRepository, + JpaSpecificationExecutor { - @NotNull - Optional findById(@NotNull String id); + @NotNull + Optional findById(@NotNull String id); } diff --git a/openbas-model/src/main/java/io/openbas/database/repository/LessonsTemplateQuestionRepository.java b/openbas-model/src/main/java/io/openbas/database/repository/LessonsTemplateQuestionRepository.java index 64f4050efe..5ed37207d2 100644 --- a/openbas-model/src/main/java/io/openbas/database/repository/LessonsTemplateQuestionRepository.java +++ b/openbas-model/src/main/java/io/openbas/database/repository/LessonsTemplateQuestionRepository.java @@ -1,16 +1,17 @@ package io.openbas.database.repository; import io.openbas.database.model.LessonsTemplateQuestion; +import jakarta.validation.constraints.NotNull; +import java.util.Optional; import org.springframework.data.jpa.repository.JpaSpecificationExecutor; import org.springframework.data.repository.CrudRepository; import org.springframework.stereotype.Repository; -import jakarta.validation.constraints.NotNull; -import java.util.Optional; - @Repository -public interface LessonsTemplateQuestionRepository extends CrudRepository, JpaSpecificationExecutor { +public interface LessonsTemplateQuestionRepository + extends CrudRepository, + JpaSpecificationExecutor { - @NotNull - Optional findById(@NotNull String id); + @NotNull + Optional findById(@NotNull String id); } diff --git a/openbas-model/src/main/java/io/openbas/database/repository/LessonsTemplateRepository.java b/openbas-model/src/main/java/io/openbas/database/repository/LessonsTemplateRepository.java index 606ed377cd..4fe01d9c20 100644 --- a/openbas-model/src/main/java/io/openbas/database/repository/LessonsTemplateRepository.java +++ b/openbas-model/src/main/java/io/openbas/database/repository/LessonsTemplateRepository.java @@ -2,15 +2,15 @@ import io.openbas.database.model.LessonsTemplate; import jakarta.validation.constraints.NotNull; +import java.util.Optional; import org.springframework.data.jpa.repository.JpaSpecificationExecutor; import org.springframework.data.repository.CrudRepository; import org.springframework.stereotype.Repository; -import java.util.Optional; - @Repository -public interface LessonsTemplateRepository extends CrudRepository, JpaSpecificationExecutor { +public interface LessonsTemplateRepository + extends CrudRepository, JpaSpecificationExecutor { - @NotNull - Optional findById(@NotNull String id); + @NotNull + Optional findById(@NotNull String id); } diff --git a/openbas-model/src/main/java/io/openbas/database/repository/LogRepository.java b/openbas-model/src/main/java/io/openbas/database/repository/LogRepository.java index bebeda4045..8477693348 100644 --- a/openbas-model/src/main/java/io/openbas/database/repository/LogRepository.java +++ b/openbas-model/src/main/java/io/openbas/database/repository/LogRepository.java @@ -2,15 +2,14 @@ import io.openbas.database.model.Log; import jakarta.validation.constraints.NotNull; +import java.util.Optional; import org.springframework.data.jpa.repository.JpaSpecificationExecutor; import org.springframework.data.repository.CrudRepository; import org.springframework.stereotype.Repository; -import java.util.Optional; - @Repository public interface LogRepository extends CrudRepository, JpaSpecificationExecutor { - @NotNull - Optional findById(@NotNull String id); + @NotNull + Optional findById(@NotNull String id); } diff --git a/openbas-model/src/main/java/io/openbas/database/repository/MitigationRepository.java b/openbas-model/src/main/java/io/openbas/database/repository/MitigationRepository.java index 025982890a..bc494366f4 100644 --- a/openbas-model/src/main/java/io/openbas/database/repository/MitigationRepository.java +++ b/openbas-model/src/main/java/io/openbas/database/repository/MitigationRepository.java @@ -2,15 +2,15 @@ import io.openbas.database.model.Mitigation; import jakarta.validation.constraints.NotNull; +import java.util.List; +import java.util.Optional; import org.springframework.data.jpa.repository.JpaSpecificationExecutor; import org.springframework.data.repository.CrudRepository; import org.springframework.stereotype.Repository; -import java.util.List; -import java.util.Optional; - @Repository -public interface MitigationRepository extends CrudRepository, JpaSpecificationExecutor { +public interface MitigationRepository + extends CrudRepository, JpaSpecificationExecutor { @NotNull Optional findById(@NotNull String id); diff --git a/openbas-model/src/main/java/io/openbas/database/repository/ObjectiveRepository.java b/openbas-model/src/main/java/io/openbas/database/repository/ObjectiveRepository.java index 86e86fcff0..c3886b12dd 100644 --- a/openbas-model/src/main/java/io/openbas/database/repository/ObjectiveRepository.java +++ b/openbas-model/src/main/java/io/openbas/database/repository/ObjectiveRepository.java @@ -3,21 +3,21 @@ import io.openbas.database.model.Objective; import io.openbas.database.raw.RawObjective; import jakarta.validation.constraints.NotNull; +import java.util.List; +import java.util.Optional; import org.springframework.data.jpa.repository.JpaSpecificationExecutor; import org.springframework.data.jpa.repository.Query; import org.springframework.data.repository.CrudRepository; import org.springframework.data.repository.query.Param; import org.springframework.stereotype.Repository; -import java.util.List; -import java.util.Optional; - @Repository -public interface ObjectiveRepository extends CrudRepository, JpaSpecificationExecutor { +public interface ObjectiveRepository + extends CrudRepository, JpaSpecificationExecutor { - @NotNull - Optional findById(@NotNull String id); + @NotNull + Optional findById(@NotNull String id); - @Query(value = "SELECT * FROM objectives WHERE objective_exercise IN :ids ;", nativeQuery = true) - List rawByExerciseIds(@Param("ids") List ids); + @Query(value = "SELECT * FROM objectives WHERE objective_exercise IN :ids ;", nativeQuery = true) + List rawByExerciseIds(@Param("ids") List ids); } diff --git a/openbas-model/src/main/java/io/openbas/database/repository/OrganizationRepository.java b/openbas-model/src/main/java/io/openbas/database/repository/OrganizationRepository.java index 67b6af5841..2a2baab2b9 100644 --- a/openbas-model/src/main/java/io/openbas/database/repository/OrganizationRepository.java +++ b/openbas-model/src/main/java/io/openbas/database/repository/OrganizationRepository.java @@ -2,6 +2,8 @@ import io.openbas.database.model.Organization; import io.openbas.database.raw.RawOrganization; +import java.util.List; +import java.util.Optional; import org.jetbrains.annotations.NotNull; import org.springframework.data.jpa.repository.JpaSpecificationExecutor; import org.springframework.data.jpa.repository.Query; @@ -9,45 +11,47 @@ import org.springframework.data.repository.query.Param; import org.springframework.stereotype.Repository; -import java.util.List; -import java.util.Optional; - @Repository -public interface OrganizationRepository extends CrudRepository, JpaSpecificationExecutor { +public interface OrganizationRepository + extends CrudRepository, JpaSpecificationExecutor { - @NotNull - Optional findById(@NotNull String id); + @NotNull + Optional findById(@NotNull String id); - @NotNull - List findByNameIgnoreCase(@NotNull final String name); + @NotNull + List findByNameIgnoreCase(@NotNull final String name); - @Query(value = - "SELECT org.*, " + - "array_agg(DISTINCT org_tags.tag_id) FILTER (WHERE org_tags.tag_id IS NOT NULL) AS organization_tags, " + - "array_agg(DISTINCT injects.inject_id) FILTER (WHERE injects.inject_id IS NOT NULL) AS organization_injects, " + - "coalesce(array_length(array_agg(DISTINCT injects.inject_id) FILTER (WHERE injects.inject_id IS NOT NULL), 1), 0) AS organization_injects_number " + - "FROM organizations org " + - "LEFT JOIN organizations_tags org_tags ON org.organization_id = org_tags.organization_id " + - "LEFT JOIN users ON users.user_organization = org.organization_id " + - "LEFT JOIN users_teams ON users.user_id = users_teams.user_id " + - "LEFT JOIN injects_teams ON injects_teams.team_id = users_teams.team_id " + - "LEFT JOIN injects ON injects.inject_id = injects_teams.inject_id OR injects.inject_all_teams " + - "GROUP BY org.organization_id", nativeQuery = true) - List rawAll(); + @Query( + value = + "SELECT org.*, " + + "array_agg(DISTINCT org_tags.tag_id) FILTER (WHERE org_tags.tag_id IS NOT NULL) AS organization_tags, " + + "array_agg(DISTINCT injects.inject_id) FILTER (WHERE injects.inject_id IS NOT NULL) AS organization_injects, " + + "coalesce(array_length(array_agg(DISTINCT injects.inject_id) FILTER (WHERE injects.inject_id IS NOT NULL), 1), 0) AS organization_injects_number " + + "FROM organizations org " + + "LEFT JOIN organizations_tags org_tags ON org.organization_id = org_tags.organization_id " + + "LEFT JOIN users ON users.user_organization = org.organization_id " + + "LEFT JOIN users_teams ON users.user_id = users_teams.user_id " + + "LEFT JOIN injects_teams ON injects_teams.team_id = users_teams.team_id " + + "LEFT JOIN injects ON injects.inject_id = injects_teams.inject_id OR injects.inject_all_teams " + + "GROUP BY org.organization_id", + nativeQuery = true) + List rawAll(); - @Query(value = - "SELECT org.*," + - "array_agg(DISTINCT org_tags.tag_id) FILTER (WHERE org_tags.tag_id IS NOT NULL) AS organization_tags, " + - "array_agg(DISTINCT injects.inject_id) FILTER (WHERE injects.inject_id IS NOT NULL) AS organization_injects, " + - "coalesce(array_length(array_agg(DISTINCT injects.inject_id) FILTER (WHERE injects.inject_id IS NOT NULL), 1), 0) AS organization_injects_number " + - "FROM users " + - "LEFT JOIN injects ON injects.inject_user = users.user_id OR injects.inject_all_teams " + - "LEFT JOIN users_groups ug ON ug.user_id = users.user_id " + - "LEFT JOIN groups ON ug.group_id = groups.group_id " + - "LEFT JOIN groups_organizations go ON go.group_id = groups.group_id " + - "INNER JOIN organizations org ON go.organization_id = org.organization_id " + - "LEFT JOIN organizations_tags org_tags ON org.organization_id = org_tags.organization_id " + - "WHERE users.user_id = :userId " + - "GROUP BY org.organization_id", nativeQuery = true) - List rawByUser(@Param("userId") String id); + @Query( + value = + "SELECT org.*," + + "array_agg(DISTINCT org_tags.tag_id) FILTER (WHERE org_tags.tag_id IS NOT NULL) AS organization_tags, " + + "array_agg(DISTINCT injects.inject_id) FILTER (WHERE injects.inject_id IS NOT NULL) AS organization_injects, " + + "coalesce(array_length(array_agg(DISTINCT injects.inject_id) FILTER (WHERE injects.inject_id IS NOT NULL), 1), 0) AS organization_injects_number " + + "FROM users " + + "LEFT JOIN injects ON injects.inject_user = users.user_id OR injects.inject_all_teams " + + "LEFT JOIN users_groups ug ON ug.user_id = users.user_id " + + "LEFT JOIN groups ON ug.group_id = groups.group_id " + + "LEFT JOIN groups_organizations go ON go.group_id = groups.group_id " + + "INNER JOIN organizations org ON go.organization_id = org.organization_id " + + "LEFT JOIN organizations_tags org_tags ON org.organization_id = org_tags.organization_id " + + "WHERE users.user_id = :userId " + + "GROUP BY org.organization_id", + nativeQuery = true) + List rawByUser(@Param("userId") String id); } diff --git a/openbas-model/src/main/java/io/openbas/database/repository/PauseRepository.java b/openbas-model/src/main/java/io/openbas/database/repository/PauseRepository.java index a374f346c6..0c24f7de32 100644 --- a/openbas-model/src/main/java/io/openbas/database/repository/PauseRepository.java +++ b/openbas-model/src/main/java/io/openbas/database/repository/PauseRepository.java @@ -3,26 +3,29 @@ import io.openbas.database.model.Pause; import io.openbas.database.raw.RawPause; import jakarta.validation.constraints.NotNull; +import java.util.List; +import java.util.Optional; import org.springframework.data.jpa.repository.JpaSpecificationExecutor; import org.springframework.data.jpa.repository.Query; import org.springframework.data.repository.CrudRepository; import org.springframework.data.repository.query.Param; import org.springframework.stereotype.Repository; -import java.util.List; -import java.util.Optional; - @Repository -public interface PauseRepository extends CrudRepository, JpaSpecificationExecutor { +public interface PauseRepository + extends CrudRepository, JpaSpecificationExecutor { - @NotNull - Optional findById(@NotNull String id); + @NotNull + Optional findById(@NotNull String id); - @Query(value = "select p from Pause p where p.exercise.id = :exerciseId") - List findAllForExercise(@Param("exerciseId") String exerciseId); + @Query(value = "select p from Pause p where p.exercise.id = :exerciseId") + List findAllForExercise(@Param("exerciseId") String exerciseId); - @Query(value = "SELECT p.pause_id, p.pause_date, p.pause_duration, p.pause_exercise " + - "FROM pauses p " + - "WHERE p.pause_exercise = :exerciseId", nativeQuery = true) - List rawAllForExercise(@Param("exerciseId") String exerciseId); + @Query( + value = + "SELECT p.pause_id, p.pause_date, p.pause_duration, p.pause_exercise " + + "FROM pauses p " + + "WHERE p.pause_exercise = :exerciseId", + nativeQuery = true) + List rawAllForExercise(@Param("exerciseId") String exerciseId); } diff --git a/openbas-model/src/main/java/io/openbas/database/repository/PayloadRepository.java b/openbas-model/src/main/java/io/openbas/database/repository/PayloadRepository.java index dbcfbf30d7..9b83ec52ef 100644 --- a/openbas-model/src/main/java/io/openbas/database/repository/PayloadRepository.java +++ b/openbas-model/src/main/java/io/openbas/database/repository/PayloadRepository.java @@ -1,24 +1,23 @@ package io.openbas.database.repository; -import io.openbas.database.model.AttackPattern; import io.openbas.database.model.Payload; import jakarta.validation.constraints.NotNull; +import java.util.List; +import java.util.Optional; import org.springframework.data.jpa.repository.JpaSpecificationExecutor; import org.springframework.data.jpa.repository.Query; import org.springframework.data.repository.CrudRepository; import org.springframework.data.repository.query.Param; import org.springframework.stereotype.Repository; -import java.util.List; -import java.util.Optional; - @Repository -public interface PayloadRepository extends CrudRepository, JpaSpecificationExecutor { - @NotNull - Optional findById(@NotNull String id); +public interface PayloadRepository + extends CrudRepository, JpaSpecificationExecutor { + @NotNull + Optional findById(@NotNull String id); - @Query("select p from Payload p where p.type IN :types") - List findByType(@Param("types") final List types); + @Query("select p from Payload p where p.type IN :types") + List findByType(@Param("types") final List types); - Optional findByExternalId(@NotNull String externalId); + Optional findByExternalId(@NotNull String externalId); } diff --git a/openbas-model/src/main/java/io/openbas/database/repository/ReportRepository.java b/openbas-model/src/main/java/io/openbas/database/repository/ReportRepository.java index c5e35a1e85..0ea25fda32 100644 --- a/openbas-model/src/main/java/io/openbas/database/repository/ReportRepository.java +++ b/openbas-model/src/main/java/io/openbas/database/repository/ReportRepository.java @@ -2,20 +2,23 @@ import io.openbas.database.model.Report; import io.openbas.database.model.ReportInjectComment; +import java.util.Optional; +import java.util.UUID; import org.jetbrains.annotations.NotNull; import org.springframework.data.jpa.repository.JpaSpecificationExecutor; import org.springframework.data.jpa.repository.Query; import org.springframework.data.repository.CrudRepository; import org.springframework.stereotype.Repository; -import java.util.Optional; -import java.util.UUID; - @Repository -public interface ReportRepository extends CrudRepository, JpaSpecificationExecutor { - @NotNull - Optional findById(@NotNull final UUID id); +public interface ReportRepository + extends CrudRepository, JpaSpecificationExecutor { + @NotNull + Optional findById(@NotNull final UUID id); - @Query(value = "SELECT injectComment FROM ReportInjectComment injectComment WHERE injectComment.report.id = :reportId AND injectComment.inject.id = :injectId") - Optional findReportInjectComment(@NotNull final UUID reportId, @NotNull final String injectId); + @Query( + value = + "SELECT injectComment FROM ReportInjectComment injectComment WHERE injectComment.report.id = :reportId AND injectComment.inject.id = :injectId") + Optional findReportInjectComment( + @NotNull final UUID reportId, @NotNull final String injectId); } diff --git a/openbas-model/src/main/java/io/openbas/database/repository/RuleAttributeRepository.java b/openbas-model/src/main/java/io/openbas/database/repository/RuleAttributeRepository.java index 3f39e7d96a..44424b1232 100644 --- a/openbas-model/src/main/java/io/openbas/database/repository/RuleAttributeRepository.java +++ b/openbas-model/src/main/java/io/openbas/database/repository/RuleAttributeRepository.java @@ -1,11 +1,9 @@ package io.openbas.database.repository; import io.openbas.database.model.RuleAttribute; +import java.util.UUID; import org.springframework.data.repository.CrudRepository; import org.springframework.stereotype.Repository; -import java.util.UUID; - @Repository -public interface RuleAttributeRepository extends CrudRepository { -} +public interface RuleAttributeRepository extends CrudRepository {} diff --git a/openbas-model/src/main/java/io/openbas/database/repository/ScenarioRepository.java b/openbas-model/src/main/java/io/openbas/database/repository/ScenarioRepository.java index b44e875e32..8e2e23ea80 100644 --- a/openbas-model/src/main/java/io/openbas/database/repository/ScenarioRepository.java +++ b/openbas-model/src/main/java/io/openbas/database/repository/ScenarioRepository.java @@ -3,6 +3,8 @@ import io.openbas.database.model.Scenario; import io.openbas.database.raw.RawExerciseSimple; import io.openbas.database.raw.RawScenario; +import java.time.Instant; +import java.util.List; import org.jetbrains.annotations.NotNull; import org.springframework.data.domain.Page; import org.springframework.data.domain.Pageable; @@ -14,94 +16,109 @@ import org.springframework.data.repository.query.Param; import org.springframework.stereotype.Repository; -import java.time.Instant; -import java.util.List; - @Repository -public interface ScenarioRepository extends CrudRepository, - StatisticRepository, - JpaSpecificationExecutor { - - @Query(value = - "SELECT ex.exercise_id, " - + "ex.exercise_status, " - + "ex.exercise_start_date, " - + "ex.exercise_updated_at, " - + "ex.exercise_end_date, " - + "ex.exercise_name, " - + "ex.exercise_category, " - + "ex.exercise_subtitle, " - + " array_agg(distinct ie.inject_id) FILTER ( WHERE ie.inject_id IS NOT NULL ) as inject_ids, " - + " array_agg(distinct et.tag_id) FILTER ( WHERE et.tag_id IS NOT NULL ) as exercise_tags " - + "FROM exercises ex " - + "LEFT JOIN scenarios_exercises se ON se.exercise_id = ex.exercise_id " - + "LEFT JOIN scenarios s ON se.scenario_id = s.scenario_id " - + "LEFT JOIN exercises_tags et ON et.exercise_id = ex.exercise_id " - + "LEFT JOIN injects_expectations ie ON ex.exercise_id = ie.exercise_id " - + "WHERE s.scenario_external_reference = :externalReference " - + "GROUP BY ex.exercise_id ;", nativeQuery = true) - List rawAllByExternalReference(@Param("externalReference") String externalReference); - - @Query("select distinct s from Scenario s " + - "join s.grants as grant " + - "join grant.group.users as user " + - "where user.id = :userId") +public interface ScenarioRepository + extends CrudRepository, + StatisticRepository, + JpaSpecificationExecutor { + + @Query( + value = + "SELECT ex.exercise_id, " + + "ex.exercise_status, " + + "ex.exercise_start_date, " + + "ex.exercise_updated_at, " + + "ex.exercise_end_date, " + + "ex.exercise_name, " + + "ex.exercise_category, " + + "ex.exercise_subtitle, " + + " array_agg(distinct ie.inject_id) FILTER ( WHERE ie.inject_id IS NOT NULL ) as inject_ids, " + + " array_agg(distinct et.tag_id) FILTER ( WHERE et.tag_id IS NOT NULL ) as exercise_tags " + + "FROM exercises ex " + + "LEFT JOIN scenarios_exercises se ON se.exercise_id = ex.exercise_id " + + "LEFT JOIN scenarios s ON se.scenario_id = s.scenario_id " + + "LEFT JOIN exercises_tags et ON et.exercise_id = ex.exercise_id " + + "LEFT JOIN injects_expectations ie ON ex.exercise_id = ie.exercise_id " + + "WHERE s.scenario_external_reference = :externalReference " + + "GROUP BY ex.exercise_id ;", + nativeQuery = true) + List rawAllByExternalReference( + @Param("externalReference") String externalReference); + + @Query( + "select distinct s from Scenario s " + + "join s.grants as grant " + + "join grant.group.users as user " + + "where user.id = :userId") List findAllGranted(@Param("userId") String userId); @Override - @Query("select count(distinct u) from User u " + - "join u.teams as team " + - "join team.scenarios as s " + - "join s.grants as grant " + - "join grant.group.users as user " + - "where user.id = :userId and u.createdAt < :creationDate") + @Query( + "select count(distinct u) from User u " + + "join u.teams as team " + + "join team.scenarios as s " + + "join s.grants as grant " + + "join grant.group.users as user " + + "where user.id = :userId and u.createdAt < :creationDate") long userCount(String userId, Instant creationDate); @Override @Query("select count(distinct s) from Scenario s where s.createdAt < :creationDate") long globalCount(@Param("creationDate") Instant creationDate); - @Query(value = "SELECT scenario_category, COUNT(*) AS category_count " + - "FROM scenarios " + - "GROUP BY scenario_category " + - "ORDER BY category_count DESC " + - "LIMIT :limit", nativeQuery = true) + @Query( + value = + "SELECT scenario_category, COUNT(*) AS category_count " + + "FROM scenarios " + + "GROUP BY scenario_category " + + "ORDER BY category_count DESC " + + "LIMIT :limit", + nativeQuery = true) List findTopCategories(@Param("limit") @NotNull final int limit); - @Query(value = "SELECT sce.scenario_id, sce.scenario_name, sce.scenario_subtitle, array_agg(sct.tag_id) FILTER (WHERE sct.tag_id IS NOT NULL) as scenario_tags " + - "FROM scenarios sce " + - "LEFT JOIN scenarios_tags sct ON sct.scenario_id = sce.scenario_id " + - "INNER join grants ON grants.grant_scenario = sce.scenario_id " + - "INNER join groups ON grants.grant_group = groups.group_id " + - "INNER JOIN users_groups ON groups.group_id = users_groups.group_id " + - "WHERE users_groups.user_id = :userId " + - "GROUP BY sce.scenario_id", nativeQuery = true) + @Query( + value = + "SELECT sce.scenario_id, sce.scenario_name, sce.scenario_subtitle, array_agg(sct.tag_id) FILTER (WHERE sct.tag_id IS NOT NULL) as scenario_tags " + + "FROM scenarios sce " + + "LEFT JOIN scenarios_tags sct ON sct.scenario_id = sce.scenario_id " + + "INNER join grants ON grants.grant_scenario = sce.scenario_id " + + "INNER join groups ON grants.grant_group = groups.group_id " + + "INNER JOIN users_groups ON groups.group_id = users_groups.group_id " + + "WHERE users_groups.user_id = :userId " + + "GROUP BY sce.scenario_id", + nativeQuery = true) List rawAllGranted(@Param("userId") String userId); - - @Query(value = "SELECT sce.scenario_id, sce.scenario_name, sce.scenario_subtitle, array_agg(sct.tag_id) FILTER (WHERE sct.tag_id IS NOT NULL) as scenario_tags " + - "FROM scenarios sce " + - "LEFT JOIN scenarios_tags sct ON sct.scenario_id = sce.scenario_id " + - "GROUP BY sce.scenario_id", nativeQuery = true) + @Query( + value = + "SELECT sce.scenario_id, sce.scenario_name, sce.scenario_subtitle, array_agg(sct.tag_id) FILTER (WHERE sct.tag_id IS NOT NULL) as scenario_tags " + + "FROM scenarios sce " + + "LEFT JOIN scenarios_tags sct ON sct.scenario_id = sce.scenario_id " + + "GROUP BY sce.scenario_id", + nativeQuery = true) List rawAll(); - @Query(value = "SELECT sce.scenario_id, " + - "coalesce(array_agg(inj.inject_id) FILTER (WHERE inj.inject_id IS NOT NULL), '{}') as scenario_injects " + - "FROM scenarios sce " + - "LEFT JOIN injects inj ON inj.inject_scenario = sce.scenario_id " + - "WHERE sce.scenario_id IN :ids " + - "GROUP BY sce.scenario_id", nativeQuery = true) + @Query( + value = + "SELECT sce.scenario_id, " + + "coalesce(array_agg(inj.inject_id) FILTER (WHERE inj.inject_id IS NOT NULL), '{}') as scenario_injects " + + "FROM scenarios sce " + + "LEFT JOIN injects inj ON inj.inject_scenario = sce.scenario_id " + + "WHERE sce.scenario_id IN :ids " + + "GROUP BY sce.scenario_id", + nativeQuery = true) List rawInjectsFromScenarios(@Param("ids") List ids); // -- CATEGORY -- - @Query("SELECT DISTINCT s.category FROM Scenario s WHERE LOWER(s.category) LIKE LOWER(CONCAT('%', :searchTerm, '%'))") - List findDistinctCategoriesBySearchTerm(@Param("searchTerm") final String searchTerm, Pageable pageable); + @Query( + "SELECT DISTINCT s.category FROM Scenario s WHERE LOWER(s.category) LIKE LOWER(CONCAT('%', :searchTerm, '%'))") + List findDistinctCategoriesBySearchTerm( + @Param("searchTerm") final String searchTerm, Pageable pageable); // -- PAGINATION -- @NotNull @EntityGraph(value = "Scenario.tags-injects", type = EntityGraph.EntityGraphType.LOAD) Page findAll(@NotNull Specification spec, @NotNull Pageable pageable); - } diff --git a/openbas-model/src/main/java/io/openbas/database/repository/ScenarioTeamUserRepository.java b/openbas-model/src/main/java/io/openbas/database/repository/ScenarioTeamUserRepository.java index 62244a3d54..4b1510f70f 100644 --- a/openbas-model/src/main/java/io/openbas/database/repository/ScenarioTeamUserRepository.java +++ b/openbas-model/src/main/java/io/openbas/database/repository/ScenarioTeamUserRepository.java @@ -3,6 +3,7 @@ import io.openbas.database.model.ScenarioTeamUser; import io.openbas.database.model.ScenarioTeamUserId; import jakarta.validation.constraints.NotNull; +import java.util.Optional; import org.springframework.data.jpa.repository.JpaSpecificationExecutor; import org.springframework.data.jpa.repository.Modifying; import org.springframework.data.jpa.repository.Query; @@ -10,26 +11,34 @@ import org.springframework.data.repository.query.Param; import org.springframework.stereotype.Repository; -import java.util.Optional; - @Repository -public interface ScenarioTeamUserRepository extends CrudRepository, JpaSpecificationExecutor { +public interface ScenarioTeamUserRepository + extends CrudRepository, + JpaSpecificationExecutor { - @NotNull - Optional findById(@NotNull final ScenarioTeamUserId id); + @NotNull + Optional findById(@NotNull final ScenarioTeamUserId id); - @Modifying - @Query(value = "delete from scenarios_teams_users i where i.user_id = :userId", nativeQuery = true) - void deleteUserFromAllReferences(@Param("userId") final String userId); + @Modifying + @Query( + value = "delete from scenarios_teams_users i where i.user_id = :userId", + nativeQuery = true) + void deleteUserFromAllReferences(@Param("userId") final String userId); - @Modifying - @Query(value = "delete from scenarios_teams_users i where i.team_id = :teamId", nativeQuery = true) - void deleteTeamFromAllReferences(@Param("teamId") final String teamId); + @Modifying + @Query( + value = "delete from scenarios_teams_users i where i.team_id = :teamId", + nativeQuery = true) + void deleteTeamFromAllReferences(@Param("teamId") final String teamId); - @Modifying - @Query(value = "insert into scenarios_teams_users (exercise_id, team_id, user_id) " + - "values (:exerciseId, :teamId, :userId)", nativeQuery = true) - void addExerciseTeamUser(@Param("exerciseId") final String exerciseId, - @Param("teamId") final String teamId, - @Param("userId") final String userId); + @Modifying + @Query( + value = + "insert into scenarios_teams_users (exercise_id, team_id, user_id) " + + "values (:exerciseId, :teamId, :userId)", + nativeQuery = true) + void addExerciseTeamUser( + @Param("exerciseId") final String exerciseId, + @Param("teamId") final String teamId, + @Param("userId") final String userId); } diff --git a/openbas-model/src/main/java/io/openbas/database/repository/SecurityPlatformRepository.java b/openbas-model/src/main/java/io/openbas/database/repository/SecurityPlatformRepository.java index 3b0ab2f30b..f7ace12351 100644 --- a/openbas-model/src/main/java/io/openbas/database/repository/SecurityPlatformRepository.java +++ b/openbas-model/src/main/java/io/openbas/database/repository/SecurityPlatformRepository.java @@ -1,29 +1,31 @@ package io.openbas.database.repository; import io.openbas.database.model.SecurityPlatform; +import java.time.Instant; +import java.util.Optional; import org.springframework.data.jpa.repository.JpaSpecificationExecutor; import org.springframework.data.jpa.repository.Query; import org.springframework.data.repository.CrudRepository; import org.springframework.data.repository.query.Param; import org.springframework.stereotype.Repository; -import java.time.Instant; -import java.util.Optional; - @Repository -public interface SecurityPlatformRepository extends CrudRepository, - StatisticRepository, - JpaSpecificationExecutor { +public interface SecurityPlatformRepository + extends CrudRepository, + StatisticRepository, + JpaSpecificationExecutor { - Optional findByExternalReference(@Param("externalReference") String externalReference); + Optional findByExternalReference( + @Param("externalReference") String externalReference); @Override - @Query("select COUNT(DISTINCT a) from Inject i " + - "join i.assets as a " + - "join i.exercise as e " + - "join e.grants as grant " + - "join grant.group.users as user " + - "where user.id = :userId and i.createdAt < :creationDate") + @Query( + "select COUNT(DISTINCT a) from Inject i " + + "join i.assets as a " + + "join i.exercise as e " + + "join e.grants as grant " + + "join grant.group.users as user " + + "where user.id = :userId and i.createdAt < :creationDate") long userCount(@Param("userId") String userId, @Param("creationDate") Instant creationDate); @Override diff --git a/openbas-model/src/main/java/io/openbas/database/repository/SettingRepository.java b/openbas-model/src/main/java/io/openbas/database/repository/SettingRepository.java index 94dcf7469b..8265cc6032 100644 --- a/openbas-model/src/main/java/io/openbas/database/repository/SettingRepository.java +++ b/openbas-model/src/main/java/io/openbas/database/repository/SettingRepository.java @@ -1,6 +1,8 @@ package io.openbas.database.repository; import io.openbas.database.model.Setting; +import java.util.Collection; +import java.util.Optional; import org.jetbrains.annotations.NotNull; import org.springframework.data.jpa.repository.JpaSpecificationExecutor; import org.springframework.data.jpa.repository.Query; @@ -8,11 +10,9 @@ import org.springframework.stereotype.Repository; import org.springframework.transaction.annotation.Transactional; -import java.util.Collection; -import java.util.Optional; - @Repository -public interface SettingRepository extends CrudRepository, JpaSpecificationExecutor { +public interface SettingRepository + extends CrudRepository, JpaSpecificationExecutor { @NotNull Optional findById(@NotNull final String id); diff --git a/openbas-model/src/main/java/io/openbas/database/repository/StatisticRepository.java b/openbas-model/src/main/java/io/openbas/database/repository/StatisticRepository.java index fa9b564158..8b61c27fbf 100644 --- a/openbas-model/src/main/java/io/openbas/database/repository/StatisticRepository.java +++ b/openbas-model/src/main/java/io/openbas/database/repository/StatisticRepository.java @@ -1,13 +1,12 @@ package io.openbas.database.repository; -import org.springframework.data.repository.query.Param; - import java.time.Instant; +import org.springframework.data.repository.query.Param; @SuppressWarnings("EmptyMethod") public interface StatisticRepository { - long globalCount(@Param("creationDate") Instant creationDate); + long globalCount(@Param("creationDate") Instant creationDate); - long userCount(@Param("userId") String userId, @Param("creationDate") Instant creationDate); + long userCount(@Param("userId") String userId, @Param("creationDate") Instant creationDate); } diff --git a/openbas-model/src/main/java/io/openbas/database/repository/TagRepository.java b/openbas-model/src/main/java/io/openbas/database/repository/TagRepository.java index a122c858e6..ba22e4c730 100644 --- a/openbas-model/src/main/java/io/openbas/database/repository/TagRepository.java +++ b/openbas-model/src/main/java/io/openbas/database/repository/TagRepository.java @@ -1,14 +1,13 @@ package io.openbas.database.repository; import io.openbas.database.model.Tag; +import java.util.List; +import java.util.Optional; import org.jetbrains.annotations.NotNull; import org.springframework.data.jpa.repository.JpaSpecificationExecutor; import org.springframework.data.repository.CrudRepository; import org.springframework.stereotype.Repository; -import java.util.List; -import java.util.Optional; - @Repository public interface TagRepository extends CrudRepository, JpaSpecificationExecutor { diff --git a/openbas-model/src/main/java/io/openbas/database/repository/TeamRepository.java b/openbas-model/src/main/java/io/openbas/database/repository/TeamRepository.java index 7435d125a7..a4639aa68d 100644 --- a/openbas-model/src/main/java/io/openbas/database/repository/TeamRepository.java +++ b/openbas-model/src/main/java/io/openbas/database/repository/TeamRepository.java @@ -2,6 +2,9 @@ import io.openbas.database.model.Team; import io.openbas.database.raw.RawTeam; +import java.time.Instant; +import java.util.List; +import java.util.Optional; import org.jetbrains.annotations.NotNull; import org.springframework.data.domain.Page; import org.springframework.data.domain.Pageable; @@ -13,14 +16,9 @@ import org.springframework.data.repository.query.Param; import org.springframework.stereotype.Repository; -import java.time.Instant; -import java.util.List; -import java.util.Optional; - @Repository -public interface TeamRepository extends CrudRepository, - StatisticRepository, - JpaSpecificationExecutor { +public interface TeamRepository + extends CrudRepository, StatisticRepository, JpaSpecificationExecutor { @NotNull Optional findById(@NotNull String id); @@ -31,160 +29,144 @@ public interface TeamRepository extends CrudRepository, @NotNull List findAllByNameIgnoreCase(@NotNull final String name); - @Query("SELECT team FROM Team team where lower(team.name) = lower(:name) and team.contextual = false") + @Query( + "SELECT team FROM Team team where lower(team.name) = lower(:name) and team.contextual = false") List findByNameIgnoreCaseAndNotContextual(@NotNull final String name); - @Query("select team from Team team where team.organization is null or team.organization.id in :organizationIds") - List teamsAccessibleFromOrganizations(@Param("organizationIds") List organizationIds); + @Query( + "select team from Team team where team.organization is null or team.organization.id in :organizationIds") + List teamsAccessibleFromOrganizations( + @Param("organizationIds") List organizationIds); @Override - @Query("select count(distinct u) from User u " + - "join u.teams as team " + - "where u.id = :userId and u.createdAt < :creationDate") + @Query( + "select count(distinct u) from User u " + + "join u.teams as team " + + "where u.id = :userId and u.createdAt < :creationDate") long userCount(String userId, Instant creationDate); @Override @Query("select count(distinct t) from Team t where t.createdAt < :creationDate") long globalCount(@Param("creationDate") Instant creationDate); - @Query(value = "SELECT team_id, team_name " + - "FROM teams " + - "WHERE team_id IN :ids ;", nativeQuery = true) + @Query( + value = "SELECT team_id, team_name " + "FROM teams " + "WHERE team_id IN :ids ;", + nativeQuery = true) List rawTeamByIds(@Param("ids") List ids); - @Query(value = "SELECT DISTINCT t.team_id AS team_id, t.team_name AS team_name " - + "FROM teams t " - + "LEFT JOIN injects_teams it ON t.team_id = it.team_id " - + "WHERE t.team_id IN (:ids) OR it.inject_id IN (:injectIds) ;", nativeQuery = true) - List rawByIdsOrInjectIds(@Param("ids") List ids, @Param("injectIds") List injectIds); - - @Query(value = - "SELECT teams.team_id, teams.team_name, teams.team_description, teams.team_created_at, teams.team_updated_at, teams.team_organization, " - + - " team_contextual, " + - " coalesce(array_agg(DISTINCT teams_tags.tag_id) FILTER ( WHERE teams_tags.tag_id IS NOT NULL ), '{}') as team_tags, " - + - " coalesce(array_agg(DISTINCT users_teams.user_id) FILTER ( WHERE users_teams.user_id IS NOT NULL ), '{}') as team_users, " - + - " coalesce(array_agg(DISTINCT exercises_teams.exercise_id) FILTER ( WHERE exercises_teams.exercise_id IS NOT NULL ), '{}') as team_exercises, " - + - " coalesce(array_agg(DISTINCT scenarios_teams.scenario_id) FILTER ( WHERE scenarios_teams.scenario_id IS NOT NULL ), '{}') as team_scenarios, " - + - " coalesce(array_agg(DISTINCT injects_expectations.inject_expectation_id) FILTER ( WHERE injects_expectations.inject_expectation_id IS NOT NULL), '{}') as team_expectations, " - + - " coalesce(array_agg(DISTINCT injects.inject_id) FILTER ( WHERE injects.inject_id IS NOT NULL), '{}') as team_exercise_injects, " - + - " coalesce(array_agg(DISTINCT communications.communication_id) FILTER ( WHERE communications.communication_id IS NOT NULL), '{}') as team_communications " - + - "FROM teams " + - "LEFT JOIN teams_tags ON teams_tags.team_id = teams.team_id " + - "LEFT JOIN users_teams ON users_teams.team_id = teams.team_id " + - "LEFT JOIN exercises_teams ON exercises_teams.team_id = teams.team_id " + - "LEFT JOIN scenarios_teams ON scenarios_teams.team_id = teams.team_id " + - "LEFT JOIN injects_expectations ON injects_expectations.team_id = teams.team_id " + - "LEFT JOIN exercises ON exercises_teams.exercise_id = exercises.exercise_id " + - "LEFT JOIN exercises_teams_users ON exercises_teams_users.team_id = teams.team_id " + - "LEFT JOIN injects ON injects.inject_exercise = exercises.exercise_id " + - "LEFT JOIN communications ON communications.communication_inject = injects.inject_id " + - "GROUP BY teams.team_id ;", nativeQuery = true) + @Query( + value = + "SELECT DISTINCT t.team_id AS team_id, t.team_name AS team_name " + + "FROM teams t " + + "LEFT JOIN injects_teams it ON t.team_id = it.team_id " + + "WHERE t.team_id IN (:ids) OR it.inject_id IN (:injectIds) ;", + nativeQuery = true) + List rawByIdsOrInjectIds( + @Param("ids") List ids, @Param("injectIds") List injectIds); + + @Query( + value = + "SELECT teams.team_id, teams.team_name, teams.team_description, teams.team_created_at, teams.team_updated_at, teams.team_organization, " + + " team_contextual, " + + " coalesce(array_agg(DISTINCT teams_tags.tag_id) FILTER ( WHERE teams_tags.tag_id IS NOT NULL ), '{}') as team_tags, " + + " coalesce(array_agg(DISTINCT users_teams.user_id) FILTER ( WHERE users_teams.user_id IS NOT NULL ), '{}') as team_users, " + + " coalesce(array_agg(DISTINCT exercises_teams.exercise_id) FILTER ( WHERE exercises_teams.exercise_id IS NOT NULL ), '{}') as team_exercises, " + + " coalesce(array_agg(DISTINCT scenarios_teams.scenario_id) FILTER ( WHERE scenarios_teams.scenario_id IS NOT NULL ), '{}') as team_scenarios, " + + " coalesce(array_agg(DISTINCT injects_expectations.inject_expectation_id) FILTER ( WHERE injects_expectations.inject_expectation_id IS NOT NULL), '{}') as team_expectations, " + + " coalesce(array_agg(DISTINCT injects.inject_id) FILTER ( WHERE injects.inject_id IS NOT NULL), '{}') as team_exercise_injects, " + + " coalesce(array_agg(DISTINCT communications.communication_id) FILTER ( WHERE communications.communication_id IS NOT NULL), '{}') as team_communications " + + "FROM teams " + + "LEFT JOIN teams_tags ON teams_tags.team_id = teams.team_id " + + "LEFT JOIN users_teams ON users_teams.team_id = teams.team_id " + + "LEFT JOIN exercises_teams ON exercises_teams.team_id = teams.team_id " + + "LEFT JOIN scenarios_teams ON scenarios_teams.team_id = teams.team_id " + + "LEFT JOIN injects_expectations ON injects_expectations.team_id = teams.team_id " + + "LEFT JOIN exercises ON exercises_teams.exercise_id = exercises.exercise_id " + + "LEFT JOIN exercises_teams_users ON exercises_teams_users.team_id = teams.team_id " + + "LEFT JOIN injects ON injects.inject_exercise = exercises.exercise_id " + + "LEFT JOIN communications ON communications.communication_inject = injects.inject_id " + + "GROUP BY teams.team_id ;", + nativeQuery = true) List rawTeams(); - @Query(value = - "SELECT teams.team_id, teams.team_name, teams.team_description, teams.team_created_at, teams.team_updated_at, teams.team_organization, " - + - " team_contextual, " + - " coalesce(array_agg(DISTINCT teams_tags.tag_id) FILTER ( WHERE teams_tags.tag_id IS NOT NULL ), '{}') as team_tags, " - + - " coalesce(array_agg(DISTINCT users_teams.user_id) FILTER ( WHERE users_teams.user_id IS NOT NULL ), '{}') as team_users, " - + - " coalesce(array_agg(DISTINCT exercises_teams.exercise_id) FILTER ( WHERE exercises_teams.exercise_id IS NOT NULL ), '{}') as team_exercises, " - + - " coalesce(array_agg(DISTINCT scenarios_teams.scenario_id) FILTER ( WHERE scenarios_teams.scenario_id IS NOT NULL ), '{}') as team_scenarios, " - + - " coalesce(array_agg(DISTINCT injects_expectations.inject_expectation_id) FILTER ( WHERE injects_expectations.inject_expectation_id IS NOT NULL), '{}') as team_expectations, " - + - " coalesce(array_agg(DISTINCT injects.inject_id) FILTER ( WHERE injects.inject_id IS NOT NULL), '{}') as team_exercise_injects, " - + - " coalesce(array_agg(DISTINCT communications.communication_id) FILTER ( WHERE communications.communication_id IS NOT NULL), '{}') as team_communications " - + - "FROM teams " + - "LEFT JOIN teams_tags ON teams_tags.team_id = teams.team_id " + - "LEFT JOIN users_teams ON users_teams.team_id = teams.team_id " + - "LEFT JOIN exercises_teams ON exercises_teams.team_id = teams.team_id " + - "LEFT JOIN scenarios_teams ON scenarios_teams.team_id = teams.team_id " + - "LEFT JOIN injects_expectations ON injects_expectations.team_id = teams.team_id " + - "LEFT JOIN exercises ON exercises_teams.exercise_id = exercises.exercise_id " + - "LEFT JOIN exercises_teams_users ON exercises_teams_users.team_id = teams.team_id " + - "LEFT JOIN injects ON injects.inject_exercise = exercises.exercise_id " + - "LEFT JOIN communications ON communications.communication_inject = injects.inject_id " + - "WHERE teams.team_organization IS NULL OR teams.team_organization IN :organizationIds " + - "GROUP BY teams.team_id ;", nativeQuery = true) - List rawTeamsAccessibleFromOrganization(@Param("organizationIds") List organizationIds); + @Query( + value = + "SELECT teams.team_id, teams.team_name, teams.team_description, teams.team_created_at, teams.team_updated_at, teams.team_organization, " + + " team_contextual, " + + " coalesce(array_agg(DISTINCT teams_tags.tag_id) FILTER ( WHERE teams_tags.tag_id IS NOT NULL ), '{}') as team_tags, " + + " coalesce(array_agg(DISTINCT users_teams.user_id) FILTER ( WHERE users_teams.user_id IS NOT NULL ), '{}') as team_users, " + + " coalesce(array_agg(DISTINCT exercises_teams.exercise_id) FILTER ( WHERE exercises_teams.exercise_id IS NOT NULL ), '{}') as team_exercises, " + + " coalesce(array_agg(DISTINCT scenarios_teams.scenario_id) FILTER ( WHERE scenarios_teams.scenario_id IS NOT NULL ), '{}') as team_scenarios, " + + " coalesce(array_agg(DISTINCT injects_expectations.inject_expectation_id) FILTER ( WHERE injects_expectations.inject_expectation_id IS NOT NULL), '{}') as team_expectations, " + + " coalesce(array_agg(DISTINCT injects.inject_id) FILTER ( WHERE injects.inject_id IS NOT NULL), '{}') as team_exercise_injects, " + + " coalesce(array_agg(DISTINCT communications.communication_id) FILTER ( WHERE communications.communication_id IS NOT NULL), '{}') as team_communications " + + "FROM teams " + + "LEFT JOIN teams_tags ON teams_tags.team_id = teams.team_id " + + "LEFT JOIN users_teams ON users_teams.team_id = teams.team_id " + + "LEFT JOIN exercises_teams ON exercises_teams.team_id = teams.team_id " + + "LEFT JOIN scenarios_teams ON scenarios_teams.team_id = teams.team_id " + + "LEFT JOIN injects_expectations ON injects_expectations.team_id = teams.team_id " + + "LEFT JOIN exercises ON exercises_teams.exercise_id = exercises.exercise_id " + + "LEFT JOIN exercises_teams_users ON exercises_teams_users.team_id = teams.team_id " + + "LEFT JOIN injects ON injects.inject_exercise = exercises.exercise_id " + + "LEFT JOIN communications ON communications.communication_inject = injects.inject_id " + + "WHERE teams.team_organization IS NULL OR teams.team_organization IN :organizationIds " + + "GROUP BY teams.team_id ;", + nativeQuery = true) + List rawTeamsAccessibleFromOrganization( + @Param("organizationIds") List organizationIds); @NotNull @EntityGraph(value = "Team.tags", type = EntityGraph.EntityGraphType.LOAD) Page findAll(@NotNull Specification spec, @NotNull Pageable pageable); - @Query(value = - "SELECT teams.team_id, teams.team_name, teams.team_description, teams.team_created_at, teams.team_updated_at, teams.team_organization, " - + - " team_contextual, " + - " coalesce(array_agg(DISTINCT teams_tags.tag_id) FILTER ( WHERE teams_tags.tag_id IS NOT NULL ), '{}') as team_tags, " - + - " coalesce(array_agg(DISTINCT users_teams.user_id) FILTER ( WHERE users_teams.user_id IS NOT NULL ), '{}') as team_users, " - + - " coalesce(array_agg(DISTINCT exercises_teams.exercise_id) FILTER ( WHERE exercises_teams.exercise_id IS NOT NULL ), '{}') as team_exercises, " - + - " coalesce(array_agg(DISTINCT scenarios_teams.scenario_id) FILTER ( WHERE scenarios_teams.scenario_id IS NOT NULL ), '{}') as team_scenarios, " - + - " coalesce(array_agg(DISTINCT injects_expectations.inject_expectation_id) FILTER ( WHERE injects_expectations.inject_expectation_id IS NOT NULL), '{}') as team_expectations, " - + - " coalesce(array_agg(DISTINCT injects.inject_id) FILTER ( WHERE injects.inject_id IS NOT NULL), '{}') as team_exercise_injects, " - + - " coalesce(array_agg(DISTINCT communications.communication_id) FILTER ( WHERE communications.communication_id IS NOT NULL), '{}') as team_communications " - + - "FROM teams " + - "LEFT JOIN teams_tags ON teams_tags.team_id = teams.team_id " + - "LEFT JOIN users_teams ON users_teams.team_id = teams.team_id " + - "LEFT JOIN exercises_teams ON exercises_teams.team_id = teams.team_id " + - "LEFT JOIN scenarios_teams ON scenarios_teams.team_id = teams.team_id " + - "LEFT JOIN injects_expectations ON injects_expectations.team_id = teams.team_id " + - "LEFT JOIN exercises ON exercises_teams.exercise_id = exercises.exercise_id " + - "LEFT JOIN exercises_teams_users ON exercises_teams_users.team_id = teams.team_id " + - "LEFT JOIN injects ON injects.inject_exercise = exercises.exercise_id " + - "LEFT JOIN communications ON communications.communication_inject = injects.inject_id " + - "WHERE exercises.exercise_id = :exerciseId GROUP BY teams.team_id ;", nativeQuery = true) + @Query( + value = + "SELECT teams.team_id, teams.team_name, teams.team_description, teams.team_created_at, teams.team_updated_at, teams.team_organization, " + + " team_contextual, " + + " coalesce(array_agg(DISTINCT teams_tags.tag_id) FILTER ( WHERE teams_tags.tag_id IS NOT NULL ), '{}') as team_tags, " + + " coalesce(array_agg(DISTINCT users_teams.user_id) FILTER ( WHERE users_teams.user_id IS NOT NULL ), '{}') as team_users, " + + " coalesce(array_agg(DISTINCT exercises_teams.exercise_id) FILTER ( WHERE exercises_teams.exercise_id IS NOT NULL ), '{}') as team_exercises, " + + " coalesce(array_agg(DISTINCT scenarios_teams.scenario_id) FILTER ( WHERE scenarios_teams.scenario_id IS NOT NULL ), '{}') as team_scenarios, " + + " coalesce(array_agg(DISTINCT injects_expectations.inject_expectation_id) FILTER ( WHERE injects_expectations.inject_expectation_id IS NOT NULL), '{}') as team_expectations, " + + " coalesce(array_agg(DISTINCT injects.inject_id) FILTER ( WHERE injects.inject_id IS NOT NULL), '{}') as team_exercise_injects, " + + " coalesce(array_agg(DISTINCT communications.communication_id) FILTER ( WHERE communications.communication_id IS NOT NULL), '{}') as team_communications " + + "FROM teams " + + "LEFT JOIN teams_tags ON teams_tags.team_id = teams.team_id " + + "LEFT JOIN users_teams ON users_teams.team_id = teams.team_id " + + "LEFT JOIN exercises_teams ON exercises_teams.team_id = teams.team_id " + + "LEFT JOIN scenarios_teams ON scenarios_teams.team_id = teams.team_id " + + "LEFT JOIN injects_expectations ON injects_expectations.team_id = teams.team_id " + + "LEFT JOIN exercises ON exercises_teams.exercise_id = exercises.exercise_id " + + "LEFT JOIN exercises_teams_users ON exercises_teams_users.team_id = teams.team_id " + + "LEFT JOIN injects ON injects.inject_exercise = exercises.exercise_id " + + "LEFT JOIN communications ON communications.communication_inject = injects.inject_id " + + "WHERE exercises.exercise_id = :exerciseId GROUP BY teams.team_id ;", + nativeQuery = true) List rawTeamByExerciseId(@Param("exerciseId") String exerciseId); - @Query(value = - "SELECT teams.team_id, teams.team_name, teams.team_description, teams.team_created_at, teams.team_updated_at, teams.team_organization, " - + - " team_contextual, " + - " coalesce(array_agg(DISTINCT teams_tags.tag_id) FILTER ( WHERE teams_tags.tag_id IS NOT NULL ), '{}') as team_tags, " - + - " coalesce(array_agg(DISTINCT users_teams.user_id) FILTER ( WHERE users_teams.user_id IS NOT NULL ), '{}') as team_users, " - + - " coalesce(array_agg(DISTINCT exercises_teams.exercise_id) FILTER ( WHERE exercises_teams.exercise_id IS NOT NULL ), '{}') as team_exercises, " - + - " coalesce(array_agg(DISTINCT scenarios_teams.scenario_id) FILTER ( WHERE scenarios_teams.scenario_id IS NOT NULL ), '{}') as team_scenarios, " - + - " coalesce(array_agg(DISTINCT injects_expectations.inject_expectation_id) FILTER ( WHERE injects_expectations.inject_expectation_id IS NOT NULL), '{}') as team_expectations, " - + - " coalesce(array_agg(DISTINCT injects.inject_id) FILTER ( WHERE injects.inject_id IS NOT NULL), '{}') as team_exercise_injects, " - + - " coalesce(array_agg(DISTINCT communications.communication_id) FILTER ( WHERE communications.communication_id IS NOT NULL), '{}') as team_communications " - + - "FROM teams " + - "LEFT JOIN teams_tags ON teams_tags.team_id = teams.team_id " + - "LEFT JOIN users_teams ON users_teams.team_id = teams.team_id " + - "LEFT JOIN exercises_teams ON exercises_teams.team_id = teams.team_id " + - "LEFT JOIN scenarios_teams ON scenarios_teams.team_id = teams.team_id " + - "LEFT JOIN injects_expectations ON injects_expectations.team_id = teams.team_id " + - "LEFT JOIN exercises ON exercises_teams.exercise_id = exercises.exercise_id " + - "LEFT JOIN exercises_teams_users ON exercises_teams_users.team_id = teams.team_id " + - "LEFT JOIN injects ON injects.inject_exercise = exercises.exercise_id " + - "LEFT JOIN communications ON communications.communication_inject = injects.inject_id " + - "WHERE scenarios_teams.scenario_id = :scenarioId GROUP BY teams.team_id ;", nativeQuery = true) + @Query( + value = + "SELECT teams.team_id, teams.team_name, teams.team_description, teams.team_created_at, teams.team_updated_at, teams.team_organization, " + + " team_contextual, " + + " coalesce(array_agg(DISTINCT teams_tags.tag_id) FILTER ( WHERE teams_tags.tag_id IS NOT NULL ), '{}') as team_tags, " + + " coalesce(array_agg(DISTINCT users_teams.user_id) FILTER ( WHERE users_teams.user_id IS NOT NULL ), '{}') as team_users, " + + " coalesce(array_agg(DISTINCT exercises_teams.exercise_id) FILTER ( WHERE exercises_teams.exercise_id IS NOT NULL ), '{}') as team_exercises, " + + " coalesce(array_agg(DISTINCT scenarios_teams.scenario_id) FILTER ( WHERE scenarios_teams.scenario_id IS NOT NULL ), '{}') as team_scenarios, " + + " coalesce(array_agg(DISTINCT injects_expectations.inject_expectation_id) FILTER ( WHERE injects_expectations.inject_expectation_id IS NOT NULL), '{}') as team_expectations, " + + " coalesce(array_agg(DISTINCT injects.inject_id) FILTER ( WHERE injects.inject_id IS NOT NULL), '{}') as team_exercise_injects, " + + " coalesce(array_agg(DISTINCT communications.communication_id) FILTER ( WHERE communications.communication_id IS NOT NULL), '{}') as team_communications " + + "FROM teams " + + "LEFT JOIN teams_tags ON teams_tags.team_id = teams.team_id " + + "LEFT JOIN users_teams ON users_teams.team_id = teams.team_id " + + "LEFT JOIN exercises_teams ON exercises_teams.team_id = teams.team_id " + + "LEFT JOIN scenarios_teams ON scenarios_teams.team_id = teams.team_id " + + "LEFT JOIN injects_expectations ON injects_expectations.team_id = teams.team_id " + + "LEFT JOIN exercises ON exercises_teams.exercise_id = exercises.exercise_id " + + "LEFT JOIN exercises_teams_users ON exercises_teams_users.team_id = teams.team_id " + + "LEFT JOIN injects ON injects.inject_exercise = exercises.exercise_id " + + "LEFT JOIN communications ON communications.communication_inject = injects.inject_id " + + "WHERE scenarios_teams.scenario_id = :scenarioId GROUP BY teams.team_id ;", + nativeQuery = true) List rawTeamByScenarioId(@Param("scenarioId") String scenarioId); - } diff --git a/openbas-model/src/main/java/io/openbas/database/repository/TokenRepository.java b/openbas-model/src/main/java/io/openbas/database/repository/TokenRepository.java index 05900276b9..df306dc24f 100644 --- a/openbas-model/src/main/java/io/openbas/database/repository/TokenRepository.java +++ b/openbas-model/src/main/java/io/openbas/database/repository/TokenRepository.java @@ -2,6 +2,8 @@ import io.openbas.database.model.Token; import jakarta.validation.constraints.NotNull; +import java.time.Instant; +import java.util.Optional; import org.springframework.data.jpa.repository.JpaSpecificationExecutor; import org.springframework.data.jpa.repository.Modifying; import org.springframework.data.jpa.repository.Query; @@ -9,11 +11,9 @@ import org.springframework.data.repository.query.Param; import org.springframework.stereotype.Repository; -import java.time.Instant; -import java.util.Optional; - @Repository -public interface TokenRepository extends CrudRepository, JpaSpecificationExecutor { +public interface TokenRepository + extends CrudRepository, JpaSpecificationExecutor { @NotNull Optional findById(@NotNull String id); @@ -24,12 +24,14 @@ public interface TokenRepository extends CrudRepository, JpaSpeci // Custom query to bypass ID generator on Token property @Modifying - @Query(value = "insert into tokens(token_id, token_user, token_value, token_created_at) " - + "values (:id, :user, :value, :createdAt)", nativeQuery = true) + @Query( + value = + "insert into tokens(token_id, token_user, token_value, token_created_at) " + + "values (:id, :user, :value, :createdAt)", + nativeQuery = true) void createToken( @Param("id") String tokenId, @Param("user") String adminUser, @Param("value") String tokenValue, - @Param("createdAt") Instant createdAt - ); + @Param("createdAt") Instant createdAt); } diff --git a/openbas-model/src/main/java/io/openbas/database/repository/UserRepository.java b/openbas-model/src/main/java/io/openbas/database/repository/UserRepository.java index 39068e0c96..72b57d5f7a 100644 --- a/openbas-model/src/main/java/io/openbas/database/repository/UserRepository.java +++ b/openbas-model/src/main/java/io/openbas/database/repository/UserRepository.java @@ -3,6 +3,9 @@ import io.openbas.database.model.User; import io.openbas.database.raw.RawPlayer; import io.openbas.database.raw.RawUser; +import java.time.Instant; +import java.util.List; +import java.util.Optional; import org.jetbrains.annotations.NotNull; import org.springframework.data.domain.Page; import org.springframework.data.domain.Pageable; @@ -15,13 +18,9 @@ import org.springframework.data.repository.query.Param; import org.springframework.stereotype.Repository; -import java.time.Instant; -import java.util.List; -import java.util.Optional; - @Repository -public interface UserRepository extends CrudRepository, JpaSpecificationExecutor, - StatisticRepository { +public interface UserRepository + extends CrudRepository, JpaSpecificationExecutor, StatisticRepository { @NotNull Optional findById(@NotNull String id); @@ -31,12 +30,13 @@ public interface UserRepository extends CrudRepository, JpaSpecifi List findAllByEmailInIgnoreCase(List emails); @Override - @Query("select count(distinct u) from User u " + - "join u.teams as team " + - "join team.exercises as e " + - "join e.grants as grant " + - "join grant.group.users as user " + - "where user.id = :userId and u.createdAt < :creationDate") + @Query( + "select count(distinct u) from User u " + + "join u.teams as team " + + "join team.exercises as e " + + "join e.grants as grant " + + "join grant.group.users as user " + + "where user.id = :userId and u.createdAt < :creationDate") long userCount(String userId, Instant creationDate); @Override @@ -47,50 +47,65 @@ public interface UserRepository extends CrudRepository, JpaSpecifi // Custom query to bypass ID generator on User property @Modifying - @Query(value = "insert into users(user_id, user_firstname, user_lastname, user_email, user_password, user_admin, user_status) " - + "values (:id, :firstname, :lastName, :email, :password, true, 1)", nativeQuery = true) + @Query( + value = + "insert into users(user_id, user_firstname, user_lastname, user_email, user_password, user_admin, user_status) " + + "values (:id, :firstname, :lastName, :email, :password, true, 1)", + nativeQuery = true) void createAdmin( @Param("id") String userId, @Param("firstname") String userFirstName, @Param("lastName") String userLastName, @Param("email") String userEmail, - @Param("password") String userPassword - ); - - @Query(value = "select us.*, " - + " array_remove(array_agg(tg.tag_id), null) as user_tags," - + " array_remove(array_agg(grp.group_id), null) as user_groups," - + " array_remove(array_agg(tm.team_id), null) as user_teams from users us" - + " left join users_groups usr_grp on us.user_id = usr_grp.user_id" - + " left join groups grp on usr_grp.group_id = grp.group_id" - + " left join users_teams usr_tm on us.user_id = usr_tm.user_id" - + " left join teams tm on usr_tm.team_id = tm.team_id" - + " left join users_tags usr_tg on us.user_id = usr_tg.user_id" - + " left join tags tg on usr_tg.tag_id = tg.tag_id" - + " group by us.user_id;", nativeQuery = true) + @Param("password") String userPassword); + + @Query( + value = + "select us.*, " + + " array_remove(array_agg(tg.tag_id), null) as user_tags," + + " array_remove(array_agg(grp.group_id), null) as user_groups," + + " array_remove(array_agg(tm.team_id), null) as user_teams from users us" + + " left join users_groups usr_grp on us.user_id = usr_grp.user_id" + + " left join groups grp on usr_grp.group_id = grp.group_id" + + " left join users_teams usr_tm on us.user_id = usr_tm.user_id" + + " left join teams tm on usr_tm.team_id = tm.team_id" + + " left join users_tags usr_tg on us.user_id = usr_tg.user_id" + + " left join tags tg on usr_tg.tag_id = tg.tag_id" + + " group by us.user_id;", + nativeQuery = true) List rawAll(); - @Query(value = "select us.user_id, us.user_email, " + - "us.user_firstname, us.user_lastname, " + - "us.user_country, us.user_organization," + - "array_remove(array_agg(tg.tag_id), null) as user_tags " + - "from users us " + - "left join users_tags usr_tg on us.user_id = usr_tg.user_id " + - "left join tags tg on usr_tg.tag_id = tg.tag_id " + - "group by us.user_id;", nativeQuery = true) + @Query( + value = + "select us.user_id, us.user_email, " + + "us.user_firstname, us.user_lastname, " + + "us.user_country, us.user_organization," + + "array_remove(array_agg(tg.tag_id), null) as user_tags " + + "from users us " + + "left join users_tags usr_tg on us.user_id = usr_tg.user_id " + + "left join tags tg on usr_tg.tag_id = tg.tag_id " + + "group by us.user_id;", + nativeQuery = true) List rawAllPlayers(); - @Query(value = "select us from users us where us.user_organization is null or us.user_organization in :organizationIds", nativeQuery = true) - List rawPlayersAccessibleFromOrganizations(@Param("organizationIds") List organizationIds); - - @Query(value = "SELECT us.user_id, " - + "us.user_firstname, " - + "us.user_lastname, " - + "us.user_email, " - + "us.user_phone, " - + "us.user_organization " - + "FROM users us " - + "WHERE us.user_id IN :ids ;", nativeQuery = true) + @Query( + value = + "select us from users us where us.user_organization is null or us.user_organization in :organizationIds", + nativeQuery = true) + List rawPlayersAccessibleFromOrganizations( + @Param("organizationIds") List organizationIds); + + @Query( + value = + "SELECT us.user_id, " + + "us.user_firstname, " + + "us.user_lastname, " + + "us.user_email, " + + "us.user_phone, " + + "us.user_organization " + + "FROM users us " + + "WHERE us.user_id IN :ids ;", + nativeQuery = true) List rawUserByIds(@Param("ids") List ids); // -- PAGINATION -- diff --git a/openbas-model/src/main/java/io/openbas/database/repository/VariableRepository.java b/openbas-model/src/main/java/io/openbas/database/repository/VariableRepository.java index f6c0ce20ca..da5fd42738 100644 --- a/openbas-model/src/main/java/io/openbas/database/repository/VariableRepository.java +++ b/openbas-model/src/main/java/io/openbas/database/repository/VariableRepository.java @@ -6,6 +6,5 @@ import org.springframework.stereotype.Repository; @Repository -public interface VariableRepository extends CrudRepository, JpaSpecificationExecutor { - -} +public interface VariableRepository + extends CrudRepository, JpaSpecificationExecutor {} diff --git a/openbas-model/src/main/java/io/openbas/database/specification/ArticleSpecification.java b/openbas-model/src/main/java/io/openbas/database/specification/ArticleSpecification.java index 53139f5805..5b61b72adb 100644 --- a/openbas-model/src/main/java/io/openbas/database/specification/ArticleSpecification.java +++ b/openbas-model/src/main/java/io/openbas/database/specification/ArticleSpecification.java @@ -6,9 +6,7 @@ public class ArticleSpecification { - private ArticleSpecification() { - - } + private ArticleSpecification() {} public static Specification
fromExercise(@NotBlank final String exerciseId) { return (root, query, cb) -> cb.equal(root.get("exercise").get("id"), exerciseId); @@ -17,5 +15,4 @@ public static Specification
fromExercise(@NotBlank final String exercis public static Specification
fromScenario(@NotBlank final String scenarioId) { return (root, query, cb) -> cb.equal(root.get("scenario").get("id"), scenarioId); } - } diff --git a/openbas-model/src/main/java/io/openbas/database/specification/AssetAgentJobSpecification.java b/openbas-model/src/main/java/io/openbas/database/specification/AssetAgentJobSpecification.java index 2da36dde29..0b7ecd1f48 100644 --- a/openbas-model/src/main/java/io/openbas/database/specification/AssetAgentJobSpecification.java +++ b/openbas-model/src/main/java/io/openbas/database/specification/AssetAgentJobSpecification.java @@ -5,11 +5,11 @@ public class AssetAgentJobSpecification { - public static Specification forEndpoint(String externalReference) { - // TODO Add time limitation - // TODO add cleanup - return (root, query, cb) -> { - return cb.equal(root.get("asset").get("externalReference"), externalReference); - }; - } + public static Specification forEndpoint(String externalReference) { + // TODO Add time limitation + // TODO add cleanup + return (root, query, cb) -> { + return cb.equal(root.get("asset").get("externalReference"), externalReference); + }; + } } diff --git a/openbas-model/src/main/java/io/openbas/database/specification/AssetGroupSpecification.java b/openbas-model/src/main/java/io/openbas/database/specification/AssetGroupSpecification.java index 0ad9815193..8e84132785 100644 --- a/openbas-model/src/main/java/io/openbas/database/specification/AssetGroupSpecification.java +++ b/openbas-model/src/main/java/io/openbas/database/specification/AssetGroupSpecification.java @@ -1,18 +1,15 @@ package io.openbas.database.specification; import io.openbas.database.model.AssetGroup; +import java.util.List; import org.jetbrains.annotations.NotNull; import org.springframework.data.jpa.domain.Specification; -import java.util.List; - public class AssetGroupSpecification { - private AssetGroupSpecification() { - } + private AssetGroupSpecification() {} public static Specification fromIds(@NotNull final List ids) { return (root, query, builder) -> root.get("id").in(ids); } - } diff --git a/openbas-model/src/main/java/io/openbas/database/specification/AttackPatternSpecification.java b/openbas-model/src/main/java/io/openbas/database/specification/AttackPatternSpecification.java index 28076925d5..bcd9bc6c42 100644 --- a/openbas-model/src/main/java/io/openbas/database/specification/AttackPatternSpecification.java +++ b/openbas-model/src/main/java/io/openbas/database/specification/AttackPatternSpecification.java @@ -4,14 +4,13 @@ import jakarta.annotation.Nullable; import org.springframework.data.jpa.domain.Specification; - public class AttackPatternSpecification { - public static Specification fromAttackPattern(String attackPatternId) { - return (root, query, cb) -> cb.equal(root.get("attackPatterns").get("id"), attackPatternId); - } + public static Specification fromAttackPattern(String attackPatternId) { + return (root, query, cb) -> cb.equal(root.get("attackPatterns").get("id"), attackPatternId); + } - public static Specification byName(@Nullable final String searchText) { - return UtilsSpecification.byName(searchText, "name"); - } + public static Specification byName(@Nullable final String searchText) { + return UtilsSpecification.byName(searchText, "name"); + } } diff --git a/openbas-model/src/main/java/io/openbas/database/specification/ComcheckSpecification.java b/openbas-model/src/main/java/io/openbas/database/specification/ComcheckSpecification.java index 71c190310e..7e4482096b 100644 --- a/openbas-model/src/main/java/io/openbas/database/specification/ComcheckSpecification.java +++ b/openbas-model/src/main/java/io/openbas/database/specification/ComcheckSpecification.java @@ -5,11 +5,11 @@ public class ComcheckSpecification { - public static Specification id(String dryRunId) { - return (root, query, cb) -> cb.equal(root.get("id"), dryRunId); - } + public static Specification id(String dryRunId) { + return (root, query, cb) -> cb.equal(root.get("id"), dryRunId); + } - public static Specification fromExercise(String exerciseId) { - return (root, query, cb) -> cb.equal(root.get("exercise").get("id"), exerciseId); - } + public static Specification fromExercise(String exerciseId) { + return (root, query, cb) -> cb.equal(root.get("exercise").get("id"), exerciseId); + } } diff --git a/openbas-model/src/main/java/io/openbas/database/specification/ComcheckStatusSpecification.java b/openbas-model/src/main/java/io/openbas/database/specification/ComcheckStatusSpecification.java index 819dfa129f..1fd87ef6f0 100644 --- a/openbas-model/src/main/java/io/openbas/database/specification/ComcheckStatusSpecification.java +++ b/openbas-model/src/main/java/io/openbas/database/specification/ComcheckStatusSpecification.java @@ -6,11 +6,13 @@ public class ComcheckStatusSpecification { - public static Specification thatNeedExecution() { - return (root, query, cb) -> cb.and( - cb.isNull(root.get("receiveDate")), // Not Checked - cb.isNull(root.get("lastSent")), // Not already sent - cb.equal(root.get("comcheck").get("state"), Comcheck.COMCHECK_STATUS.RUNNING) // fromRunning - ); - } + public static Specification thatNeedExecution() { + return (root, query, cb) -> + cb.and( + cb.isNull(root.get("receiveDate")), // Not Checked + cb.isNull(root.get("lastSent")), // Not already sent + cb.equal( + root.get("comcheck").get("state"), Comcheck.COMCHECK_STATUS.RUNNING) // fromRunning + ); + } } diff --git a/openbas-model/src/main/java/io/openbas/database/specification/CommunicationSpecification.java b/openbas-model/src/main/java/io/openbas/database/specification/CommunicationSpecification.java index fc7d11f501..b3bd94e2c6 100644 --- a/openbas-model/src/main/java/io/openbas/database/specification/CommunicationSpecification.java +++ b/openbas-model/src/main/java/io/openbas/database/specification/CommunicationSpecification.java @@ -5,7 +5,7 @@ public class CommunicationSpecification { - public static Specification fromInject(String injectId) { - return (root, query, cb) -> cb.equal(root.get("inject").get("id"), injectId); - } + public static Specification fromInject(String injectId) { + return (root, query, cb) -> cb.equal(root.get("inject").get("id"), injectId); + } } diff --git a/openbas-model/src/main/java/io/openbas/database/specification/DocumentSpecification.java b/openbas-model/src/main/java/io/openbas/database/specification/DocumentSpecification.java index 4796173dde..da6d87d54f 100644 --- a/openbas-model/src/main/java/io/openbas/database/specification/DocumentSpecification.java +++ b/openbas-model/src/main/java/io/openbas/database/specification/DocumentSpecification.java @@ -9,23 +9,14 @@ public class DocumentSpecification { public static Specification findGrantedFor(@NotBlank final String userId) { return (root, query, criteriaBuilder) -> { - Path exercisePath = root - .join("exercises") - .join("grants") - .join("group") - .join("users").get("id"); + Path exercisePath = + root.join("exercises").join("grants").join("group").join("users").get("id"); - Path scenarioPath = root - .join("scenarios") - .join("grants") - .join("group") - .join("users").get("id"); + Path scenarioPath = + root.join("scenarios").join("grants").join("group").join("users").get("id"); return criteriaBuilder.or( - criteriaBuilder.equal(exercisePath, userId), - criteriaBuilder.equal(scenarioPath, userId) - ); + criteriaBuilder.equal(exercisePath, userId), criteriaBuilder.equal(scenarioPath, userId)); }; } - } diff --git a/openbas-model/src/main/java/io/openbas/database/specification/DryInjectSpecification.java b/openbas-model/src/main/java/io/openbas/database/specification/DryInjectSpecification.java index 30aa833aca..6bf8c3431e 100644 --- a/openbas-model/src/main/java/io/openbas/database/specification/DryInjectSpecification.java +++ b/openbas-model/src/main/java/io/openbas/database/specification/DryInjectSpecification.java @@ -1,17 +1,16 @@ package io.openbas.database.specification; import io.openbas.database.model.DryInject; -import org.springframework.data.jpa.domain.Specification; - import jakarta.persistence.criteria.JoinType; +import org.springframework.data.jpa.domain.Specification; public class DryInjectSpecification { - public static Specification executable() { - return (root, query, cb) -> cb.isNull(root.join("status", JoinType.LEFT).get("name")); - } + public static Specification executable() { + return (root, query, cb) -> cb.isNull(root.join("status", JoinType.LEFT).get("name")); + } - public static Specification fromDryRun(String dryrunId) { - return (root, query, cb) -> cb.equal(root.get("run").get("id"), dryrunId); - } + public static Specification fromDryRun(String dryrunId) { + return (root, query, cb) -> cb.equal(root.get("run").get("id"), dryrunId); + } } diff --git a/openbas-model/src/main/java/io/openbas/database/specification/DryRunSpecification.java b/openbas-model/src/main/java/io/openbas/database/specification/DryRunSpecification.java index 4d40050171..774716dde0 100644 --- a/openbas-model/src/main/java/io/openbas/database/specification/DryRunSpecification.java +++ b/openbas-model/src/main/java/io/openbas/database/specification/DryRunSpecification.java @@ -5,11 +5,11 @@ public class DryRunSpecification { - public static Specification id(String dryRunId) { - return (root, query, cb) -> cb.equal(root.get("id"), dryRunId); - } + public static Specification id(String dryRunId) { + return (root, query, cb) -> cb.equal(root.get("id"), dryRunId); + } - public static Specification fromExercise(String exerciseId) { - return (root, query, cb) -> cb.equal(root.get("exercise").get("id"), exerciseId); - } + public static Specification fromExercise(String exerciseId) { + return (root, query, cb) -> cb.equal(root.get("exercise").get("id"), exerciseId); + } } diff --git a/openbas-model/src/main/java/io/openbas/database/specification/EndpointSpecification.java b/openbas-model/src/main/java/io/openbas/database/specification/EndpointSpecification.java index 292880d045..e12f4fb83a 100644 --- a/openbas-model/src/main/java/io/openbas/database/specification/EndpointSpecification.java +++ b/openbas-model/src/main/java/io/openbas/database/specification/EndpointSpecification.java @@ -4,11 +4,16 @@ import org.springframework.data.jpa.domain.Specification; public class EndpointSpecification { - public static Specification findEndpointsForInjection() { - return (root, query, criteriaBuilder) -> criteriaBuilder.and(criteriaBuilder.isNull(root.get("parent")), criteriaBuilder.isNull(root.get("inject"))); - } + public static Specification findEndpointsForInjection() { + return (root, query, criteriaBuilder) -> + criteriaBuilder.and( + criteriaBuilder.isNull(root.get("parent")), criteriaBuilder.isNull(root.get("inject"))); + } - public static Specification findEndpointsForExecution() { - return (root, query, criteriaBuilder) -> criteriaBuilder.or(criteriaBuilder.isNotNull(root.get("parent")), criteriaBuilder.isNotNull(root.get("inject"))); - } + public static Specification findEndpointsForExecution() { + return (root, query, criteriaBuilder) -> + criteriaBuilder.or( + criteriaBuilder.isNotNull(root.get("parent")), + criteriaBuilder.isNotNull(root.get("inject"))); + } } diff --git a/openbas-model/src/main/java/io/openbas/database/specification/EvaluationSpecification.java b/openbas-model/src/main/java/io/openbas/database/specification/EvaluationSpecification.java index 8ed5e65f09..85a5482f4c 100644 --- a/openbas-model/src/main/java/io/openbas/database/specification/EvaluationSpecification.java +++ b/openbas-model/src/main/java/io/openbas/database/specification/EvaluationSpecification.java @@ -3,10 +3,9 @@ import io.openbas.database.model.Evaluation; import org.springframework.data.jpa.domain.Specification; - public class EvaluationSpecification { - public static Specification fromObjective(String objectiveId) { - return (root, query, cb) -> cb.equal(root.get("objective").get("id"), objectiveId); - } + public static Specification fromObjective(String objectiveId) { + return (root, query, cb) -> cb.equal(root.get("objective").get("id"), objectiveId); + } } diff --git a/openbas-model/src/main/java/io/openbas/database/specification/ExerciseLogSpecification.java b/openbas-model/src/main/java/io/openbas/database/specification/ExerciseLogSpecification.java index a0b54355e4..bb4a2e4550 100644 --- a/openbas-model/src/main/java/io/openbas/database/specification/ExerciseLogSpecification.java +++ b/openbas-model/src/main/java/io/openbas/database/specification/ExerciseLogSpecification.java @@ -5,7 +5,7 @@ public class ExerciseLogSpecification { - public static Specification fromExercise(String exerciseId) { - return (root, query, cb) -> cb.equal(root.get("exercise").get("id"), exerciseId); - } + public static Specification fromExercise(String exerciseId) { + return (root, query, cb) -> cb.equal(root.get("exercise").get("id"), exerciseId); + } } diff --git a/openbas-model/src/main/java/io/openbas/database/specification/ExerciseSpecification.java b/openbas-model/src/main/java/io/openbas/database/specification/ExerciseSpecification.java index 8378a856ac..d853622a50 100644 --- a/openbas-model/src/main/java/io/openbas/database/specification/ExerciseSpecification.java +++ b/openbas-model/src/main/java/io/openbas/database/specification/ExerciseSpecification.java @@ -1,31 +1,24 @@ package io.openbas.database.specification; +import static io.openbas.database.model.ExerciseStatus.SCHEDULED; + import io.openbas.database.model.Exercise; import jakarta.persistence.criteria.Path; import org.jetbrains.annotations.NotNull; import org.springframework.data.jpa.domain.Specification; -import static io.openbas.database.model.ExerciseStatus.SCHEDULED; - public class ExerciseSpecification { - private ExerciseSpecification() { - - } + private ExerciseSpecification() {} public static Specification recurringInstanceNotStarted() { - return (root, query, cb) -> cb.and( - cb.equal(root.get("status"), SCHEDULED), - cb.isNotNull(root.get("scenario")) - ); + return (root, query, cb) -> + cb.and(cb.equal(root.get("status"), SCHEDULED), cb.isNotNull(root.get("scenario"))); } public static Specification findGrantedFor(@NotNull final String userId) { return (root, query, cb) -> { - Path path = root - .join("grants") - .join("group") - .join("users").get("id"); + Path path = root.join("grants").join("group").join("users").get("id"); return cb.equal(path, userId); }; } diff --git a/openbas-model/src/main/java/io/openbas/database/specification/GrantSpecification.java b/openbas-model/src/main/java/io/openbas/database/specification/GrantSpecification.java index dc371806e0..16a02544c6 100644 --- a/openbas-model/src/main/java/io/openbas/database/specification/GrantSpecification.java +++ b/openbas-model/src/main/java/io/openbas/database/specification/GrantSpecification.java @@ -9,5 +9,4 @@ public class GrantSpecification { public static Specification fromName(@NotBlank final Grant.GRANT_TYPE name) { return (root, query, cb) -> cb.equal(root.get("name"), name); } - } diff --git a/openbas-model/src/main/java/io/openbas/database/specification/GroupSpecification.java b/openbas-model/src/main/java/io/openbas/database/specification/GroupSpecification.java index f2e1d364a3..884d87db38 100644 --- a/openbas-model/src/main/java/io/openbas/database/specification/GroupSpecification.java +++ b/openbas-model/src/main/java/io/openbas/database/specification/GroupSpecification.java @@ -6,11 +6,11 @@ public class GroupSpecification { - public static Specification defaultUserAssignable() { - return (root, query, cb) -> cb.equal(root.get("defaultUserAssignation"), true); - } + public static Specification defaultUserAssignable() { + return (root, query, cb) -> cb.equal(root.get("defaultUserAssignation"), true); + } - public static Specification fromName(@NotBlank final String name) { - return (root, query, cb) -> cb.equal(root.get("name"), name); - } + public static Specification fromName(@NotBlank final String name) { + return (root, query, cb) -> cb.equal(root.get("name"), name); + } } diff --git a/openbas-model/src/main/java/io/openbas/database/specification/InjectExpectationSpecification.java b/openbas-model/src/main/java/io/openbas/database/specification/InjectExpectationSpecification.java index 5596f8fe20..d617a33251 100644 --- a/openbas-model/src/main/java/io/openbas/database/specification/InjectExpectationSpecification.java +++ b/openbas-model/src/main/java/io/openbas/database/specification/InjectExpectationSpecification.java @@ -4,10 +4,9 @@ import io.openbas.database.model.InjectExpectation.EXPECTATION_TYPE; import jakarta.validation.constraints.NotBlank; import jakarta.validation.constraints.NotEmpty; -import org.springframework.data.jpa.domain.Specification; - import java.time.Instant; import java.util.List; +import org.springframework.data.jpa.domain.Specification; public class InjectExpectationSpecification { @@ -20,12 +19,10 @@ public static Specification from(@NotBlank final Instant date } public static Specification fromAssets( - @NotBlank final String injectId, - @NotEmpty final List assetIds) { - return (root, query, cb) -> cb.and( - cb.equal(root.get("inject").get("id"), injectId), - root.get("asset").get("id").in(assetIds) - ); + @NotBlank final String injectId, @NotEmpty final List assetIds) { + return (root, query, cb) -> + cb.and( + cb.equal(root.get("inject").get("id"), injectId), + root.get("asset").get("id").in(assetIds)); } - } diff --git a/openbas-model/src/main/java/io/openbas/database/specification/InjectSpecification.java b/openbas-model/src/main/java/io/openbas/database/specification/InjectSpecification.java index e0dd6c53b5..23cecbbaf0 100644 --- a/openbas-model/src/main/java/io/openbas/database/specification/InjectSpecification.java +++ b/openbas-model/src/main/java/io/openbas/database/specification/InjectSpecification.java @@ -6,82 +6,79 @@ import jakarta.persistence.criteria.JoinType; import jakarta.persistence.criteria.Path; import jakarta.validation.constraints.NotBlank; -import org.springframework.data.jpa.domain.Specification; - import java.util.Arrays; import java.util.HashSet; import java.util.List; import java.util.Set; +import org.springframework.data.jpa.domain.Specification; public class InjectSpecification { - private InjectSpecification() { - - } - - public static Specification fromExercise(String exerciseId) { - return (root, query, cb) -> cb.equal(root.get("exercise").get("id"), exerciseId); - } - - public static Specification fromScenario(String scenarioId) { - return (root, query, cb) -> cb.equal(root.get("scenario").get("id"), scenarioId); - } - - public static Specification next() { - return (root, query, cb) -> { - Path exercisePath = root.get("exercise"); - return cb.and( - cb.equal(root.get("enabled"), true), // isEnable - cb.isNotNull(exercisePath.get("start")), // fromScheduled - cb.isNull(root.join("status", JoinType.LEFT).get("name")) // notExecuted - ); - }; - } - - public static Specification executable() { - return (root, query, cb) -> { - Path exercisePath = root.get("exercise"); - return cb.and( - // cb.notEqual(root.get("type"), ManualContract.TYPE), // notManual - cb.equal(root.get("enabled"), true), // isEnable - cb.isNotNull(exercisePath.get("start")), // fromScheduled - cb.equal(exercisePath.get("status"), ExerciseStatus.RUNNING), // fromRunningExercise - cb.isNull(root.join("status", JoinType.LEFT).get("name")) // notExecuted + private InjectSpecification() {} + + public static Specification fromExercise(String exerciseId) { + return (root, query, cb) -> cb.equal(root.get("exercise").get("id"), exerciseId); + } + + public static Specification fromScenario(String scenarioId) { + return (root, query, cb) -> cb.equal(root.get("scenario").get("id"), scenarioId); + } + + public static Specification next() { + return (root, query, cb) -> { + Path exercisePath = root.get("exercise"); + return cb.and( + cb.equal(root.get("enabled"), true), // isEnable + cb.isNotNull(exercisePath.get("start")), // fromScheduled + cb.isNull(root.join("status", JoinType.LEFT).get("name")) // notExecuted + ); + }; + } + + public static Specification executable() { + return (root, query, cb) -> { + Path exercisePath = root.get("exercise"); + return cb.and( + // cb.notEqual(root.get("type"), ManualContract.TYPE), // notManual + cb.equal(root.get("enabled"), true), // isEnable + cb.isNotNull(exercisePath.get("start")), // fromScheduled + cb.equal(exercisePath.get("status"), ExerciseStatus.RUNNING), // fromRunningExercise + cb.isNull(root.join("status", JoinType.LEFT).get("name")) // notExecuted + ); + }; + } + + public static Specification forDryrun(String exerciseId) { + return (root, query, cb) -> + cb.and( + // cb.notEqual(root.get("type"), ManualContract.TYPE), // notManual + cb.equal(root.get("enabled"), true), // isEnable + cb.equal(root.get("exercise").get("id"), exerciseId) // fromWantedExercise ); - }; - } - - public static Specification forDryrun(String exerciseId) { - return (root, query, cb) -> cb.and( - // cb.notEqual(root.get("type"), ManualContract.TYPE), // notManual - cb.equal(root.get("enabled"), true), // isEnable - cb.equal(root.get("exercise").get("id"), exerciseId) // fromWantedExercise - ); - } - - public static Specification forAtomicTesting() { - return (root, query, cb) -> cb.and( - cb.isNull(root.get("exercise")), // No exercise - cb.isNull(root.get("scenario")), // No scenario - cb.equal(root.get("status").get("name"), ExecutionStatus.QUEUING), - cb.notEqual(root.get("status").get("name"), ExecutionStatus.PENDING) - ); - } - - public static Specification fromContract(@NotBlank final String contract) { - return (root, query, cb) -> cb.equal(root.get("injectorContract").get("id"), contract); - } - - public static final Set VALID_TESTABLE_TYPES = new HashSet<>( - Arrays.asList("openbas_email", "openbas_ovh_sms") - ); - - public static Specification byIds(List injectIds) { - return (root, query, cb) -> root.get("id").in(injectIds); - } - - public static Specification testable() { - return (root, query, cb) -> root.get("injectorContract").get("injector").get("type").in(VALID_TESTABLE_TYPES); - } - + } + + public static Specification forAtomicTesting() { + return (root, query, cb) -> + cb.and( + cb.isNull(root.get("exercise")), // No exercise + cb.isNull(root.get("scenario")), // No scenario + cb.equal(root.get("status").get("name"), ExecutionStatus.QUEUING), + cb.notEqual(root.get("status").get("name"), ExecutionStatus.PENDING)); + } + + public static Specification fromContract(@NotBlank final String contract) { + return (root, query, cb) -> cb.equal(root.get("injectorContract").get("id"), contract); + } + + public static final Set VALID_TESTABLE_TYPES = + new HashSet<>(Arrays.asList("openbas_email", "openbas_ovh_sms")); + + public static Specification byIds(List injectIds) { + return (root, query, cb) -> root.get("id").in(injectIds); + } + + public static Specification testable() { + return (root, query, cb) -> + root.get("injectorContract").get("injector").get("type").in(VALID_TESTABLE_TYPES); + } } diff --git a/openbas-model/src/main/java/io/openbas/database/specification/InjectTestSpecification.java b/openbas-model/src/main/java/io/openbas/database/specification/InjectTestSpecification.java index b491878e64..cef95e58d3 100644 --- a/openbas-model/src/main/java/io/openbas/database/specification/InjectTestSpecification.java +++ b/openbas-model/src/main/java/io/openbas/database/specification/InjectTestSpecification.java @@ -10,8 +10,8 @@ public class InjectTestSpecification { public static Specification findInjectTestInExercise(String exerciseId) { return (root, query, criteriaBuilder) -> { - Path path = root.join("inject", JoinType.INNER) - .join("exercise", JoinType.INNER).get("id"); + Path path = + root.join("inject", JoinType.INNER).join("exercise", JoinType.INNER).get("id"); return criteriaBuilder.equal(path, exerciseId); }; } @@ -19,10 +19,9 @@ public static Specification findInjectTestInExercise(String ex public static Specification findInjectTestInScenario(String scenarioId) { return (root, query, criteriaBuilder) -> { - Path path = root.join("inject", JoinType.INNER) - .join("scenario", JoinType.INNER).get("id"); + Path path = + root.join("inject", JoinType.INNER).join("scenario", JoinType.INNER).get("id"); return criteriaBuilder.equal(path, scenarioId); }; } - } diff --git a/openbas-model/src/main/java/io/openbas/database/specification/InjectorContractSpecification.java b/openbas-model/src/main/java/io/openbas/database/specification/InjectorContractSpecification.java index b0b6a6dbe1..4eae754f18 100644 --- a/openbas-model/src/main/java/io/openbas/database/specification/InjectorContractSpecification.java +++ b/openbas-model/src/main/java/io/openbas/database/specification/InjectorContractSpecification.java @@ -4,21 +4,18 @@ import jakarta.persistence.criteria.Path; import org.springframework.data.jpa.domain.Specification; - public class InjectorContractSpecification { - private InjectorContractSpecification() { - - } + private InjectorContractSpecification() {} - public static Specification fromAttackPattern(String attackPatternId) { - return (root, query, cb) -> cb.equal(root.get("attackPatterns").get("id"), attackPatternId); - } + public static Specification fromAttackPattern(String attackPatternId) { + return (root, query, cb) -> cb.equal(root.get("attackPatterns").get("id"), attackPatternId); + } - public static Specification fromKillChainPhase(String killChainPhaseId) { - return (root, query, criteriaBuilder) -> { - Path path = root.join("attackPatterns").join("killChainPhases").get("id"); - return criteriaBuilder.equal(path, killChainPhaseId); - }; - } + public static Specification fromKillChainPhase(String killChainPhaseId) { + return (root, query, criteriaBuilder) -> { + Path path = root.join("attackPatterns").join("killChainPhases").get("id"); + return criteriaBuilder.equal(path, killChainPhaseId); + }; + } } diff --git a/openbas-model/src/main/java/io/openbas/database/specification/InjectorSpecification.java b/openbas-model/src/main/java/io/openbas/database/specification/InjectorSpecification.java index cf8a8ee3f2..7c43c0e715 100644 --- a/openbas-model/src/main/java/io/openbas/database/specification/InjectorSpecification.java +++ b/openbas-model/src/main/java/io/openbas/database/specification/InjectorSpecification.java @@ -6,13 +6,9 @@ public class InjectorSpecification { - private InjectorSpecification() { - - } + private InjectorSpecification() {} public static Specification byName(@Nullable final String searchText) { return UtilsSpecification.byName(searchText, "name"); } - - } diff --git a/openbas-model/src/main/java/io/openbas/database/specification/KillChainPhaseSpecification.java b/openbas-model/src/main/java/io/openbas/database/specification/KillChainPhaseSpecification.java index e9cc7d41d1..462e268362 100644 --- a/openbas-model/src/main/java/io/openbas/database/specification/KillChainPhaseSpecification.java +++ b/openbas-model/src/main/java/io/openbas/database/specification/KillChainPhaseSpecification.java @@ -6,12 +6,9 @@ public class KillChainPhaseSpecification { - private KillChainPhaseSpecification() { - - } + private KillChainPhaseSpecification() {} public static Specification byName(@Nullable final String searchText) { return UtilsSpecification.byName(searchText, "name"); } - } diff --git a/openbas-model/src/main/java/io/openbas/database/specification/LessonsAnswerSpecification.java b/openbas-model/src/main/java/io/openbas/database/specification/LessonsAnswerSpecification.java index 4dc47ed600..545fab6ddc 100644 --- a/openbas-model/src/main/java/io/openbas/database/specification/LessonsAnswerSpecification.java +++ b/openbas-model/src/main/java/io/openbas/database/specification/LessonsAnswerSpecification.java @@ -5,7 +5,7 @@ public class LessonsAnswerSpecification { - public static Specification fromQuestion(String questionId) { - return (root, query, cb) -> cb.equal(root.get("question").get("id"), questionId); - } + public static Specification fromQuestion(String questionId) { + return (root, query, cb) -> cb.equal(root.get("question").get("id"), questionId); + } } diff --git a/openbas-model/src/main/java/io/openbas/database/specification/LessonsCategorySpecification.java b/openbas-model/src/main/java/io/openbas/database/specification/LessonsCategorySpecification.java index 40e00d08ae..19c99afe27 100644 --- a/openbas-model/src/main/java/io/openbas/database/specification/LessonsCategorySpecification.java +++ b/openbas-model/src/main/java/io/openbas/database/specification/LessonsCategorySpecification.java @@ -3,14 +3,13 @@ import io.openbas.database.model.LessonsCategory; import org.springframework.data.jpa.domain.Specification; - public class LessonsCategorySpecification { - public static Specification fromExercise(String exerciseId) { - return (root, query, cb) -> cb.equal(root.get("exercise").get("id"), exerciseId); - } + public static Specification fromExercise(String exerciseId) { + return (root, query, cb) -> cb.equal(root.get("exercise").get("id"), exerciseId); + } - public static Specification fromScenario(String scenarioId) { - return (root, query, cb) -> cb.equal(root.get("scenario").get("id"), scenarioId); - } + public static Specification fromScenario(String scenarioId) { + return (root, query, cb) -> cb.equal(root.get("scenario").get("id"), scenarioId); + } } diff --git a/openbas-model/src/main/java/io/openbas/database/specification/LessonsQuestionSpecification.java b/openbas-model/src/main/java/io/openbas/database/specification/LessonsQuestionSpecification.java index b0aa2b02be..82757e9f80 100644 --- a/openbas-model/src/main/java/io/openbas/database/specification/LessonsQuestionSpecification.java +++ b/openbas-model/src/main/java/io/openbas/database/specification/LessonsQuestionSpecification.java @@ -3,10 +3,9 @@ import io.openbas.database.model.LessonsQuestion; import org.springframework.data.jpa.domain.Specification; - public class LessonsQuestionSpecification { - public static Specification fromCategory(String categoryId) { - return (root, query, cb) -> cb.equal(root.get("category").get("id"), categoryId); - } + public static Specification fromCategory(String categoryId) { + return (root, query, cb) -> cb.equal(root.get("category").get("id"), categoryId); + } } diff --git a/openbas-model/src/main/java/io/openbas/database/specification/LessonsTemplateCategorySpecification.java b/openbas-model/src/main/java/io/openbas/database/specification/LessonsTemplateCategorySpecification.java index c851d490e6..0f46f11064 100644 --- a/openbas-model/src/main/java/io/openbas/database/specification/LessonsTemplateCategorySpecification.java +++ b/openbas-model/src/main/java/io/openbas/database/specification/LessonsTemplateCategorySpecification.java @@ -3,10 +3,9 @@ import io.openbas.database.model.LessonsTemplateCategory; import org.springframework.data.jpa.domain.Specification; - public class LessonsTemplateCategorySpecification { - public static Specification fromTemplate(String templateId) { - return (root, query, cb) -> cb.equal(root.get("template").get("id"), templateId); - } + public static Specification fromTemplate(String templateId) { + return (root, query, cb) -> cb.equal(root.get("template").get("id"), templateId); + } } diff --git a/openbas-model/src/main/java/io/openbas/database/specification/LessonsTemplateQuestionSpecification.java b/openbas-model/src/main/java/io/openbas/database/specification/LessonsTemplateQuestionSpecification.java index 451c938772..48835ff2df 100644 --- a/openbas-model/src/main/java/io/openbas/database/specification/LessonsTemplateQuestionSpecification.java +++ b/openbas-model/src/main/java/io/openbas/database/specification/LessonsTemplateQuestionSpecification.java @@ -3,10 +3,9 @@ import io.openbas.database.model.LessonsTemplateQuestion; import org.springframework.data.jpa.domain.Specification; - public class LessonsTemplateQuestionSpecification { - public static Specification fromCategory(String categoryId) { - return (root, query, cb) -> cb.equal(root.get("category").get("id"), categoryId); - } + public static Specification fromCategory(String categoryId) { + return (root, query, cb) -> cb.equal(root.get("category").get("id"), categoryId); + } } diff --git a/openbas-model/src/main/java/io/openbas/database/specification/ObjectiveSpecification.java b/openbas-model/src/main/java/io/openbas/database/specification/ObjectiveSpecification.java index e31e215b36..8f8e9be416 100644 --- a/openbas-model/src/main/java/io/openbas/database/specification/ObjectiveSpecification.java +++ b/openbas-model/src/main/java/io/openbas/database/specification/ObjectiveSpecification.java @@ -3,14 +3,13 @@ import io.openbas.database.model.Objective; import org.springframework.data.jpa.domain.Specification; - public class ObjectiveSpecification { - public static Specification fromExercise(String exerciseId) { - return (root, query, cb) -> cb.equal(root.get("exercise").get("id"), exerciseId); - } + public static Specification fromExercise(String exerciseId) { + return (root, query, cb) -> cb.equal(root.get("exercise").get("id"), exerciseId); + } - public static Specification fromScenario(String scenarioId) { - return (root, query, cb) -> cb.equal(root.get("scenario").get("id"), scenarioId); - } + public static Specification fromScenario(String scenarioId) { + return (root, query, cb) -> cb.equal(root.get("scenario").get("id"), scenarioId); + } } diff --git a/openbas-model/src/main/java/io/openbas/database/specification/OrganizationSpecification.java b/openbas-model/src/main/java/io/openbas/database/specification/OrganizationSpecification.java index a8164e39ff..c8b817e505 100644 --- a/openbas-model/src/main/java/io/openbas/database/specification/OrganizationSpecification.java +++ b/openbas-model/src/main/java/io/openbas/database/specification/OrganizationSpecification.java @@ -6,12 +6,9 @@ public class OrganizationSpecification { - private OrganizationSpecification() { - - } + private OrganizationSpecification() {} public static Specification byName(@Nullable final String searchText) { return UtilsSpecification.byName(searchText, "name"); } - } diff --git a/openbas-model/src/main/java/io/openbas/database/specification/ReportSpecification.java b/openbas-model/src/main/java/io/openbas/database/specification/ReportSpecification.java index 7aed3544fe..b890572e68 100644 --- a/openbas-model/src/main/java/io/openbas/database/specification/ReportSpecification.java +++ b/openbas-model/src/main/java/io/openbas/database/specification/ReportSpecification.java @@ -3,10 +3,9 @@ import io.openbas.database.model.Report; import org.springframework.data.jpa.domain.Specification; - public class ReportSpecification { - public static Specification fromExercise(String exerciseId) { - return (root, query, cb) -> cb.equal(root.get("exercise").get("id"), exerciseId); - } + public static Specification fromExercise(String exerciseId) { + return (root, query, cb) -> cb.equal(root.get("exercise").get("id"), exerciseId); + } } diff --git a/openbas-model/src/main/java/io/openbas/database/specification/ScenarioSpecification.java b/openbas-model/src/main/java/io/openbas/database/specification/ScenarioSpecification.java index c2acb707cb..361c8dd3ee 100644 --- a/openbas-model/src/main/java/io/openbas/database/specification/ScenarioSpecification.java +++ b/openbas-model/src/main/java/io/openbas/database/specification/ScenarioSpecification.java @@ -4,15 +4,12 @@ import jakarta.annotation.Nullable; import jakarta.persistence.criteria.Path; import jakarta.validation.constraints.NotNull; -import org.springframework.data.jpa.domain.Specification; - import java.time.Instant; +import org.springframework.data.jpa.domain.Specification; public class ScenarioSpecification { - private ScenarioSpecification() { - - } + private ScenarioSpecification() {} public static Specification isRecurring() { return (root, query, cb) -> cb.isNotNull(root.get("recurrence")); @@ -22,33 +19,31 @@ public static Specification noRecurring() { return (root, query, cb) -> cb.isNull(root.get("recurrence")); } - public static Specification recurrenceStartDateBefore(@NotNull final Instant startDate) { - return (root, query, cb) -> cb.or( - cb.isNull(root.get("recurrenceStart")), - cb.lessThanOrEqualTo(root.get("recurrenceStart"), startDate) - ); + public static Specification recurrenceStartDateBefore( + @NotNull final Instant startDate) { + return (root, query, cb) -> + cb.or( + cb.isNull(root.get("recurrenceStart")), + cb.lessThanOrEqualTo(root.get("recurrenceStart"), startDate)); } public static Specification recurrenceStopDateAfter(@NotNull final Instant stopDate) { - return (root, query, cb) -> cb.or( - cb.isNull(root.get("recurrenceEnd")), - cb.greaterThanOrEqualTo(root.get("recurrenceEnd"), stopDate) - ); + return (root, query, cb) -> + cb.or( + cb.isNull(root.get("recurrenceEnd")), + cb.greaterThanOrEqualTo(root.get("recurrenceEnd"), stopDate)); } public static Specification recurrenceStopDateBefore(@NotNull final Instant stopDate) { - return (root, query, cb) -> cb.or( - cb.isNull(root.get("recurrenceEnd")), - cb.lessThanOrEqualTo(root.get("recurrenceEnd"), stopDate) - ); + return (root, query, cb) -> + cb.or( + cb.isNull(root.get("recurrenceEnd")), + cb.lessThanOrEqualTo(root.get("recurrenceEnd"), stopDate)); } public static Specification findGrantedFor(String userId) { return (root, query, criteriaBuilder) -> { - Path path = root - .join("grants") - .join("group") - .join("users").get("id"); + Path path = root.join("grants").join("group").join("users").get("id"); return criteriaBuilder.equal(path, userId); }; } diff --git a/openbas-model/src/main/java/io/openbas/database/specification/SpecificationUtils.java b/openbas-model/src/main/java/io/openbas/database/specification/SpecificationUtils.java index a276e3859e..1d5ac53c8c 100644 --- a/openbas-model/src/main/java/io/openbas/database/specification/SpecificationUtils.java +++ b/openbas-model/src/main/java/io/openbas/database/specification/SpecificationUtils.java @@ -4,26 +4,27 @@ import jakarta.persistence.criteria.Expression; import jakarta.persistence.criteria.Predicate; import jakarta.validation.constraints.NotBlank; -import org.springframework.data.jpa.domain.Specification; - import java.util.ArrayList; import java.util.List; +import org.springframework.data.jpa.domain.Specification; public class SpecificationUtils { /** * Full Text Search with several properties instead of just one + * * @param searchTerm the search term * @param properties the properties to check */ public static Specification fullTextSearch( - @NotBlank final String searchTerm, - @NotBlank final List properties) { + @NotBlank final String searchTerm, @NotBlank final List properties) { return (root, query, cb) -> { List listOfPredicates = new ArrayList<>(); - for (String property: properties) { - Expression tsVector = cb.function("to_tsvector", Double.class, cb.literal("simple"), root.get(property)); - Expression tsQuery = cb.function("to_tsquery", Double.class, cb.literal("simple"), cb.literal(searchTerm)); + for (String property : properties) { + Expression tsVector = + cb.function("to_tsvector", Double.class, cb.literal("simple"), root.get(property)); + Expression tsQuery = + cb.function("to_tsquery", Double.class, cb.literal("simple"), cb.literal(searchTerm)); Expression rank = cb.function("ts_rank", Double.class, tsVector, tsQuery); query.orderBy(cb.desc(rank)); listOfPredicates.add(cb.greaterThan(rank, 0.01)); @@ -32,5 +33,4 @@ public static Specification fullTextSearch( return cb.or(listOfPredicates.toArray(new Predicate[0])); }; } - } diff --git a/openbas-model/src/main/java/io/openbas/database/specification/TagSpecification.java b/openbas-model/src/main/java/io/openbas/database/specification/TagSpecification.java index 501508a02a..835b0cf220 100644 --- a/openbas-model/src/main/java/io/openbas/database/specification/TagSpecification.java +++ b/openbas-model/src/main/java/io/openbas/database/specification/TagSpecification.java @@ -6,12 +6,9 @@ public class TagSpecification { - private TagSpecification() { - - } + private TagSpecification() {} public static Specification byName(@Nullable final String searchText) { return UtilsSpecification.byName(searchText, "name"); } - } diff --git a/openbas-model/src/main/java/io/openbas/database/specification/TeamSpecification.java b/openbas-model/src/main/java/io/openbas/database/specification/TeamSpecification.java index b522ce398e..d6e1d7f41f 100644 --- a/openbas-model/src/main/java/io/openbas/database/specification/TeamSpecification.java +++ b/openbas-model/src/main/java/io/openbas/database/specification/TeamSpecification.java @@ -6,25 +6,23 @@ import jakarta.persistence.criteria.Join; import jakarta.persistence.criteria.JoinType; import jakarta.validation.constraints.NotBlank; +import java.util.List; import org.jetbrains.annotations.NotNull; import org.springframework.data.jpa.domain.Specification; -import java.util.List; - public class TeamSpecification { - private TeamSpecification() { - } + private TeamSpecification() {} public static Specification fromIds(@NotNull final List ids) { return (root, query, builder) -> root.get("id").in(ids); } public static Specification teamsAccessibleFromOrganizations(List organizationIds) { - return (root, query, builder) -> builder.or( - builder.isNull(root.get("organization")), - root.get("organization").get("id").in(organizationIds) - ); + return (root, query, builder) -> + builder.or( + builder.isNull(root.get("organization")), + root.get("organization").get("id").in(organizationIds)); } public static Specification contextual(final boolean contextual) { @@ -47,5 +45,4 @@ public static Specification fromScenario(@NotBlank final String scenarioId return cb.equal(scenariosJoin.get("id"), scenarioId); }; } - } diff --git a/openbas-model/src/main/java/io/openbas/database/specification/TokenSpecification.java b/openbas-model/src/main/java/io/openbas/database/specification/TokenSpecification.java index 0d73df04f5..0f2a61a323 100644 --- a/openbas-model/src/main/java/io/openbas/database/specification/TokenSpecification.java +++ b/openbas-model/src/main/java/io/openbas/database/specification/TokenSpecification.java @@ -5,7 +5,7 @@ public class TokenSpecification { - public static Specification fromUser(String userId) { - return (root, query, cb) -> cb.equal(root.get("user").get("id"), userId); - } + public static Specification fromUser(String userId) { + return (root, query, cb) -> cb.equal(root.get("user").get("id"), userId); + } } diff --git a/openbas-model/src/main/java/io/openbas/database/specification/UserSpecification.java b/openbas-model/src/main/java/io/openbas/database/specification/UserSpecification.java index c191f41390..5012a9a53f 100644 --- a/openbas-model/src/main/java/io/openbas/database/specification/UserSpecification.java +++ b/openbas-model/src/main/java/io/openbas/database/specification/UserSpecification.java @@ -1,18 +1,15 @@ package io.openbas.database.specification; import io.openbas.database.model.User; -import org.springframework.data.jpa.domain.Specification; - import java.util.List; +import org.springframework.data.jpa.domain.Specification; public class UserSpecification { public static Specification accessibleFromOrganizations(List organizationIds) { - return (root, query, criteriaBuilder) -> criteriaBuilder.or( - criteriaBuilder.isNull(root.get("organization")), - root.get("organization").get("id").in(organizationIds) - ); + return (root, query, criteriaBuilder) -> + criteriaBuilder.or( + criteriaBuilder.isNull(root.get("organization")), + root.get("organization").get("id").in(organizationIds)); } - - } diff --git a/openbas-model/src/main/java/io/openbas/database/specification/UtilsSpecification.java b/openbas-model/src/main/java/io/openbas/database/specification/UtilsSpecification.java index 1903329f8f..95656366cc 100644 --- a/openbas-model/src/main/java/io/openbas/database/specification/UtilsSpecification.java +++ b/openbas-model/src/main/java/io/openbas/database/specification/UtilsSpecification.java @@ -7,13 +7,10 @@ public class UtilsSpecification { - private UtilsSpecification() { - - } + private UtilsSpecification() {} public static Specification byName( - @Nullable final String searchText, - @NotBlank final String property) { + @Nullable final String searchText, @NotBlank final String property) { return (root, query, cb) -> { if (searchText == null || searchText.isEmpty()) { return cb.conjunction(); @@ -22,5 +19,4 @@ public static Specification byName( return cb.like(cb.lower(root.get(property)), likePattern); }; } - } diff --git a/openbas-model/src/main/java/io/openbas/database/specification/VariableSpecification.java b/openbas-model/src/main/java/io/openbas/database/specification/VariableSpecification.java index 843828fd59..714897eb38 100644 --- a/openbas-model/src/main/java/io/openbas/database/specification/VariableSpecification.java +++ b/openbas-model/src/main/java/io/openbas/database/specification/VariableSpecification.java @@ -13,5 +13,4 @@ public static Specification fromExercise(@NotNull final String exercis public static Specification fromScenario(@NotNull final String scenarioId) { return (root, query, cb) -> cb.equal(root.get("scenario").get("id"), scenarioId); } - } diff --git a/openbas-model/src/main/java/io/openbas/driver/MinioDriver.java b/openbas-model/src/main/java/io/openbas/driver/MinioDriver.java index c1916d8ebd..f4ce382aa8 100644 --- a/openbas-model/src/main/java/io/openbas/driver/MinioDriver.java +++ b/openbas-model/src/main/java/io/openbas/driver/MinioDriver.java @@ -10,25 +10,27 @@ @Component public class MinioDriver { - private MinioConfig minioConfig; + private MinioConfig minioConfig; - @Autowired - public void setMinioConfig(MinioConfig minioConfig) { - this.minioConfig = minioConfig; - } + @Autowired + public void setMinioConfig(MinioConfig minioConfig) { + this.minioConfig = minioConfig; + } - @Bean - public MinioClient minioClient() throws Exception { - MinioClient minioClient = MinioClient.builder() - .endpoint(minioConfig.getEndpoint(), minioConfig.getPort(), minioConfig.isSecure()) - .credentials(minioConfig.getAccessKey(), minioConfig.getAccessSecret()) - .build(); - // Make bucket if not exist. - BucketExistsArgs bucketExistsArgs = BucketExistsArgs.builder().bucket(minioConfig.getBucket()).build(); - boolean found = minioClient.bucketExists(bucketExistsArgs); - if (!found) { - minioClient.makeBucket(MakeBucketArgs.builder().bucket(minioConfig.getBucket()).build()); - } - return minioClient; + @Bean + public MinioClient minioClient() throws Exception { + MinioClient minioClient = + MinioClient.builder() + .endpoint(minioConfig.getEndpoint(), minioConfig.getPort(), minioConfig.isSecure()) + .credentials(minioConfig.getAccessKey(), minioConfig.getAccessSecret()) + .build(); + // Make bucket if not exist. + BucketExistsArgs bucketExistsArgs = + BucketExistsArgs.builder().bucket(minioConfig.getBucket()).build(); + boolean found = minioClient.bucketExists(bucketExistsArgs); + if (!found) { + minioClient.makeBucket(MakeBucketArgs.builder().bucket(minioConfig.getBucket()).build()); } + return minioClient; + } } diff --git a/openbas-model/src/main/java/io/openbas/helper/CryptoHelper.java b/openbas-model/src/main/java/io/openbas/helper/CryptoHelper.java index ada0109233..34348b696a 100644 --- a/openbas-model/src/main/java/io/openbas/helper/CryptoHelper.java +++ b/openbas-model/src/main/java/io/openbas/helper/CryptoHelper.java @@ -4,21 +4,21 @@ public class CryptoHelper { - private static String hex(byte[] array) { - StringBuilder sb = new StringBuilder(); - for (byte b : array) { - sb.append(Integer.toHexString((b & 0xFF) | 0x100), 1, 3); - } - return sb.toString(); + private static String hex(byte[] array) { + StringBuilder sb = new StringBuilder(); + for (byte b : array) { + sb.append(Integer.toHexString((b & 0xFF) | 0x100), 1, 3); } + return sb.toString(); + } - public static String md5Hex(String message) { - try { - MessageDigest md = MessageDigest.getInstance("MD5"); - return hex(md.digest(message.getBytes("CP1252"))); - } catch (Exception e) { - // Nothing to do - } - return null; + public static String md5Hex(String message) { + try { + MessageDigest md = MessageDigest.getInstance("MD5"); + return hex(md.digest(message.getBytes("CP1252"))); + } catch (Exception e) { + // Nothing to do } + return null; + } } diff --git a/openbas-model/src/main/java/io/openbas/helper/InjectModelHelper.java b/openbas-model/src/main/java/io/openbas/helper/InjectModelHelper.java index fb39b73f27..77d7ab7fef 100644 --- a/openbas-model/src/main/java/io/openbas/helper/InjectModelHelper.java +++ b/openbas-model/src/main/java/io/openbas/helper/InjectModelHelper.java @@ -1,10 +1,14 @@ package io.openbas.helper; +import static io.openbas.database.model.Inject.SPEED_STANDARD; +import static java.time.Duration.between; +import static java.time.Instant.now; +import static java.util.Optional.ofNullable; + import com.fasterxml.jackson.databind.JsonNode; import com.fasterxml.jackson.databind.node.ObjectNode; import io.openbas.database.model.*; import jakarta.validation.constraints.NotNull; - import java.time.Instant; import java.time.LocalDateTime; import java.time.ZoneOffset; @@ -13,15 +17,9 @@ import java.util.concurrent.atomic.AtomicBoolean; import java.util.stream.StreamSupport; -import static io.openbas.database.model.Inject.SPEED_STANDARD; -import static java.time.Duration.between; -import static java.time.Instant.now; -import static java.util.Optional.ofNullable; - public class InjectModelHelper { - private InjectModelHelper() { - } + private InjectModelHelper() {} public static boolean isReady( InjectorContract injectorContract, @@ -38,70 +36,78 @@ public static boolean isReady( } AtomicBoolean ready = new AtomicBoolean(true); ObjectNode contractContent = injectorContract.getConvertedContent(); - List contractMandatoryFields = StreamSupport.stream(contractContent.get("fields").spliterator(), false) - .filter(contractElement -> (contractElement.get("key").asText().equals("assets") || contractElement.get("mandatory").asBoolean() || (contractElement.get("mandatoryGroups") != null && contractElement.get("mandatoryGroups").asBoolean()))).toList(); + List contractMandatoryFields = + StreamSupport.stream(contractContent.get("fields").spliterator(), false) + .filter( + contractElement -> + (contractElement.get("key").asText().equals("assets") + || contractElement.get("mandatory").asBoolean() + || (contractElement.get("mandatoryGroups") != null + && contractElement.get("mandatoryGroups").asBoolean()))) + .toList(); if (!contractMandatoryFields.isEmpty()) { - contractMandatoryFields.forEach(jsonField -> { - String key = jsonField.get("key").asText(); - if (key.equals("teams")) { - if (teams.isEmpty() && !allTeams) { - ready.set(false); - } - } else if (key.equals("assets")) { - if (assets.isEmpty() && assetGroups.isEmpty()) { - ready.set(false); - } - } else if (jsonField.get("type").asText().equals("text") && content.get(key) == null) { - ready.set(false); - } else if (jsonField.get("type").asText().equals("text") && content.get(key).asText().isEmpty()) { - ready.set(false); - } - }); + contractMandatoryFields.forEach( + jsonField -> { + String key = jsonField.get("key").asText(); + if (key.equals("teams")) { + if (teams.isEmpty() && !allTeams) { + ready.set(false); + } + } else if (key.equals("assets")) { + if (assets.isEmpty() && assetGroups.isEmpty()) { + ready.set(false); + } + } else if (jsonField.get("type").asText().equals("text") && content.get(key) == null) { + ready.set(false); + } else if (jsonField.get("type").asText().equals("text") + && content.get(key).asText().isEmpty()) { + ready.set(false); + } + }); } return ready.get(); } public static Instant computeInjectDate( - Instant source, - int speed, - Inject dependsOn, - Long dependsDuration, - Exercise exercise) { + Instant source, int speed, Inject dependsOn, Long dependsDuration, Exercise exercise) { // Compute origin execution date Optional dependsOnInject = ofNullable(dependsOn); long duration = ofNullable(dependsDuration).orElse(0L) / speed; - Instant dependingStart = dependsOnInject - .map(inject -> inject.computeInjectDate(source, speed)) - .orElse(source); + Instant dependingStart = + dependsOnInject.map(inject -> inject.computeInjectDate(source, speed)).orElse(source); Instant standardExecutionDate = dependingStart.plusSeconds(duration); // Compute execution dates with previous terminated pauses long previousPauseDelay = 0L; if (exercise != null) { - previousPauseDelay = exercise.getPauses() - .stream() - .filter(pause -> pause.getDate().isBefore(standardExecutionDate)) - .mapToLong(pause -> pause.getDuration().orElse(0L)).sum(); + previousPauseDelay = + exercise.getPauses().stream() + .filter(pause -> pause.getDate().isBefore(standardExecutionDate)) + .mapToLong(pause -> pause.getDuration().orElse(0L)) + .sum(); } Instant afterPausesExecutionDate = standardExecutionDate.plusSeconds(previousPauseDelay); // Add current pause duration in date computation if needed long currentPauseDelay = 0L; if (exercise != null) { - currentPauseDelay = exercise.getCurrentPause() - .map(last -> last.isBefore(afterPausesExecutionDate) ? between(last, now()).getSeconds() : 0L) - .orElse(0L); + currentPauseDelay = + exercise + .getCurrentPause() + .map( + last -> + last.isBefore(afterPausesExecutionDate) + ? between(last, now()).getSeconds() + : 0L) + .orElse(0L); } long globalPauseDelay = previousPauseDelay + currentPauseDelay; long minuteAlignModulo = globalPauseDelay % 60; - long alignedPauseDelay = minuteAlignModulo > 0 ? globalPauseDelay + (60 - minuteAlignModulo) : globalPauseDelay; + long alignedPauseDelay = + minuteAlignModulo > 0 ? globalPauseDelay + (60 - minuteAlignModulo) : globalPauseDelay; return standardExecutionDate.plusSeconds(alignedPauseDelay); } public static Optional getDate( - Exercise exercise, - Scenario scenario, - Inject dependsOn, - Long dependsDuration - ) { + Exercise exercise, Scenario scenario, Inject dependsOn, Long dependsDuration) { if (exercise == null && scenario == null) { return Optional.ofNullable(now().minusSeconds(30)); } @@ -116,18 +122,17 @@ public static Optional getDate( } return exercise .getStart() - .map(source -> computeInjectDate(source, SPEED_STANDARD, dependsOn, dependsDuration, exercise)); + .map( + source -> + computeInjectDate(source, SPEED_STANDARD, dependsOn, dependsDuration, exercise)); } return Optional.ofNullable(LocalDateTime.now().toInstant(ZoneOffset.UTC)); } - public static Instant getSentAt( - Optional status - ) { + public static Instant getSentAt(Optional status) { if (status.isPresent()) { return status.orElseThrow().getTrackingSentDate(); } return null; } - } diff --git a/openbas-model/src/main/java/io/openbas/helper/InjectStatisticsHelper.java b/openbas-model/src/main/java/io/openbas/helper/InjectStatisticsHelper.java index cedf04114c..7bb2569520 100644 --- a/openbas-model/src/main/java/io/openbas/helper/InjectStatisticsHelper.java +++ b/openbas-model/src/main/java/io/openbas/helper/InjectStatisticsHelper.java @@ -2,7 +2,6 @@ import io.openbas.database.model.Inject; import jakarta.validation.constraints.NotNull; - import java.util.HashMap; import java.util.List; import java.util.Map; @@ -21,5 +20,4 @@ public static Map getInjectStatistics(@NotNull final List stats.put("total_progress", total > 0 ? (executed * 100 / total) : 0); return stats; } - } diff --git a/openbas-model/src/main/java/io/openbas/helper/MonoIdDeserializer.java b/openbas-model/src/main/java/io/openbas/helper/MonoIdDeserializer.java index 5d26ca7c95..0c5f9ac046 100644 --- a/openbas-model/src/main/java/io/openbas/helper/MonoIdDeserializer.java +++ b/openbas-model/src/main/java/io/openbas/helper/MonoIdDeserializer.java @@ -4,21 +4,22 @@ import com.fasterxml.jackson.databind.SerializerProvider; import com.fasterxml.jackson.databind.ser.std.StdSerializer; import io.openbas.database.model.Base; - import java.io.IOException; public class MonoIdDeserializer extends StdSerializer { - public MonoIdDeserializer() { - this(null); - } + public MonoIdDeserializer() { + this(null); + } - public MonoIdDeserializer(Class t) { - super(t); - } + public MonoIdDeserializer(Class t) { + super(t); + } - @Override - public void serialize(Base base, JsonGenerator jsonGenerator, SerializerProvider serializerProvider) throws IOException { - jsonGenerator.writeString(base.getId()); - } + @Override + public void serialize( + Base base, JsonGenerator jsonGenerator, SerializerProvider serializerProvider) + throws IOException { + jsonGenerator.writeString(base.getId()); + } } diff --git a/openbas-model/src/main/java/io/openbas/helper/MultiIdListDeserializer.java b/openbas-model/src/main/java/io/openbas/helper/MultiIdListDeserializer.java index c28365cce9..bdb1b342b1 100644 --- a/openbas-model/src/main/java/io/openbas/helper/MultiIdListDeserializer.java +++ b/openbas-model/src/main/java/io/openbas/helper/MultiIdListDeserializer.java @@ -4,24 +4,25 @@ import com.fasterxml.jackson.databind.SerializerProvider; import com.fasterxml.jackson.databind.ser.std.StdSerializer; import io.openbas.database.model.Base; - import java.io.IOException; import java.util.List; public class MultiIdListDeserializer extends StdSerializer> { - public MultiIdListDeserializer() { - this(null); - } + public MultiIdListDeserializer() { + this(null); + } - public MultiIdListDeserializer(Class> t) { - super(t); - } + public MultiIdListDeserializer(Class> t) { + super(t); + } - @Override - public void serialize(List base, JsonGenerator jsonGenerator, SerializerProvider serializerProvider) throws IOException { - List ids = base.stream().map(Base::getId).toList(); - String[] arrayIds = ids.toArray(new String[0]); - jsonGenerator.writeArray(arrayIds, 0, arrayIds.length); - } + @Override + public void serialize( + List base, JsonGenerator jsonGenerator, SerializerProvider serializerProvider) + throws IOException { + List ids = base.stream().map(Base::getId).toList(); + String[] arrayIds = ids.toArray(new String[0]); + jsonGenerator.writeArray(arrayIds, 0, arrayIds.length); + } } diff --git a/openbas-model/src/main/java/io/openbas/helper/MultiIdSetDeserializer.java b/openbas-model/src/main/java/io/openbas/helper/MultiIdSetDeserializer.java index 989f346591..c27cf3dfb5 100644 --- a/openbas-model/src/main/java/io/openbas/helper/MultiIdSetDeserializer.java +++ b/openbas-model/src/main/java/io/openbas/helper/MultiIdSetDeserializer.java @@ -4,25 +4,26 @@ import com.fasterxml.jackson.databind.SerializerProvider; import com.fasterxml.jackson.databind.ser.std.StdSerializer; import io.openbas.database.model.Base; - import java.io.IOException; import java.util.List; import java.util.Set; public class MultiIdSetDeserializer extends StdSerializer> { - public MultiIdSetDeserializer() { - this(null); - } + public MultiIdSetDeserializer() { + this(null); + } - public MultiIdSetDeserializer(Class> t) { - super(t); - } + public MultiIdSetDeserializer(Class> t) { + super(t); + } - @Override - public void serialize(Set base, JsonGenerator jsonGenerator, SerializerProvider serializerProvider) throws IOException { - List ids = base.stream().map(Base::getId).toList(); - String[] arrayIds = ids.toArray(new String[0]); - jsonGenerator.writeArray(arrayIds, 0, arrayIds.length); - } + @Override + public void serialize( + Set base, JsonGenerator jsonGenerator, SerializerProvider serializerProvider) + throws IOException { + List ids = base.stream().map(Base::getId).toList(); + String[] arrayIds = ids.toArray(new String[0]); + jsonGenerator.writeArray(arrayIds, 0, arrayIds.length); + } } diff --git a/openbas-model/src/main/java/io/openbas/helper/MultiModelDeserializer.java b/openbas-model/src/main/java/io/openbas/helper/MultiModelDeserializer.java index e7a2d5f61f..2f750b89da 100644 --- a/openbas-model/src/main/java/io/openbas/helper/MultiModelDeserializer.java +++ b/openbas-model/src/main/java/io/openbas/helper/MultiModelDeserializer.java @@ -4,22 +4,23 @@ import com.fasterxml.jackson.databind.SerializerProvider; import com.fasterxml.jackson.databind.ser.std.StdSerializer; import io.openbas.database.model.Base; - import java.io.IOException; import java.util.List; public class MultiModelDeserializer extends StdSerializer> { - public MultiModelDeserializer() { - this(null); - } + public MultiModelDeserializer() { + this(null); + } - public MultiModelDeserializer(Class> t) { - super(t); - } + public MultiModelDeserializer(Class> t) { + super(t); + } - @Override - public void serialize(List base, JsonGenerator jsonGenerator, SerializerProvider serializerProvider) throws IOException { - jsonGenerator.writeObject(base); - } + @Override + public void serialize( + List base, JsonGenerator jsonGenerator, SerializerProvider serializerProvider) + throws IOException { + jsonGenerator.writeObject(base); + } } diff --git a/openbas-model/src/main/java/io/openbas/helper/UserHelper.java b/openbas-model/src/main/java/io/openbas/helper/UserHelper.java index 6633aedede..5050742ae8 100644 --- a/openbas-model/src/main/java/io/openbas/helper/UserHelper.java +++ b/openbas-model/src/main/java/io/openbas/helper/UserHelper.java @@ -1,12 +1,11 @@ package io.openbas.helper; +import static java.util.Arrays.asList; + import io.openbas.database.model.Grant; import io.openbas.database.model.User; - import java.util.List; -import static java.util.Arrays.asList; - public class UserHelper { public static List getUsersByType(List grants, Grant.GRANT_TYPE... types) { @@ -22,5 +21,4 @@ public static String getGravatar(String email) { String emailMd5 = CryptoHelper.md5Hex(email.trim().toLowerCase()); return "https://www.gravatar.com/avatar/" + emailMd5 + "?d=mm"; } - } diff --git a/openbas-model/src/main/java/io/openbas/service/FileContainer.java b/openbas-model/src/main/java/io/openbas/service/FileContainer.java index 5a7c0dcd4c..4ae9549691 100644 --- a/openbas-model/src/main/java/io/openbas/service/FileContainer.java +++ b/openbas-model/src/main/java/io/openbas/service/FileContainer.java @@ -4,39 +4,39 @@ public class FileContainer { - private String name; + private String name; - private String contentType; + private String contentType; - private InputStream inputStream; + private InputStream inputStream; - public FileContainer(String name, String contentType, InputStream inputStream) { - this.name = name; - this.contentType = contentType; - this.inputStream = inputStream; - } + public FileContainer(String name, String contentType, InputStream inputStream) { + this.name = name; + this.contentType = contentType; + this.inputStream = inputStream; + } - public String getName() { - return name; - } + public String getName() { + return name; + } - public void setName(String name) { - this.name = name; - } + public void setName(String name) { + this.name = name; + } - public String getContentType() { - return contentType; - } + public String getContentType() { + return contentType; + } - public void setContentType(String contentType) { - this.contentType = contentType; - } + public void setContentType(String contentType) { + this.contentType = contentType; + } - public InputStream getInputStream() { - return inputStream; - } + public InputStream getInputStream() { + return inputStream; + } - public void setInputStream(InputStream inputStream) { - this.inputStream = inputStream; - } + public void setInputStream(InputStream inputStream) { + this.inputStream = inputStream; + } } diff --git a/openbas-model/src/main/java/io/openbas/service/FileService.java b/openbas-model/src/main/java/io/openbas/service/FileService.java index 51ca7a8704..faa8df97ce 100644 --- a/openbas-model/src/main/java/io/openbas/service/FileService.java +++ b/openbas-model/src/main/java/io/openbas/service/FileService.java @@ -6,146 +6,140 @@ import io.minio.messages.Item; import io.openbas.config.MinioConfig; import io.openbas.database.model.Document; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.core.io.InputStreamResource; -import org.springframework.stereotype.Service; -import org.springframework.web.multipart.MultipartFile; - import java.io.InputStream; import java.util.ArrayList; import java.util.List; import java.util.Map; import java.util.Optional; import java.util.logging.Logger; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.core.io.InputStreamResource; +import org.springframework.stereotype.Service; +import org.springframework.web.multipart.MultipartFile; @Service public class FileService { - private static final Logger LOGGER = Logger.getLogger(FileService.class.getName()); - public static final String INJECTORS_IMAGES_BASE_PATH = "/injectors/images/"; - public static final String COLLECTORS_IMAGES_BASE_PATH = "/collectors/images/"; - public static final String EXECUTORS_IMAGES_BASE_PATH = "/executors/images/"; - private MinioConfig minioConfig; - private MinioClient minioClient; - - @Autowired - public void setMinioConfig(MinioConfig minioConfig) { - this.minioConfig = minioConfig; - } - - @Autowired - public void setMinioClient(MinioClient minioClient) { - this.minioClient = minioClient; - } - - public void uploadFile(String name, InputStream data, long size, String contentType) throws Exception { - minioClient.putObject( - PutObjectArgs.builder() - .bucket(minioConfig.getBucket()) - .object(name) - .stream(data, size, -1) - .contentType(contentType) - .build()); - } - - public String uploadStream(String path, String name, InputStream data) throws Exception { - String file = path + "/" + name; - minioClient.putObject( - PutObjectArgs.builder() - .bucket(minioConfig.getBucket()) - .object(file) - .userMetadata(Map.of("filename", name)) - .stream(data, data.available(), -1) - .build()); - return file; - } - - public void deleteFile(String name) throws Exception { - minioClient.removeObject(RemoveObjectArgs - .builder() - .bucket(minioConfig.getBucket()) - .object(name) - .build()); - } - - public void deleteDirectory(String directory) { - Iterable> files = minioClient.listObjects(ListObjectsArgs - .builder() + private static final Logger LOGGER = Logger.getLogger(FileService.class.getName()); + public static final String INJECTORS_IMAGES_BASE_PATH = "/injectors/images/"; + public static final String COLLECTORS_IMAGES_BASE_PATH = "/collectors/images/"; + public static final String EXECUTORS_IMAGES_BASE_PATH = "/executors/images/"; + private MinioConfig minioConfig; + private MinioClient minioClient; + + @Autowired + public void setMinioConfig(MinioConfig minioConfig) { + this.minioConfig = minioConfig; + } + + @Autowired + public void setMinioClient(MinioClient minioClient) { + this.minioClient = minioClient; + } + + public void uploadFile(String name, InputStream data, long size, String contentType) + throws Exception { + minioClient.putObject( + PutObjectArgs.builder().bucket(minioConfig.getBucket()).object(name).stream(data, size, -1) + .contentType(contentType) + .build()); + } + + public String uploadStream(String path, String name, InputStream data) throws Exception { + String file = path + "/" + name; + minioClient.putObject( + PutObjectArgs.builder() + .bucket(minioConfig.getBucket()) + .object(file) + .userMetadata(Map.of("filename", name)) + .stream(data, data.available(), -1) + .build()); + return file; + } + + public void deleteFile(String name) throws Exception { + minioClient.removeObject( + RemoveObjectArgs.builder().bucket(minioConfig.getBucket()).object(name).build()); + } + + public void deleteDirectory(String directory) { + Iterable> files = + minioClient.listObjects( + ListObjectsArgs.builder() .bucket(minioConfig.getBucket()) .recursive(true) .prefix(directory) .build()); - List deleteObjects = new ArrayList<>(); - files.forEach(itemResult -> { - try { - Item item = itemResult.get(); - deleteObjects.add(new DeleteObject(item.objectName())); - } catch (Exception e) { - // Dont care - } + List deleteObjects = new ArrayList<>(); + files.forEach( + itemResult -> { + try { + Item item = itemResult.get(); + deleteObjects.add(new DeleteObject(item.objectName())); + } catch (Exception e) { + // Dont care + } }); - Iterable> removedObjects = minioClient.removeObjects(RemoveObjectsArgs - .builder() + Iterable> removedObjects = + minioClient.removeObjects( + RemoveObjectsArgs.builder() .bucket(minioConfig.getBucket()) .objects(deleteObjects) .build()); - for (Result result : removedObjects) { - try { - DeleteError error = result.get(); - LOGGER.severe("Error in deleting object " + error.objectName() + "; " + error.message()); - } catch (Exception e) { - // Nothing to do - } - } + for (Result result : removedObjects) { + try { + DeleteError error = result.get(); + LOGGER.severe("Error in deleting object " + error.objectName() + "; " + error.message()); + } catch (Exception e) { + // Nothing to do + } } - - public void uploadFile(String name, MultipartFile file) throws Exception { - uploadFile(name, file.getInputStream(), file.getSize(), file.getContentType()); - } - - private Optional getFilePath(String name) { - try { - GetObjectResponse objectStream = minioClient.getObject( - GetObjectArgs.builder() - .bucket(minioConfig.getBucket()) - .object(name) - .build()); - InputStreamResource streamResource = new InputStreamResource(objectStream); - return Optional.of(streamResource.getInputStream()); - } catch (Exception e) { - return Optional.empty(); - } + } + + public void uploadFile(String name, MultipartFile file) throws Exception { + uploadFile(name, file.getInputStream(), file.getSize(), file.getContentType()); + } + + private Optional getFilePath(String name) { + try { + GetObjectResponse objectStream = + minioClient.getObject( + GetObjectArgs.builder().bucket(minioConfig.getBucket()).object(name).build()); + InputStreamResource streamResource = new InputStreamResource(objectStream); + return Optional.of(streamResource.getInputStream()); + } catch (Exception e) { + return Optional.empty(); } - - public Optional getFile(Document document) { - return getFilePath(document.getTarget()); - } - - public Optional getInjectorImage(String injectType) { - return getFilePath(INJECTORS_IMAGES_BASE_PATH + injectType + ".png"); - } - - public Optional getCollectorImage(String collectorId) { - return getFilePath(COLLECTORS_IMAGES_BASE_PATH + collectorId + ".png"); - } - - public Optional getExecutorImage(String executorId) { - return getFilePath(EXECUTORS_IMAGES_BASE_PATH + executorId + ".png"); - } - - public Optional getFileContainer(String fileTarget) { - try { - StatObjectResponse response = minioClient.statObject( - StatObjectArgs.builder() - .bucket(minioConfig.getBucket()) - .object(fileTarget) - .build()); - String filename = response.userMetadata().get("filename"); - Optional inputStream = getFilePath(fileTarget); - FileContainer fileContainer = new FileContainer(filename, response.contentType(), inputStream.orElseThrow()); - return Optional.of(fileContainer); - } catch (Exception e) { - return Optional.empty(); - } + } + + public Optional getFile(Document document) { + return getFilePath(document.getTarget()); + } + + public Optional getInjectorImage(String injectType) { + return getFilePath(INJECTORS_IMAGES_BASE_PATH + injectType + ".png"); + } + + public Optional getCollectorImage(String collectorId) { + return getFilePath(COLLECTORS_IMAGES_BASE_PATH + collectorId + ".png"); + } + + public Optional getExecutorImage(String executorId) { + return getFilePath(EXECUTORS_IMAGES_BASE_PATH + executorId + ".png"); + } + + public Optional getFileContainer(String fileTarget) { + try { + StatObjectResponse response = + minioClient.statObject( + StatObjectArgs.builder().bucket(minioConfig.getBucket()).object(fileTarget).build()); + String filename = response.userMetadata().get("filename"); + Optional inputStream = getFilePath(fileTarget); + FileContainer fileContainer = + new FileContainer(filename, response.contentType(), inputStream.orElseThrow()); + return Optional.of(fileContainer); + } catch (Exception e) { + return Optional.empty(); } + } } diff --git a/openbas-model/src/main/java/io/openbas/validator/Ipv4OrIpv6Validator.java b/openbas-model/src/main/java/io/openbas/validator/Ipv4OrIpv6Validator.java index 3b388f9740..7714d49f26 100644 --- a/openbas-model/src/main/java/io/openbas/validator/Ipv4OrIpv6Validator.java +++ b/openbas-model/src/main/java/io/openbas/validator/Ipv4OrIpv6Validator.java @@ -3,9 +3,8 @@ import io.openbas.annotation.Ipv4OrIpv6Constraint; import jakarta.validation.ConstraintValidator; import jakarta.validation.ConstraintValidatorContext; -import org.apache.commons.validator.routines.InetAddressValidator; - import java.util.Arrays; +import org.apache.commons.validator.routines.InetAddressValidator; public class Ipv4OrIpv6Validator implements ConstraintValidator { @@ -14,5 +13,4 @@ public boolean isValid(final String[] ips, final ConstraintValidatorContext cxt) InetAddressValidator validator = InetAddressValidator.getInstance(); return Arrays.stream(ips).allMatch(validator::isValid); } - }