From 6276f028ac26d3d8bd38ac2b9a9915fd823111c7 Mon Sep 17 00:00:00 2001 From: Anthony Stirling <77850077+Frooodle@users.noreply.github.com> Date: Mon, 25 Dec 2023 16:15:42 +0000 Subject: [PATCH] validate operations --- .../api/pipeline/ApiDocService.java | 82 +++++++++++++++++++ .../api/pipeline/PipelineController.java | 8 ++ .../software/SPDF/model/ApiEndpoint.java | 28 +++++++ 3 files changed, 118 insertions(+) create mode 100644 src/main/java/stirling/software/SPDF/controller/api/pipeline/ApiDocService.java create mode 100644 src/main/java/stirling/software/SPDF/model/ApiEndpoint.java diff --git a/src/main/java/stirling/software/SPDF/controller/api/pipeline/ApiDocService.java b/src/main/java/stirling/software/SPDF/controller/api/pipeline/ApiDocService.java new file mode 100644 index 00000000..40684489 --- /dev/null +++ b/src/main/java/stirling/software/SPDF/controller/api/pipeline/ApiDocService.java @@ -0,0 +1,82 @@ +package stirling.software.SPDF.controller.api.pipeline; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.context.event.EventListener; +import org.springframework.http.HttpHeaders; +import org.springframework.stereotype.Service; +import org.springframework.web.client.RestTemplate; +import com.fasterxml.jackson.databind.JsonNode; +import com.fasterxml.jackson.databind.ObjectMapper; + +import stirling.software.SPDF.model.ApiEndpoint; +import stirling.software.SPDF.model.Role; + +import java.util.HashMap; +import java.util.Map; +import org.springframework.http.HttpEntity; +import org.springframework.http.HttpHeaders; +import org.springframework.http.HttpMethod; +import org.springframework.http.HttpStatus; +import org.springframework.http.ResponseEntity; +import org.springframework.boot.context.event.ApplicationReadyEvent; +import stirling.software.SPDF.model.ApiEndpoint; +@Service +public class ApiDocService { + + private final Map apiDocumentation = new HashMap<>(); + private final String apiDocsUrl = "http://localhost:8080/v1/api-docs"; // URL to your API documentation + + + @Autowired(required=false) + private UserServiceInterface userService; + + private String getApiKeyForUser() { + if(userService == null) + return ""; + return userService.getApiKeyForUser(Role.INTERNAL_API_USER.getRoleId()); + } + + @EventListener(ApplicationReadyEvent.class) + private void loadApiDocumentation() { + try { + HttpHeaders headers = new HttpHeaders(); + String apiKey = getApiKeyForUser(); + if (!apiKey.isEmpty()) { + headers.set("X-API-KEY", apiKey); + } + HttpEntity entity = new HttpEntity<>(headers); + + RestTemplate restTemplate = new RestTemplate(); + ResponseEntity response = restTemplate.exchange(apiDocsUrl, HttpMethod.GET, entity, String.class); + String apiDocsJson = response.getBody(); + + ObjectMapper mapper = new ObjectMapper(); + JsonNode root = mapper.readTree(apiDocsJson); + + JsonNode paths = root.path("paths"); + paths.fields().forEachRemaining(entry -> { + String path = entry.getKey(); + JsonNode pathNode = entry.getValue(); + if (pathNode.has("post")) { + JsonNode postNode = pathNode.get("post"); + String operation = path.substring(1); // Assuming operation name is the path without leading '/' + ApiEndpoint endpoint = new ApiEndpoint(operation, postNode); + apiDocumentation.put(operation, endpoint); + } + }); + } catch (Exception e) { + // Handle exceptions + e.printStackTrace(); + } + } + + public boolean isValidOperation(String operationName, Map parameters) { + if (!apiDocumentation.containsKey(operationName)) { + return false; + } + ApiEndpoint endpoint = apiDocumentation.get(operationName); + return endpoint.areParametersValid(parameters); + } +} + +// Model class for API Endpoint + diff --git a/src/main/java/stirling/software/SPDF/controller/api/pipeline/PipelineController.java b/src/main/java/stirling/software/SPDF/controller/api/pipeline/PipelineController.java index d04017e2..7954b943 100644 --- a/src/main/java/stirling/software/SPDF/controller/api/pipeline/PipelineController.java +++ b/src/main/java/stirling/software/SPDF/controller/api/pipeline/PipelineController.java @@ -69,6 +69,9 @@ public class PipelineController { final String watchedFoldersDir = "./pipeline/watchedFolders/"; final String finishedFoldersDir = "./pipeline/finishedFolders/"; + @Autowired + private ApiDocService apiDocService; + @Scheduled(fixedRate = 25000) public void scanFolders() { logger.info("Scanning folders..."); @@ -145,6 +148,11 @@ public class PipelineController { // For each operation in the pipeline for (PipelineOperation operation : config.getOperations()) { + if (!apiDocService.isValidOperation(operation.getOperation(), operation.getParameters())) { + logger.error("Invalid operation: " + operation.getOperation()); + // Handle invalid operation + throw new Exception("Invalid operation: " + operation.getOperation()); + } // Collect all files based on fileInput File[] files; String fileInput = (String) operation.getParameters().get("fileInput"); diff --git a/src/main/java/stirling/software/SPDF/model/ApiEndpoint.java b/src/main/java/stirling/software/SPDF/model/ApiEndpoint.java new file mode 100644 index 00000000..0ee58132 --- /dev/null +++ b/src/main/java/stirling/software/SPDF/model/ApiEndpoint.java @@ -0,0 +1,28 @@ +package stirling.software.SPDF.model; + +import java.util.Map; +import java.util.HashMap; +import com.fasterxml.jackson.databind.JsonNode; + +public class ApiEndpoint { + private String name; + private Map parameters; + + public ApiEndpoint(String name, JsonNode postNode) { + this.name = name; + this.parameters = new HashMap<>(); + postNode.path("parameters").forEach(paramNode -> { + String paramName = paramNode.path("name").asText(); + parameters.put(paramName, paramNode); + }); + } + + public boolean areParametersValid(Map providedParams) { + for (String requiredParam : parameters.keySet()) { + if (!providedParams.containsKey(requiredParam)) { + return false; + } + } + return true; + } +} \ No newline at end of file