//////////////////////////////////////////////////////////////////////// // // Copyright (c) 2009-2013 Denim Group, Ltd. // // The contents of this file are subject to the Mozilla Public License // Version 2.0 (the "License"); you may not use this file except in // compliance with the License. You may obtain a copy of the License at // http://www.mozilla.org/MPL/ // // Software distributed under the License is distributed on an "AS IS" // basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the // License for the specific language governing rights and limitations // under the License. // // The Original Code is ThreadFix. // // The Initial Developer of the Original Code is Denim Group, Ltd. // Portions created by Denim Group, Ltd. are Copyright (C) // Denim Group, Ltd. All Rights Reserved. // // Contributor(s): Denim Group, Ltd. // //////////////////////////////////////////////////////////////////////// package com.denimgroup.threadfix.data.entities; import java.util.ArrayList; import java.util.Arrays; import java.util.Calendar; import java.util.Comparator; import java.util.List; import javax.persistence.CascadeType; import javax.persistence.Column; import javax.persistence.Entity; import javax.persistence.JoinColumn; import javax.persistence.ManyToOne; import javax.persistence.OneToMany; import javax.persistence.Table; import javax.persistence.Temporal; import javax.persistence.TemporalType; import javax.persistence.Transient; import org.codehaus.jackson.annotate.JsonIgnore; @Entity @Table(name = "Scan") public class Scan extends BaseEntity { private static final long serialVersionUID = -8461350611851383656L; private ApplicationChannel applicationChannel; private Calendar importTime; private Application application; private Integer numberClosedVulnerabilities; private Integer numberNewVulnerabilities; private Integer numberOldVulnerabilities; private Integer numberResurfacedVulnerabilities; private Integer numberTotalVulnerabilities; private Integer numberRepeatResults; private Integer numberRepeatFindings; private Long numberInfoVulnerabilities = 0L, numberLowVulnerabilities = 0L, numberMediumVulnerabilities = 0L, numberHighVulnerabilities = 0L, numberCriticalVulnerabilities = 0L; private User user; private List<ScanRepeatFindingMap> scanRepeatFindingMaps; private List<ScanReopenVulnerabilityMap> scanReopenVulnerabilityMaps; private List<ScanCloseVulnerabilityMap> scanCloseVulnerabilityMaps; // TODO probably rename this - it's for the graphs private Integer numberOldVulnerabilitiesInitiallyFromThisChannel; private List<Finding> findings; private Integer numWithoutChannelVulns = null; private Integer numWithoutGenericMappings = null; private Integer totalNumberSkippedResults = null; private Integer totalNumberFindingsMergedInScan = null; // These are for determining what type of scanner was used // updated by Michael Xin by adding new type private static final List<String> DYNAMIC_TYPES = Arrays.asList(new String[]{ ChannelType.ACUNETIX_WVS, ChannelType.APPSCAN_ENTERPRISE, ChannelType.ARACHNI, ChannelType.BURPSUITE, ChannelType.NESSUS, ChannelType.NETSPARKER, ChannelType.NTO_SPIDER, ChannelType.SKIPFISH, ChannelType.W3AF, ChannelType.WEBINSPECT, ChannelType.ZAPROXY, ChannelType.QUALYSGUARD_WAS, ChannelType.APPSCAN_DYNAMIC, ChannelType.PRODUCT_SECURITY_TEST, ChannelType.NESSUS_SCAN }); private static final List<String> STATIC_TYPES = Arrays.asList(new String[]{ ChannelType.APPSCAN_SOURCE, ChannelType.FINDBUGS, ChannelType.FORTIFY, ChannelType.VERACODE, ChannelType.CAT_NET, ChannelType.BRAKEMAN }); private static final List<String> MIXED_TYPES = Arrays.asList(new String[]{ ChannelType.SENTINEL }); private static final String DYNAMIC="Dynamic", STATIC="Static", MIXED="Mixed"; @ManyToOne(cascade = CascadeType.MERGE) @JoinColumn(name = "applicationChannelId") @JsonIgnore public ApplicationChannel getApplicationChannel() { return applicationChannel; } public void setApplicationChannel(ApplicationChannel applicationChannel) { this.applicationChannel = applicationChannel; } @Temporal(TemporalType.TIMESTAMP) public Calendar getImportTime() { return importTime; } public void setImportTime(Calendar importTime) { this.importTime = importTime; } @ManyToOne @JoinColumn(name = "applicationId") @JsonIgnore public Application getApplication() { return application; } public void setApplication(Application application) { this.application = application; } @ManyToOne @JoinColumn(nullable = true, name = "userId") @JsonIgnore public User getUser() { return user; } public void setUser(User user) { this.user = user; } @OneToMany(mappedBy = "scan", cascade = CascadeType.ALL) public List<Finding> getFindings() { return findings; } public void setFindings(List<Finding> findings) { this.findings = findings; } @OneToMany(mappedBy = "scan", cascade = CascadeType.ALL) public List<ScanRepeatFindingMap> getScanRepeatFindingMaps() { return scanRepeatFindingMaps; } public void setScanRepeatFindingMaps(List<ScanRepeatFindingMap> scanRepeatFindingMaps) { this.scanRepeatFindingMaps = scanRepeatFindingMaps; } @OneToMany(mappedBy = "scan", cascade = CascadeType.ALL) public List<ScanReopenVulnerabilityMap> getScanReopenVulnerabilityMaps() { return scanReopenVulnerabilityMaps; } public void setScanReopenVulnerabilityMaps(List<ScanReopenVulnerabilityMap> ScanReopenVulnerabilityMaps) { this.scanReopenVulnerabilityMaps = ScanReopenVulnerabilityMaps; } @OneToMany(mappedBy = "scan", cascade = CascadeType.ALL) public List<ScanCloseVulnerabilityMap> getScanCloseVulnerabilityMaps() { return scanCloseVulnerabilityMaps; } public void setScanCloseVulnerabilityMaps(List<ScanCloseVulnerabilityMap> ScanCloseVulnerabilityMaps) { this.scanCloseVulnerabilityMaps = ScanCloseVulnerabilityMaps; } @Column public Integer getNumberClosedVulnerabilities() { return numberClosedVulnerabilities; } public void setNumberClosedVulnerabilities(Integer numberClosedVulnerabilities) { this.numberClosedVulnerabilities = numberClosedVulnerabilities; } @Column public Integer getNumberNewVulnerabilities() { return numberNewVulnerabilities; } public void setNumberNewVulnerabilities(Integer numberNewVulnerabilities) { this.numberNewVulnerabilities = numberNewVulnerabilities; } @Column public Integer getNumberOldVulnerabilities() { return numberOldVulnerabilities; } public void setNumberOldVulnerabilities(Integer numberOldVulnerabilities) { this.numberOldVulnerabilities = numberOldVulnerabilities; } /** * Keeping track of this information allows us to produce scans without extensive recalculation, * because we don't have to track down which application channel we should count a vulnerability for. * * This may lead to a small bug if a vuln is opened in one channel, then found in another and * subsequently closed there. This needs to be looked into. * @return */ @Column public Integer getNumberOldVulnerabilitiesInitiallyFromThisChannel() { return numberOldVulnerabilitiesInitiallyFromThisChannel; } public void setNumberOldVulnerabilitiesInitiallyFromThisChannel( Integer numberOldVulnerabilitiesInitiallyFromThisChannel) { this.numberOldVulnerabilitiesInitiallyFromThisChannel = numberOldVulnerabilitiesInitiallyFromThisChannel; } @Column public Integer getNumberResurfacedVulnerabilities() { return numberResurfacedVulnerabilities; } public void setNumberResurfacedVulnerabilities(Integer numberResurfacedVulnerabilities) { this.numberResurfacedVulnerabilities = numberResurfacedVulnerabilities; } @Column public Integer getNumberTotalVulnerabilities() { return numberTotalVulnerabilities; } public void setNumberTotalVulnerabilities(Integer numberTotalVulnerabilities) { this.numberTotalVulnerabilities = numberTotalVulnerabilities; } @Column public Integer getNumberRepeatFindings() { return numberRepeatFindings; } public void setNumberRepeatFindings(Integer numberRepeatFindings) { this.numberRepeatFindings = numberRepeatFindings; } @Column public Integer getNumberRepeatResults() { return numberRepeatResults; } public void setNumberRepeatResults(Integer numberRepeatResults) { this.numberRepeatResults = numberRepeatResults; } @Transient public Integer getNumWithoutGenericMappings() { return numWithoutGenericMappings; } public void setNumWithoutGenericMappings(Integer numWithoutGenericMappings) { this.numWithoutGenericMappings = numWithoutGenericMappings; } @Transient public Integer getNumWithoutChannelVulns() { return numWithoutChannelVulns; } public void setNumWithoutChannelVulns(Integer numWithoutChannelVulns) { this.numWithoutChannelVulns = numWithoutChannelVulns; } @Transient public Integer getTotalNumberSkippedResults() { return totalNumberSkippedResults; } public void setTotalNumberSkippedResults(Integer totalNumberSkippedResults) { this.totalNumberSkippedResults = totalNumberSkippedResults; } @Transient public Integer getTotalNumberFindingsMergedInScan() { return totalNumberFindingsMergedInScan; } public void setTotalNumberFindingsMergedInScan( Integer totalNumberFindingsMergedInScan) { this.totalNumberFindingsMergedInScan = totalNumberFindingsMergedInScan; } // These two functions establish the order the integers come in and this // order should not be changed. @Transient @JsonIgnore public List<Integer> getReportList() { List<Integer> integerList = new ArrayList<Integer>(); integerList.add(getId()); integerList.add(getNumberTotalVulnerabilities()); integerList.add(getNumberNewVulnerabilities()); integerList.add(getNumberOldVulnerabilities()); integerList.add(getNumberResurfacedVulnerabilities()); integerList.add(getNumberClosedVulnerabilities()); return integerList; } @JsonIgnore public static ScanTimeComparator getTimeComparator() { return new ScanTimeComparator(); } static public class ScanTimeComparator implements Comparator<Scan> { public int compare(Scan scan1, Scan scan2){ Calendar scan1Time = scan1.getImportTime(); Calendar scan2Time = scan2.getImportTime(); if (scan1Time == null || scan2Time == null) return 0; return scan1Time.compareTo(scan2Time); } } @Column public Long getNumberInfoVulnerabilities() { return numberInfoVulnerabilities; } public void setNumberInfoVulnerabilities(Long numberInfoVulnerabilities) { this.numberInfoVulnerabilities = numberInfoVulnerabilities; } @Column public Long getNumberLowVulnerabilities() { return numberLowVulnerabilities; } public void setNumberLowVulnerabilities(Long numberLowVulnerabilities) { this.numberLowVulnerabilities = numberLowVulnerabilities; } @Column public Long getNumberMediumVulnerabilities() { return numberMediumVulnerabilities; } public void setNumberMediumVulnerabilities(Long numberMediumVulnerabilities) { this.numberMediumVulnerabilities = numberMediumVulnerabilities; } @Column public Long getNumberHighVulnerabilities() { return numberHighVulnerabilities; } public void setNumberHighVulnerabilities(Long numberHighVulnerabilities) { this.numberHighVulnerabilities = numberHighVulnerabilities; } @Column public Long getNumberCriticalVulnerabilities() { return numberCriticalVulnerabilities; } public void setNumberCriticalVulnerabilities( Long numberCriticalVulnerabilities) { this.numberCriticalVulnerabilities = numberCriticalVulnerabilities; } @Transient public String getScannerType() { if (getApplicationChannel() != null && getApplicationChannel().getChannelType() != null && getApplicationChannel().getChannelType().getName() != null) { String scannerName = getApplicationChannel().getChannelType().getName(); if (DYNAMIC_TYPES.contains(scannerName)) { return DYNAMIC; } else if (STATIC_TYPES.contains(scannerName)) { return STATIC; } else if (MIXED_TYPES.contains(scannerName)) { return MIXED; } } return null; } }