1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18 package org.owasp.dependencycheck.dependency;
19
20 import java.io.File;
21 import java.io.IOException;
22 import java.io.Serializable;
23 import java.security.NoSuchAlgorithmException;
24 import java.util.ArrayList;
25 import java.util.HashSet;
26 import java.util.List;
27 import java.util.Set;
28 import java.util.SortedSet;
29 import java.util.TreeSet;
30
31 import org.apache.commons.lang3.builder.EqualsBuilder;
32 import org.apache.commons.lang3.builder.HashCodeBuilder;
33 import org.owasp.dependencycheck.data.nexus.MavenArtifact;
34 import org.owasp.dependencycheck.utils.Checksum;
35 import org.slf4j.Logger;
36 import org.slf4j.LoggerFactory;
37
38
39
40
41
42
43
44
45 public class Dependency implements Serializable, Comparable<Dependency> {
46
47
48
49
50 private static final long serialVersionUID = 1L;
51
52
53
54 private static final Logger LOGGER = LoggerFactory.getLogger(Dependency.class);
55
56
57
58 private static final int MAGIC_HASH_INIT_VALUE = 3;
59
60
61
62 private static final int MAGIC_HASH_MULTIPLIER = 47;
63
64
65
66 private String actualFilePath;
67
68
69
70 private String filePath;
71
72
73
74 private String fileName;
75
76
77
78 private String md5sum;
79
80
81
82 private String sha1sum;
83
84
85
86 private Set<Identifier> identifiers;
87
88
89
90 private final EvidenceCollection vendorEvidence;
91
92
93
94 private final EvidenceCollection productEvidence;
95
96
97
98 private final EvidenceCollection versionEvidence;
99
100
101
102
103 public Dependency() {
104 vendorEvidence = new EvidenceCollection();
105 productEvidence = new EvidenceCollection();
106 versionEvidence = new EvidenceCollection();
107 identifiers = new TreeSet<Identifier>();
108 vulnerabilities = new TreeSet<Vulnerability>(new VulnerabilityComparator());
109 suppressedIdentifiers = new TreeSet<Identifier>();
110 suppressedVulnerabilities = new TreeSet<Vulnerability>(new VulnerabilityComparator());
111 }
112
113
114
115
116
117
118 public Dependency(File file) {
119 this();
120 this.actualFilePath = file.getAbsolutePath();
121 this.filePath = this.actualFilePath;
122 this.fileName = file.getName();
123 determineHashes(file);
124 }
125
126
127
128
129
130
131 public String getFileName() {
132 return this.fileName;
133 }
134
135
136
137
138
139
140
141 public String getFileNameForJavaScript() {
142 return this.fileName.replace("\\", "\\\\");
143 }
144
145
146
147
148
149
150 public void setFileName(String fileName) {
151 this.fileName = fileName;
152 }
153
154
155
156
157
158
159 public void setActualFilePath(String actualFilePath) {
160 this.actualFilePath = actualFilePath;
161 if (this.sha1sum == null) {
162 final File file = new File(this.actualFilePath);
163 determineHashes(file);
164 }
165 }
166
167
168
169
170
171
172 public String getActualFilePath() {
173 return this.actualFilePath;
174 }
175
176
177
178
179
180
181 public File getActualFile() {
182 return new File(this.actualFilePath);
183 }
184
185
186
187
188
189
190 public void setFilePath(String filePath) {
191 this.filePath = filePath;
192 }
193
194
195
196
197 private String displayName = null;
198
199
200
201
202
203
204 public void setDisplayFileName(String displayName) {
205 this.displayName = displayName;
206 }
207
208
209
210
211
212
213 public String getDisplayFileName() {
214 if (displayName == null) {
215 return this.fileName;
216 }
217 return this.displayName;
218 }
219
220
221
222
223
224
225
226
227
228
229 public String getFilePath() {
230 return this.filePath;
231 }
232
233
234
235
236
237
238 public String getMd5sum() {
239 return this.md5sum;
240 }
241
242
243
244
245
246
247 public void setMd5sum(String md5sum) {
248 this.md5sum = md5sum;
249 }
250
251
252
253
254
255
256 public String getSha1sum() {
257 return this.sha1sum;
258 }
259
260
261
262
263
264
265 public void setSha1sum(String sha1sum) {
266 this.sha1sum = sha1sum;
267 }
268
269
270
271
272
273
274 public Set<Identifier> getIdentifiers() {
275 return this.identifiers;
276 }
277
278
279
280
281
282
283 public void setIdentifiers(Set<Identifier> identifiers) {
284 this.identifiers = identifiers;
285 }
286
287
288
289
290
291
292
293
294 public void addIdentifier(String type, String value, String url) {
295 final Identifier i = new Identifier(type, value, url);
296 this.identifiers.add(i);
297 }
298
299
300
301
302
303
304
305
306
307 public void addIdentifier(String type, String value, String url, Confidence confidence) {
308 final Identifier i = new Identifier(type, value, url);
309 i.setConfidence(confidence);
310 this.identifiers.add(i);
311 }
312
313
314
315
316
317
318
319
320 public void addAsEvidence(String source, MavenArtifact mavenArtifact, Confidence confidence) {
321 if (mavenArtifact.getGroupId() != null && !mavenArtifact.getGroupId().isEmpty()) {
322 this.getVendorEvidence().addEvidence(source, "groupid", mavenArtifact.getGroupId(), confidence);
323 }
324 if (mavenArtifact.getArtifactId() != null && !mavenArtifact.getArtifactId().isEmpty()) {
325 this.getProductEvidence().addEvidence(source, "artifactid", mavenArtifact.getArtifactId(), confidence);
326 }
327 if (mavenArtifact.getVersion() != null && !mavenArtifact.getVersion().isEmpty()) {
328 this.getVersionEvidence().addEvidence(source, "version", mavenArtifact.getVersion(), confidence);
329 }
330 if (mavenArtifact.getArtifactUrl() != null && !mavenArtifact.getArtifactUrl().isEmpty()) {
331 boolean found = false;
332 for (Identifier i : this.getIdentifiers()) {
333 if ("maven".equals(i.getType()) && i.getValue().equals(mavenArtifact.toString())) {
334 found = true;
335 i.setConfidence(Confidence.HIGHEST);
336 final String url = "http://search.maven.org/#search|ga|1|1%3A%22" + this.getSha1sum() + "%22";
337 i.setUrl(url);
338
339 LOGGER.debug("Already found identifier {}. Confidence set to highest", i.getValue());
340 break;
341 }
342 }
343 if (!found) {
344 LOGGER.debug("Adding new maven identifier {}", mavenArtifact);
345 this.addIdentifier("maven", mavenArtifact.toString(), mavenArtifact.getArtifactUrl(), Confidence.HIGHEST);
346 }
347 }
348 }
349
350
351
352
353
354
355 public void addIdentifier(Identifier identifier) {
356 this.identifiers.add(identifier);
357 }
358
359
360
361
362 private Set<Identifier> suppressedIdentifiers;
363
364
365
366
367
368
369 public Set<Identifier> getSuppressedIdentifiers() {
370 return suppressedIdentifiers;
371 }
372
373
374
375
376
377
378 public void setSuppressedIdentifiers(Set<Identifier> suppressedIdentifiers) {
379 this.suppressedIdentifiers = suppressedIdentifiers;
380 }
381
382
383
384
385
386
387 public void addSuppressedIdentifier(Identifier identifier) {
388 this.suppressedIdentifiers.add(identifier);
389 }
390
391
392
393
394 private SortedSet<Vulnerability> suppressedVulnerabilities;
395
396
397
398
399
400
401 public SortedSet<Vulnerability> getSuppressedVulnerabilities() {
402 return suppressedVulnerabilities;
403 }
404
405
406
407
408
409
410 public void setSuppressedVulnerabilities(SortedSet<Vulnerability> suppressedVulnerabilities) {
411 this.suppressedVulnerabilities = suppressedVulnerabilities;
412 }
413
414
415
416
417
418
419 public void addSuppressedVulnerability(Vulnerability vulnerability) {
420 this.suppressedVulnerabilities.add(vulnerability);
421 }
422
423
424
425
426
427
428 public EvidenceCollection getEvidence() {
429 return EvidenceCollection.merge(this.productEvidence, this.vendorEvidence, this.versionEvidence);
430 }
431
432
433
434
435
436
437 public Set<Evidence> getEvidenceForDisplay() {
438 return EvidenceCollection.mergeForDisplay(this.productEvidence, this.vendorEvidence, this.versionEvidence);
439 }
440
441
442
443
444
445
446 public EvidenceCollection getEvidenceUsed() {
447 return EvidenceCollection.mergeUsed(this.productEvidence, this.vendorEvidence, this.versionEvidence);
448 }
449
450
451
452
453
454
455 public EvidenceCollection getVendorEvidence() {
456 return this.vendorEvidence;
457 }
458
459
460
461
462
463
464 public EvidenceCollection getProductEvidence() {
465 return this.productEvidence;
466 }
467
468
469
470
471
472
473 public EvidenceCollection getVersionEvidence() {
474 return this.versionEvidence;
475 }
476
477
478
479
480 private String description;
481
482
483
484
485
486
487 public String getDescription() {
488 return description;
489 }
490
491
492
493
494
495
496 public void setDescription(String description) {
497 this.description = description;
498 }
499
500
501
502
503 private String license;
504
505
506
507
508
509
510 public String getLicense() {
511 return license;
512 }
513
514
515
516
517
518
519 public void setLicense(String license) {
520 this.license = license;
521 }
522
523
524
525
526 private SortedSet<Vulnerability> vulnerabilities;
527
528
529
530
531
532
533 public SortedSet<Vulnerability> getVulnerabilities() {
534 return vulnerabilities;
535 }
536
537
538
539
540
541
542 public void setVulnerabilities(SortedSet<Vulnerability> vulnerabilities) {
543 this.vulnerabilities = vulnerabilities;
544 }
545
546
547
548
549
550
551 private void determineHashes(File file) {
552 String md5 = null;
553 String sha1 = null;
554 try {
555 md5 = Checksum.getMD5Checksum(file);
556 sha1 = Checksum.getSHA1Checksum(file);
557 } catch (IOException ex) {
558 LOGGER.warn("Unable to read '{}' to determine hashes.", file.getName());
559 LOGGER.debug("", ex);
560 } catch (NoSuchAlgorithmException ex) {
561 LOGGER.warn("Unable to use MD5 of SHA1 checksums.");
562 LOGGER.debug("", ex);
563 }
564 this.setMd5sum(md5);
565 this.setSha1sum(sha1);
566 }
567
568
569
570
571
572
573 public void addVulnerability(Vulnerability vulnerability) {
574 this.vulnerabilities.add(vulnerability);
575 }
576
577
578
579
580 private Set<Dependency> relatedDependencies = new TreeSet<Dependency>();
581
582
583
584
585
586
587
588 public Set<Dependency> getRelatedDependencies() {
589 return relatedDependencies;
590 }
591
592
593
594
595 private Set<String> projectReferences = new HashSet<String>();
596
597
598
599
600
601
602 public Set<String> getProjectReferences() {
603 return projectReferences;
604 }
605
606
607
608
609
610
611 public void setProjectReferences(Set<String> projectReferences) {
612 this.projectReferences = projectReferences;
613 }
614
615
616
617
618
619
620 public void addProjectReference(String projectReference) {
621 this.projectReferences.add(projectReference);
622 }
623
624
625
626
627
628
629 public void addAllProjectReferences(Set<String> projectReferences) {
630 this.projectReferences.addAll(projectReferences);
631 }
632
633
634
635
636
637
638 public void setRelatedDependencies(Set<Dependency> relatedDependencies) {
639 this.relatedDependencies = relatedDependencies;
640 }
641
642
643
644
645
646
647
648
649 public void addRelatedDependency(Dependency dependency) {
650 if (this == dependency) {
651 LOGGER.warn("Attempted to add a circular reference - please post the log file to issue #172 here "
652 + "https://github.com/jeremylong/DependencyCheck/issues/172");
653 LOGGER.debug("this: {}", this);
654 LOGGER.debug("dependency: {}", dependency);
655 } else if (!relatedDependencies.add(dependency)) {
656 LOGGER.debug("Failed to add dependency, likely due to referencing the same file as another dependency in the set.");
657 LOGGER.debug("this: {}", this);
658 LOGGER.debug("dependency: {}", dependency);
659 }
660 }
661
662
663
664
665 private List<String> availableVersions = new ArrayList<String>();
666
667
668
669
670
671
672 public List<String> getAvailableVersions() {
673 return availableVersions;
674 }
675
676
677
678
679
680
681 public void setAvailableVersions(List<String> availableVersions) {
682 this.availableVersions = availableVersions;
683 }
684
685
686
687
688
689
690 public void addAvailableVersion(String version) {
691 this.availableVersions.add(version);
692 }
693
694
695
696
697
698
699
700 @Override
701 public int compareTo(Dependency o) {
702 return this.getFilePath().compareToIgnoreCase(o.getFilePath());
703 }
704
705
706
707
708
709
710
711 @Override
712 public boolean equals(Object obj) {
713 if (obj == null || getClass() != obj.getClass()) {
714 return false;
715 }
716 final Dependency other = (Dependency) obj;
717 return new EqualsBuilder()
718 .appendSuper(super.equals(obj))
719 .append(this.actualFilePath, other.actualFilePath)
720 .append(this.filePath, other.filePath)
721 .append(this.fileName, other.fileName)
722 .append(this.md5sum, other.md5sum)
723 .append(this.sha1sum, other.sha1sum)
724 .append(this.identifiers, other.identifiers)
725 .append(this.vendorEvidence, other.vendorEvidence)
726 .append(this.productEvidence, other.productEvidence)
727 .append(this.versionEvidence, other.versionEvidence)
728 .append(this.description, other.description)
729 .append(this.license, other.license)
730 .append(this.vulnerabilities, other.vulnerabilities)
731
732 .append(this.projectReferences, other.projectReferences)
733 .append(this.availableVersions, other.availableVersions)
734 .isEquals();
735 }
736
737
738
739
740
741
742 @Override
743 public int hashCode() {
744 return new HashCodeBuilder(MAGIC_HASH_INIT_VALUE, MAGIC_HASH_MULTIPLIER)
745 .append(actualFilePath)
746 .append(filePath)
747 .append(fileName)
748 .append(md5sum)
749 .append(sha1sum)
750 .append(identifiers)
751 .append(vendorEvidence)
752 .append(productEvidence)
753 .append(versionEvidence)
754 .append(description)
755 .append(license)
756 .append(vulnerabilities)
757
758 .append(projectReferences)
759 .append(availableVersions)
760 .toHashCode();
761 }
762
763
764
765
766
767
768 @Override
769 public String toString() {
770 return "Dependency{ fileName='" + fileName + "', actualFilePath='" + actualFilePath + "', filePath='" + filePath + "'}";
771 }
772 }