Skip to content

Commit

Permalink
Merge: Main <- juwon/#14-modular
Browse files Browse the repository at this point in the history
[Feat] 모듈화 및 데이터베이스 연동 - #14
  • Loading branch information
Juser0 authored Oct 15, 2023
2 parents 5ba351f + 1668447 commit 2816b68
Show file tree
Hide file tree
Showing 13 changed files with 200 additions and 27 deletions.
6 changes: 4 additions & 2 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,9 @@ build/
!gradle/wrapper/gradle-wrapper.jar
!**/src/main/**/build/
!**/src/test/**/build/
!**/wrapper/
!**/wrapper/**/
!**/wrapper/gradle-wrapper.jar

### STS ###
.apt_generated
Expand Down Expand Up @@ -64,5 +67,4 @@ out/

### Configuration Files ###
application-dev.yml
application-prod.yml
gradle.properties
gradle.properties
3 changes: 3 additions & 0 deletions manager/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,9 @@ dependencies {
implementation 'org.springframework.boot:spring-boot-starter-webflux'
implementation 'org.springdoc:springdoc-openapi-ui:1.6.15'
implementation 'org.jsoup:jsoup:1.16.1'
implementation 'org.springframework.boot:spring-boot-starter-data-jpa'
implementation 'com.mysql:mysql-connector-j:8.1.0'

compileOnly 'org.projectlombok:lombok'
developmentOnly 'org.springframework.boot:spring-boot-devtools'
annotationProcessor 'org.projectlombok:lombok'
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,16 +19,14 @@ private CommonResponse(String responseCode, String responseMessage, T data) {
this.data = data;
}

public static CommonResponse resWithoutData (final String responseCode, final String responseMessage) {
public static CommonResponse from (final String responseCode) {
return CommonResponse.builder()
.responseCode(responseCode)
.responseMessage(responseMessage)
.build();
}
public static <T> CommonResponse<T> resWithData (final String responseCode, final String responseMessage, final T data) {
public static <T> CommonResponse<T> from (final String responseCode, final T data) {
return CommonResponse.<T>builder()
.responseCode(responseCode)
.responseMessage(responseMessage)
.data(data)
.build();
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,11 @@
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.http.HttpHeaders;
import org.springframework.http.client.reactive.ReactorClientHttpConnector;
import org.springframework.web.reactive.function.client.WebClient;
import reactor.netty.http.client.HttpClient;

import java.time.Duration;


@Configuration
Expand All @@ -12,6 +16,9 @@ public class WebClientConfig {
public WebClient.Builder webclientBuilder() {
return WebClient.builder()
.defaultHeader(HttpHeaders.ACCEPT, "*/*")
.defaultHeader(HttpHeaders.CONTENT_TYPE, "application/json");
.defaultHeader(HttpHeaders.CONTENT_TYPE, "application/json")
.clientConnector(new ReactorClientHttpConnector(HttpClient.newConnection()
.responseTimeout(Duration.ofSeconds(60))
));
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -31,13 +31,13 @@ public class SbomController {
@Operation(summary = "SBOM Scan", description = "Scan Software Bill of Materials")
public ResponseEntity<CommonResponse<JsonNode>> scanSBOM(@RequestParam String token, @RequestParam String projectId, @RequestParam String baseUrl) throws JsonProcessingException {
JsonNode sbomResult = sbomService.scanVulnerability(token, projectId, baseUrl);
return ResponseEntity.status(OK).body(CommonResponse.resWithData("SBOM_SCAN_COMPLETED", "SBOM 스캔이 완료되었습니다", sbomResult));
return ResponseEntity.status(OK).body(CommonResponse.from("SBOM_SCAN_COMPLETED", sbomResult));
}

@GetMapping("/report")
@Operation(summary = "Get SBOM Report", description = "Get Software Bill of Materials' security report")
public ResponseEntity<CommonResponse<List<SbomResponseDto>>> getReport(@RequestParam String token, @RequestParam String projectId, @RequestParam String baseUrl) throws IOException {
List<SbomResponseDto> sbomReport = sbomService.generateReport(token, projectId, baseUrl);
return ResponseEntity.status(OK).body(CommonResponse.resWithData("SBOM_REPORT_GENERATED", "SBOM 보안 보고서가 생성되었습니다", sbomReport));
return ResponseEntity.status(OK).body(CommonResponse.from("SBOM_REPORT_GENERATED", sbomReport));
}
}
30 changes: 30 additions & 0 deletions manager/src/main/java/com/analyzer/sbom/domain/Reference.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
package com.analyzer.sbom.domain;

import com.analyzer.sbom.dto.request.ReferenceRequestDto;
import lombok.AccessLevel;
import lombok.Getter;
import lombok.NoArgsConstructor;

import javax.persistence.*;

@Entity
@Getter
@Table(name = "reference_tb")
@NoArgsConstructor(access = AccessLevel.PROTECTED)
public class Reference {

@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;

@Column(name = "cve")
private String cveId;

@Column(name = "reference_url")
private String referenceUrl;

public Reference(ReferenceRequestDto requestDto) {
this.cveId = requestDto.getCveId();
this.referenceUrl = requestDto.getReferenceUrl();
}
}
33 changes: 33 additions & 0 deletions manager/src/main/java/com/analyzer/sbom/domain/Suggestion.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
package com.analyzer.sbom.domain;

import com.analyzer.sbom.dto.request.SuggestionRequestDto;
import lombok.AccessLevel;
import lombok.Getter;
import lombok.NoArgsConstructor;

import javax.persistence.*;

@Entity
@Getter
@Table(name = "suggestion_tb")
@NoArgsConstructor(access = AccessLevel.PROTECTED)
public class Suggestion {

@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;

@Column(name = "cve")
private String cveId;

private String suggestion;

@Column(name = "suggestion_url")
private String suggestionUrl;

public Suggestion(SuggestionRequestDto requestDto) {
this.cveId = requestDto.getCveId();
this.suggestion = requestDto.getSuggestion();
this.suggestionUrl = requestDto.getSuggestionUrl();
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
package com.analyzer.sbom.dto.request;

import com.analyzer.sbom.domain.Reference;
import lombok.Getter;

import javax.validation.constraints.NotBlank;

@Getter
public class ReferenceRequestDto {
@NotBlank
private String cveId;

@NotBlank
private String referenceUrl;

public Reference toEntity(ReferenceRequestDto requestDto) {
return new Reference(requestDto);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
package com.analyzer.sbom.dto.request;

import com.analyzer.sbom.domain.Suggestion;
import lombok.Getter;

import javax.validation.constraints.NotBlank;

@Getter
public class SuggestionRequestDto {

@NotBlank
private String cveId;

@NotBlank
private String suggestion;

@NotBlank
private String suggestionUrl;

public Suggestion toEntity(SuggestionRequestDto requestDto) {
return new Suggestion(requestDto);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
package com.analyzer.sbom.dto.response;

import com.analyzer.sbom.domain.Reference;
import lombok.Getter;

import javax.validation.constraints.NotBlank;

@Getter
public class ReferenceResponseDto {
@NotBlank
private Long id;

@NotBlank
private String cveId;

@NotBlank
private String referenceUrl;

private ReferenceResponseDto(Reference reference) {
this.id = reference.getId();
this.cveId = reference.getCveId();
this.referenceUrl = reference.getReferenceUrl();
}

public static ReferenceResponseDto from(Reference reference) {
return new ReferenceResponseDto(reference);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
package com.analyzer.sbom.dto.response;

import com.analyzer.sbom.domain.Suggestion;
import lombok.Getter;

import javax.validation.constraints.NotBlank;

@Getter
public class SuggestionResponseDto {

@NotBlank
private Long id;

@NotBlank
private String cveId;

@NotBlank
private String suggestion;

@NotBlank
private String suggestionUrl;

private SuggestionResponseDto(Suggestion suggestion) {
this.id = suggestion.getId();
this.cveId = suggestion.getCveId();
this.suggestion = suggestion.getSuggestion();
this.suggestionUrl = suggestion.getSuggestionUrl();
}

public static SuggestionResponseDto from(Suggestion suggestion) {
return new SuggestionResponseDto(suggestion);
}
}
33 changes: 15 additions & 18 deletions manager/src/main/java/com/analyzer/sbom/service/SbomService.java
Original file line number Diff line number Diff line change
Expand Up @@ -14,9 +14,7 @@
import org.springframework.web.reactive.function.client.WebClient;

import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
import java.util.Objects;
import java.util.*;
import java.util.stream.Collectors;

@Service
Expand Down Expand Up @@ -55,22 +53,21 @@ public List<SbomResponseDto> generateReport(String token, String projectId, Stri
List<SbomResponseDto> sbomReport = new ArrayList<>();

JsonNode jsonNode = objectMapper.readTree(sbomResult).get("findings");
if (jsonNode.isArray()) {
for (JsonNode finding : jsonNode) {
JsonNode component = finding.get("component");
String name = isExist(component, "name") ? component.get("name").asText() : "";
String version = isExist(component, "version") ? component.get("version").asText() : "";
String purl = isExist(component, "purl") ? component.get("purl").asText() : "";
String group = isExist(component, "group") ? component.get("group").asText() : "";
String name = parseText(component, "name");
String version = parseText(component, "text");
String purl = parseText(component, "purl");
String group = parseText(component, "group");

JsonNode attribution = finding.get("attribution");
String suggestionLink = isExist(attribution, "referenceUrl") ? attribution.get("referenceUrl").asText() : "";
String suggestionLink = parseText(attribution, "referenceUrl");

JsonNode vulnerability = finding.get("vulnerability");
String severity = isExist(vulnerability, "severity") ? vulnerability.get("severity").asText() : "";
String vulnId = isExist(vulnerability, "vulnId") ? vulnerability.get("vulnId").asText() : "";
String source = isExist(vulnerability, "source") ? vulnerability.get("source").asText() : "";
String description = isExist(vulnerability, "description") ? vulnerability.get("description").asText() : "";
String severity = parseText(vulnerability, "severity");
String vulnId = parseText(vulnerability, "vulnId");
String source = parseText(vulnerability, "source");
String description = parseText(vulnerability, "description");

String referenceUrl = cveUrl + vulnId;

Expand All @@ -96,7 +93,6 @@ public List<SbomResponseDto> generateReport(String token, String projectId, Stri

sbomReport.add(sbomResponseDto);
}
}
return sbomReport;
}

Expand All @@ -114,10 +110,6 @@ private String getAPI(String token, String projectId, String baseUrl) {
.block();
}

private boolean isExist(JsonNode source, String fieldName) {
return source.has(fieldName);
}

private List<String> getSuggestionUrl(String cveUrl) throws IOException {
Document doc = Jsoup.connect(cveUrl).get();
Element table = doc.select(nvdSelector).first();
Expand All @@ -134,10 +126,15 @@ private String getSuggestion(String snykUrl, Boolean isLink) throws IOException
String link = String.join("", doc.selectXpath(snykXpath).eachAttr("href"));
String suggestionLink = snykBase + link;

if(isLink) return suggestionLink;

Document solutionDoc = Jsoup.connect(suggestionLink).get();
String suggestion = solutionDoc.selectXpath(snykSearchXpath).text();

return isLink ? suggestionLink : suggestion;
}

private String parseText(JsonNode source, String subject) {
return source.has(subject) ? source.get(subject).asText() : "";
}
}
File renamed without changes.

0 comments on commit 2816b68

Please sign in to comment.