From b29d6a885065bdb11fd58161a6720a95be068c2c Mon Sep 17 00:00:00 2001 From: Florian Wilhelm <2292245+fwilhe@users.noreply.github.com> Date: Wed, 8 May 2024 12:20:07 +0200 Subject: [PATCH] Parse CVE DB objects into domain objects (#11) --- .../io/gardenlinux/glvd/GlvdController.java | 5 +- .../java/io/gardenlinux/glvd/GlvdService.java | 25 ++++++-- .../io/gardenlinux/glvd/db/CveRepository.java | 5 +- .../gardenlinux/glvd/dto/Configuration.java | 7 +++ .../io/gardenlinux/glvd/dto/CpeMatch.java | 6 ++ .../java/io/gardenlinux/glvd/dto/Cve.java | 59 ++----------------- .../java/io/gardenlinux/glvd/dto/Deb.java | 5 ++ .../io/gardenlinux/glvd/dto/Description.java | 4 ++ .../java/io/gardenlinux/glvd/dto/Node.java | 7 +++ .../io/gardenlinux/glvd/dto/Readiness.java | 30 +--------- .../io/gardenlinux/glvd/dto/Reference.java | 7 +++ .../io/gardenlinux/glvd/dto/Weakness.java | 7 +++ .../exceptions/CantParseJSONException.java | 8 +++ src/main/resources/application.properties | 2 +- 14 files changed, 84 insertions(+), 93 deletions(-) create mode 100644 src/main/java/io/gardenlinux/glvd/dto/Configuration.java create mode 100644 src/main/java/io/gardenlinux/glvd/dto/CpeMatch.java create mode 100644 src/main/java/io/gardenlinux/glvd/dto/Deb.java create mode 100644 src/main/java/io/gardenlinux/glvd/dto/Description.java create mode 100644 src/main/java/io/gardenlinux/glvd/dto/Node.java create mode 100644 src/main/java/io/gardenlinux/glvd/dto/Reference.java create mode 100644 src/main/java/io/gardenlinux/glvd/dto/Weakness.java create mode 100644 src/main/java/io/gardenlinux/glvd/exceptions/CantParseJSONException.java diff --git a/src/main/java/io/gardenlinux/glvd/GlvdController.java b/src/main/java/io/gardenlinux/glvd/GlvdController.java index de4f66f..44778ea 100644 --- a/src/main/java/io/gardenlinux/glvd/GlvdController.java +++ b/src/main/java/io/gardenlinux/glvd/GlvdController.java @@ -1,6 +1,7 @@ package io.gardenlinux.glvd; import io.gardenlinux.glvd.dto.Cve; +import io.gardenlinux.glvd.exceptions.CantParseJSONException; import io.gardenlinux.glvd.exceptions.NotFoundException; import jakarta.annotation.Nonnull; import org.springframework.http.MediaType; @@ -29,8 +30,8 @@ ResponseEntity getCveId(@PathVariable("cveId") final String cveId) throws N } @GetMapping("/{vendor}/{product}/{codename}") - ResponseEntity> getCveDistro(@PathVariable final String vendor, @PathVariable final String product, - @PathVariable final String codename) { + ResponseEntity> getCveDistro(@PathVariable final String vendor, @PathVariable final String product, + @PathVariable final String codename) throws CantParseJSONException { return ResponseEntity.ok().body(glvdService.getCveForDistribution(vendor, product, codename)); } diff --git a/src/main/java/io/gardenlinux/glvd/GlvdService.java b/src/main/java/io/gardenlinux/glvd/GlvdService.java index 857cc4a..8104b6d 100644 --- a/src/main/java/io/gardenlinux/glvd/GlvdService.java +++ b/src/main/java/io/gardenlinux/glvd/GlvdService.java @@ -1,9 +1,13 @@ package io.gardenlinux.glvd; +import com.fasterxml.jackson.core.JsonProcessingException; +import com.fasterxml.jackson.databind.ObjectMapper; +import io.gardenlinux.glvd.db.CveEntity; import io.gardenlinux.glvd.db.CveRepository; import io.gardenlinux.glvd.db.HealthCheckRepository; import io.gardenlinux.glvd.dto.Cve; import io.gardenlinux.glvd.dto.Readiness; +import io.gardenlinux.glvd.exceptions.CantParseJSONException; import io.gardenlinux.glvd.exceptions.DbNotConnectedException; import io.gardenlinux.glvd.exceptions.NotFoundException; import jakarta.annotation.Nonnull; @@ -20,9 +24,12 @@ public class GlvdService { @Nonnull private final HealthCheckRepository healthCheckRepository; + private final ObjectMapper objectMapper; + public GlvdService(@Nonnull CveRepository cveRepository, @Nonnull HealthCheckRepository healthCheckRepository) { this.cveRepository = cveRepository; this.healthCheckRepository = healthCheckRepository; + this.objectMapper = new ObjectMapper(); } public Readiness getReadiness() throws DbNotConnectedException { @@ -34,15 +41,23 @@ public Readiness getReadiness() throws DbNotConnectedException { } } - public Cve getCve(String cveId) throws NotFoundException { + public Cve getCve(String cveId) throws NotFoundException, CantParseJSONException { var cveEntity = cveRepository.findById(cveId).orElseThrow(NotFoundException::new); - // Todo: more specific transformation from db type 'cve' to response type 'cve' - return new Cve(cveEntity.getId(), cveEntity.getLastModified(), cveEntity.getData()); + return cveEntityDataToDomainEntity(cveEntity); } - public List getCveForDistribution(String vendor, String product, String codename) { - return cveRepository.cvesForDistribution(vendor, product, codename); + public List getCveForDistribution(String vendor, String product, String codename) throws CantParseJSONException { + var entities = cveRepository.cvesForDistribution(vendor, product, codename); + + return entities.stream().map(this::cveEntityDataToDomainEntity).toList(); } + private Cve cveEntityDataToDomainEntity(CveEntity cveEntity) throws CantParseJSONException { + try { + return objectMapper.readValue(cveEntity.getData(), Cve.class); + } catch (JsonProcessingException e) { + throw new CantParseJSONException("Failed to parse JSON object into domain classes:\n====\n" + cveEntity.getData() + "\n===="); + } + } } diff --git a/src/main/java/io/gardenlinux/glvd/db/CveRepository.java b/src/main/java/io/gardenlinux/glvd/db/CveRepository.java index 708701d..dc6e7f1 100644 --- a/src/main/java/io/gardenlinux/glvd/db/CveRepository.java +++ b/src/main/java/io/gardenlinux/glvd/db/CveRepository.java @@ -1,5 +1,6 @@ package io.gardenlinux.glvd.db; +import io.gardenlinux.glvd.dto.Cve; import org.springframework.data.jpa.repository.JpaRepository; import org.springframework.data.jpa.repository.Query; @@ -9,7 +10,7 @@ public interface CveRepository extends JpaRepository { @Query(value = """ SELECT - all_cve.data AS cveEntity + all_cve.* FROM all_cve INNER JOIN deb_cve USING (cve_id) @@ -21,6 +22,6 @@ INNER JOIN dist_cpe ON (deb_cve.dist_id = dist_cpe.id) ORDER BY all_cve.cve_id """, nativeQuery = true) - List cvesForDistribution(String vendor, String product, String codename); + List cvesForDistribution(String vendor, String product, String codename); } diff --git a/src/main/java/io/gardenlinux/glvd/dto/Configuration.java b/src/main/java/io/gardenlinux/glvd/dto/Configuration.java new file mode 100644 index 0000000..b90df38 --- /dev/null +++ b/src/main/java/io/gardenlinux/glvd/dto/Configuration.java @@ -0,0 +1,7 @@ +package io.gardenlinux.glvd.dto; + +import java.util.List; + +public record Configuration(List nodes) { + +} diff --git a/src/main/java/io/gardenlinux/glvd/dto/CpeMatch.java b/src/main/java/io/gardenlinux/glvd/dto/CpeMatch.java new file mode 100644 index 0000000..7d6ea3a --- /dev/null +++ b/src/main/java/io/gardenlinux/glvd/dto/CpeMatch.java @@ -0,0 +1,6 @@ +package io.gardenlinux.glvd.dto; + +public record CpeMatch(String criteria, Deb deb, boolean vulnerable, String versionStartIncluding, + String versionEndExcluding, String matchCriteriaId) { + +} diff --git a/src/main/java/io/gardenlinux/glvd/dto/Cve.java b/src/main/java/io/gardenlinux/glvd/dto/Cve.java index 93b66e8..b754c23 100644 --- a/src/main/java/io/gardenlinux/glvd/dto/Cve.java +++ b/src/main/java/io/gardenlinux/glvd/dto/Cve.java @@ -1,59 +1,10 @@ package io.gardenlinux.glvd.dto; -import jakarta.annotation.Nonnull; +import java.util.List; -import java.util.Objects; - -public class Cve { - - private String id; - - @Nonnull - private String lastModified; - - @Nonnull - private String data; - - public Cve() { - } - - public Cve(String id, @Nonnull String lastModified, @Nonnull String data) { - this.id = id; - this.lastModified = lastModified; - this.data = data; - } - - public String getId() { - return id; - } - - @Nonnull - public String getLastModified() { - return lastModified; - } - - @Nonnull - public String getData() { - return data; - } - - @Override - public boolean equals(Object o) { - if (this == o) - return true; - if (o == null || getClass() != o.getClass()) - return false; - - Cve Cve = (Cve) o; - return Objects.equals(id, Cve.id) && lastModified.equals(Cve.lastModified) && data.equals(Cve.data); - } - - @Override - public int hashCode() { - int result = Objects.hashCode(id); - result = 31 * result + lastModified.hashCode(); - result = 31 * result + data.hashCode(); - return result; - } +public record Cve(String id, String lastModified, String sourceIdentifier, String published, String vulnStatus, + List descriptions, Object metrics, List references, List weaknesses, + List configurations) { } + diff --git a/src/main/java/io/gardenlinux/glvd/dto/Deb.java b/src/main/java/io/gardenlinux/glvd/dto/Deb.java new file mode 100644 index 0000000..5267e32 --- /dev/null +++ b/src/main/java/io/gardenlinux/glvd/dto/Deb.java @@ -0,0 +1,5 @@ +package io.gardenlinux.glvd.dto; + +public record Deb(String versionLatest, String versionEndExcluding, String cvssSeverity) { + +} diff --git a/src/main/java/io/gardenlinux/glvd/dto/Description.java b/src/main/java/io/gardenlinux/glvd/dto/Description.java new file mode 100644 index 0000000..48727ee --- /dev/null +++ b/src/main/java/io/gardenlinux/glvd/dto/Description.java @@ -0,0 +1,4 @@ +package io.gardenlinux.glvd.dto; + +public record Description(String lang, String value) { +} diff --git a/src/main/java/io/gardenlinux/glvd/dto/Node.java b/src/main/java/io/gardenlinux/glvd/dto/Node.java new file mode 100644 index 0000000..91c6651 --- /dev/null +++ b/src/main/java/io/gardenlinux/glvd/dto/Node.java @@ -0,0 +1,7 @@ +package io.gardenlinux.glvd.dto; + +import java.util.List; + +public record Node(List cpeMatch, boolean negate, String operator) { + +} diff --git a/src/main/java/io/gardenlinux/glvd/dto/Readiness.java b/src/main/java/io/gardenlinux/glvd/dto/Readiness.java index 671a24a..04cf1a3 100644 --- a/src/main/java/io/gardenlinux/glvd/dto/Readiness.java +++ b/src/main/java/io/gardenlinux/glvd/dto/Readiness.java @@ -1,33 +1,5 @@ package io.gardenlinux.glvd.dto; -import java.util.Objects; - -public class Readiness { - - private final String dbCheck; - - public Readiness(String dbCheck) { - this.dbCheck = dbCheck; - } - - public String getDbCheck() { - return dbCheck; - } - - @Override - public boolean equals(Object o) { - if (this == o) - return true; - if (o == null || getClass() != o.getClass()) - return false; - - Readiness readiness = (Readiness) o; - return Objects.equals(dbCheck, readiness.dbCheck); - } - - @Override - public int hashCode() { - return Objects.hashCode(dbCheck); - } +public record Readiness(String dbCheck) { } diff --git a/src/main/java/io/gardenlinux/glvd/dto/Reference.java b/src/main/java/io/gardenlinux/glvd/dto/Reference.java new file mode 100644 index 0000000..75d10bb --- /dev/null +++ b/src/main/java/io/gardenlinux/glvd/dto/Reference.java @@ -0,0 +1,7 @@ +package io.gardenlinux.glvd.dto; + +import java.util.List; + +public record Reference(String url, String source, List tags) { + +} diff --git a/src/main/java/io/gardenlinux/glvd/dto/Weakness.java b/src/main/java/io/gardenlinux/glvd/dto/Weakness.java new file mode 100644 index 0000000..6f62882 --- /dev/null +++ b/src/main/java/io/gardenlinux/glvd/dto/Weakness.java @@ -0,0 +1,7 @@ +package io.gardenlinux.glvd.dto; + +import java.util.List; + +public record Weakness(String source, String type, List description) { + +} diff --git a/src/main/java/io/gardenlinux/glvd/exceptions/CantParseJSONException.java b/src/main/java/io/gardenlinux/glvd/exceptions/CantParseJSONException.java new file mode 100644 index 0000000..44fd9c8 --- /dev/null +++ b/src/main/java/io/gardenlinux/glvd/exceptions/CantParseJSONException.java @@ -0,0 +1,8 @@ +package io.gardenlinux.glvd.exceptions; + +public class CantParseJSONException extends RuntimeException{ + + public CantParseJSONException(String message) { + super(message); + } +} diff --git a/src/main/resources/application.properties b/src/main/resources/application.properties index 12930c7..2066b40 100644 --- a/src/main/resources/application.properties +++ b/src/main/resources/application.properties @@ -3,4 +3,4 @@ spring.datasource.url=jdbc:postgresql://localhost:5432/glvd spring.datasource.username=glvd spring.datasource.password=glvd spring.sql.init.mode=never -spring.jpa.properties.javax.persistence.query.timeout=5000 +jakarta.persistence.query.timeout=5000