mirror of
https://github.com/ysoftdevs/DependencyCheck.git
synced 2026-01-14 15:53:36 +01:00
Compare commits
1893 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
6f9ba0033f | ||
|
|
4d4672fc4d | ||
|
|
70859eb719 | ||
|
|
ae9daf7f33 | ||
|
|
ff0daa8d66 | ||
|
|
09f1a0ac92 | ||
|
|
e562be77f6 | ||
|
|
af7c6bc2a0 | ||
|
|
e49cbcf345 | ||
|
|
b4218ff0e8 | ||
|
|
4af174d27b | ||
|
|
203a7da23a | ||
|
|
9833ff20d1 | ||
|
|
638b3c0695 | ||
|
|
01ef2e1061 | ||
|
|
56aea8ad24 | ||
|
|
d530eddc57 | ||
|
|
1eab76aab8 | ||
|
|
167dbd7368 | ||
|
|
2594fb1c5f | ||
|
|
c57d21e9bc | ||
|
|
9c15bdfe41 | ||
|
|
64dedf892d | ||
|
|
d6fc456039 | ||
|
|
df606674db | ||
|
|
1e3a7ff4ba | ||
|
|
b53de8c69b | ||
|
|
0f3ffaf270 | ||
|
|
25238d5fb5 | ||
|
|
cf677bd70e | ||
|
|
42939e4922 | ||
|
|
7c4cc1334b | ||
|
|
ff4a1e0ac6 | ||
|
|
069e22049d | ||
|
|
135ed5c614 | ||
|
|
13d7d29630 | ||
|
|
889f315c0a | ||
|
|
5a0e280899 | ||
|
|
ccb5e234b3 | ||
|
|
2caccab85f | ||
|
|
085ab48f3f | ||
|
|
a28c2819fa | ||
|
|
40beec2e40 | ||
|
|
d136aeda84 | ||
|
|
fdd6c47cd5 | ||
|
|
c5a2b5b3d8 | ||
|
|
babe4739c5 | ||
|
|
49e8ee443c | ||
|
|
a5d8ce07d8 | ||
|
|
babc016b48 | ||
|
|
a5f378d755 | ||
|
|
ebf995537e | ||
|
|
49edb6c2e1 | ||
|
|
423f26852f | ||
|
|
f931412bee | ||
|
|
bef0657801 | ||
|
|
d79d5b5f33 | ||
|
|
4c5489efd3 | ||
|
|
d5753b9589 | ||
|
|
a841027d48 | ||
|
|
73bea8e63f | ||
|
|
bbc8bab4da | ||
|
|
019f6dfb8b | ||
|
|
3b6a2a2908 | ||
|
|
c2b757ad6f | ||
|
|
efeba40f2b | ||
|
|
018e4bc382 | ||
|
|
88924ea520 | ||
|
|
4461c2e4a4 | ||
|
|
1c4aceb0fb | ||
|
|
a5b396a60d | ||
|
|
efd96ed892 | ||
|
|
fe88785846 | ||
|
|
0dcb0fb325 | ||
|
|
0825843d0f | ||
|
|
8c4df134e4 | ||
|
|
dfed5067f3 | ||
|
|
2b78e8fdc1 | ||
|
|
63c7a9d926 | ||
|
|
6609481cc1 | ||
|
|
a37853def6 | ||
|
|
9f348cfa16 | ||
|
|
52293f2596 | ||
|
|
54d3a73282 | ||
|
|
ab2d3b70cb | ||
|
|
451df460f6 | ||
|
|
b4afa01887 | ||
|
|
2ea95f5bf9 | ||
|
|
22602f42f2 | ||
|
|
b2c5183043 | ||
|
|
9f6559c7fb | ||
|
|
ef04c16237 | ||
|
|
dd85bfd2ab | ||
|
|
7152a05bfd | ||
|
|
754c2fc9bf | ||
|
|
85ad0b881f | ||
|
|
db6c471cc6 | ||
|
|
300d990276 | ||
|
|
9c55b889cb | ||
|
|
735f76cc0b | ||
|
|
d1c27a4298 | ||
|
|
650f09bbc5 | ||
|
|
08bf16971a | ||
|
|
ccb149240e | ||
|
|
ae22719985 | ||
|
|
55c4d729bb | ||
|
|
429f0966f0 | ||
|
|
7a246b90b9 | ||
|
|
d2e7de5505 | ||
|
|
a9eab16502 | ||
|
|
d59cce8080 | ||
|
|
9390e71dd9 | ||
|
|
65992243fa | ||
|
|
c81b8b0171 | ||
|
|
0671d12628 | ||
|
|
a892c5e7b7 | ||
|
|
b5c21ffbf0 | ||
|
|
bb2b25cca5 | ||
|
|
b3867244ba | ||
|
|
6bf8d396e0 | ||
|
|
6394c1a7b4 | ||
|
|
ccd656845d | ||
|
|
2931e8454c | ||
|
|
112b158795 | ||
|
|
921001000f | ||
|
|
3e3a8e9f98 | ||
|
|
7440a039fd | ||
|
|
e73f9ab02f | ||
|
|
59815b858e | ||
|
|
7df7f59d93 | ||
|
|
e971bc1991 | ||
|
|
a3f0f12779 | ||
|
|
2a9c214593 | ||
|
|
3fc37f3e5e | ||
|
|
ebe4423e25 | ||
|
|
cfafb4a101 | ||
|
|
8d538a9977 | ||
|
|
cc2953d6a3 | ||
|
|
c888019068 | ||
|
|
56639d3965 | ||
|
|
09ff99823e | ||
|
|
5078e32dc7 | ||
|
|
ecaadff0d8 | ||
|
|
f2ad8cc7d1 | ||
|
|
c8d77eb213 | ||
|
|
fe3d9e8bf6 | ||
|
|
6c4171be75 | ||
|
|
4bbb466e43 | ||
|
|
c478415667 | ||
|
|
fc832b67c5 | ||
|
|
943a9ea97e | ||
|
|
2c7ab297d7 | ||
|
|
d8299f7db1 | ||
|
|
4deeb33f08 | ||
|
|
3bf4cf8c85 | ||
|
|
e0217fc6c3 | ||
|
|
62a3efa23a | ||
|
|
cc7ebe6d52 | ||
|
|
5d920e4b44 | ||
|
|
1264ea54a1 | ||
|
|
caa1d77d23 | ||
|
|
20a55b3342 | ||
|
|
8bfe67fc60 | ||
|
|
d42a1c6ab1 | ||
|
|
80a89ef6d1 | ||
|
|
1a0e605f0c | ||
|
|
573c8eb509 | ||
|
|
e676e3a14b | ||
|
|
af8c807ee0 | ||
|
|
dfaa5df965 | ||
|
|
32055ecdcc | ||
|
|
9db71c5f0c | ||
|
|
99856bf285 | ||
|
|
4d006b3e05 | ||
|
|
4e37165ba6 | ||
|
|
38a5834785 | ||
|
|
d6e1352869 | ||
|
|
bf1b7bd7a2 | ||
|
|
2306327057 | ||
|
|
2d389ba73f | ||
|
|
ce8d5bc635 | ||
|
|
8fdc2007e0 | ||
|
|
88a97769de | ||
|
|
589c761cb0 | ||
|
|
3e6787fd61 | ||
|
|
aff52ee3f5 | ||
|
|
4555b02592 | ||
|
|
e1d4599a93 | ||
|
|
1a1e141cb8 | ||
|
|
33218f41e8 | ||
|
|
8772cda47a | ||
|
|
512eb713e4 | ||
|
|
0f90d48c62 | ||
|
|
658860e396 | ||
|
|
7522dae557 | ||
|
|
e34e65a3ba | ||
|
|
5a001a2c32 | ||
|
|
13a03eb250 | ||
|
|
cd863b6cca | ||
|
|
83b182dda5 | ||
|
|
3b90d1a564 | ||
|
|
d724855dfc | ||
|
|
78008330fe | ||
|
|
e716aad224 | ||
|
|
aa0d7cb4e9 | ||
|
|
0cd43ce35c | ||
|
|
ac98c8e395 | ||
|
|
70a8fc09c6 | ||
|
|
5b00d05e2e | ||
|
|
28c1730a02 | ||
|
|
c54483d36f | ||
|
|
2dd02ff8cb | ||
|
|
46c5501b7a | ||
|
|
f154826749 | ||
|
|
96383ef985 | ||
|
|
ab4b19dbab | ||
|
|
cdc53ac570 | ||
|
|
143cc1912e | ||
|
|
0d90b676bc | ||
|
|
5fadbb3d25 | ||
|
|
0ec99a3e12 | ||
|
|
1efbc44cc4 | ||
|
|
735fcfeee2 | ||
|
|
4a77150566 | ||
|
|
180a420219 | ||
|
|
d12ba8f3ef | ||
|
|
f333ef76d9 | ||
|
|
af5ba6854e | ||
|
|
8b7ce06793 | ||
|
|
297a5e516f | ||
|
|
92b11526be | ||
|
|
299350f655 | ||
|
|
127eafc9b3 | ||
|
|
ad1ad3a997 | ||
|
|
82151c5b3f | ||
|
|
90457c89ff | ||
|
|
3f3ac86d38 | ||
|
|
aa126039e5 | ||
|
|
662815b1ee | ||
|
|
243c36849c | ||
|
|
52d5baaf3f | ||
|
|
89217f778e | ||
|
|
9bc9bc9169 | ||
|
|
6b73430473 | ||
|
|
5ca5bca3df | ||
|
|
89ab382a18 | ||
|
|
bad425c0d7 | ||
|
|
cdbbb1b94c | ||
|
|
0a9d8a9b22 | ||
|
|
e662041d06 | ||
|
|
155464bc87 | ||
|
|
06cd811ae4 | ||
|
|
1b2cd354db | ||
|
|
1b31268f59 | ||
|
|
b57ef7291f | ||
|
|
c3bf6aa3f8 | ||
|
|
d2fa14bbe2 | ||
|
|
9b6e55e90c | ||
|
|
afb07b651f | ||
|
|
e6806fdf2b | ||
|
|
e5ff2cff4e | ||
|
|
17d7d47b9a | ||
|
|
64e32061ab | ||
|
|
931110ba6c | ||
|
|
d90e7820cd | ||
|
|
824898dba5 | ||
|
|
761dd61ed4 | ||
|
|
89c63e6d87 | ||
|
|
a2361f9327 | ||
|
|
ea15205be8 | ||
|
|
0a45048535 | ||
|
|
1c51655ce3 | ||
|
|
7749f0da7c | ||
|
|
5695238f95 | ||
|
|
e1feeb7e21 | ||
|
|
84fecaf040 | ||
|
|
da77727673 | ||
|
|
f8c913a3e8 | ||
|
|
2024881ee1 | ||
|
|
35ed3a51e5 | ||
|
|
24b1c4d0a4 | ||
|
|
7ec2458fb5 | ||
|
|
175feaea23 | ||
|
|
dda6cf728b | ||
|
|
a7fd410b01 | ||
|
|
d281c36733 | ||
|
|
dc91e44c0a | ||
|
|
7967a858f4 | ||
|
|
2081407e38 | ||
|
|
976eabd527 | ||
|
|
b6d6a5de2b | ||
|
|
2d58cfe0ce | ||
|
|
9df8bdff5f | ||
|
|
c86b821951 | ||
|
|
4def086bf9 | ||
|
|
885c890d7d | ||
|
|
06060a6694 | ||
|
|
70667814f6 | ||
|
|
766b7a940c | ||
|
|
0c37586357 | ||
|
|
b4aa55ce1f | ||
|
|
109443ce77 | ||
|
|
5f38741831 | ||
|
|
c6f391501d | ||
|
|
d1f3105fbd | ||
|
|
8f88ca9d3d | ||
|
|
f9e4ca0cc2 | ||
|
|
5caf023677 | ||
|
|
35c2f4873c | ||
|
|
1ed7bab375 | ||
|
|
f0d1bfb777 | ||
|
|
42519ac843 | ||
|
|
8869e13385 | ||
|
|
8f9cbfe806 | ||
|
|
6481938626 | ||
|
|
9c7cc2acbf | ||
|
|
89a57d4ed3 | ||
|
|
732378592b | ||
|
|
19dc46660b | ||
|
|
4aad3471af | ||
|
|
533b455356 | ||
|
|
92bd305b00 | ||
|
|
f71eb09f74 | ||
|
|
83d4a7bc18 | ||
|
|
58807d9021 | ||
|
|
29595324c4 | ||
|
|
f9064e526f | ||
|
|
93ec2e8639 | ||
|
|
0e2a31709a | ||
|
|
c785b39eda | ||
|
|
8fab2f58da | ||
|
|
e44ee3bfe1 | ||
|
|
62065c9d28 | ||
|
|
c76275275f | ||
|
|
257f78879d | ||
|
|
894263809c | ||
|
|
bc9458101c | ||
|
|
c503935d6a | ||
|
|
d4756c9eb8 | ||
|
|
0004767775 | ||
|
|
74908642c7 | ||
|
|
aadfb71c98 | ||
|
|
1244af649d | ||
|
|
7bd48cc811 | ||
|
|
8f3ce38418 | ||
|
|
1b2d9b4245 | ||
|
|
c6b2b34fde | ||
|
|
e58fc13fdb | ||
|
|
922d53d2e4 | ||
|
|
fec53b3951 | ||
|
|
e72e2c6a02 | ||
|
|
08d001ee05 | ||
|
|
99d8a07f4a | ||
|
|
eef565134b | ||
|
|
9d78293437 | ||
|
|
fc0a556e5f | ||
|
|
b6b070584f | ||
|
|
e13225eee6 | ||
|
|
da20fb2922 | ||
|
|
459c2beb12 | ||
|
|
f1cc44dead | ||
|
|
d24cfdc382 | ||
|
|
ae4cc543f6 | ||
|
|
abdb3d17f9 | ||
|
|
4095c5da38 | ||
|
|
78fab728e4 | ||
|
|
52097a6867 | ||
|
|
cb990b55b5 | ||
|
|
5070fe303a | ||
|
|
b4405ebf3e | ||
|
|
d9e6bf5068 | ||
|
|
6822188f52 | ||
|
|
15858d03ff | ||
|
|
814a733258 | ||
|
|
3ce85d8ca9 | ||
|
|
d3bff2f39d | ||
|
|
f2272730ac | ||
|
|
fe19c97d86 | ||
|
|
d49556bf3d | ||
|
|
56b447493e | ||
|
|
e45b68eda7 | ||
|
|
8df1ef5986 | ||
|
|
dac34cda82 | ||
|
|
9925e30c8b | ||
|
|
dc5566b5ae | ||
|
|
8132ee651a | ||
|
|
f49a134a3d | ||
|
|
bd955cda06 | ||
|
|
c6dbc01912 | ||
|
|
fabe1aa940 | ||
|
|
ba5dbb94b8 | ||
|
|
6ccc053d7e | ||
|
|
cf21dfaa3a | ||
|
|
54ceb630de | ||
|
|
0a0c302cb2 | ||
|
|
f6eef54566 | ||
|
|
a69804f84d | ||
|
|
0b06b194b0 | ||
|
|
73f6ce304c | ||
|
|
195818a432 | ||
|
|
47c817de1c | ||
|
|
8b3894f213 | ||
|
|
a411252f07 | ||
|
|
d7626aeb3f | ||
|
|
3565098650 | ||
|
|
803fcf146b | ||
|
|
d9d646c5fb | ||
|
|
034a274b07 | ||
|
|
718d7af8bc | ||
|
|
860d3d9c8b | ||
|
|
f28b566992 | ||
|
|
1c261c7463 | ||
|
|
226b2482b1 | ||
|
|
ff346dc429 | ||
|
|
2dcef25175 | ||
|
|
46702bbb5c | ||
|
|
5600c9bc69 | ||
|
|
d7e46b1693 | ||
|
|
fe8c60ade1 | ||
|
|
288892441f | ||
|
|
e1179a8e22 | ||
|
|
4b06d0fd87 | ||
|
|
464d91f45a | ||
|
|
5cc7aa25cc | ||
|
|
20ec224070 | ||
|
|
9cbcc29ddb | ||
|
|
0badbfc4a0 | ||
|
|
e042148c62 | ||
|
|
d8ba04ae7f | ||
|
|
314d5fdad2 | ||
|
|
5c874cafd1 | ||
|
|
8cafc14d09 | ||
|
|
25ac5033fc | ||
|
|
848be0db6c | ||
|
|
0f9da0731e | ||
|
|
8bc2364cce | ||
|
|
b64916ce3f | ||
|
|
452955667c | ||
|
|
f38bbf4cc7 | ||
|
|
25eaa11a52 | ||
|
|
4b4da8d467 | ||
|
|
13116c5381 | ||
|
|
d2cd406a62 | ||
|
|
acbce05fbf | ||
|
|
bee4d3a338 | ||
|
|
b9003a2f02 | ||
|
|
bce226002b | ||
|
|
a417db7c7a | ||
|
|
0ffef12a8b | ||
|
|
4539b040e0 | ||
|
|
f85014a86d | ||
|
|
d90d07c68b | ||
|
|
ce292b84fa | ||
|
|
01690860db | ||
|
|
89fb2d4915 | ||
|
|
5cc3a42832 | ||
|
|
6b303410d1 | ||
|
|
60b0145e04 | ||
|
|
8cae2f24b1 | ||
|
|
ce48823d38 | ||
|
|
0a04d753ea | ||
|
|
d43fee5585 | ||
|
|
35402c7bd3 | ||
|
|
5dc9e51dd4 | ||
|
|
847a97f61c | ||
|
|
235fcccbd7 | ||
|
|
fac27a6120 | ||
|
|
91c971b8fd | ||
|
|
2e24eda00d | ||
|
|
e43003cadc | ||
|
|
7a653abf22 | ||
|
|
9a96165655 | ||
|
|
ae09229107 | ||
|
|
994aef411c | ||
|
|
be35f48bdd | ||
|
|
094a180935 | ||
|
|
846173844e | ||
|
|
74e9de6370 | ||
|
|
59c28d8e51 | ||
|
|
c7f31b3d79 | ||
|
|
abdfa3ccf6 | ||
|
|
98d0239d03 | ||
|
|
99ad6634c4 | ||
|
|
ffeab147ce | ||
|
|
84556fb055 | ||
|
|
90bdbd6b84 | ||
|
|
26e14e0151 | ||
|
|
e29dd3cd33 | ||
|
|
3df2daa5cb | ||
|
|
23b95178ff | ||
|
|
c55efddc81 | ||
|
|
9bde80357f | ||
|
|
a59c8908f0 | ||
|
|
1485733715 | ||
|
|
a421c5f952 | ||
|
|
d125a7f09d | ||
|
|
37b0612d45 | ||
|
|
77486dffd4 | ||
|
|
07bc94f9f6 | ||
|
|
c84bcb433f | ||
|
|
82511880ac | ||
|
|
f1e5221257 | ||
|
|
2f5cc6a8a4 | ||
|
|
b8bf01acc3 | ||
|
|
f9a0f5e7a1 | ||
|
|
65aa7bd1de | ||
|
|
47b083eaca | ||
|
|
6f511444a7 | ||
|
|
8fcf5ee760 | ||
|
|
ef5174d89f | ||
|
|
f2006206d3 | ||
|
|
e2a97e75d8 | ||
|
|
c32361a428 | ||
|
|
9fc6e265eb | ||
|
|
ac83c2bc3c | ||
|
|
f81c42b1fd | ||
|
|
32808c16e7 | ||
|
|
8594e146eb | ||
|
|
e4e2433396 | ||
|
|
cda0dfdafe | ||
|
|
8196b6e69e | ||
|
|
363568b02c | ||
|
|
8dd49b6156 | ||
|
|
443ab02788 | ||
|
|
c4ab83a801 | ||
|
|
65784d6dc4 | ||
|
|
2c51b7b835 | ||
|
|
da805d037f | ||
|
|
bab49d04b7 | ||
|
|
d383776245 | ||
|
|
6963d66240 | ||
|
|
51eba8da73 | ||
|
|
8cbf3ffc6b | ||
|
|
14b4d64244 | ||
|
|
2a4693f6ed | ||
|
|
7cb7f68cda | ||
|
|
217256746c | ||
|
|
83300d028b | ||
|
|
6c90225024 | ||
|
|
e891ce39c0 | ||
|
|
92d8a894e3 | ||
|
|
e58b7782ac | ||
|
|
c89d619808 | ||
|
|
1ddb468a08 | ||
|
|
31dd4f6305 | ||
|
|
95e3f0e0d9 | ||
|
|
ff9715ede7 | ||
|
|
0edf017ddc | ||
|
|
ffd1e383c2 | ||
|
|
ad601fd1ee | ||
|
|
2cc4f8c2fe | ||
|
|
e7eaccb5e0 | ||
|
|
6f513eb359 | ||
|
|
6b201da3ff | ||
|
|
b235a5bb49 | ||
|
|
a85a47bc20 | ||
|
|
25f1912573 | ||
|
|
69b8f51319 | ||
|
|
d24d6f6b52 | ||
|
|
0d943ba805 | ||
|
|
afdb156c84 | ||
|
|
56fe3b5892 | ||
|
|
643d3600b8 | ||
|
|
c177f12e1d | ||
|
|
9c51bff55b | ||
|
|
72f9564757 | ||
|
|
81c91b3877 | ||
|
|
ab1a80152d | ||
|
|
3d365eb258 | ||
|
|
a87c677a35 | ||
|
|
6857f6d8f8 | ||
|
|
9e0ed57cec | ||
|
|
81bd9991bb | ||
|
|
767f4797b0 | ||
|
|
056fa9ded2 | ||
|
|
8f8c9c4582 | ||
|
|
a3792c474b | ||
|
|
9acfe3afdb | ||
|
|
ec233dbb46 | ||
|
|
9c03962c26 | ||
|
|
d89cd789ac | ||
|
|
a135460caa | ||
|
|
69088e162d | ||
|
|
7f72ef88e0 | ||
|
|
ec53bd4125 | ||
|
|
fa1adc5294 | ||
|
|
35a264d21c | ||
|
|
579b526196 | ||
|
|
0372c2eccc | ||
|
|
654e6942cb | ||
|
|
08c7ffc6d9 | ||
|
|
b7ed1429de | ||
|
|
e386f6ac20 | ||
|
|
6642c23761 | ||
|
|
60ab893888 | ||
|
|
f2b908c859 | ||
|
|
f2d960c3eb | ||
|
|
709840ca02 | ||
|
|
fb88aeaeb9 | ||
|
|
9fe596f3de | ||
|
|
94561de719 | ||
|
|
228bb2fc86 | ||
|
|
89ed18cea3 | ||
|
|
d07947f712 | ||
|
|
b996fa234b | ||
|
|
70022088fb | ||
|
|
f6cd5cb4b2 | ||
|
|
9143564d41 | ||
|
|
6ac8caaf5f | ||
|
|
55440ae32b | ||
|
|
e5a4145e37 | ||
|
|
db65c0b422 | ||
|
|
2c8b408bfb | ||
|
|
f0297938b6 | ||
|
|
58c5c04feb | ||
|
|
4d390b65fe | ||
|
|
b0d6070d28 | ||
|
|
294df359d5 | ||
|
|
3728594f73 | ||
|
|
a855d53542 | ||
|
|
dc2f1eabb2 | ||
|
|
57a0c48293 | ||
|
|
eda08e7454 | ||
|
|
bbc82d827e | ||
|
|
1bf4b6daa9 | ||
|
|
742b49e302 | ||
|
|
f757266282 | ||
|
|
8716f14941 | ||
|
|
0321823125 | ||
|
|
8b7b41de47 | ||
|
|
33d190afaa | ||
|
|
36fd4dbcf4 | ||
|
|
ff16c4f127 | ||
|
|
291a8c2bfb | ||
|
|
134728438e | ||
|
|
a1db394d93 | ||
|
|
754bd68a87 | ||
|
|
0933d96954 | ||
|
|
bd32eeeaa2 | ||
|
|
c4fcb6c88c | ||
|
|
1b9a3bd4bd | ||
|
|
2390b20e68 | ||
|
|
584d369b0b | ||
|
|
a6fd0434de | ||
|
|
0ebe052752 | ||
|
|
53b36472a0 | ||
|
|
535863bc52 | ||
|
|
ccefea6b59 | ||
|
|
dd925cd92b | ||
|
|
b24c63cb49 | ||
|
|
5529de3d95 | ||
|
|
38f69fd7cc | ||
|
|
ce6b65adb8 | ||
|
|
6a9ea3bc0f | ||
|
|
9897109332 | ||
|
|
d1b4e93f9e | ||
|
|
cfc851a99b | ||
|
|
9a6a61151d | ||
|
|
380178ccc8 | ||
|
|
497d0f0c74 | ||
|
|
3227ddd9f9 | ||
|
|
ecf1c90c22 | ||
|
|
336be63237 | ||
|
|
1aa13c1c8c | ||
|
|
37c9b9e1f5 | ||
|
|
251ad23a9e | ||
|
|
ebb3e02dcc | ||
|
|
22876e5a25 | ||
|
|
352505c54f | ||
|
|
12162e2aae | ||
|
|
0c7998712e | ||
|
|
2af09fb49d | ||
|
|
b9a20e7ac5 | ||
|
|
c58589026c | ||
|
|
7ab89b900c | ||
|
|
5b83919eb2 | ||
|
|
9620956727 | ||
|
|
f26f02c986 | ||
|
|
9b85768b7e | ||
|
|
c5d16a49d0 | ||
|
|
5276e1863d | ||
|
|
260b2c3532 | ||
|
|
0fc1a30a2c | ||
|
|
420da8f476 | ||
|
|
8609b98b1c | ||
|
|
c2a39d3296 | ||
|
|
c85514a17a | ||
|
|
6cd4bf337e | ||
|
|
d00bef5546 | ||
|
|
095c48a942 | ||
|
|
b905f46f98 | ||
|
|
e61ef1ae85 | ||
|
|
cdd4765d38 | ||
|
|
886b21af68 | ||
|
|
d62793f4ad | ||
|
|
7bba66737f | ||
|
|
d83d325a49 | ||
|
|
52fd2772cf | ||
|
|
e5baf99814 | ||
|
|
48043b5ec4 | ||
|
|
b4aeab3501 | ||
|
|
1f67ae82bd | ||
|
|
039bfd372d | ||
|
|
e7749c161d | ||
|
|
1a92de71d1 | ||
|
|
144f913aa9 | ||
|
|
d8279e11aa | ||
|
|
e28b6b9f73 | ||
|
|
b1b8584641 | ||
|
|
691636de7b | ||
|
|
11e75df1a9 | ||
|
|
6f2b1b8f06 | ||
|
|
25fc2bfbea | ||
|
|
139640e768 | ||
|
|
a93c84ff64 | ||
|
|
ae2fa19c0e | ||
|
|
986a4182d9 | ||
|
|
f8867abe49 | ||
|
|
d38a8b109b | ||
|
|
fd83e72177 | ||
|
|
711d8c8c6b | ||
|
|
1ff45c8e02 | ||
|
|
0d1d22aeff | ||
|
|
608c338403 | ||
|
|
ac2231f0f3 | ||
|
|
f23da0dd5a | ||
|
|
21344dacfc | ||
|
|
8c3f887cac | ||
|
|
ca22ba5bbc | ||
|
|
6e6f16d6ee | ||
|
|
fc64c34214 | ||
|
|
8a83385c7f | ||
|
|
c35bc2476d | ||
|
|
147bc797a2 | ||
|
|
222826af95 | ||
|
|
1735f36b82 | ||
|
|
db28db0bc7 | ||
|
|
a782354874 | ||
|
|
931f7d47ea | ||
|
|
21a709cf89 | ||
|
|
987ed1cefc | ||
|
|
76a0c1d96e | ||
|
|
3e9a77abfa | ||
|
|
1c30e555dc | ||
|
|
3879eb6b3a | ||
|
|
9bdff89833 | ||
|
|
5e5a2040fc | ||
|
|
08105eee48 | ||
|
|
eea44d7de2 | ||
|
|
40e13184ca | ||
|
|
3fcbf075fb | ||
|
|
b5a65c5e43 | ||
|
|
b2641494cc | ||
|
|
7eac65fec2 | ||
|
|
c48a794aee | ||
|
|
9bc974661c | ||
|
|
e53906aea8 | ||
|
|
b8c41a91e1 | ||
|
|
05a4a1670f | ||
|
|
3264becdc2 | ||
|
|
4bd35852a5 | ||
|
|
845bf6ada1 | ||
|
|
be4d56f8d2 | ||
|
|
865ef2beb3 | ||
|
|
dfbcd616f2 | ||
|
|
ace5353595 | ||
|
|
dc0106348d | ||
|
|
56a43fe17b | ||
|
|
f2666d4a30 | ||
|
|
46f36dc7ab | ||
|
|
4220e58d26 | ||
|
|
db0ac70b71 | ||
|
|
07de43981a | ||
|
|
6cfcc903df | ||
|
|
fa352c1a8f | ||
|
|
2ccae9f434 | ||
|
|
e5d582b30b | ||
|
|
139bf0ee35 | ||
|
|
8fb14ffdf3 | ||
|
|
1ce6e37e78 | ||
|
|
c16e85e7db | ||
|
|
462026e7e9 | ||
|
|
25a72e3508 | ||
|
|
2f180510b8 | ||
|
|
20411da67b | ||
|
|
53e67dfb27 | ||
|
|
81bfdc69dd | ||
|
|
ff951130b6 | ||
|
|
5e2829fe49 | ||
|
|
69ebb53a05 | ||
|
|
2aba09f090 | ||
|
|
1a2a3d1945 | ||
|
|
38e27309fb | ||
|
|
c8b967ba37 | ||
|
|
6b586684e6 | ||
|
|
83b713a781 | ||
|
|
773e280339 | ||
|
|
c930568df7 | ||
|
|
297a67cd00 | ||
|
|
95e2c6179f | ||
|
|
ceb61ebe74 | ||
|
|
dfdf690575 | ||
|
|
6c85e3502e | ||
|
|
db30517516 | ||
|
|
690192300f | ||
|
|
534b2e59a0 | ||
|
|
3ba963f474 | ||
|
|
5028216058 | ||
|
|
9b2cacc3a0 | ||
|
|
173947fd7d | ||
|
|
315a616293 | ||
|
|
9aa6ad216d | ||
|
|
3c56cd6738 | ||
|
|
b2a5963f5a | ||
|
|
a48ac013e8 | ||
|
|
c80fdee99b | ||
|
|
258602ce1a | ||
|
|
270db7829d | ||
|
|
c85b547502 | ||
|
|
5ff9ec9942 | ||
|
|
d6266c36bf | ||
|
|
2fc554e1d4 | ||
|
|
fdd7f30e9a | ||
|
|
7a35c1638b | ||
|
|
3994ef3619 | ||
|
|
916243468f | ||
|
|
633028a63f | ||
|
|
cb56bbc122 | ||
|
|
013374e9db | ||
|
|
d1b2d5cb27 | ||
|
|
4358b47e91 | ||
|
|
884b56a4ef | ||
|
|
6decc1ce30 | ||
|
|
eeb8d9cdf5 | ||
|
|
8a3dba3064 | ||
|
|
e8d7bbd280 | ||
|
|
27bcead1bc | ||
|
|
277ee4c4b2 | ||
|
|
acb9c01776 | ||
|
|
efa6c8135d | ||
|
|
79fd23d51b | ||
|
|
cbb705c367 | ||
|
|
776614d211 | ||
|
|
44326cd8c1 | ||
|
|
b03a498cd7 | ||
|
|
4592ab4bf5 | ||
|
|
b612926fb6 | ||
|
|
870849f01a | ||
|
|
b67377f505 | ||
|
|
a00bcc3df2 | ||
|
|
2033acbe2a | ||
|
|
122dc5baf4 | ||
|
|
e435cfc489 | ||
|
|
a276d2da4f | ||
|
|
a3199a52af | ||
|
|
6f04d4d43b | ||
|
|
99be870ab9 | ||
|
|
a966f263a2 | ||
|
|
9b2ecb4701 | ||
|
|
ac5a23ef29 | ||
|
|
be7443a0a0 | ||
|
|
b82804018d | ||
|
|
0de6557872 | ||
|
|
35b0b684df | ||
|
|
258e890056 | ||
|
|
a627ca2127 | ||
|
|
d84bbad79a | ||
|
|
05a1096e25 | ||
|
|
07e6477686 | ||
|
|
9600e56344 | ||
|
|
acde161412 | ||
|
|
1bb0871948 | ||
|
|
8d8f9c6d26 | ||
|
|
6ff50689e1 | ||
|
|
c7507d9743 | ||
|
|
9b025ddece | ||
|
|
ff970fde56 | ||
|
|
12fd77f0b2 | ||
|
|
2c4a997c64 | ||
|
|
0e60883b3d | ||
|
|
5c787e0b69 | ||
|
|
33b6bfe5be | ||
|
|
41da8435cc | ||
|
|
8167146372 | ||
|
|
84ecc4c664 | ||
|
|
21bbedaf04 | ||
|
|
d18a36af22 | ||
|
|
998aedde33 | ||
|
|
b3e766aa50 | ||
|
|
25050da2c9 | ||
|
|
0cee54c51b | ||
|
|
a74cf8ec4d | ||
|
|
41e436a183 | ||
|
|
e06f0a5d49 | ||
|
|
743fc19fa3 | ||
|
|
9d1ea4b551 | ||
|
|
76e8c66b1b | ||
|
|
e0410783be | ||
|
|
4379ea63f0 | ||
|
|
d064337c15 | ||
|
|
00ae54b4b2 | ||
|
|
6379bfb8b8 | ||
|
|
3a7fd7d271 | ||
|
|
220539e51a | ||
|
|
94a0c98bfe | ||
|
|
95cd215e9e | ||
|
|
c2b2b2698d | ||
|
|
88c04714f8 | ||
|
|
9bb630bae6 | ||
|
|
6d47e32cac | ||
|
|
c47b2f5b18 | ||
|
|
fc34b40c0a | ||
|
|
ecdc9a968d | ||
|
|
d95fa8a893 | ||
|
|
c041ff66e2 | ||
|
|
b48f83ff49 | ||
|
|
fe0e2d5c2d | ||
|
|
c189b258b4 | ||
|
|
2cf3bca8de | ||
|
|
06fc5e71c3 | ||
|
|
b2a817e17b | ||
|
|
8093927579 | ||
|
|
d1ca951ffa | ||
|
|
d9eed4a460 | ||
|
|
b3932ae8c5 | ||
|
|
9d609b6085 | ||
|
|
35223d5737 | ||
|
|
ef97f9c088 | ||
|
|
9d263f11e5 | ||
|
|
bb8aa0fe6f | ||
|
|
3f28b30e95 | ||
|
|
be441d2aa5 | ||
|
|
d797abdb1f | ||
|
|
73e089d330 | ||
|
|
3b3a940ee4 | ||
|
|
0a24fb57aa | ||
|
|
1b5b61b25e | ||
|
|
7f2c51f337 | ||
|
|
00d29b88df | ||
|
|
537e490f0f | ||
|
|
ab9bc9da74 | ||
|
|
4340368e49 | ||
|
|
b79f7b7ab8 | ||
|
|
a85fb3a871 | ||
|
|
9b34b5ca89 | ||
|
|
05a49ff5db | ||
|
|
b486788993 | ||
|
|
0bec242b2e | ||
|
|
563e9c51e1 | ||
|
|
831624897b | ||
|
|
6ab5e3ed4f | ||
|
|
ca8a0e9a88 | ||
|
|
43a6c81151 | ||
|
|
865ff7911a | ||
|
|
887a5d50a4 | ||
|
|
eefc6a5567 | ||
|
|
be68f8c3f7 | ||
|
|
bf3bc83fd8 | ||
|
|
86a4923157 | ||
|
|
03b06eee67 | ||
|
|
f80ff31412 | ||
|
|
3bc17e7b83 | ||
|
|
94acc82bf5 | ||
|
|
458297bf56 | ||
|
|
3c1a1fcca1 | ||
|
|
9673b2aa7c | ||
|
|
b3d08e4cb8 | ||
|
|
a55710df7b | ||
|
|
ab766ce85b | ||
|
|
73edd3bc40 | ||
|
|
bcb8245c61 | ||
|
|
f2ee243628 | ||
|
|
c9e60d5c3a | ||
|
|
88b1e668ee | ||
|
|
eb7c74eea7 | ||
|
|
1c92a47d75 | ||
|
|
40f5911ceb | ||
|
|
d2a9f0583a | ||
|
|
2a8809adbb | ||
|
|
2621d2e1dc | ||
|
|
39524c4064 | ||
|
|
1ce683a95a | ||
|
|
c1cc2d6350 | ||
|
|
3d5f725004 | ||
|
|
acb857f433 | ||
|
|
655bc4bee3 | ||
|
|
d343d92b17 | ||
|
|
c67d372667 | ||
|
|
43cb4716a9 | ||
|
|
54e45dac51 | ||
|
|
6222561431 | ||
|
|
5b0b594761 | ||
|
|
07b10e9e23 | ||
|
|
cdf6e3b456 | ||
|
|
dffe8cef7a | ||
|
|
cf46afea94 | ||
|
|
bb26626fd5 | ||
|
|
ea6cca588c | ||
|
|
2f207de1a0 | ||
|
|
1f9996fe62 | ||
|
|
a69419ed04 | ||
|
|
e0be6c746c | ||
|
|
be7c1ba914 | ||
|
|
2b62bf0337 | ||
|
|
461f6ad2c1 | ||
|
|
845825c0bf | ||
|
|
aff85cbfb8 | ||
|
|
f9b09e5b61 | ||
|
|
c0ce4523fa | ||
|
|
1403aa18eb | ||
|
|
65f8b3978d | ||
|
|
ba2fff249d | ||
|
|
80ca3e114e | ||
|
|
17447d3cdc | ||
|
|
330e803675 | ||
|
|
3f4c1e7029 | ||
|
|
337e9ac3ef | ||
|
|
543bbf34c2 | ||
|
|
dfb78788f9 | ||
|
|
5394151e42 | ||
|
|
2dc560f583 | ||
|
|
9349e9cd99 | ||
|
|
7355400548 | ||
|
|
594aa03c5a | ||
|
|
50b4630436 | ||
|
|
ff1328dbdd | ||
|
|
132d43f999 | ||
|
|
9ba44e32fb | ||
|
|
0627f20f5e | ||
|
|
245becdc8c | ||
|
|
40f329512b | ||
|
|
56f77e88a8 | ||
|
|
c196c08ada | ||
|
|
695e35634c | ||
|
|
8f1e0d57bf | ||
|
|
1f408dd7a7 | ||
|
|
c30c455a9f | ||
|
|
303a3ac376 | ||
|
|
cd0e8e1c6b | ||
|
|
221537601f | ||
|
|
cbeb91f9a9 | ||
|
|
f08919a829 | ||
|
|
a3830989ba | ||
|
|
cfb1f8c767 | ||
|
|
86427e2042 | ||
|
|
39d3e447ab | ||
|
|
8f079de0aa | ||
|
|
bb76242632 | ||
|
|
651727c697 | ||
|
|
6bfb709233 | ||
|
|
5c55f4d4bb | ||
|
|
ab9ec7145d | ||
|
|
c8502d3b7b | ||
|
|
6ec931fcd7 | ||
|
|
22e3b9b544 | ||
|
|
ae76a7f7d4 | ||
|
|
f16db8298b | ||
|
|
2f20bf1bee | ||
|
|
cf4a32b260 | ||
|
|
f9d01d2fad | ||
|
|
b8d83c37d9 | ||
|
|
1eb1329f68 | ||
|
|
617f6bb8ef | ||
|
|
51a3e60913 | ||
|
|
0c9f2bf5d2 | ||
|
|
30c88a2fe7 | ||
|
|
eb9afecd66 | ||
|
|
4ffd336c72 | ||
|
|
2c1f2ae589 | ||
|
|
7cbc047b41 | ||
|
|
9387b09a19 | ||
|
|
adf4222b24 | ||
|
|
f17f04f00a | ||
|
|
c095118e98 | ||
|
|
07f0192088 | ||
|
|
11d7d25037 | ||
|
|
0fd19f0de8 | ||
|
|
c45ff40250 | ||
|
|
e954fa6478 | ||
|
|
2f8c2b05bd | ||
|
|
a0fdfc0f39 | ||
|
|
a4c17bb308 | ||
|
|
57a4372b65 | ||
|
|
75eff7f083 | ||
|
|
c11cb38269 | ||
|
|
a5b9a707a4 | ||
|
|
e4fd446946 | ||
|
|
1b013db312 | ||
|
|
714d8ac3ba | ||
|
|
158250e98d | ||
|
|
f09293e077 | ||
|
|
f9f4be181d | ||
|
|
389e8bc325 | ||
|
|
3bea99c000 | ||
|
|
367f763ce5 | ||
|
|
05e52ca236 | ||
|
|
3febed82f1 | ||
|
|
f268a48a16 | ||
|
|
8a6371fe68 | ||
|
|
96bb9a2f8e | ||
|
|
93937feb13 | ||
|
|
f9b977d266 | ||
|
|
21e62d8597 | ||
|
|
7fca2a9cc6 | ||
|
|
88e8019858 | ||
|
|
e473ef36b1 | ||
|
|
cbe562a204 | ||
|
|
3b5b832bbc | ||
|
|
4dc40389a3 | ||
|
|
4cfb451755 | ||
|
|
0552f10c38 | ||
|
|
368d1ad354 | ||
|
|
c9ac7401e8 | ||
|
|
9a8f7ccba8 | ||
|
|
60625b9978 | ||
|
|
032c8e9fac | ||
|
|
b4b53cfa4c | ||
|
|
20d1abd2e1 | ||
|
|
f1e1d67f4e | ||
|
|
73903cbd1f | ||
|
|
982641752f | ||
|
|
bff22a4e4e | ||
|
|
ba66cbbc95 | ||
|
|
daaaed4118 | ||
|
|
750d13a300 | ||
|
|
c2c9db66e2 | ||
|
|
3c69a87fc2 | ||
|
|
09308083a9 | ||
|
|
dbaddab07b | ||
|
|
cf492355b4 | ||
|
|
1d58811680 | ||
|
|
1cd1b1cb08 | ||
|
|
4d78fe9ca4 | ||
|
|
56d3082696 | ||
|
|
8f573aba2f | ||
|
|
96633360d0 | ||
|
|
8ae7935cee | ||
|
|
68e860baad | ||
|
|
38ead3133f | ||
|
|
553d1f85c4 | ||
|
|
ca44e3062e | ||
|
|
d9a985ff38 | ||
|
|
3d919f1836 | ||
|
|
d3a2d2b248 | ||
|
|
f4fa2150b5 | ||
|
|
575b8e5f62 | ||
|
|
37ff924c74 | ||
|
|
7ccbc4c77c | ||
|
|
27b7a60a8d | ||
|
|
dca731ffb8 | ||
|
|
0d56de99a7 | ||
|
|
ac5e11d327 | ||
|
|
9d315b0ff9 | ||
|
|
038fe84498 | ||
|
|
4fd59f2a19 | ||
|
|
f77c3bfdf7 | ||
|
|
dc7d941316 | ||
|
|
433cc1e32c | ||
|
|
c066a03683 | ||
|
|
562a8036bc | ||
|
|
53ac703f09 | ||
|
|
a2891d97d0 | ||
|
|
2bd5169f20 | ||
|
|
b3fd6d8c92 | ||
|
|
cea281b1d3 | ||
|
|
e85b2a8961 | ||
|
|
77b879d6bb | ||
|
|
9de3ae5cf2 | ||
|
|
b3a0dc3506 | ||
|
|
383731da4d | ||
|
|
67abb42652 | ||
|
|
edcc24bc12 | ||
|
|
a6836cab15 | ||
|
|
8f985737b0 | ||
|
|
6e2f102177 | ||
|
|
46a768339a | ||
|
|
f1dbbd62e9 | ||
|
|
8bb94889e0 | ||
|
|
da38e4e00c | ||
|
|
d8e8156b1c | ||
|
|
77a1b18673 | ||
|
|
9abd51f318 | ||
|
|
c7d51a29ac | ||
|
|
ac453ef32a | ||
|
|
db25493c04 | ||
|
|
8d4b4d3cd9 | ||
|
|
b05f13d82b | ||
|
|
438622d450 | ||
|
|
4f79efedc9 | ||
|
|
845fa89d0f | ||
|
|
29768576c8 | ||
|
|
4e659d799d | ||
|
|
10596bcb54 | ||
|
|
5ac6f4f7b3 | ||
|
|
957bb46e5c | ||
|
|
1042a537c1 | ||
|
|
2159b4b691 | ||
|
|
ce48e07e18 | ||
|
|
48dded02c6 | ||
|
|
b7d77042bf | ||
|
|
b4ea2569e3 | ||
|
|
42a9f864eb | ||
|
|
22e6de19c4 | ||
|
|
572a65d661 | ||
|
|
108ecb7e12 | ||
|
|
9c87d61528 | ||
|
|
dd903dd7e5 | ||
|
|
ae13cb2513 | ||
|
|
40f47ccd4e | ||
|
|
c344cd2a2b | ||
|
|
7601af24f0 | ||
|
|
0197eb0d08 | ||
|
|
a248967ae8 | ||
|
|
a4beb58b54 | ||
|
|
922cc942a4 | ||
|
|
f11b086381 | ||
|
|
e5eab69f65 | ||
|
|
961884ef12 | ||
|
|
5dbbf643a4 | ||
|
|
f937458c25 | ||
|
|
c617e62a16 | ||
|
|
343c886d54 | ||
|
|
824d85b2a0 | ||
|
|
0289fc5ce2 | ||
|
|
914a886bfe | ||
|
|
f65c30e975 | ||
|
|
48ac0049aa | ||
|
|
fea1117eae | ||
|
|
ace1a060db | ||
|
|
be6ad9c5e3 | ||
|
|
b2d51a2a9b | ||
|
|
74411d8656 | ||
|
|
332392b7ba | ||
|
|
e441414854 | ||
|
|
4b1d79e7f7 | ||
|
|
d7889e27e5 | ||
|
|
e65a68ce78 | ||
|
|
990f6d3730 | ||
|
|
84a62b3707 | ||
|
|
e18789b8d3 | ||
|
|
cb7be0e460 | ||
|
|
df825d0109 | ||
|
|
ce4baecb4b | ||
|
|
48907517e9 | ||
|
|
dde1d96058 | ||
|
|
b2f688a032 | ||
|
|
b4664f85f0 | ||
|
|
2725d32c33 | ||
|
|
c9f80db3c6 | ||
|
|
cb53ddf8a8 | ||
|
|
fdca41a71b | ||
|
|
d59ceee0f7 | ||
|
|
38b08835c2 | ||
|
|
dbbdb1bcbe | ||
|
|
b408e5d0d3 | ||
|
|
30f00508f5 | ||
|
|
75bb6aa966 | ||
|
|
eff206fb2b | ||
|
|
98da419c96 | ||
|
|
efe226045d | ||
|
|
35ba1532f4 | ||
|
|
476d732a3c | ||
|
|
21efc0c4a5 | ||
|
|
c20c6665fd | ||
|
|
cd497bfe9b | ||
|
|
25c42bee6d | ||
|
|
6d639385da | ||
|
|
fd1c0efedf | ||
|
|
5d2010aa73 | ||
|
|
d9333b2e93 | ||
|
|
3034306fcc | ||
|
|
0c7bae6fd7 | ||
|
|
855233f498 | ||
|
|
6b859a0478 | ||
|
|
2f37b658f1 | ||
|
|
3bd952e5c5 | ||
|
|
ae58c1fa99 | ||
|
|
dfb411cb6a | ||
|
|
449e3f5cc6 | ||
|
|
1b1fe17fca | ||
|
|
f3c457745e | ||
|
|
26f2e2b223 | ||
|
|
fcdd399eea | ||
|
|
c1d16782ab | ||
|
|
860434a1d5 | ||
|
|
38b493ee9d | ||
|
|
19dc560d56 | ||
|
|
bb10214db0 | ||
|
|
6a871c51a1 | ||
|
|
d7ff3050c2 | ||
|
|
8e0a0379d5 | ||
|
|
b7ceb90e61 | ||
|
|
c1935c83f6 | ||
|
|
62f08a2105 | ||
|
|
38d7f6e671 | ||
|
|
3c2c99c236 | ||
|
|
7694402ae4 | ||
|
|
7ed1d13221 | ||
|
|
47e89e35b2 | ||
|
|
3633759295 | ||
|
|
98bdb0479b | ||
|
|
1e40df227d | ||
|
|
caf0a709b8 | ||
|
|
daef951e59 | ||
|
|
73eab87dd9 | ||
|
|
1a2720649b | ||
|
|
1083cdb743 | ||
|
|
06eb8f9c10 | ||
|
|
31af15d267 | ||
|
|
12938df375 | ||
|
|
24d8dbcf64 | ||
|
|
2b7585357f | ||
|
|
5b659966c8 | ||
|
|
2834d6cac7 | ||
|
|
65dd4c873f | ||
|
|
8c834e634b | ||
|
|
f92430d092 | ||
|
|
b110e944c3 | ||
|
|
77eb5b5147 | ||
|
|
1fabdb9e2d | ||
|
|
e8682ac058 | ||
|
|
08603ad905 | ||
|
|
224b867737 | ||
|
|
0eb4ac5bcc | ||
|
|
876ca5927d | ||
|
|
98b4509014 | ||
|
|
c0013a0ba5 | ||
|
|
cc915e39c5 | ||
|
|
b569ad4ef5 | ||
|
|
6ab5388075 | ||
|
|
ded3079390 | ||
|
|
44fe358766 | ||
|
|
cee4b089c6 | ||
|
|
ba8bd4f95c | ||
|
|
c602072e5b | ||
|
|
76061c84aa | ||
|
|
cd01d3e923 | ||
|
|
ff23e7aba7 | ||
|
|
e61fb6f206 | ||
|
|
a6cab8fddc | ||
|
|
ec16d9abfc | ||
|
|
b5c67a47d1 | ||
|
|
a4c1e3b0bc | ||
|
|
b160d58d1b | ||
|
|
b6a4dfb424 | ||
|
|
5837718cf4 | ||
|
|
962e579434 | ||
|
|
63a249ecb0 | ||
|
|
3f40ca65f5 | ||
|
|
57668fc618 | ||
|
|
e82d14c973 | ||
|
|
8e9aa23c3c | ||
|
|
4687c7dcda | ||
|
|
5d857c731f | ||
|
|
eaec1205a1 | ||
|
|
e3d03c3d78 | ||
|
|
927fb013ff | ||
|
|
4deb14ccfb | ||
|
|
e04dba610b | ||
|
|
99a5dfee31 | ||
|
|
66842fca8e | ||
|
|
a47280f47b | ||
|
|
2808ca139c | ||
|
|
d87467aa88 | ||
|
|
382aad5119 | ||
|
|
93f94b65f1 | ||
|
|
bc66d4b0e7 | ||
|
|
ff044c831f | ||
|
|
cb85292f99 | ||
|
|
7c7722e8fc | ||
|
|
78cc6764bf | ||
|
|
0b540d6406 | ||
|
|
f1e0b7a94f | ||
|
|
611635a9a2 | ||
|
|
26c30b013b | ||
|
|
899f5231b5 | ||
|
|
0cfeee18c9 | ||
|
|
3e44835687 | ||
|
|
d5ac67071f | ||
|
|
6aee9ce92e | ||
|
|
6a268bfb68 | ||
|
|
63848e815f | ||
|
|
6640df18ac | ||
|
|
b9436c0cab | ||
|
|
c730f7931f | ||
|
|
ef6035b5be | ||
|
|
8502c0f048 | ||
|
|
acc4d5201a | ||
|
|
8248f31b20 | ||
|
|
39c1624d42 | ||
|
|
7eb82f2e84 | ||
|
|
df0d0d820a | ||
|
|
e0c0d8bc04 | ||
|
|
97619d8ba1 | ||
|
|
80df96fd0d | ||
|
|
579e76430d | ||
|
|
36dd7269e2 | ||
|
|
6596cb014f | ||
|
|
62ac63fd77 | ||
|
|
e6e8d96f12 | ||
|
|
f80464ea31 | ||
|
|
75b0c6f7a3 | ||
|
|
f95ce8c7b5 | ||
|
|
c991a3ccfd | ||
|
|
a1d612b1f6 | ||
|
|
d3cbd20c5e | ||
|
|
cff4f29ba4 | ||
|
|
dc08363360 | ||
|
|
a2aa8d9336 | ||
|
|
ab2bfa951c | ||
|
|
e871d37044 | ||
|
|
e32ee71bea | ||
|
|
3bc8823e54 | ||
|
|
a4b9dfaf1c | ||
|
|
c7c85ac676 | ||
|
|
1af445a390 | ||
|
|
4236a2e6f7 | ||
|
|
47e58942f8 | ||
|
|
f854ed50d6 | ||
|
|
2933a173a2 | ||
|
|
39c45cd329 | ||
|
|
93e6473828 | ||
|
|
2cf96bef52 | ||
|
|
3850ef4355 | ||
|
|
d29f989c22 | ||
|
|
0e31d503d0 | ||
|
|
8c2d552238 | ||
|
|
1b6cb61f8a | ||
|
|
b6e0fa9085 | ||
|
|
1f983d502e | ||
|
|
13637be1aa | ||
|
|
8f22740e07 | ||
|
|
03d5cc7521 | ||
|
|
c9f9e2b97d | ||
|
|
8ca4ede403 | ||
|
|
b50be86615 | ||
|
|
fe1a8f4425 | ||
|
|
dd472c1322 | ||
|
|
a636adec10 | ||
|
|
e3960445ae | ||
|
|
c631b7cd8a | ||
|
|
bb2bf12808 | ||
|
|
db95dfe208 | ||
|
|
86d052e51e | ||
|
|
fb55b9db17 | ||
|
|
ad3ad81c1e | ||
|
|
dccb84ded8 | ||
|
|
510c693871 | ||
|
|
8696df12ac | ||
|
|
d56e0b0eba | ||
|
|
29d77b2f2c | ||
|
|
4e131cd059 | ||
|
|
4c1f3948a3 | ||
|
|
c40ff67704 | ||
|
|
af6ac8bd4f | ||
|
|
70211a8407 | ||
|
|
4d6b83425b | ||
|
|
985396aaf9 | ||
|
|
d86c14d3a6 | ||
|
|
3bdb3a6b87 | ||
|
|
8dac57d4cf | ||
|
|
a91e7b9ed0 | ||
|
|
220b2c9a2a | ||
|
|
06bc8ed4a4 | ||
|
|
648863d21b | ||
|
|
3232e60467 | ||
|
|
da81ea4e57 | ||
|
|
42baec7c72 | ||
|
|
1accdfe2e6 | ||
|
|
f625653b30 | ||
|
|
2682187fa3 | ||
|
|
090f3fafa9 | ||
|
|
de81ed0c61 | ||
|
|
49465888b2 | ||
|
|
1555185d60 | ||
|
|
e5235bd714 | ||
|
|
1b4fe6135f | ||
|
|
9481b29d6b | ||
|
|
20115e6557 | ||
|
|
ee47136fb4 | ||
|
|
83dece68fc | ||
|
|
fce7083e28 | ||
|
|
5268375153 | ||
|
|
3598f59123 | ||
|
|
557f491a7e | ||
|
|
5aa876da72 | ||
|
|
7e7a66595b | ||
|
|
c429bdf139 | ||
|
|
22d22f3afa | ||
|
|
f5845908b9 | ||
|
|
138ce1c69a | ||
|
|
8366ec5831 | ||
|
|
383f0a7f43 | ||
|
|
22e5a5cafd | ||
|
|
8d6255aa55 | ||
|
|
8fd6f7add9 | ||
|
|
623c2cb9f1 | ||
|
|
259e87442d | ||
|
|
8655e025a2 | ||
|
|
aba2a9f504 | ||
|
|
9aa76bd088 | ||
|
|
10faef62fa | ||
|
|
6b291a5ce5 | ||
|
|
164f1dcfd4 | ||
|
|
b7d6d027d3 | ||
|
|
c4869f1917 | ||
|
|
79c31b5f54 | ||
|
|
89e99219d7 | ||
|
|
a9b6c68ce3 | ||
|
|
0563077fb9 | ||
|
|
e2f174e92e | ||
|
|
861bdb47ed | ||
|
|
9f9e2d12c4 | ||
|
|
03f504cadc | ||
|
|
182c7e827b | ||
|
|
61e0cfc979 | ||
|
|
3ea3f01394 | ||
|
|
fc5b8ca1e5 | ||
|
|
5d67b2f9dc | ||
|
|
bcf4fd9e93 | ||
|
|
5b5faad553 | ||
|
|
5299261d18 | ||
|
|
f852851886 | ||
|
|
20a4d9adb8 | ||
|
|
13997cd282 | ||
|
|
965429296b | ||
|
|
d9750ce4dc | ||
|
|
d0fb41e582 | ||
|
|
f7a83d5a60 | ||
|
|
fc52462df4 | ||
|
|
119804794f | ||
|
|
f23bd0b268 | ||
|
|
d6f61b4faf | ||
|
|
4e4b7a1c39 | ||
|
|
376bfb6799 | ||
|
|
12bdba9a9c | ||
|
|
33fa1e1350 | ||
|
|
94e1a4f793 | ||
|
|
2603d960b7 | ||
|
|
b8433c4ea7 | ||
|
|
fc30aeea61 | ||
|
|
01d6e1f14d | ||
|
|
3b4a65deaa | ||
|
|
2ec5ec78a9 | ||
|
|
6b416b8494 | ||
|
|
eac470e081 | ||
|
|
34ce50b7b5 | ||
|
|
6d85e7cdf7 | ||
|
|
23a47a6f63 | ||
|
|
d2bfcc6f0e | ||
|
|
7495392aa2 | ||
|
|
c4ddf84ba8 | ||
|
|
aad6c28e4d | ||
|
|
2bd03dada4 | ||
|
|
5fab16ad06 | ||
|
|
6a4d1ed44d | ||
|
|
db22159a89 | ||
|
|
029e0e5044 | ||
|
|
3f1ee0b1b8 | ||
|
|
8009794cca | ||
|
|
12ce96d802 | ||
|
|
53bd62b236 | ||
|
|
cd7362c654 | ||
|
|
788b5633cb | ||
|
|
46d106e6e2 | ||
|
|
8ffb91022e | ||
|
|
57c09d1772 | ||
|
|
0731ed2c7a | ||
|
|
19ecb67f2d | ||
|
|
d16123c276 | ||
|
|
f90b168fdd | ||
|
|
09f416efdf | ||
|
|
05f40f3451 | ||
|
|
d81206fe2e | ||
|
|
f166ef9313 | ||
|
|
14704f9b4d | ||
|
|
8381daeeb7 | ||
|
|
164ed75af2 | ||
|
|
1f7c64e279 | ||
|
|
a76bf03bc9 | ||
|
|
e50d7f7b95 | ||
|
|
45b1327c58 | ||
|
|
fe60421731 | ||
|
|
0404fe9044 | ||
|
|
8cf6c59ec7 | ||
|
|
7b817ff866 | ||
|
|
f087f70a2c | ||
|
|
b05752f430 | ||
|
|
c4cde366e8 | ||
|
|
33249fad21 | ||
|
|
f0dd28d4db | ||
|
|
c0e35aa9fa | ||
|
|
1fd633a23b | ||
|
|
9a65e26e71 | ||
|
|
f22cabc32a | ||
|
|
b97d57f00b | ||
|
|
5db3544683 | ||
|
|
96eee95596 | ||
|
|
ffb3243bb6 | ||
|
|
09f07902ef | ||
|
|
43583bbc2e | ||
|
|
2ebc713cbb | ||
|
|
65ecc0f3bb | ||
|
|
ebabc1117e | ||
|
|
672e59e657 | ||
|
|
882e11f558 | ||
|
|
1cd5acb972 | ||
|
|
464a6efd28 | ||
|
|
18c3c1f475 | ||
|
|
52de46aeb3 | ||
|
|
b80d088254 | ||
|
|
7d0d85aeb7 | ||
|
|
d19ef8322e | ||
|
|
840b4d7619 | ||
|
|
e4a36545d7 | ||
|
|
31fbc7389b | ||
|
|
19ec936d38 | ||
|
|
939c67d41c | ||
|
|
9614e4f115 | ||
|
|
c48150a792 | ||
|
|
60687502d1 | ||
|
|
2fab58759e | ||
|
|
a42c586bb2 | ||
|
|
a6b76b3494 | ||
|
|
a6eaf7fc84 | ||
|
|
97ba9b42eb | ||
|
|
e0a71f0373 | ||
|
|
b8875d7f1c | ||
|
|
67dfd9a942 | ||
|
|
db46b03d0c | ||
|
|
5672c86905 | ||
|
|
d5406270a5 | ||
|
|
0b3f5e408b | ||
|
|
2ce432ac77 | ||
|
|
6cb26b3fbb | ||
|
|
a9b5949191 | ||
|
|
6016370515 | ||
|
|
f3c026f278 | ||
|
|
8f218bd6d6 | ||
|
|
59fd89bf68 | ||
|
|
d27a6235f0 | ||
|
|
c23febbcf0 | ||
|
|
81e85a4d0d | ||
|
|
44ba1bc85b | ||
|
|
6244fe5a93 | ||
|
|
973335db56 | ||
|
|
4b2c4f88d3 | ||
|
|
bbd2ca0d68 | ||
|
|
a82c225841 | ||
|
|
f9a6852aaa | ||
|
|
fad704b692 | ||
|
|
e362632477 | ||
|
|
4558b49c1b | ||
|
|
4357d8788a | ||
|
|
78b7c24c15 | ||
|
|
127e9e9f74 | ||
|
|
1951ae1cce | ||
|
|
79e2fd4b52 | ||
|
|
2265a2c43d | ||
|
|
1e7e543ab0 | ||
|
|
9671a73bd6 | ||
|
|
5bbee94d68 | ||
|
|
9d7122d69c | ||
|
|
6b1270a4f9 | ||
|
|
3c8de2be3f | ||
|
|
5afb5f0e83 | ||
|
|
7f42d0df40 | ||
|
|
0df54c9021 | ||
|
|
41bc33f4ba | ||
|
|
dcc883fa27 | ||
|
|
492c5d01bf | ||
|
|
49eaca1290 | ||
|
|
ce43b586ad | ||
|
|
ae49cd6a26 | ||
|
|
6ad3897af8 | ||
|
|
53ddb067ea | ||
|
|
a9762170bc | ||
|
|
4d91403fd2 | ||
|
|
e1cd4a63d0 | ||
|
|
18f3874dab | ||
|
|
6efcee500d | ||
|
|
8c0532f363 | ||
|
|
fdb0d07ab8 | ||
|
|
58e30649a3 | ||
|
|
85feef3a60 | ||
|
|
fccd913a8a | ||
|
|
dd119edafe | ||
|
|
f6633fb16c | ||
|
|
d243bf4f48 | ||
|
|
92d306f777 | ||
|
|
0ea29b3d7c | ||
|
|
c8e6e8eb32 | ||
|
|
a6aae6292e | ||
|
|
e33100b075 | ||
|
|
84a229d286 | ||
|
|
ab32c42487 | ||
|
|
0dc3744859 | ||
|
|
d22eab4155 | ||
|
|
ea9bfec3c9 | ||
|
|
02b43a5d66 | ||
|
|
e0fc7952f4 | ||
|
|
66ec2c5d27 | ||
|
|
f5a78402a6 | ||
|
|
29bfd7325d | ||
|
|
318962c01f | ||
|
|
8ca49fafa1 | ||
|
|
656e783894 | ||
|
|
18c6d60a85 | ||
|
|
b202121c21 | ||
|
|
ea3672dd08 | ||
|
|
88037af7ef | ||
|
|
4bda5b619d | ||
|
|
a0645ea30f | ||
|
|
a3e4adb0af | ||
|
|
e18aedfabf | ||
|
|
44529a78d2 | ||
|
|
bb9025364b | ||
|
|
7c78283b46 | ||
|
|
f7d6ca5c11 | ||
|
|
172a341b40 | ||
|
|
09aef67808 | ||
|
|
a400312d3a | ||
|
|
1b01b35b03 | ||
|
|
2d0acaa8ae | ||
|
|
a31a73320b | ||
|
|
75da352806 | ||
|
|
61b0c9b1c1 | ||
|
|
2185fe0f4c | ||
|
|
4ee0977aa1 | ||
|
|
1ba44771bb | ||
|
|
9966eec1df | ||
|
|
dd444f5f76 | ||
|
|
a0a6089057 | ||
|
|
4be72fc989 | ||
|
|
033cbf696a | ||
|
|
805bc85ea9 | ||
|
|
0d057d500e | ||
|
|
7462500e20 | ||
|
|
3e06a4a7c5 | ||
|
|
e0684ab086 | ||
|
|
e7be883e2e | ||
|
|
8fe80a4507 | ||
|
|
68084c4567 | ||
|
|
9c27545f5f | ||
|
|
6da8af7680 | ||
|
|
1b7ce93623 | ||
|
|
5f6480527e | ||
|
|
4d7b4ce877 | ||
|
|
fd61f7d363 | ||
|
|
47cc3d7358 | ||
|
|
d180618634 | ||
|
|
b2b96426d7 | ||
|
|
5796d4b969 | ||
|
|
37957613df | ||
|
|
cb82f02eb4 | ||
|
|
3feccefee8 | ||
|
|
910b1dca85 | ||
|
|
d71c6f055b | ||
|
|
536f373b91 | ||
|
|
6987845228 | ||
|
|
2edd2bf763 | ||
|
|
2605761d76 | ||
|
|
391d261ca1 | ||
|
|
6a7531f1e6 | ||
|
|
fb294e8bea | ||
|
|
a1046488c3 | ||
|
|
8cef56265c | ||
|
|
ec30851247 | ||
|
|
7420c12b89 | ||
|
|
895c770c24 | ||
|
|
606070f449 | ||
|
|
ec41493d91 | ||
|
|
d551093199 | ||
|
|
f7f8b2da62 | ||
|
|
1378b630a6 | ||
|
|
9726d86ab0 | ||
|
|
c9364e7b94 | ||
|
|
1e6780a2e3 | ||
|
|
72855d4d7a | ||
|
|
c0359da930 | ||
|
|
b4f39b0bfc | ||
|
|
d7af145f3b | ||
|
|
b078d8477e | ||
|
|
02b64e1a4b | ||
|
|
f444825e42 | ||
|
|
9fa62ef388 | ||
|
|
e73ad07836 | ||
|
|
a680e79686 | ||
|
|
728c05262c | ||
|
|
23e08c1ca1 | ||
|
|
198d73acfa | ||
|
|
71e210b66c | ||
|
|
2f31c53fd4 | ||
|
|
9f661535e0 | ||
|
|
5b0d4bf8e6 | ||
|
|
a639264149 | ||
|
|
91ab257eb6 | ||
|
|
e24a62d621 | ||
|
|
ec9f4b2b61 | ||
|
|
b66c7da4b3 | ||
|
|
6544cc98d5 | ||
|
|
2dbef9e1fa | ||
|
|
a924e81adb | ||
|
|
1ded1b603e | ||
|
|
a3012a29c2 | ||
|
|
8fcd800aff | ||
|
|
4d414ea082 | ||
|
|
d5b2380bc2 | ||
|
|
d2853fafa9 | ||
|
|
0e5a207c44 | ||
|
|
d7744537ae | ||
|
|
9e79e9efb6 | ||
|
|
a04338d184 | ||
|
|
772b0ca2b0 | ||
|
|
13eb2b75d5 | ||
|
|
c800440e44 | ||
|
|
05f822380c | ||
|
|
7896c81e98 | ||
|
|
ea50569b2a | ||
|
|
7bce07aa0e | ||
|
|
5ef02290dd | ||
|
|
34d5ba7d35 | ||
|
|
55004e7832 | ||
|
|
4945446171 | ||
|
|
0e2d2408ca | ||
|
|
8b8707c36e | ||
|
|
3bd9caf113 | ||
|
|
f713a83abf | ||
|
|
b0e0f8c8bf | ||
|
|
c8623fd3a2 | ||
|
|
c6aad2c2d4 | ||
|
|
7ede87753b | ||
|
|
59bed5a0fa | ||
|
|
e59377d9a3 | ||
|
|
6274cfce4b | ||
|
|
9d624702f6 | ||
|
|
f9d8ff3f74 | ||
|
|
6c837f0639 | ||
|
|
03c9ce3589 | ||
|
|
1ac7cdacb0 | ||
|
|
ba93be1814 | ||
|
|
1404bbab9f | ||
|
|
a5f8ed6378 | ||
|
|
1b59212003 | ||
|
|
4142901dc6 | ||
|
|
4ba9431e6f | ||
|
|
5da83517a8 | ||
|
|
a7e95c2a4d | ||
|
|
ae7fbbb04f | ||
|
|
cc18ef9aa8 | ||
|
|
4202e8a7ba | ||
|
|
882ff8a325 | ||
|
|
1b29957731 | ||
|
|
5702543bc5 | ||
|
|
c810f0647a | ||
|
|
d366b67bee | ||
|
|
85286b3cf9 | ||
|
|
ae4b5464c7 | ||
|
|
dec2536e3e | ||
|
|
30ea512dcc | ||
|
|
f6cdf34b25 | ||
|
|
99818d038b | ||
|
|
c35ce8e195 | ||
|
|
2ae856b0dd | ||
|
|
e592598990 | ||
|
|
07af34fbd0 | ||
|
|
0b3e313260 | ||
|
|
21947de4e0 | ||
|
|
3cdd0baabb | ||
|
|
f851e62330 | ||
|
|
bea19ad8ce | ||
|
|
f5b48f5390 | ||
|
|
cc712b86d5 | ||
|
|
0cf6cfc2b0 | ||
|
|
6f19360da5 | ||
|
|
f216b4716f | ||
|
|
3bf638f7c6 | ||
|
|
5ec9a24c99 | ||
|
|
23caa1d0b5 | ||
|
|
36ecf7c7fd | ||
|
|
0027e75a45 | ||
|
|
4cd759bfa6 | ||
|
|
0f2752220a | ||
|
|
ce1ed46851 | ||
|
|
aa795ee7eb | ||
|
|
5c83671739 | ||
|
|
3fb9390040 | ||
|
|
965687186c | ||
|
|
83742437d6 | ||
|
|
a37e53769c | ||
|
|
084a389a02 | ||
|
|
7971c42814 | ||
|
|
c694461abc |
9
.gitignore
vendored
9
.gitignore
vendored
@@ -7,6 +7,9 @@
|
||||
# Eclipse project files
|
||||
.classpath
|
||||
.project
|
||||
.settings
|
||||
maven-eclipse.xml
|
||||
.externalToolBuilders
|
||||
# Netbeans configuration
|
||||
nb-configuration.xml
|
||||
/target/
|
||||
@@ -15,4 +18,8 @@ dependency-reduced-pom.xml
|
||||
#ruby Gemfile, etc. This is a java project, Gemfile is here to check site problem with Jekyll
|
||||
Gemfile
|
||||
Gemfile.lock
|
||||
_site/**
|
||||
_site/**
|
||||
#unknown as to why these are showing up... but need to be ignored.
|
||||
.LCKpom.xml~
|
||||
#coverity
|
||||
/cov-int/
|
||||
@@ -29,7 +29,7 @@ On Windows
|
||||
|
||||
### Maven Plugin
|
||||
|
||||
More detailed instructions can be found on the [dependency-check-maven github pages](http://jeremylong.github.io/DependencyCheck/dependency-check-maven/installation.html).
|
||||
More detailed instructions can be found on the [dependency-check-maven github pages](http://jeremylong.github.io/DependencyCheck/dependency-check-maven/usage.html).
|
||||
The plugin can be configured using the following:
|
||||
|
||||
```xml
|
||||
@@ -40,7 +40,6 @@ The plugin can be configured using the following:
|
||||
<plugin>
|
||||
<groupId>org.owasp</groupId>
|
||||
<artifactId>dependency-check-maven</artifactId>
|
||||
<version>1.0.2</version>
|
||||
<executions>
|
||||
<execution>
|
||||
<goals>
|
||||
@@ -59,7 +58,7 @@ The plugin can be configured using the following:
|
||||
|
||||
### Ant Task
|
||||
|
||||
For instructions on the use of the Ant Task, please see the [dependency-check-ant github page](http://jeremylong.github.io/DependencyCheck/dependency-check-maven/installation.html).
|
||||
For instructions on the use of the Ant Task, please see the [dependency-check-ant github page](http://jeremylong.github.io/DependencyCheck/dependency-check-ant/installation.html).
|
||||
|
||||
Development Usage
|
||||
-------------
|
||||
@@ -106,4 +105,4 @@ Dependency-Check makes use of several other open source libraries. Please see th
|
||||
[wiki]: https://github.com/jeremylong/DependencyCheck/wiki
|
||||
[subscribe]: mailto:dependency-check+subscribe@googlegroups.com
|
||||
[post]: mailto:dependency-check@googlegroups.com
|
||||
[notices]: https://github.com/jeremylong/DependencyCheck/blob/master/NOTICES.txt
|
||||
[notices]: https://github.com/jeremylong/DependencyCheck/blob/master/NOTICES.txt
|
||||
|
||||
@@ -1,223 +0,0 @@
|
||||
<?xml version="1.0"?>
|
||||
<!DOCTYPE module PUBLIC
|
||||
"-//Puppy Crawl//DTD Check Configuration 1.3//EN"
|
||||
"http://www.puppycrawl.com/dtds/configuration_1_3.dtd">
|
||||
|
||||
<module name="Checker">
|
||||
<!--
|
||||
If you set the basedir property below, then all reported file
|
||||
names will be relative to the specified directory. See
|
||||
http://checkstyle.sourceforge.net/5.x/config.html#Checker
|
||||
|
||||
<property name="basedir" value="${basedir}"/>
|
||||
-->
|
||||
|
||||
<property name="severity" value="error"/>
|
||||
|
||||
<module name="SuppressionFilter">
|
||||
<property name="file" value="${checkstyle.suppressions.file}"/>
|
||||
</module>
|
||||
|
||||
<module name="JavadocPackage">
|
||||
<property name="allowLegacy" value="false"/>
|
||||
</module>
|
||||
|
||||
<module name="Translation">
|
||||
<property name="severity" value="warning"/>
|
||||
</module>
|
||||
|
||||
<module name="FileTabCharacter">
|
||||
<property name="eachLine" value="false"/>
|
||||
</module>
|
||||
|
||||
<module name="FileLength">
|
||||
<property name="fileExtensions" value="java"/>
|
||||
</module>
|
||||
|
||||
<module name="NewlineAtEndOfFile">
|
||||
<property name="fileExtensions" value="java"/>
|
||||
<property name="lineSeparator" value="lf"/>
|
||||
</module>
|
||||
|
||||
<module name="RegexpHeader">
|
||||
<property name="headerFile" value="${checkstyle.header.file}"/>
|
||||
<property name="fileExtensions" value="java"/>
|
||||
<property name="id" value="header"/>
|
||||
</module>
|
||||
|
||||
<module name="RegexpSingleline">
|
||||
<property name="format" value="\s+$"/>
|
||||
<property name="minimum" value="0"/>
|
||||
<property name="maximum" value="0"/>
|
||||
</module>
|
||||
|
||||
<module name="TreeWalker">
|
||||
<property name="tabWidth" value="4"/>
|
||||
|
||||
<module name="AvoidStarImport"/>
|
||||
<module name="ConstantName"/>
|
||||
<module name="EmptyBlock"/>
|
||||
<module name="EmptyForIteratorPad"/>
|
||||
<module name="EqualsHashCode"/>
|
||||
<module name="OneStatementPerLine"/>
|
||||
|
||||
<!-- module name="IllegalCatch"/ -->
|
||||
<!--module name="ImportControl">
|
||||
<property name="file" value="${checkstyle.importcontrol.file}"/>
|
||||
</module-->
|
||||
<module name="IllegalImport"/>
|
||||
<module name="IllegalInstantiation"/>
|
||||
<module name="IllegalThrows"/>
|
||||
<module name="InnerAssignment"/>
|
||||
<module name="JavadocType">
|
||||
<property name="authorFormat" value="\S"/>
|
||||
</module>
|
||||
<module name="JavadocMethod">
|
||||
<property name="allowUndeclaredRTE" value="true"/>
|
||||
<property name="allowThrowsTagsForSubclasses" value="true"/>
|
||||
<property name="allowMissingPropertyJavadoc" value="true"/>
|
||||
</module>
|
||||
<module name="JavadocVariable"/>
|
||||
<module name="JavadocStyle">
|
||||
<property name="scope" value="public"/>
|
||||
</module>
|
||||
|
||||
<module name="LeftCurly">
|
||||
<property name="option" value="eol"/>
|
||||
<property name="tokens" value="CLASS_DEF"/>
|
||||
<property name="tokens" value="CTOR_DEF"/>
|
||||
<property name="tokens" value="INTERFACE_DEF"/>
|
||||
<property name="tokens" value="METHOD_DEF"/>
|
||||
<property name="tokens" value="LITERAL_CATCH"/>
|
||||
<property name="tokens" value="LITERAL_DO"/>
|
||||
<property name="tokens" value="LITERAL_ELSE"/>
|
||||
<property name="tokens" value="LITERAL_FINALLY"/>
|
||||
<property name="tokens" value="LITERAL_FOR"/>
|
||||
<property name="tokens" value="LITERAL_IF"/>
|
||||
<property name="tokens" value="LITERAL_SWITCH"/>
|
||||
<property name="tokens" value="LITERAL_SYNCHRONIZED"/>
|
||||
<property name="tokens" value="LITERAL_TRY"/>
|
||||
<property name="tokens" value="LITERAL_WHILE"/>
|
||||
</module>
|
||||
|
||||
<module name="OuterTypeNumber"/>
|
||||
<module name="LineLength">
|
||||
<property name="ignorePattern" value="^ *\* *[^ ]+$"/>
|
||||
<property name="max" value="150"/>
|
||||
</module>
|
||||
|
||||
<module name="MethodCount">
|
||||
<property name="maxTotal" value="40"/>
|
||||
</module>
|
||||
|
||||
<module name="LocalFinalVariableName"/>
|
||||
<module name="LocalVariableName"/>
|
||||
<module name="MemberName">
|
||||
<property name="format" value="^[a-z][a-zA-Z0-9]*$"/>
|
||||
</module>
|
||||
<module name="MethodLength">
|
||||
<property name="max" value="160"/>
|
||||
<property name="countEmpty" value="false"/>
|
||||
</module>
|
||||
<module name="MethodName"/>
|
||||
<module name="MethodParamPad"/>
|
||||
<module name="ModifierOrder"/>
|
||||
<module name="NeedBraces"/>
|
||||
<module name="NoWhitespaceAfter">
|
||||
<property name="tokens" value="ARRAY_INIT"/>
|
||||
<property name="tokens" value="BNOT"/>
|
||||
<property name="tokens" value="DEC"/>
|
||||
<property name="tokens" value="DOT"/>
|
||||
<property name="tokens" value="INC"/>
|
||||
<property name="tokens" value="LNOT"/>
|
||||
<property name="tokens" value="UNARY_MINUS"/>
|
||||
<property name="tokens" value="UNARY_PLUS"/>
|
||||
</module>
|
||||
|
||||
<module name="NoWhitespaceBefore"/>
|
||||
<module name="NoWhitespaceBefore">
|
||||
<property name="tokens" value="DOT"/>
|
||||
<property name="allowLineBreaks" value="true"/>
|
||||
</module>
|
||||
|
||||
<module name="OperatorWrap"/>
|
||||
<module name="OperatorWrap">
|
||||
<property name="tokens" value="ASSIGN"/>
|
||||
<property name="tokens" value="DIV_ASSIGN"/>
|
||||
<property name="tokens" value="PLUS_ASSIGN"/>
|
||||
<property name="tokens" value="MINUS_ASSIGN"/>
|
||||
<property name="tokens" value="STAR_ASSIGN"/>
|
||||
<property name="tokens" value="MOD_ASSIGN"/>
|
||||
<property name="tokens" value="SR_ASSIGN"/>
|
||||
<property name="tokens" value="BSR_ASSIGN"/>
|
||||
<property name="tokens" value="SL_ASSIGN"/>
|
||||
<property name="tokens" value="BXOR_ASSIGN"/>
|
||||
<property name="tokens" value="BOR_ASSIGN"/>
|
||||
<property name="tokens" value="BAND_ASSIGN"/>
|
||||
<property name="option" value="eol"/>
|
||||
</module>
|
||||
<module name="PackageName"/>
|
||||
<module name="ParameterName">
|
||||
<property name="format" value="^[a-z][a-zA-Z0-9]*$"/>
|
||||
</module>
|
||||
<module name="ParameterNumber">
|
||||
<property name="id" value="paramNum"/>
|
||||
</module>
|
||||
<module name="ParenPad"/>
|
||||
<module name="TypecastParenPad"/>
|
||||
<module name="RedundantImport"/>
|
||||
<module name="RedundantModifier"/>
|
||||
<module name="RightCurly">
|
||||
<property name="option" value="same"/>
|
||||
</module>
|
||||
<module name="SimplifyBooleanExpression"/>
|
||||
<module name="SimplifyBooleanReturn"/>
|
||||
<module name="StaticVariableName">
|
||||
<property name="format" value="^[a-z][a-zA-Z0-9]*$"/>
|
||||
</module>
|
||||
<module name="TypeName"/>
|
||||
<module name="UnusedImports"/>
|
||||
<module name="UpperEll"/>
|
||||
<module name="VisibilityModifier"/>
|
||||
<module name="WhitespaceAfter"/>
|
||||
<module name="WhitespaceAround"/>
|
||||
<module name="GenericWhitespace"/>
|
||||
<module name="FinalClass"/>
|
||||
<module name="MissingSwitchDefault"/>
|
||||
<!--module name="MagicNumber"/-->
|
||||
<!--module name="Indentation">
|
||||
<property name="basicOffset" value="4"/>
|
||||
<property name="braceAdjustment" value="0"/>
|
||||
<property name="caseIndent" value="0"/>
|
||||
</module-->
|
||||
<module name="ArrayTrailingComma"/>
|
||||
<module name="FinalLocalVariable"/>
|
||||
<module name="EqualsAvoidNull"/>
|
||||
<module name="ParameterAssignment"/>
|
||||
|
||||
<!-- Generates quite a few errors -->
|
||||
<module name="CyclomaticComplexity">
|
||||
<property name="severity" value="ignore"/>
|
||||
</module>
|
||||
|
||||
<module name="NestedForDepth">
|
||||
<property name="max" value="2"/>
|
||||
</module>
|
||||
<module name="NestedIfDepth">
|
||||
<property name="max" value="4"/>
|
||||
</module>
|
||||
<module name="NestedTryDepth">
|
||||
<property name="max" value="2"/>
|
||||
</module>
|
||||
<!--module name="ExplicitInitialization"/-->
|
||||
<module name="AnnotationUseStyle"/>
|
||||
<module name="MissingDeprecated"/>
|
||||
<module name="MissingOverride">
|
||||
<property name="javaFiveCompatibility" value="true"/>
|
||||
</module>
|
||||
<module name="PackageAnnotation"/>
|
||||
<module name="SuppressWarnings"/>
|
||||
<module name="OuterTypeFilename"/>
|
||||
<module name="HideUtilityClassConstructor"/>
|
||||
</module>
|
||||
</module>
|
||||
@@ -1,18 +0,0 @@
|
||||
^/\*\s*$
|
||||
^ \* This file is part of dependency-check-ant\.\s*$
|
||||
^ \*\s*$
|
||||
^ \* Licensed under the Apache License, Version 2\.0 \(the "License"\);\s*$
|
||||
^ \* you may not use this file except in compliance with the License.\s*$
|
||||
^ \* You may obtain a copy of the License at\s*$
|
||||
^ \*\s*$
|
||||
^ \*\s*http://www.apache.org/licenses/LICENSE-2\.0\s*$
|
||||
^ \*\s*$
|
||||
^ \* Unless required by applicable law or agreed to in writing, software\s*$
|
||||
^ \* distributed under the License is distributed on an "AS IS" BASIS,\s*$
|
||||
^ \* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied\.\s*$
|
||||
^ \* See the License for the specific language governing permissions and\s*$
|
||||
^ \* limitations under the License\.\s*$
|
||||
^ \*\s*$
|
||||
^ \* Copyright \(c\) 201[234] (Jeremy Long|Steve Springett)\. All Rights Reserved\.\s*$
|
||||
^ \*/\s*$
|
||||
^package
|
||||
@@ -1,9 +0,0 @@
|
||||
<?xml version="1.0"?>
|
||||
|
||||
<!DOCTYPE suppressions PUBLIC
|
||||
"-//Puppy Crawl//DTD Suppressions 1.0//EN"
|
||||
"http://www.puppycrawl.com/dtds/suppressions_1_0.dtd">
|
||||
|
||||
<suppressions>
|
||||
<suppress checks=".*" files=".*[\\/]package-info\.java" />
|
||||
</suppressions>
|
||||
@@ -15,20 +15,19 @@ limitations under the License.
|
||||
|
||||
Copyright (c) 2013 - Jeremy Long. All Rights Reserved.
|
||||
-->
|
||||
|
||||
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
<parent>
|
||||
<groupId>org.owasp</groupId>
|
||||
<artifactId>dependency-check-parent</artifactId>
|
||||
<version>1.1.1</version>
|
||||
<version>1.2.9</version>
|
||||
</parent>
|
||||
|
||||
<artifactId>dependency-check-ant</artifactId>
|
||||
<packaging>jar</packaging>
|
||||
|
||||
<name>Dependency-Check Ant Task</name>
|
||||
<description>Dependency-check is a utility that attempts to detect publicly disclosed vulnerabilities contained within project dependencies. It does this by determining if there is a Common Platform Enumeration (CPE) identifier for a given dependency. If found, it will generate a report linking to the associated CVE entries.</description>
|
||||
<description>dependency-check-ant is an Ant Task that uses dependency-check-core to detect publicly disclosed vulnerabilities associated with the project's dependencies. The task will generate a report listing the dependency, any identified Common Platform Enumeration (CPE) identifiers, and the associated Common Vulnerability and Exposure (CVE) entries.</description>
|
||||
<!-- begin copy from http://minds.coremedia.com/2012/09/11/problem-solved-deploy-multi-module-maven-project-site-as-github-pages/ -->
|
||||
<distributionManagement>
|
||||
<site>
|
||||
@@ -69,7 +68,6 @@ Copyright (c) 2013 - Jeremy Long. All Rights Reserved.
|
||||
<plugin>
|
||||
<groupId>org.apache.maven.plugins</groupId>
|
||||
<artifactId>maven-resources-plugin</artifactId>
|
||||
<version>2.6</version>
|
||||
<configuration>
|
||||
<escapeWindowsPaths>false</escapeWindowsPaths>
|
||||
</configuration>
|
||||
@@ -192,10 +190,18 @@ Copyright (c) 2013 - Jeremy Long. All Rights Reserved.
|
||||
</execution>
|
||||
</executions>
|
||||
</plugin>
|
||||
<plugin>
|
||||
<groupId>org.apache.maven.plugins</groupId>
|
||||
<artifactId>maven-compiler-plugin</artifactId>
|
||||
</plugin>
|
||||
<plugin>
|
||||
<groupId>org.apache.maven.plugins</groupId>
|
||||
<artifactId>maven-jar-plugin</artifactId>
|
||||
</plugin>
|
||||
<plugin>
|
||||
<groupId>org.apache.maven.plugins</groupId>
|
||||
<artifactId>maven-shade-plugin</artifactId>
|
||||
<version>2.1</version>
|
||||
<version>2.3</version>
|
||||
<configuration>
|
||||
<transformers>
|
||||
<transformer implementation="org.apache.maven.plugins.shade.resource.ServicesResourceTransformer" />
|
||||
@@ -219,26 +225,13 @@ Copyright (c) 2013 - Jeremy Long. All Rights Reserved.
|
||||
</execution>
|
||||
</executions>
|
||||
</plugin>
|
||||
<plugin>
|
||||
<groupId>org.apache.maven.plugins</groupId>
|
||||
<artifactId>maven-jar-plugin</artifactId>
|
||||
<version>2.4</version>
|
||||
<configuration>
|
||||
<archive>
|
||||
<manifest>
|
||||
<addDefaultImplementationEntries>true</addDefaultImplementationEntries>
|
||||
</manifest>
|
||||
</archive>
|
||||
<excludes>
|
||||
<exclude>**/checkstyle*</exclude>
|
||||
</excludes>
|
||||
</configuration>
|
||||
</plugin>
|
||||
<plugin>
|
||||
<groupId>org.codehaus.mojo</groupId>
|
||||
<artifactId>cobertura-maven-plugin</artifactId>
|
||||
<version>2.5.2</version>
|
||||
<configuration>
|
||||
<!--instrumentation>
|
||||
<ignoreTrivial>true</ignoreTrivial>
|
||||
</instrumentation-->
|
||||
<check>
|
||||
<branchRate>85</branchRate>
|
||||
<lineRate>85</lineRate>
|
||||
@@ -267,14 +260,8 @@ Copyright (c) 2013 - Jeremy Long. All Rights Reserved.
|
||||
<plugin>
|
||||
<groupId>org.apache.maven.plugins</groupId>
|
||||
<artifactId>maven-surefire-plugin</artifactId>
|
||||
<version>2.16</version>
|
||||
<configuration>
|
||||
<systemProperties>
|
||||
<property>
|
||||
<name>net.sourceforge.cobertura.datafile</name>
|
||||
<value>${project.build.directory}/cobertura/cobertura.ser</value>
|
||||
<workingDirectory>target</workingDirectory>
|
||||
</property>
|
||||
<property>
|
||||
<name>data.directory</name>
|
||||
<value>${project.build.directory}/dependency-check-data</value>
|
||||
@@ -282,156 +269,150 @@ Copyright (c) 2013 - Jeremy Long. All Rights Reserved.
|
||||
</systemProperties>
|
||||
</configuration>
|
||||
</plugin>
|
||||
<plugin>
|
||||
<groupId>org.apache.maven.plugins</groupId>
|
||||
<artifactId>maven-compiler-plugin</artifactId>
|
||||
<version>3.1</version>
|
||||
<configuration>
|
||||
<showDeprecation>false</showDeprecation>
|
||||
<source>1.6</source>
|
||||
<target>1.6</target>
|
||||
</configuration>
|
||||
</plugin>
|
||||
|
||||
<plugin>
|
||||
<groupId>org.apache.maven.plugins</groupId>
|
||||
<artifactId>maven-site-plugin</artifactId>
|
||||
<version>3.3</version>
|
||||
<dependencies>
|
||||
<dependency>
|
||||
<groupId>org.apache.maven.doxia</groupId>
|
||||
<artifactId>doxia-module-markdown</artifactId>
|
||||
<version>1.5</version>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
<configuration>
|
||||
<skipDeploy>true</skipDeploy>
|
||||
<reportPlugins>
|
||||
<plugin>
|
||||
<groupId>org.apache.maven.plugins</groupId>
|
||||
<artifactId>maven-project-info-reports-plugin</artifactId>
|
||||
<version>2.7</version>
|
||||
<reportSets>
|
||||
<reportSet>
|
||||
<reports>
|
||||
<report>index</report>
|
||||
<report>summary</report>
|
||||
<report>license</report>
|
||||
<report>help</report>
|
||||
</reports>
|
||||
</reportSet>
|
||||
</reportSets>
|
||||
</plugin>
|
||||
<plugin>
|
||||
<groupId>org.apache.maven.plugins</groupId>
|
||||
<artifactId>maven-javadoc-plugin</artifactId>
|
||||
<version>2.9.1</version>
|
||||
<reportSets>
|
||||
<reportSet>
|
||||
<id>default</id>
|
||||
<reports>
|
||||
<report>javadoc</report>
|
||||
</reports>
|
||||
</reportSet>
|
||||
</reportSets>
|
||||
</plugin>
|
||||
<plugin>
|
||||
<groupId>org.codehaus.mojo</groupId>
|
||||
<artifactId>versions-maven-plugin</artifactId>
|
||||
<version>2.1</version>
|
||||
<reportSets>
|
||||
<reportSet>
|
||||
<reports>
|
||||
<report>dependency-updates-report</report>
|
||||
<report>plugin-updates-report</report>
|
||||
</reports>
|
||||
</reportSet>
|
||||
</reportSets>
|
||||
</plugin>
|
||||
<plugin>
|
||||
<groupId>org.apache.maven.plugins</groupId>
|
||||
<artifactId>maven-jxr-plugin</artifactId>
|
||||
<version>2.4</version>
|
||||
</plugin>
|
||||
<plugin>
|
||||
<groupId>org.codehaus.mojo</groupId>
|
||||
<artifactId>cobertura-maven-plugin</artifactId>
|
||||
<version>2.5.2</version>
|
||||
</plugin>
|
||||
<plugin>
|
||||
<groupId>org.apache.maven.plugins</groupId>
|
||||
<artifactId>maven-surefire-report-plugin</artifactId>
|
||||
<version>2.16</version>
|
||||
<reportSets>
|
||||
<reportSet>
|
||||
<reports>
|
||||
<report>report-only</report>
|
||||
</reports>
|
||||
</reportSet>
|
||||
</reportSets>
|
||||
</plugin>
|
||||
<plugin>
|
||||
<groupId>org.codehaus.mojo</groupId>
|
||||
<artifactId>taglist-maven-plugin</artifactId>
|
||||
<version>2.4</version>
|
||||
<configuration>
|
||||
<tagListOptions>
|
||||
<tagClasses>
|
||||
<tagClass>
|
||||
<displayName>Todo Work</displayName>
|
||||
<tags>
|
||||
<tag>
|
||||
<matchString>todo</matchString>
|
||||
<matchType>ignoreCase</matchType>
|
||||
</tag>
|
||||
<tag>
|
||||
<matchString>FIXME</matchString>
|
||||
<matchType>exact</matchType>
|
||||
</tag>
|
||||
</tags>
|
||||
</tagClass>
|
||||
</tagClasses>
|
||||
</tagListOptions>
|
||||
</configuration>
|
||||
</plugin>
|
||||
<plugin>
|
||||
<groupId>org.apache.maven.plugins</groupId>
|
||||
<artifactId>maven-checkstyle-plugin</artifactId>
|
||||
<version>2.11</version>
|
||||
<configuration>
|
||||
<enableRulesSummary>false</enableRulesSummary>
|
||||
<configLocation>${basedir}/config/checkstyle-checks.xml</configLocation>
|
||||
<headerLocation>${basedir}/config/checkstyle-header.txt</headerLocation>
|
||||
<suppressionsLocation>${basedir}/config/checkstyle-suppressions.xml</suppressionsLocation>
|
||||
<suppressionsFileExpression>checkstyle.suppressions.file</suppressionsFileExpression>
|
||||
</configuration>
|
||||
</plugin>
|
||||
<plugin>
|
||||
<groupId>org.apache.maven.plugins</groupId>
|
||||
<artifactId>maven-pmd-plugin</artifactId>
|
||||
<version>3.0.1</version>
|
||||
<configuration>
|
||||
<targetJdk>1.6</targetJdk>
|
||||
<linkXref>true</linkXref>
|
||||
<sourceEncoding>utf-8</sourceEncoding>
|
||||
</configuration>
|
||||
</plugin>
|
||||
<plugin>
|
||||
<groupId>org.codehaus.mojo</groupId>
|
||||
<artifactId>findbugs-maven-plugin</artifactId>
|
||||
<version>2.5.3</version>
|
||||
</plugin>
|
||||
</reportPlugins>
|
||||
</configuration>
|
||||
</plugin>
|
||||
</plugins>
|
||||
</build>
|
||||
<reporting>
|
||||
<plugins>
|
||||
<plugin>
|
||||
<groupId>org.apache.maven.plugins</groupId>
|
||||
<artifactId>maven-project-info-reports-plugin</artifactId>
|
||||
<version>2.7</version>
|
||||
<reportSets>
|
||||
<reportSet>
|
||||
<reports>
|
||||
<report>index</report>
|
||||
<report>summary</report>
|
||||
<report>license</report>
|
||||
<report>help</report>
|
||||
</reports>
|
||||
</reportSet>
|
||||
</reportSets>
|
||||
</plugin>
|
||||
<plugin>
|
||||
<groupId>org.apache.maven.plugins</groupId>
|
||||
<artifactId>maven-javadoc-plugin</artifactId>
|
||||
<version>2.9.1</version>
|
||||
<configuration>
|
||||
<bottom>Copyright© 2012-15 Jeremy Long. All Rights Reserved.</bottom>
|
||||
</configuration>
|
||||
<reportSets>
|
||||
<reportSet>
|
||||
<id>default</id>
|
||||
<reports>
|
||||
<report>javadoc</report>
|
||||
</reports>
|
||||
</reportSet>
|
||||
</reportSets>
|
||||
</plugin>
|
||||
<plugin>
|
||||
<groupId>org.codehaus.mojo</groupId>
|
||||
<artifactId>versions-maven-plugin</artifactId>
|
||||
<version>2.1</version>
|
||||
<reportSets>
|
||||
<reportSet>
|
||||
<reports>
|
||||
<report>dependency-updates-report</report>
|
||||
<report>plugin-updates-report</report>
|
||||
</reports>
|
||||
</reportSet>
|
||||
</reportSets>
|
||||
</plugin>
|
||||
<plugin>
|
||||
<groupId>org.apache.maven.plugins</groupId>
|
||||
<artifactId>maven-jxr-plugin</artifactId>
|
||||
<version>2.4</version>
|
||||
</plugin>
|
||||
<plugin>
|
||||
<groupId>org.codehaus.mojo</groupId>
|
||||
<artifactId>cobertura-maven-plugin</artifactId>
|
||||
<version>2.6</version>
|
||||
</plugin>
|
||||
<plugin>
|
||||
<groupId>org.apache.maven.plugins</groupId>
|
||||
<artifactId>maven-surefire-report-plugin</artifactId>
|
||||
<version>2.16</version>
|
||||
<reportSets>
|
||||
<reportSet>
|
||||
<reports>
|
||||
<report>report-only</report>
|
||||
</reports>
|
||||
</reportSet>
|
||||
</reportSets>
|
||||
</plugin>
|
||||
<plugin>
|
||||
<groupId>org.codehaus.mojo</groupId>
|
||||
<artifactId>taglist-maven-plugin</artifactId>
|
||||
<version>2.4</version>
|
||||
<configuration>
|
||||
<tagListOptions>
|
||||
<tagClasses>
|
||||
<tagClass>
|
||||
<displayName>Todo Work</displayName>
|
||||
<tags>
|
||||
<tag>
|
||||
<matchString>todo</matchString>
|
||||
<matchType>ignoreCase</matchType>
|
||||
</tag>
|
||||
<tag>
|
||||
<matchString>FIXME</matchString>
|
||||
<matchType>exact</matchType>
|
||||
</tag>
|
||||
</tags>
|
||||
</tagClass>
|
||||
</tagClasses>
|
||||
</tagListOptions>
|
||||
</configuration>
|
||||
</plugin>
|
||||
<plugin>
|
||||
<groupId>org.apache.maven.plugins</groupId>
|
||||
<artifactId>maven-checkstyle-plugin</artifactId>
|
||||
<version>2.11</version>
|
||||
<configuration>
|
||||
<enableRulesSummary>false</enableRulesSummary>
|
||||
<enableFilesSummary>false</enableFilesSummary>
|
||||
<configLocation>${basedir}/../src/main/config/checkstyle-checks.xml</configLocation>
|
||||
<headerLocation>${basedir}/../src/main/config/checkstyle-header.txt</headerLocation>
|
||||
<suppressionsLocation>${basedir}/../src/main/config/checkstyle-suppressions.xml</suppressionsLocation>
|
||||
<suppressionsFileExpression>checkstyle.suppressions.file</suppressionsFileExpression>
|
||||
</configuration>
|
||||
</plugin>
|
||||
<plugin>
|
||||
<groupId>org.apache.maven.plugins</groupId>
|
||||
<artifactId>maven-pmd-plugin</artifactId>
|
||||
<version>3.0.1</version>
|
||||
<configuration>
|
||||
<targetJdk>1.6</targetJdk>
|
||||
<linkXref>true</linkXref>
|
||||
<sourceEncoding>utf-8</sourceEncoding>
|
||||
<excludes>
|
||||
<exclude>**/generated/*.java</exclude>
|
||||
</excludes>
|
||||
<rulesets>
|
||||
<ruleset>../src/main/config/dcrules.xml</ruleset>
|
||||
<ruleset>/rulesets/java/basic.xml</ruleset>
|
||||
<ruleset>/rulesets/java/imports.xml</ruleset>
|
||||
<ruleset>/rulesets/java/unusedcode.xml</ruleset>
|
||||
</rulesets>
|
||||
</configuration>
|
||||
</plugin>
|
||||
<plugin>
|
||||
<groupId>org.codehaus.mojo</groupId>
|
||||
<artifactId>findbugs-maven-plugin</artifactId>
|
||||
<version>2.5.3</version>
|
||||
</plugin>
|
||||
</plugins>
|
||||
</reporting>
|
||||
<dependencies>
|
||||
<dependency>
|
||||
<groupId>org.owasp</groupId>
|
||||
<artifactId>dependency-check-core</artifactId>
|
||||
<version>${project.parent.version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.owasp</groupId>
|
||||
<artifactId>dependency-check-utils</artifactId>
|
||||
<version>${project.parent.version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.owasp</groupId>
|
||||
<artifactId>dependency-check-core</artifactId>
|
||||
@@ -442,12 +423,12 @@ Copyright (c) 2013 - Jeremy Long. All Rights Reserved.
|
||||
<dependency>
|
||||
<groupId>org.apache.ant</groupId>
|
||||
<artifactId>ant</artifactId>
|
||||
<version>1.9.3</version>
|
||||
<version>1.9.4</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.apache.ant</groupId>
|
||||
<artifactId>ant-testutil</artifactId>
|
||||
<version>1.9.3</version>
|
||||
<version>1.9.4</version>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
|
||||
@@ -62,6 +62,10 @@ public class DependencyCheckTask extends Task {
|
||||
* System specific new line character.
|
||||
*/
|
||||
private static final String NEW_LINE = System.getProperty("line.separator", "\n").intern();
|
||||
/**
|
||||
* The logger.
|
||||
*/
|
||||
private static final Logger LOGGER = Logger.getLogger(DependencyCheckTask.class.getName());
|
||||
|
||||
/**
|
||||
* Construct a new DependencyCheckTask.
|
||||
@@ -94,8 +98,8 @@ public class DependencyCheckTask extends Task {
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the path. If the path has not been initialized yet, this class is synchronized, and will instantiate the
|
||||
* path object.
|
||||
* Returns the path. If the path has not been initialized yet, this class is synchronized, and will instantiate the path
|
||||
* object.
|
||||
*
|
||||
* @return the path
|
||||
*/
|
||||
@@ -211,9 +215,9 @@ public class DependencyCheckTask extends Task {
|
||||
this.reportOutputDirectory = reportOutputDirectory;
|
||||
}
|
||||
/**
|
||||
* Specifies if the build should be failed if a CVSS score above a specified level is identified. The default is 11
|
||||
* which means since the CVSS scores are 0-10, by default the build will never fail and the CVSS score is set to 11.
|
||||
* The valid range for the fail build on CVSS is 0 to 11, where anything above 10 will not cause the build to fail.
|
||||
* Specifies if the build should be failed if a CVSS score above a specified level is identified. The default is 11 which
|
||||
* means since the CVSS scores are 0-10, by default the build will never fail and the CVSS score is set to 11. The valid range
|
||||
* for the fail build on CVSS is 0 to 11, where anything above 10 will not cause the build to fail.
|
||||
*/
|
||||
private float failBuildOnCVSS = 11;
|
||||
|
||||
@@ -235,8 +239,8 @@ public class DependencyCheckTask extends Task {
|
||||
this.failBuildOnCVSS = failBuildOnCVSS;
|
||||
}
|
||||
/**
|
||||
* Sets whether auto-updating of the NVD CVE/CPE data is enabled. It is not recommended that this be turned to
|
||||
* false. Default is true.
|
||||
* Sets whether auto-updating of the NVD CVE/CPE data is enabled. It is not recommended that this be turned to false. Default
|
||||
* is true.
|
||||
*/
|
||||
private boolean autoUpdate = true;
|
||||
|
||||
@@ -258,8 +262,8 @@ public class DependencyCheckTask extends Task {
|
||||
this.autoUpdate = autoUpdate;
|
||||
}
|
||||
/**
|
||||
* The report format to be generated (HTML, XML, VULN, ALL). This configuration option has no affect if using this
|
||||
* within the Site plugin unless the externalReport is set to true. Default is HTML.
|
||||
* The report format to be generated (HTML, XML, VULN, ALL). This configuration option has no affect if using this within the
|
||||
* Site plugin unless the externalReport is set to true. Default is HTML.
|
||||
*/
|
||||
private String reportFormat = "HTML";
|
||||
|
||||
@@ -281,26 +285,49 @@ public class DependencyCheckTask extends Task {
|
||||
this.reportFormat = reportFormat.getValue();
|
||||
}
|
||||
/**
|
||||
* The Proxy URL.
|
||||
* The Proxy Server.
|
||||
*/
|
||||
private String proxyUrl;
|
||||
private String proxyServer;
|
||||
|
||||
/**
|
||||
* Get the value of proxyUrl.
|
||||
* Get the value of proxyServer.
|
||||
*
|
||||
* @return the value of proxyUrl
|
||||
* @return the value of proxyServer
|
||||
*/
|
||||
public String getProxyUrl() {
|
||||
return proxyUrl;
|
||||
public String getProxyServer() {
|
||||
return proxyServer;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the value of proxyUrl.
|
||||
* Set the value of proxyServer.
|
||||
*
|
||||
* @param proxyUrl new value of proxyUrl
|
||||
* @param server new value of proxyServer
|
||||
*/
|
||||
public void setProxyServer(String server) {
|
||||
this.proxyServer = server;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the value of proxyServer.
|
||||
*
|
||||
* @return the value of proxyServer
|
||||
* @deprecated use {@link org.owasp.dependencycheck.taskdefs.DependencyCheckTask#getProxyServer()} instead
|
||||
*/
|
||||
@Deprecated
|
||||
public String getProxyUrl() {
|
||||
return proxyServer;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the value of proxyServer.
|
||||
*
|
||||
* @param proxyUrl new value of proxyServer
|
||||
* @deprecated use {@link org.owasp.dependencycheck.taskdefs.DependencyCheckTask#setProxyServer(java.lang.String)} instead
|
||||
*/
|
||||
@Deprecated
|
||||
public void setProxyUrl(String proxyUrl) {
|
||||
this.proxyUrl = proxyUrl;
|
||||
LOGGER.warning("A deprecated configuration option 'proxyUrl' was detected; use 'proxyServer' instead.");
|
||||
this.proxyServer = proxyUrl;
|
||||
}
|
||||
/**
|
||||
* The Proxy Port.
|
||||
@@ -457,6 +484,103 @@ public class DependencyCheckTask extends Task {
|
||||
this.showSummary = showSummary;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets whether or not the analyzer is enabled.
|
||||
*
|
||||
* @param jarAnalyzerEnabled the value of the new setting
|
||||
*/
|
||||
public void setJarAnalyzerEnabled(boolean jarAnalyzerEnabled) {
|
||||
this.jarAnalyzerEnabled = jarAnalyzerEnabled;
|
||||
}
|
||||
/**
|
||||
* Whether or not the Archive Analyzer is enabled.
|
||||
*/
|
||||
private boolean archiveAnalyzerEnabled = true;
|
||||
|
||||
/**
|
||||
* Returns whether or not the analyzer is enabled.
|
||||
*
|
||||
* @return true if the analyzer is enabled
|
||||
*/
|
||||
public boolean isArchiveAnalyzerEnabled() {
|
||||
return archiveAnalyzerEnabled;
|
||||
}
|
||||
/**
|
||||
* Whether or not the .NET Assembly Analyzer is enabled.
|
||||
*/
|
||||
private boolean assemblyAnalyzerEnabled = true;
|
||||
|
||||
/**
|
||||
* Sets whether or not the analyzer is enabled.
|
||||
*
|
||||
* @param archiveAnalyzerEnabled the value of the new setting
|
||||
*/
|
||||
public void setArchiveAnalyzerEnabled(boolean archiveAnalyzerEnabled) {
|
||||
this.archiveAnalyzerEnabled = archiveAnalyzerEnabled;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns whether or not the analyzer is enabled.
|
||||
*
|
||||
* @return true if the analyzer is enabled
|
||||
*/
|
||||
public boolean isAssemblyAnalyzerEnabled() {
|
||||
return assemblyAnalyzerEnabled;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets whether or not the analyzer is enabled.
|
||||
*
|
||||
* @param assemblyAnalyzerEnabled the value of the new setting
|
||||
*/
|
||||
public void setAssemblyAnalyzerEnabled(boolean assemblyAnalyzerEnabled) {
|
||||
this.assemblyAnalyzerEnabled = assemblyAnalyzerEnabled;
|
||||
}
|
||||
/**
|
||||
* Whether or not the .NET Nuspec Analyzer is enabled.
|
||||
*/
|
||||
private boolean nuspecAnalyzerEnabled = true;
|
||||
|
||||
/**
|
||||
* Returns whether or not the analyzer is enabled.
|
||||
*
|
||||
* @return true if the analyzer is enabled
|
||||
*/
|
||||
public boolean isNuspecAnalyzerEnabled() {
|
||||
return nuspecAnalyzerEnabled;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets whether or not the analyzer is enabled.
|
||||
*
|
||||
* @param nuspecAnalyzerEnabled the value of the new setting
|
||||
*/
|
||||
public void setNuspecAnalyzerEnabled(boolean nuspecAnalyzerEnabled) {
|
||||
this.nuspecAnalyzerEnabled = nuspecAnalyzerEnabled;
|
||||
}
|
||||
/**
|
||||
* Whether or not the central analyzer is enabled.
|
||||
*/
|
||||
private boolean centralAnalyzerEnabled = false;
|
||||
|
||||
/**
|
||||
* Get the value of centralAnalyzerEnabled.
|
||||
*
|
||||
* @return the value of centralAnalyzerEnabled
|
||||
*/
|
||||
public boolean isCentralAnalyzerEnabled() {
|
||||
return centralAnalyzerEnabled;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the value of centralAnalyzerEnabled.
|
||||
*
|
||||
* @param centralAnalyzerEnabled new value of centralAnalyzerEnabled
|
||||
*/
|
||||
public void setCentralAnalyzerEnabled(boolean centralAnalyzerEnabled) {
|
||||
this.centralAnalyzerEnabled = centralAnalyzerEnabled;
|
||||
}
|
||||
|
||||
/**
|
||||
* Whether or not the nexus analyzer is enabled.
|
||||
*/
|
||||
@@ -502,6 +626,28 @@ public class DependencyCheckTask extends Task {
|
||||
public void setNexusUrl(String nexusUrl) {
|
||||
this.nexusUrl = nexusUrl;
|
||||
}
|
||||
/**
|
||||
* Whether or not the defined proxy should be used when connecting to Nexus.
|
||||
*/
|
||||
private boolean nexusUsesProxy = true;
|
||||
|
||||
/**
|
||||
* Get the value of nexusUsesProxy.
|
||||
*
|
||||
* @return the value of nexusUsesProxy
|
||||
*/
|
||||
public boolean isNexusUsesProxy() {
|
||||
return nexusUsesProxy;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the value of nexusUsesProxy.
|
||||
*
|
||||
* @param nexusUsesProxy new value of nexusUsesProxy
|
||||
*/
|
||||
public void setNexusUsesProxy(boolean nexusUsesProxy) {
|
||||
this.nexusUsesProxy = nexusUsesProxy;
|
||||
}
|
||||
|
||||
/**
|
||||
* The database driver name; such as org.h2.Driver.
|
||||
@@ -616,6 +762,144 @@ public class DependencyCheckTask extends Task {
|
||||
this.databasePassword = databasePassword;
|
||||
}
|
||||
|
||||
/**
|
||||
* Additional ZIP File extensions to add analyze. This should be a comma-separated list of file extensions to treat like ZIP
|
||||
* files.
|
||||
*/
|
||||
private String zipExtensions;
|
||||
|
||||
/**
|
||||
* Get the value of zipExtensions.
|
||||
*
|
||||
* @return the value of zipExtensions
|
||||
*/
|
||||
public String getZipExtensions() {
|
||||
return zipExtensions;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the value of zipExtensions.
|
||||
*
|
||||
* @param zipExtensions new value of zipExtensions
|
||||
*/
|
||||
public void setZipExtensions(String zipExtensions) {
|
||||
this.zipExtensions = zipExtensions;
|
||||
}
|
||||
|
||||
/**
|
||||
* The url for the modified NVD CVE (1.2 schema).
|
||||
*/
|
||||
private String cveUrl12Modified;
|
||||
|
||||
/**
|
||||
* Get the value of cveUrl12Modified.
|
||||
*
|
||||
* @return the value of cveUrl12Modified
|
||||
*/
|
||||
public String getCveUrl12Modified() {
|
||||
return cveUrl12Modified;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the value of cveUrl12Modified.
|
||||
*
|
||||
* @param cveUrl12Modified new value of cveUrl12Modified
|
||||
*/
|
||||
public void setCveUrl12Modified(String cveUrl12Modified) {
|
||||
this.cveUrl12Modified = cveUrl12Modified;
|
||||
}
|
||||
|
||||
/**
|
||||
* The url for the modified NVD CVE (2.0 schema).
|
||||
*/
|
||||
private String cveUrl20Modified;
|
||||
|
||||
/**
|
||||
* Get the value of cveUrl20Modified.
|
||||
*
|
||||
* @return the value of cveUrl20Modified
|
||||
*/
|
||||
public String getCveUrl20Modified() {
|
||||
return cveUrl20Modified;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the value of cveUrl20Modified.
|
||||
*
|
||||
* @param cveUrl20Modified new value of cveUrl20Modified
|
||||
*/
|
||||
public void setCveUrl20Modified(String cveUrl20Modified) {
|
||||
this.cveUrl20Modified = cveUrl20Modified;
|
||||
}
|
||||
|
||||
/**
|
||||
* Base Data Mirror URL for CVE 1.2.
|
||||
*/
|
||||
private String cveUrl12Base;
|
||||
|
||||
/**
|
||||
* Get the value of cveUrl12Base.
|
||||
*
|
||||
* @return the value of cveUrl12Base
|
||||
*/
|
||||
public String getCveUrl12Base() {
|
||||
return cveUrl12Base;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the value of cveUrl12Base.
|
||||
*
|
||||
* @param cveUrl12Base new value of cveUrl12Base
|
||||
*/
|
||||
public void setCveUrl12Base(String cveUrl12Base) {
|
||||
this.cveUrl12Base = cveUrl12Base;
|
||||
}
|
||||
|
||||
/**
|
||||
* Data Mirror URL for CVE 2.0.
|
||||
*/
|
||||
private String cveUrl20Base;
|
||||
|
||||
/**
|
||||
* Get the value of cveUrl20Base.
|
||||
*
|
||||
* @return the value of cveUrl20Base
|
||||
*/
|
||||
public String getCveUrl20Base() {
|
||||
return cveUrl20Base;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the value of cveUrl20Base.
|
||||
*
|
||||
* @param cveUrl20Base new value of cveUrl20Base
|
||||
*/
|
||||
public void setCveUrl20Base(String cveUrl20Base) {
|
||||
this.cveUrl20Base = cveUrl20Base;
|
||||
}
|
||||
/**
|
||||
* The path to Mono for .NET assembly analysis on non-windows systems.
|
||||
*/
|
||||
private String pathToMono;
|
||||
|
||||
/**
|
||||
* Get the value of pathToMono.
|
||||
*
|
||||
* @return the value of pathToMono
|
||||
*/
|
||||
public String getPathToMono() {
|
||||
return pathToMono;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the value of pathToMono.
|
||||
*
|
||||
* @param pathToMono new value of pathToMono
|
||||
*/
|
||||
public void setPathToMono(String pathToMono) {
|
||||
this.pathToMono = pathToMono;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void execute() throws BuildException {
|
||||
final InputStream in = DependencyCheckTask.class.getClassLoader().getResourceAsStream(LOG_PROPERTIES_FILE);
|
||||
@@ -625,46 +909,58 @@ public class DependencyCheckTask extends Task {
|
||||
validateConfiguration();
|
||||
populateSettings();
|
||||
|
||||
final Engine engine = new Engine();
|
||||
for (Resource resource : path) {
|
||||
final FileProvider provider = resource.as(FileProvider.class);
|
||||
if (provider != null) {
|
||||
final File file = provider.getFile();
|
||||
if (file != null && file.exists()) {
|
||||
engine.scan(file);
|
||||
}
|
||||
}
|
||||
}
|
||||
Engine engine = null;
|
||||
try {
|
||||
engine.analyzeDependencies();
|
||||
DatabaseProperties prop = null;
|
||||
CveDB cve = null;
|
||||
try {
|
||||
cve = new CveDB();
|
||||
cve.open();
|
||||
prop = cve.getDatabaseProperties();
|
||||
} catch (DatabaseException ex) {
|
||||
Logger.getLogger(DependencyCheckTask.class.getName()).log(Level.FINE, "Unable to retrieve DB Properties", ex);
|
||||
} finally {
|
||||
if (cve != null) {
|
||||
cve.close();
|
||||
engine = new Engine(DependencyCheckTask.class.getClassLoader());
|
||||
|
||||
for (Resource resource : path) {
|
||||
final FileProvider provider = resource.as(FileProvider.class);
|
||||
if (provider != null) {
|
||||
final File file = provider.getFile();
|
||||
if (file != null && file.exists()) {
|
||||
engine.scan(file);
|
||||
}
|
||||
}
|
||||
}
|
||||
final ReportGenerator reporter = new ReportGenerator(applicationName, engine.getDependencies(), engine.getAnalyzers(), prop);
|
||||
reporter.generateReports(reportOutputDirectory, reportFormat);
|
||||
try {
|
||||
engine.analyzeDependencies();
|
||||
DatabaseProperties prop = null;
|
||||
CveDB cve = null;
|
||||
try {
|
||||
cve = new CveDB();
|
||||
cve.open();
|
||||
prop = cve.getDatabaseProperties();
|
||||
} catch (DatabaseException ex) {
|
||||
LOGGER.log(Level.FINE, "Unable to retrieve DB Properties", ex);
|
||||
} finally {
|
||||
if (cve != null) {
|
||||
cve.close();
|
||||
}
|
||||
}
|
||||
final ReportGenerator reporter = new ReportGenerator(applicationName, engine.getDependencies(), engine.getAnalyzers(), prop);
|
||||
reporter.generateReports(reportOutputDirectory, reportFormat);
|
||||
|
||||
if (this.failBuildOnCVSS <= 10) {
|
||||
checkForFailure(engine.getDependencies());
|
||||
if (this.failBuildOnCVSS <= 10) {
|
||||
checkForFailure(engine.getDependencies());
|
||||
}
|
||||
if (this.showSummary) {
|
||||
showSummary(engine.getDependencies());
|
||||
}
|
||||
} catch (IOException ex) {
|
||||
LOGGER.log(Level.FINE, "Unable to generate dependency-check report", ex);
|
||||
throw new BuildException("Unable to generate dependency-check report", ex);
|
||||
} catch (Exception ex) {
|
||||
LOGGER.log(Level.FINE, "An exception occurred; unable to continue task", ex);
|
||||
throw new BuildException("An exception occurred; unable to continue task", ex);
|
||||
}
|
||||
if (this.showSummary) {
|
||||
showSummary(engine.getDependencies());
|
||||
} catch (DatabaseException ex) {
|
||||
LOGGER.log(Level.SEVERE, "Unable to connect to the dependency-check database; analysis has stopped");
|
||||
LOGGER.log(Level.FINE, "", ex);
|
||||
} finally {
|
||||
Settings.cleanup(true);
|
||||
if (engine != null) {
|
||||
engine.cleanup();
|
||||
}
|
||||
} catch (IOException ex) {
|
||||
Logger.getLogger(DependencyCheckTask.class.getName()).log(Level.FINE, "Unable to generate dependency-check report", ex);
|
||||
throw new BuildException("Unable to generate dependency-check report", ex);
|
||||
} catch (Exception ex) {
|
||||
Logger.getLogger(DependencyCheckTask.class.getName()).log(Level.FINE, "An exception occurred; unable to continue task", ex);
|
||||
throw new BuildException("An exception occurred; unable to continue task", ex);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -683,23 +979,24 @@ public class DependencyCheckTask extends Task {
|
||||
}
|
||||
|
||||
/**
|
||||
* Takes the properties supplied and updates the dependency-check settings. Additionally, this sets the system
|
||||
* properties required to change the proxy url, port, and connection timeout.
|
||||
* Takes the properties supplied and updates the dependency-check settings. Additionally, this sets the system properties
|
||||
* required to change the proxy server, port, and connection timeout.
|
||||
*/
|
||||
private void populateSettings() {
|
||||
Settings.initialize();
|
||||
InputStream taskProperties = null;
|
||||
try {
|
||||
taskProperties = this.getClass().getClassLoader().getResourceAsStream(PROPERTIES_FILE);
|
||||
Settings.mergeProperties(taskProperties);
|
||||
} catch (IOException ex) {
|
||||
Logger.getLogger(DependencyCheckTask.class.getName()).log(Level.WARNING, "Unable to load the dependency-check ant task.properties file.");
|
||||
Logger.getLogger(DependencyCheckTask.class.getName()).log(Level.FINE, null, ex);
|
||||
LOGGER.log(Level.WARNING, "Unable to load the dependency-check ant task.properties file.");
|
||||
LOGGER.log(Level.FINE, null, ex);
|
||||
} finally {
|
||||
if (taskProperties != null) {
|
||||
try {
|
||||
taskProperties.close();
|
||||
} catch (IOException ex) {
|
||||
Logger.getLogger(DependencyCheckTask.class.getName()).log(Level.FINEST, null, ex);
|
||||
LOGGER.log(Level.FINEST, null, ex);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -715,8 +1012,8 @@ public class DependencyCheckTask extends Task {
|
||||
|
||||
Settings.setBoolean(Settings.KEYS.AUTO_UPDATE, autoUpdate);
|
||||
|
||||
if (proxyUrl != null && !proxyUrl.isEmpty()) {
|
||||
Settings.setString(Settings.KEYS.PROXY_URL, proxyUrl);
|
||||
if (proxyServer != null && !proxyServer.isEmpty()) {
|
||||
Settings.setString(Settings.KEYS.PROXY_SERVER, proxyServer);
|
||||
}
|
||||
if (proxyPort != null && !proxyPort.isEmpty()) {
|
||||
Settings.setString(Settings.KEYS.PROXY_PORT, proxyPort);
|
||||
@@ -733,10 +1030,31 @@ public class DependencyCheckTask extends Task {
|
||||
if (suppressionFile != null && !suppressionFile.isEmpty()) {
|
||||
Settings.setString(Settings.KEYS.SUPPRESSION_FILE, suppressionFile);
|
||||
}
|
||||
|
||||
//File Type Analyzer Settings
|
||||
//JAR ANALYZER
|
||||
Settings.setBoolean(Settings.KEYS.ANALYZER_JAR_ENABLED, jarAnalyzerEnabled);
|
||||
//NUSPEC ANALYZER
|
||||
Settings.setBoolean(Settings.KEYS.ANALYZER_NUSPEC_ENABLED, nuspecAnalyzerEnabled);
|
||||
//CENTRAL ANALYZER
|
||||
Settings.setBoolean(Settings.KEYS.ANALYZER_CENTRAL_ENABLED, centralAnalyzerEnabled);
|
||||
//NEXUS ANALYZER
|
||||
Settings.setBoolean(Settings.KEYS.ANALYZER_NEXUS_ENABLED, nexusAnalyzerEnabled);
|
||||
if (nexusUrl != null && !nexusUrl.isEmpty()) {
|
||||
Settings.setString(Settings.KEYS.ANALYZER_NEXUS_URL, nexusUrl);
|
||||
}
|
||||
Settings.setBoolean(Settings.KEYS.ANALYZER_NEXUS_PROXY, nexusUsesProxy);
|
||||
//ARCHIVE ANALYZER
|
||||
Settings.setBoolean(Settings.KEYS.ANALYZER_ARCHIVE_ENABLED, archiveAnalyzerEnabled);
|
||||
if (zipExtensions != null && !zipExtensions.isEmpty()) {
|
||||
Settings.setString(Settings.KEYS.ADDITIONAL_ZIP_EXTENSIONS, zipExtensions);
|
||||
}
|
||||
//ASSEMBLY ANALYZER
|
||||
Settings.setBoolean(Settings.KEYS.ANALYZER_ASSEMBLY_ENABLED, assemblyAnalyzerEnabled);
|
||||
if (pathToMono != null && !pathToMono.isEmpty()) {
|
||||
Settings.setString(Settings.KEYS.ANALYZER_ASSEMBLY_MONO_PATH, pathToMono);
|
||||
}
|
||||
|
||||
if (databaseDriverName != null && !databaseDriverName.isEmpty()) {
|
||||
Settings.setString(Settings.KEYS.DB_DRIVER_NAME, databaseDriverName);
|
||||
}
|
||||
@@ -752,6 +1070,18 @@ public class DependencyCheckTask extends Task {
|
||||
if (databasePassword != null && !databasePassword.isEmpty()) {
|
||||
Settings.setString(Settings.KEYS.DB_PASSWORD, databasePassword);
|
||||
}
|
||||
if (cveUrl12Modified != null && !cveUrl12Modified.isEmpty()) {
|
||||
Settings.setString(Settings.KEYS.CVE_MODIFIED_12_URL, cveUrl12Modified);
|
||||
}
|
||||
if (cveUrl20Modified != null && !cveUrl20Modified.isEmpty()) {
|
||||
Settings.setString(Settings.KEYS.CVE_MODIFIED_20_URL, cveUrl20Modified);
|
||||
}
|
||||
if (cveUrl12Base != null && !cveUrl12Base.isEmpty()) {
|
||||
Settings.setString(Settings.KEYS.CVE_SCHEMA_1_2, cveUrl12Base);
|
||||
}
|
||||
if (cveUrl20Base != null && !cveUrl20Base.isEmpty()) {
|
||||
Settings.setString(Settings.KEYS.CVE_SCHEMA_2_0, cveUrl20Base);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -818,7 +1148,7 @@ public class DependencyCheckTask extends Task {
|
||||
final String msg = String.format("%n%n"
|
||||
+ "One or more dependencies were identified with known vulnerabilities:%n%n%s"
|
||||
+ "%n%nSee the dependency-check report for more details.%n%n", summary.toString());
|
||||
Logger.getLogger(DependencyCheckTask.class.getName()).log(Level.WARNING, msg);
|
||||
LOGGER.log(Level.WARNING, msg);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -843,4 +1173,18 @@ public class DependencyCheckTask extends Task {
|
||||
return values;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Whether or not the Jar Analyzer is enabled.
|
||||
*/
|
||||
private boolean jarAnalyzerEnabled = true;
|
||||
|
||||
/**
|
||||
* Returns whether or not the analyzer is enabled.
|
||||
*
|
||||
* @return true if the analyzer is enabled
|
||||
*/
|
||||
public boolean isJarAnalyzerEnabled() {
|
||||
return jarAnalyzerEnabled;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -18,29 +18,61 @@ the project's dependencies.
|
||||
</dependency-check>
|
||||
</target>
|
||||
```
|
||||
The following table lists the configurable properties:
|
||||
|
||||
Property | Description | Requirement
|
||||
----------------------|-------------|---------
|
||||
ApplicationName | The name of the application to use in the generated report. | Required
|
||||
ReportFormat | The format of the report to be generated. Allowed values are: HTML, XML, VULN, or ALL. The default value is HTML.| Optional
|
||||
ReportOutputDirectory | The directory where dependency-check will store data used for analysis. Defaults to the current working directory. | Optional
|
||||
FailBuildOn | If set and a CVE is found that is greater then the specified value the build will fail. The default value is 11 which means that the build will not fail. Valid values are 0-11. | Optional
|
||||
AutoUpdate | If set to false the NVD CVE data is not automatically updated. Setting this to false could result in false negatives. However, this may be required in some environments. The default value is true. | Optional
|
||||
DataDirectory | The directory where dependency-check will store data used for analysis. Defaults to a folder called, called 'dependency-check-data', that is in the same directory as the dependency-check-ant jar file was installed in. *It is not recommended to change this.* | Optional
|
||||
LogFile | The file path to write verbose logging information. | Optional
|
||||
SuppressionFile | An XML file conforming to the suppression schema that suppresses findings; this is used to hide [false positives](../suppression.html). | Optional
|
||||
ProxyUrl | Defines the proxy used to connect to the Internet. | Optional
|
||||
ProxyPort | Defines the port for the proxy. | Optional
|
||||
ProxyUsername | Defines the proxy user name. | Optional
|
||||
ProxyPassword | Defines the proxy password. | Optional
|
||||
ConnectionTimeout | The connection timeout used when downloading data files from the Internet. | Optional
|
||||
nexusAnalyzerEnabled | The connection timeout used when downloading data files from the Internet. | Optional
|
||||
nexusUrl | The connection timeout used when downloading data files from the Internet. | Optional
|
||||
databaseDriverName | The name of the database driver. Example: org.h2.Driver. | Optional
|
||||
databaseDriverPath | The path to the database driver JAR file; only used if the driver is not in the class path. | Optional
|
||||
connectionString | The connection string used to connect to the database. | Optional
|
||||
databaseUser | The username used when connecting to the database. | Optional
|
||||
databasePassword | The password used when connecting to the database. | Optional
|
||||
Configuration
|
||||
====================
|
||||
The following properties can be set on the dependency-check-maven plugin.
|
||||
|
||||
Property | Description | Default Value
|
||||
---------------------|------------------------------------|------------------
|
||||
autoUpdate | Sets whether auto-updating of the NVD CVE/CPE data is enabled. It is not recommended that this be turned to false. | true
|
||||
externalReport | When using as a Site plugin this parameter sets whether or not the external report format should be used. | false
|
||||
outputDirectory | The location to write the report(s). Note, this is not used if generating the report as part of a `mvn site` build | 'target'
|
||||
failBuildOnCVSS | Specifies if the build should be failed if a CVSS score above a specified level is identified. The default is 11 which means since the CVSS scores are 0-10, by default the build will never fail. | 11
|
||||
format | The report format to be generated (HTML, XML, VULN, ALL). This configuration option has no affect if using this within the Site plugin unless the externalReport is set to true. | HTML
|
||||
logFile | The file path to write verbose logging information. |
|
||||
suppressionFile | The file path to the XML suppression file \- used to suppress [false positives](../suppression.html) |
|
||||
proxyServer | The Proxy Server. |
|
||||
proxyPort | The Proxy Port. |
|
||||
proxyUsername | Defines the proxy user name. |
|
||||
proxyPassword | Defines the proxy password. |
|
||||
connectionTimeout | The URL Connection Timeout. |
|
||||
|
||||
Analyzer Configuration
|
||||
====================
|
||||
The following properties are used to configure the various file type analyzers.
|
||||
These properties can be used to turn off specific analyzers if it is not needed.
|
||||
Note, that specific analyzers will automatically disable themselves if no file
|
||||
types that they support are detected - so specifically disabling them may not
|
||||
be needed.
|
||||
|
||||
Property | Description | Default Value
|
||||
------------------------|---------------------------------------------------------------------------|------------------
|
||||
archiveAnalyzerEnabled | Sets whether the Archive Analyzer will be used. | true
|
||||
zipExtensions | A comma-separated list of additional file extensions to be treated like a ZIP file, the contents will be extracted and analyzed. |
|
||||
jarAnalyzer | Sets whether the Jar Analyzer will be used. | true
|
||||
centralAnalyzerEnabled | Sets whether the Central Analyzer will be used. **Disabling this analyzer is not recommended as it could lead to false negatives (e.g. libraries that have vulnerabilities may not be reported correctly).** If this analyzer is being disabled there is a good chance you also want to disable the Nexus Analyzer (see below). | true
|
||||
nexusAnalyzerEnabled | Sets whether Nexus Analyzer will be used. This analyzer is superceded by the Central Analyzer; however, you can configure this to run against a Nexus Pro installation. | true
|
||||
nexusUrl | Defines the Nexus Pro URL. If not set the Nexus Analyzer will be disabled. |
|
||||
nexusUsesProxy | Whether or not the defined proxy should be used when connecting to Nexus. | true
|
||||
nuspecAnalyzerEnabled | Sets whether or not the .NET Nuget Nuspec Analyzer will be used. | true
|
||||
assemblyAnalyzerEnabled | Sets whether or not the .NET Assembly Analyzer should be used. | true
|
||||
pathToMono | The path to Mono for .NET assembly analysis on non-windows systems. |
|
||||
|
||||
Advanced Configuration
|
||||
====================
|
||||
The following properties can be configured in the plugin. However, they are less frequently changed. One exception
|
||||
may be the cvedUrl properties, which can be used to host a mirror of the NVD within an enterprise environment.
|
||||
|
||||
Property | Description | Default Value
|
||||
---------------------|-------------------------------------------------------------------------|------------------
|
||||
cveUrl12Modified | URL for the modified CVE 1.2 | http://nvd.nist.gov/download/nvdcve-modified.xml
|
||||
cveUrl20Modified | URL for the modified CVE 2.0 | http://static.nvd.nist.gov/feeds/xml/cve/nvdcve-2.0-modified.xml
|
||||
cveUrl12Base | Base URL for each year's CVE 1.2, the %d will be replaced with the year | http://nvd.nist.gov/download/nvdcve-%d.xml
|
||||
cveUrl20Base | Base URL for each year's CVE 2.0, the %d will be replaced with the year | http://static.nvd.nist.gov/feeds/xml/cve/nvdcve-2.0-%d.xml
|
||||
dataDirectory | Data directory to hold SQL CVEs contents. This should generally not be changed. |
|
||||
databaseDriverName | The name of the database driver. Example: org.h2.Driver. |
|
||||
databaseDriverPath | The path to the database driver JAR file; only used if the driver is not in the class path. |
|
||||
connectionString | The connection string used to connect to the database. |
|
||||
databaseUser | The username used when connecting to the database. |
|
||||
databasePassword | The password used when connecting to the database. |
|
||||
|
||||
@@ -3,7 +3,20 @@ Installation
|
||||
Download dependency-check-ant from [bintray here](http://dl.bintray.com/jeremy-long/owasp/dependency-check-ant-${project.version}.jar).
|
||||
To install dependency-check-ant place the dependency-check-ant-${project.version}.jar into
|
||||
the lib directory of your Ant instalation directory. Once installed you can add
|
||||
the taskdef to you build.xml and add the task to a new or existing target.
|
||||
the taskdef to you build.xml and add the task to a new or existing target:
|
||||
|
||||
```xml
|
||||
<taskdef name="dependency-check" classname="org.owasp.dependencycheck.taskdefs.DependencyCheckTask"/>
|
||||
```
|
||||
|
||||
If you do not want to install dependency-check-ant into your ant's lib directory when you define the task def you
|
||||
must add the classpath to the taskdef:
|
||||
|
||||
```xml
|
||||
<taskdef name="dependency-check" classname="org.owasp.dependencycheck.taskdefs.DependencyCheckTask">
|
||||
<classpath path="[path]/[to]/dependency-check-ant-${project.version}.jar"/>
|
||||
</taskdef>
|
||||
```
|
||||
|
||||
It is important to understand that the first time this task is executed it may
|
||||
take 20 minutes or more as it downloads and processes the data from the National
|
||||
|
||||
@@ -1,11 +1,19 @@
|
||||
Usage
|
||||
====================
|
||||
First, add the dependency-check-ant taskdef to your build.xml:
|
||||
First, add the dependency-check-ant taskdef to your build.xml (see the [installation guide](installation.html):
|
||||
|
||||
```xml
|
||||
<taskdef name="dependency-check" classname="org.owasp.dependencycheck.taskdefs.DependencyCheckTask"/>
|
||||
```
|
||||
|
||||
Or
|
||||
|
||||
```xml
|
||||
<taskdef name="dependency-check" classname="org.owasp.dependencycheck.taskdefs.DependencyCheckTask">
|
||||
<classpath path="[path]/[to]/dependency-check-ant-${project.version}.jar"/>
|
||||
</taskdef>
|
||||
```
|
||||
|
||||
Next, add the task to a target of your choosing:
|
||||
|
||||
```xml
|
||||
@@ -18,35 +18,27 @@
|
||||
package org.owasp.dependencycheck.taskdefs;
|
||||
|
||||
import java.io.File;
|
||||
import static junit.framework.TestCase.assertTrue;
|
||||
import org.apache.tools.ant.BuildFileTest;
|
||||
import org.junit.After;
|
||||
import org.junit.AfterClass;
|
||||
import org.junit.Before;
|
||||
import org.junit.BeforeClass;
|
||||
import org.junit.Test;
|
||||
import org.owasp.dependencycheck.data.nvdcve.BaseDBTestCase;
|
||||
import org.owasp.dependencycheck.utils.Settings;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author Jeremy Long <jeremy.long@owasp.org>
|
||||
*/
|
||||
public class DependencyCheckTaskTest extends BuildFileTest {
|
||||
|
||||
public DependencyCheckTaskTest() {
|
||||
}
|
||||
|
||||
@BeforeClass
|
||||
public static void setUpClass() {
|
||||
}
|
||||
|
||||
@AfterClass
|
||||
public static void tearDownClass() {
|
||||
}
|
||||
//TODO: The use of deprecated class BuildFileTestcan possibly
|
||||
//be replaced with BuildFileRule. However, it currently isn't included in the ant-testutil jar.
|
||||
//This should be fixed in ant-testutil 1.9.5, so we can check back once that has been released.
|
||||
//Reference: http://mail-archives.apache.org/mod_mbox/ant-user/201406.mbox/%3C000001cf87ba$8949b690$9bdd23b0$@de%3E
|
||||
|
||||
@Before
|
||||
@Override
|
||||
public void setUp() throws Exception {
|
||||
Settings.initialize();
|
||||
BaseDBTestCase.ensureDBExists();
|
||||
final String buildFile = this.getClass().getClassLoader().getResource("build.xml").getPath();
|
||||
configureProject(buildFile);
|
||||
@@ -57,6 +49,7 @@ public class DependencyCheckTaskTest extends BuildFileTest {
|
||||
public void tearDown() {
|
||||
//no cleanup...
|
||||
//executeTarget("cleanup");
|
||||
Settings.cleanup(true);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -64,7 +57,7 @@ public class DependencyCheckTaskTest extends BuildFileTest {
|
||||
*/
|
||||
@Test
|
||||
public void testAddFileSet() throws Exception {
|
||||
File report = new File("target/DependencyCheck-Report.html");
|
||||
File report = new File("target/dependency-check-report.html");
|
||||
if (report.exists()) {
|
||||
if (!report.delete()) {
|
||||
throw new Exception("Unable to delete 'target/DependencyCheck-Report.html' prior to test.");
|
||||
@@ -83,7 +76,7 @@ public class DependencyCheckTaskTest extends BuildFileTest {
|
||||
*/
|
||||
@Test
|
||||
public void testAddFileList() throws Exception {
|
||||
File report = new File("target/DependencyCheck-Report.xml");
|
||||
File report = new File("target/dependency-check-report.xml");
|
||||
if (report.exists()) {
|
||||
if (!report.delete()) {
|
||||
throw new Exception("Unable to delete 'target/DependencyCheck-Report.xml' prior to test.");
|
||||
@@ -101,7 +94,7 @@ public class DependencyCheckTaskTest extends BuildFileTest {
|
||||
*/
|
||||
@Test
|
||||
public void testAddDirSet() throws Exception {
|
||||
File report = new File("target/DependencyCheck-Vulnerability.html");
|
||||
File report = new File("target/dependency-check-vulnerability.html");
|
||||
if (report.exists()) {
|
||||
if (!report.delete()) {
|
||||
throw new Exception("Unable to delete 'target/DependencyCheck-Vulnerability.html' prior to test.");
|
||||
|
||||
@@ -1,223 +0,0 @@
|
||||
<?xml version="1.0"?>
|
||||
<!DOCTYPE module PUBLIC
|
||||
"-//Puppy Crawl//DTD Check Configuration 1.3//EN"
|
||||
"http://www.puppycrawl.com/dtds/configuration_1_3.dtd">
|
||||
|
||||
<module name="Checker">
|
||||
<!--
|
||||
If you set the basedir property below, then all reported file
|
||||
names will be relative to the specified directory. See
|
||||
http://checkstyle.sourceforge.net/5.x/config.html#Checker
|
||||
|
||||
<property name="basedir" value="${basedir}"/>
|
||||
-->
|
||||
|
||||
<property name="severity" value="error"/>
|
||||
|
||||
<module name="SuppressionFilter">
|
||||
<property name="file" value="${checkstyle.suppressions.file}"/>
|
||||
</module>
|
||||
|
||||
<module name="JavadocPackage">
|
||||
<property name="allowLegacy" value="false"/>
|
||||
</module>
|
||||
|
||||
<module name="Translation">
|
||||
<property name="severity" value="warning"/>
|
||||
</module>
|
||||
|
||||
<module name="FileTabCharacter">
|
||||
<property name="eachLine" value="false"/>
|
||||
</module>
|
||||
|
||||
<module name="FileLength">
|
||||
<property name="fileExtensions" value="java"/>
|
||||
</module>
|
||||
|
||||
<module name="NewlineAtEndOfFile">
|
||||
<property name="fileExtensions" value="java"/>
|
||||
<property name="lineSeparator" value="lf"/>
|
||||
</module>
|
||||
|
||||
<module name="RegexpHeader">
|
||||
<property name="headerFile" value="${checkstyle.header.file}"/>
|
||||
<property name="fileExtensions" value="java"/>
|
||||
<property name="id" value="header"/>
|
||||
</module>
|
||||
|
||||
<module name="RegexpSingleline">
|
||||
<property name="format" value="\s+$"/>
|
||||
<property name="minimum" value="0"/>
|
||||
<property name="maximum" value="0"/>
|
||||
</module>
|
||||
|
||||
<module name="TreeWalker">
|
||||
<property name="tabWidth" value="4"/>
|
||||
|
||||
<module name="AvoidStarImport"/>
|
||||
<module name="ConstantName"/>
|
||||
<module name="EmptyBlock"/>
|
||||
<module name="EmptyForIteratorPad"/>
|
||||
<module name="EqualsHashCode"/>
|
||||
<module name="OneStatementPerLine"/>
|
||||
|
||||
<!-- module name="IllegalCatch"/ -->
|
||||
<!--module name="ImportControl">
|
||||
<property name="file" value="${checkstyle.importcontrol.file}"/>
|
||||
</module-->
|
||||
<module name="IllegalImport"/>
|
||||
<module name="IllegalInstantiation"/>
|
||||
<module name="IllegalThrows"/>
|
||||
<module name="InnerAssignment"/>
|
||||
<module name="JavadocType">
|
||||
<property name="authorFormat" value="\S"/>
|
||||
</module>
|
||||
<module name="JavadocMethod">
|
||||
<property name="allowUndeclaredRTE" value="true"/>
|
||||
<property name="allowThrowsTagsForSubclasses" value="true"/>
|
||||
<property name="allowMissingPropertyJavadoc" value="true"/>
|
||||
</module>
|
||||
<module name="JavadocVariable"/>
|
||||
<module name="JavadocStyle">
|
||||
<property name="scope" value="public"/>
|
||||
</module>
|
||||
|
||||
<module name="LeftCurly">
|
||||
<property name="option" value="eol"/>
|
||||
<property name="tokens" value="CLASS_DEF"/>
|
||||
<property name="tokens" value="CTOR_DEF"/>
|
||||
<property name="tokens" value="INTERFACE_DEF"/>
|
||||
<property name="tokens" value="METHOD_DEF"/>
|
||||
<property name="tokens" value="LITERAL_CATCH"/>
|
||||
<property name="tokens" value="LITERAL_DO"/>
|
||||
<property name="tokens" value="LITERAL_ELSE"/>
|
||||
<property name="tokens" value="LITERAL_FINALLY"/>
|
||||
<property name="tokens" value="LITERAL_FOR"/>
|
||||
<property name="tokens" value="LITERAL_IF"/>
|
||||
<property name="tokens" value="LITERAL_SWITCH"/>
|
||||
<property name="tokens" value="LITERAL_SYNCHRONIZED"/>
|
||||
<property name="tokens" value="LITERAL_TRY"/>
|
||||
<property name="tokens" value="LITERAL_WHILE"/>
|
||||
</module>
|
||||
|
||||
<module name="OuterTypeNumber"/>
|
||||
<module name="LineLength">
|
||||
<property name="ignorePattern" value="^ *\* *[^ ]+$"/>
|
||||
<property name="max" value="150"/>
|
||||
</module>
|
||||
|
||||
<module name="MethodCount">
|
||||
<property name="maxTotal" value="40"/>
|
||||
</module>
|
||||
|
||||
<module name="LocalFinalVariableName"/>
|
||||
<module name="LocalVariableName"/>
|
||||
<module name="MemberName">
|
||||
<property name="format" value="^[a-z][a-zA-Z0-9]*$"/>
|
||||
</module>
|
||||
<module name="MethodLength">
|
||||
<property name="max" value="160"/>
|
||||
<property name="countEmpty" value="false"/>
|
||||
</module>
|
||||
<module name="MethodName"/>
|
||||
<module name="MethodParamPad"/>
|
||||
<module name="ModifierOrder"/>
|
||||
<module name="NeedBraces"/>
|
||||
<module name="NoWhitespaceAfter">
|
||||
<property name="tokens" value="ARRAY_INIT"/>
|
||||
<property name="tokens" value="BNOT"/>
|
||||
<property name="tokens" value="DEC"/>
|
||||
<property name="tokens" value="DOT"/>
|
||||
<property name="tokens" value="INC"/>
|
||||
<property name="tokens" value="LNOT"/>
|
||||
<property name="tokens" value="UNARY_MINUS"/>
|
||||
<property name="tokens" value="UNARY_PLUS"/>
|
||||
</module>
|
||||
|
||||
<module name="NoWhitespaceBefore"/>
|
||||
<module name="NoWhitespaceBefore">
|
||||
<property name="tokens" value="DOT"/>
|
||||
<property name="allowLineBreaks" value="true"/>
|
||||
</module>
|
||||
|
||||
<module name="OperatorWrap"/>
|
||||
<module name="OperatorWrap">
|
||||
<property name="tokens" value="ASSIGN"/>
|
||||
<property name="tokens" value="DIV_ASSIGN"/>
|
||||
<property name="tokens" value="PLUS_ASSIGN"/>
|
||||
<property name="tokens" value="MINUS_ASSIGN"/>
|
||||
<property name="tokens" value="STAR_ASSIGN"/>
|
||||
<property name="tokens" value="MOD_ASSIGN"/>
|
||||
<property name="tokens" value="SR_ASSIGN"/>
|
||||
<property name="tokens" value="BSR_ASSIGN"/>
|
||||
<property name="tokens" value="SL_ASSIGN"/>
|
||||
<property name="tokens" value="BXOR_ASSIGN"/>
|
||||
<property name="tokens" value="BOR_ASSIGN"/>
|
||||
<property name="tokens" value="BAND_ASSIGN"/>
|
||||
<property name="option" value="eol"/>
|
||||
</module>
|
||||
<module name="PackageName"/>
|
||||
<module name="ParameterName">
|
||||
<property name="format" value="^[a-z][a-zA-Z0-9]*$"/>
|
||||
</module>
|
||||
<module name="ParameterNumber">
|
||||
<property name="id" value="paramNum"/>
|
||||
</module>
|
||||
<module name="ParenPad"/>
|
||||
<module name="TypecastParenPad"/>
|
||||
<module name="RedundantImport"/>
|
||||
<module name="RedundantModifier"/>
|
||||
<module name="RightCurly">
|
||||
<property name="option" value="same"/>
|
||||
</module>
|
||||
<module name="SimplifyBooleanExpression"/>
|
||||
<module name="SimplifyBooleanReturn"/>
|
||||
<module name="StaticVariableName">
|
||||
<property name="format" value="^[a-z][a-zA-Z0-9]*$"/>
|
||||
</module>
|
||||
<module name="TypeName"/>
|
||||
<module name="UnusedImports"/>
|
||||
<module name="UpperEll"/>
|
||||
<module name="VisibilityModifier"/>
|
||||
<module name="WhitespaceAfter"/>
|
||||
<module name="WhitespaceAround"/>
|
||||
<module name="GenericWhitespace"/>
|
||||
<module name="FinalClass"/>
|
||||
<module name="MissingSwitchDefault"/>
|
||||
<!--module name="MagicNumber"/-->
|
||||
<!--module name="Indentation">
|
||||
<property name="basicOffset" value="4"/>
|
||||
<property name="braceAdjustment" value="0"/>
|
||||
<property name="caseIndent" value="0"/>
|
||||
</module-->
|
||||
<module name="ArrayTrailingComma"/>
|
||||
<module name="FinalLocalVariable"/>
|
||||
<module name="EqualsAvoidNull"/>
|
||||
<module name="ParameterAssignment"/>
|
||||
|
||||
<!-- Generates quite a few errors -->
|
||||
<module name="CyclomaticComplexity">
|
||||
<property name="severity" value="ignore"/>
|
||||
</module>
|
||||
|
||||
<module name="NestedForDepth">
|
||||
<property name="max" value="2"/>
|
||||
</module>
|
||||
<module name="NestedIfDepth">
|
||||
<property name="max" value="4"/>
|
||||
</module>
|
||||
<module name="NestedTryDepth">
|
||||
<property name="max" value="2"/>
|
||||
</module>
|
||||
<!--module name="ExplicitInitialization"/-->
|
||||
<module name="AnnotationUseStyle"/>
|
||||
<module name="MissingDeprecated"/>
|
||||
<module name="MissingOverride">
|
||||
<property name="javaFiveCompatibility" value="true"/>
|
||||
</module>
|
||||
<module name="PackageAnnotation"/>
|
||||
<module name="SuppressWarnings"/>
|
||||
<module name="OuterTypeFilename"/>
|
||||
<module name="HideUtilityClassConstructor"/>
|
||||
</module>
|
||||
</module>
|
||||
@@ -1,9 +0,0 @@
|
||||
<?xml version="1.0"?>
|
||||
|
||||
<!DOCTYPE suppressions PUBLIC
|
||||
"-//Puppy Crawl//DTD Suppressions 1.0//EN"
|
||||
"http://www.puppycrawl.com/dtds/suppressions_1_0.dtd">
|
||||
|
||||
<suppressions>
|
||||
<suppress checks=".*" files=".*[\\/]package-info\.java" />
|
||||
</suppressions>
|
||||
@@ -15,20 +15,19 @@ limitations under the License.
|
||||
|
||||
Copyright (c) 2012 - Jeremy Long. All Rights Reserved.
|
||||
-->
|
||||
|
||||
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
<parent>
|
||||
<groupId>org.owasp</groupId>
|
||||
<artifactId>dependency-check-parent</artifactId>
|
||||
<version>1.1.1</version>
|
||||
<version>1.2.9</version>
|
||||
</parent>
|
||||
|
||||
<artifactId>dependency-check-cli</artifactId>
|
||||
<packaging>jar</packaging>
|
||||
|
||||
<name>Dependency-Check Command Line</name>
|
||||
<description>Dependency-Check-Maven is a Maven Plugin that attempts to detect publicly disclosed vulnerabilities contained within project dependencies. It does this by determining if there is a Common Platform Enumeration (CPE) identifier for a given dependency. If found, it will generate a report linking to the associated CVE entries.</description>
|
||||
<description>dependency-check-cli is an command line tool that uses dependency-check-core to detect publicly disclosed vulnerabilities associated with the scanned project dependencies. The tool will generate a report listing the dependency, any identified Common Platform Enumeration (CPE) identifiers, and the associated Common Vulnerability and Exposure (CVE) entries.</description>
|
||||
<!-- begin copy from http://minds.coremedia.com/2012/09/11/problem-solved-deploy-multi-module-maven-project-site-as-github-pages/ -->
|
||||
<distributionManagement>
|
||||
<site>
|
||||
@@ -61,24 +60,21 @@ Copyright (c) 2012 - Jeremy Long. All Rights Reserved.
|
||||
<plugin>
|
||||
<groupId>org.apache.maven.plugins</groupId>
|
||||
<artifactId>maven-jar-plugin</artifactId>
|
||||
<version>2.4</version>
|
||||
<configuration>
|
||||
<archive>
|
||||
<manifest>
|
||||
<mainClass>org.owasp.dependencycheck.App</mainClass>
|
||||
<addDefaultImplementationEntries>true</addDefaultImplementationEntries>
|
||||
</manifest>
|
||||
</archive>
|
||||
<excludes>
|
||||
<exclude>**/checkstyle*</exclude>
|
||||
</excludes>
|
||||
</configuration>
|
||||
</plugin>
|
||||
<plugin>
|
||||
<groupId>org.codehaus.mojo</groupId>
|
||||
<artifactId>cobertura-maven-plugin</artifactId>
|
||||
<version>2.5.2</version>
|
||||
<configuration>
|
||||
<!--instrumentation>
|
||||
<ignoreTrivial>true</ignoreTrivial>
|
||||
</instrumentation-->
|
||||
<check>
|
||||
<branchRate>85</branchRate>
|
||||
<lineRate>85</lineRate>
|
||||
@@ -112,14 +108,8 @@ Copyright (c) 2012 - Jeremy Long. All Rights Reserved.
|
||||
<plugin>
|
||||
<groupId>org.apache.maven.plugins</groupId>
|
||||
<artifactId>maven-surefire-plugin</artifactId>
|
||||
<version>2.16</version>
|
||||
<configuration>
|
||||
<systemProperties>
|
||||
<property>
|
||||
<name>net.sourceforge.cobertura.datafile</name>
|
||||
<value>${project.build.directory}/cobertura/cobertura.ser</value>
|
||||
<workingDirectory>target</workingDirectory>
|
||||
</property>
|
||||
<property>
|
||||
<name>cpe</name>
|
||||
<value>data/cpe</value>
|
||||
@@ -136,156 +126,15 @@ Copyright (c) 2012 - Jeremy Long. All Rights Reserved.
|
||||
<plugin>
|
||||
<groupId>org.apache.maven.plugins</groupId>
|
||||
<artifactId>maven-compiler-plugin</artifactId>
|
||||
<version>3.1</version>
|
||||
<configuration>
|
||||
<showDeprecation>false</showDeprecation>
|
||||
<source>1.6</source>
|
||||
<target>1.6</target>
|
||||
</configuration>
|
||||
</plugin>
|
||||
<plugin>
|
||||
<groupId>org.apache.maven.plugins</groupId>
|
||||
<artifactId>maven-site-plugin</artifactId>
|
||||
<version>3.3</version>
|
||||
<dependencies>
|
||||
<dependency>
|
||||
<groupId>org.apache.maven.doxia</groupId>
|
||||
<artifactId>doxia-module-markdown</artifactId>
|
||||
<version>1.5</version>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
<configuration>
|
||||
<skipDeploy>true</skipDeploy>
|
||||
<reportPlugins>
|
||||
<plugin>
|
||||
<groupId>org.apache.maven.plugins</groupId>
|
||||
<artifactId>maven-project-info-reports-plugin</artifactId>
|
||||
<version>2.7</version>
|
||||
<reportSets>
|
||||
<reportSet>
|
||||
<reports>
|
||||
<report>index</report>
|
||||
<report>summary</report>
|
||||
<report>license</report>
|
||||
<report>help</report>
|
||||
</reports>
|
||||
</reportSet>
|
||||
</reportSets>
|
||||
</plugin>
|
||||
<plugin>
|
||||
<groupId>org.apache.maven.plugins</groupId>
|
||||
<artifactId>maven-javadoc-plugin</artifactId>
|
||||
<version>2.9.1</version>
|
||||
<reportSets>
|
||||
<reportSet>
|
||||
<id>default</id>
|
||||
<reports>
|
||||
<report>javadoc</report>
|
||||
</reports>
|
||||
</reportSet>
|
||||
</reportSets>
|
||||
</plugin>
|
||||
<plugin>
|
||||
<groupId>org.codehaus.mojo</groupId>
|
||||
<artifactId>versions-maven-plugin</artifactId>
|
||||
<version>2.1</version>
|
||||
<reportSets>
|
||||
<reportSet>
|
||||
<reports>
|
||||
<report>dependency-updates-report</report>
|
||||
<report>plugin-updates-report</report>
|
||||
</reports>
|
||||
</reportSet>
|
||||
</reportSets>
|
||||
</plugin>
|
||||
<plugin>
|
||||
<groupId>org.apache.maven.plugins</groupId>
|
||||
<artifactId>maven-jxr-plugin</artifactId>
|
||||
<version>2.4</version>
|
||||
</plugin>
|
||||
<plugin>
|
||||
<groupId>org.codehaus.mojo</groupId>
|
||||
<artifactId>cobertura-maven-plugin</artifactId>
|
||||
<version>2.5.2</version>
|
||||
</plugin>
|
||||
<plugin>
|
||||
<groupId>org.apache.maven.plugins</groupId>
|
||||
<artifactId>maven-surefire-report-plugin</artifactId>
|
||||
<version>2.16</version>
|
||||
<reportSets>
|
||||
<reportSet>
|
||||
<reports>
|
||||
<report>report-only</report>
|
||||
</reports>
|
||||
</reportSet>
|
||||
</reportSets>
|
||||
</plugin>
|
||||
<plugin>
|
||||
<groupId>org.codehaus.mojo</groupId>
|
||||
<artifactId>taglist-maven-plugin</artifactId>
|
||||
<version>2.4</version>
|
||||
<configuration>
|
||||
<tagListOptions>
|
||||
<tagClasses>
|
||||
<tagClass>
|
||||
<displayName>Todo Work</displayName>
|
||||
<tags>
|
||||
<tag>
|
||||
<matchString>todo</matchString>
|
||||
<matchType>ignoreCase</matchType>
|
||||
</tag>
|
||||
<tag>
|
||||
<matchString>FIXME</matchString>
|
||||
<matchType>exact</matchType>
|
||||
</tag>
|
||||
</tags>
|
||||
</tagClass>
|
||||
</tagClasses>
|
||||
</tagListOptions>
|
||||
</configuration>
|
||||
</plugin>
|
||||
<plugin>
|
||||
<groupId>org.apache.maven.plugins</groupId>
|
||||
<artifactId>maven-checkstyle-plugin</artifactId>
|
||||
<version>2.11</version>
|
||||
<configuration>
|
||||
<enableRulesSummary>false</enableRulesSummary>
|
||||
<configLocation>${basedir}/config/checkstyle-checks.xml</configLocation>
|
||||
<headerLocation>${basedir}/config/checkstyle-header.txt</headerLocation>
|
||||
<suppressionsLocation>${basedir}/config/checkstyle-suppressions.xml</suppressionsLocation>
|
||||
<suppressionsFileExpression>checkstyle.suppressions.file</suppressionsFileExpression>
|
||||
</configuration>
|
||||
</plugin>
|
||||
<plugin>
|
||||
<groupId>org.apache.maven.plugins</groupId>
|
||||
<artifactId>maven-pmd-plugin</artifactId>
|
||||
<version>3.0.1</version>
|
||||
<configuration>
|
||||
<targetJdk>1.6</targetJdk>
|
||||
<linkXref>true</linkXref>
|
||||
<sourceEncoding>utf-8</sourceEncoding>
|
||||
<excludes>
|
||||
<exclude>**/generated/*.java</exclude>
|
||||
</excludes>
|
||||
</configuration>
|
||||
</plugin>
|
||||
<plugin>
|
||||
<groupId>org.codehaus.mojo</groupId>
|
||||
<artifactId>findbugs-maven-plugin</artifactId>
|
||||
<version>2.5.3</version>
|
||||
</plugin>
|
||||
</reportPlugins>
|
||||
</configuration>
|
||||
</plugin>
|
||||
<plugin>
|
||||
<groupId>org.codehaus.mojo</groupId>
|
||||
<artifactId>appassembler-maven-plugin</artifactId>
|
||||
<version>1.7</version>
|
||||
<configuration>
|
||||
<programs>
|
||||
<program>
|
||||
<mainClass>org.owasp.dependencycheck.App</mainClass>
|
||||
<name>dependency-check</name>
|
||||
<id>dependency-check</id>
|
||||
</program>
|
||||
</programs>
|
||||
<assembleDirectory>${project.build.directory}/release</assembleDirectory>
|
||||
@@ -326,6 +175,137 @@ Copyright (c) 2012 - Jeremy Long. All Rights Reserved.
|
||||
</plugin>
|
||||
</plugins>
|
||||
</build>
|
||||
<reporting>
|
||||
<plugins>
|
||||
<plugin>
|
||||
<groupId>org.apache.maven.plugins</groupId>
|
||||
<artifactId>maven-project-info-reports-plugin</artifactId>
|
||||
<version>2.7</version>
|
||||
<reportSets>
|
||||
<reportSet>
|
||||
<reports>
|
||||
<report>index</report>
|
||||
<report>summary</report>
|
||||
<report>license</report>
|
||||
<report>help</report>
|
||||
</reports>
|
||||
</reportSet>
|
||||
</reportSets>
|
||||
</plugin>
|
||||
<plugin>
|
||||
<groupId>org.apache.maven.plugins</groupId>
|
||||
<artifactId>maven-javadoc-plugin</artifactId>
|
||||
<version>2.9.1</version>
|
||||
<configuration>
|
||||
<bottom>Copyright© 2012-15 Jeremy Long. All Rights Reserved.</bottom>
|
||||
</configuration>
|
||||
<reportSets>
|
||||
<reportSet>
|
||||
<id>default</id>
|
||||
<reports>
|
||||
<report>javadoc</report>
|
||||
</reports>
|
||||
</reportSet>
|
||||
</reportSets>
|
||||
</plugin>
|
||||
<plugin>
|
||||
<groupId>org.codehaus.mojo</groupId>
|
||||
<artifactId>versions-maven-plugin</artifactId>
|
||||
<version>2.1</version>
|
||||
<reportSets>
|
||||
<reportSet>
|
||||
<reports>
|
||||
<report>dependency-updates-report</report>
|
||||
<report>plugin-updates-report</report>
|
||||
</reports>
|
||||
</reportSet>
|
||||
</reportSets>
|
||||
</plugin>
|
||||
<plugin>
|
||||
<groupId>org.apache.maven.plugins</groupId>
|
||||
<artifactId>maven-jxr-plugin</artifactId>
|
||||
<version>2.4</version>
|
||||
</plugin>
|
||||
<plugin>
|
||||
<groupId>org.codehaus.mojo</groupId>
|
||||
<artifactId>cobertura-maven-plugin</artifactId>
|
||||
<version>2.6</version>
|
||||
</plugin>
|
||||
<plugin>
|
||||
<groupId>org.apache.maven.plugins</groupId>
|
||||
<artifactId>maven-surefire-report-plugin</artifactId>
|
||||
<version>2.16</version>
|
||||
<reportSets>
|
||||
<reportSet>
|
||||
<reports>
|
||||
<report>report-only</report>
|
||||
</reports>
|
||||
</reportSet>
|
||||
</reportSets>
|
||||
</plugin>
|
||||
<plugin>
|
||||
<groupId>org.codehaus.mojo</groupId>
|
||||
<artifactId>taglist-maven-plugin</artifactId>
|
||||
<version>2.4</version>
|
||||
<configuration>
|
||||
<tagListOptions>
|
||||
<tagClasses>
|
||||
<tagClass>
|
||||
<displayName>Todo Work</displayName>
|
||||
<tags>
|
||||
<tag>
|
||||
<matchString>todo</matchString>
|
||||
<matchType>ignoreCase</matchType>
|
||||
</tag>
|
||||
<tag>
|
||||
<matchString>FIXME</matchString>
|
||||
<matchType>exact</matchType>
|
||||
</tag>
|
||||
</tags>
|
||||
</tagClass>
|
||||
</tagClasses>
|
||||
</tagListOptions>
|
||||
</configuration>
|
||||
</plugin>
|
||||
<plugin>
|
||||
<groupId>org.apache.maven.plugins</groupId>
|
||||
<artifactId>maven-checkstyle-plugin</artifactId>
|
||||
<version>2.11</version>
|
||||
<configuration>
|
||||
<enableRulesSummary>false</enableRulesSummary>
|
||||
<enableFilesSummary>false</enableFilesSummary>
|
||||
<configLocation>${basedir}/../src/main/config/checkstyle-checks.xml</configLocation>
|
||||
<headerLocation>${basedir}/../src/main/config/checkstyle-header.txt</headerLocation>
|
||||
<suppressionsLocation>${basedir}/../src/main/config/checkstyle-suppressions.xml</suppressionsLocation>
|
||||
<suppressionsFileExpression>checkstyle.suppressions.file</suppressionsFileExpression>
|
||||
</configuration>
|
||||
</plugin>
|
||||
<plugin>
|
||||
<groupId>org.apache.maven.plugins</groupId>
|
||||
<artifactId>maven-pmd-plugin</artifactId>
|
||||
<version>3.1</version>
|
||||
<configuration>
|
||||
<targetJdk>1.6</targetJdk>
|
||||
<linkXref>true</linkXref>
|
||||
<sourceEncoding>utf-8</sourceEncoding>
|
||||
<excludes>
|
||||
<exclude>**/generated/*.java</exclude>
|
||||
</excludes>
|
||||
<rulesets>
|
||||
<ruleset>../src/main/config/dcrules.xml</ruleset>
|
||||
<ruleset>/rulesets/java/basic.xml</ruleset>
|
||||
<ruleset>/rulesets/java/imports.xml</ruleset>
|
||||
<ruleset>/rulesets/java/unusedcode.xml</ruleset>
|
||||
</rulesets>
|
||||
</configuration>
|
||||
</plugin>
|
||||
<plugin>
|
||||
<groupId>org.codehaus.mojo</groupId>
|
||||
<artifactId>findbugs-maven-plugin</artifactId>
|
||||
<version>2.5.3</version>
|
||||
</plugin>
|
||||
</plugins>
|
||||
</reporting>
|
||||
<dependencies>
|
||||
<dependency>
|
||||
<groupId>commons-cli</groupId>
|
||||
@@ -337,5 +317,10 @@ Copyright (c) 2012 - Jeremy Long. All Rights Reserved.
|
||||
<artifactId>dependency-check-core</artifactId>
|
||||
<version>${project.parent.version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.owasp</groupId>
|
||||
<artifactId>dependency-check-utils</artifactId>
|
||||
<version>${project.parent.version}</version>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
</project>
|
||||
|
||||
@@ -2,10 +2,8 @@
|
||||
<assembly
|
||||
xmlns="http://maven.apache.org/plugins/maven-assembly-plugin/assembly/1.1.2"
|
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:schemaLocation="
|
||||
http://maven.apache.org/plugins/maven-assembly-plugin/assembly/1.1.2
|
||||
http://maven.apache.org/xsd/assembly-1.1.2.xsd
|
||||
"
|
||||
xsi:schemaLocation="http://maven.apache.org/plugins/maven-assembly-plugin/assembly/1.1.2
|
||||
http://maven.apache.org/xsd/assembly-1.1.2.xsd"
|
||||
>
|
||||
<id>release</id>
|
||||
<formats>
|
||||
|
||||
@@ -21,15 +21,19 @@ import java.io.File;
|
||||
import java.io.FileNotFoundException;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
import java.util.logging.Level;
|
||||
import java.util.logging.Logger;
|
||||
import org.apache.commons.cli.ParseException;
|
||||
import org.owasp.dependencycheck.cli.CliParser;
|
||||
import org.owasp.dependencycheck.data.nvdcve.CveDB;
|
||||
import org.owasp.dependencycheck.data.nvdcve.DatabaseException;
|
||||
import org.owasp.dependencycheck.data.nvdcve.DatabaseProperties;
|
||||
import org.owasp.dependencycheck.dependency.Dependency;
|
||||
import org.owasp.dependencycheck.org.apache.tools.ant.DirectoryScanner;
|
||||
import org.owasp.dependencycheck.reporting.ReportGenerator;
|
||||
import org.owasp.dependencycheck.utils.LogUtils;
|
||||
import org.owasp.dependencycheck.utils.Settings;
|
||||
@@ -46,14 +50,24 @@ public class App {
|
||||
*/
|
||||
private static final String LOG_PROPERTIES_FILE = "log.properties";
|
||||
|
||||
/**
|
||||
* The logger.
|
||||
*/
|
||||
private static final Logger LOGGER = Logger.getLogger(App.class.getName());
|
||||
|
||||
/**
|
||||
* The main method for the application.
|
||||
*
|
||||
* @param args the command line arguments
|
||||
*/
|
||||
public static void main(String[] args) {
|
||||
final App app = new App();
|
||||
app.run(args);
|
||||
try {
|
||||
Settings.initialize();
|
||||
final App app = new App();
|
||||
app.run(args);
|
||||
} finally {
|
||||
Settings.cleanup(true);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -62,8 +76,8 @@ public class App {
|
||||
* @param args the command line arguments
|
||||
*/
|
||||
public void run(String[] args) {
|
||||
|
||||
final CliParser cli = new CliParser();
|
||||
|
||||
try {
|
||||
cli.parse(args);
|
||||
} catch (FileNotFoundException ex) {
|
||||
@@ -82,8 +96,12 @@ public class App {
|
||||
if (cli.isGetVersion()) {
|
||||
cli.printVersionInfo();
|
||||
} else if (cli.isRunScan()) {
|
||||
updateSettings(cli);
|
||||
runScan(cli.getReportDirectory(), cli.getReportFormat(), cli.getApplicationName(), cli.getScanFiles());
|
||||
populateSettings(cli);
|
||||
try {
|
||||
runScan(cli.getReportDirectory(), cli.getReportFormat(), cli.getApplicationName(), cli.getScanFiles(), cli.getExcludeList());
|
||||
} catch (InvalidScanPathException ex) {
|
||||
Logger.getLogger(App.class.getName()).log(Level.SEVERE, "An invalid scan path was detected; unable to scan '//*' paths");
|
||||
}
|
||||
} else {
|
||||
cli.printHelp();
|
||||
}
|
||||
@@ -96,38 +114,101 @@ public class App {
|
||||
* @param outputFormat the output format of the report
|
||||
* @param applicationName the application name for the report
|
||||
* @param files the files/directories to scan
|
||||
* @param excludes the patterns for files/directories to exclude
|
||||
*
|
||||
* @throws InvalidScanPathException thrown if the path to scan starts with "//"
|
||||
*/
|
||||
private void runScan(String reportDirectory, String outputFormat, String applicationName, String[] files) {
|
||||
final Engine scanner = new Engine();
|
||||
|
||||
for (String file : files) {
|
||||
scanner.scan(file);
|
||||
}
|
||||
|
||||
scanner.analyzeDependencies();
|
||||
final List<Dependency> dependencies = scanner.getDependencies();
|
||||
DatabaseProperties prop = null;
|
||||
CveDB cve = null;
|
||||
private void runScan(String reportDirectory, String outputFormat, String applicationName, String[] files,
|
||||
String[] excludes) throws InvalidScanPathException {
|
||||
Engine engine = null;
|
||||
try {
|
||||
cve = new CveDB();
|
||||
cve.open();
|
||||
prop = cve.getDatabaseProperties();
|
||||
} catch (DatabaseException ex) {
|
||||
Logger.getLogger(App.class.getName()).log(Level.FINE, "Unable to retrieve DB Properties", ex);
|
||||
} finally {
|
||||
if (cve != null) {
|
||||
cve.close();
|
||||
engine = new Engine();
|
||||
List<String> antStylePaths = new ArrayList<String>();
|
||||
if (excludes == null || excludes.length == 0) {
|
||||
for (String file : files) {
|
||||
if (file.contains("*") || file.contains("?")) {
|
||||
antStylePaths.add(file);
|
||||
} else {
|
||||
engine.scan(file);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
antStylePaths = Arrays.asList(files);
|
||||
}
|
||||
|
||||
final Set<File> paths = new HashSet<File>();
|
||||
for (String file : antStylePaths) {
|
||||
final DirectoryScanner scanner = new DirectoryScanner();
|
||||
String include = file.replace('\\', '/');
|
||||
File baseDir;
|
||||
|
||||
if (include.startsWith("//")) {
|
||||
throw new InvalidScanPathException("Unable to scan paths specified by //");
|
||||
} else if (include.startsWith("./")) {
|
||||
baseDir = new File(".");
|
||||
include = include.substring(2);
|
||||
} else if (include.startsWith("/")) {
|
||||
baseDir = new File("/");
|
||||
include = include.substring(1);
|
||||
} else if (include.contains("/")) {
|
||||
final int pos = include.indexOf('/');
|
||||
final String tmp = include.substring(0, pos);
|
||||
if (tmp.contains("*") || tmp.contains("?")) {
|
||||
baseDir = new File(".");
|
||||
} else {
|
||||
baseDir = new File(tmp);
|
||||
include = include.substring(pos + 1);
|
||||
}
|
||||
} else { //no path info - must just be a file in the working directory
|
||||
baseDir = new File(".");
|
||||
}
|
||||
scanner.setBasedir(baseDir);
|
||||
scanner.setIncludes(include);
|
||||
if (excludes != null && excludes.length > 0) {
|
||||
scanner.addExcludes(excludes);
|
||||
}
|
||||
scanner.scan();
|
||||
if (scanner.getIncludedFilesCount() > 0) {
|
||||
for (String s : scanner.getIncludedFiles()) {
|
||||
final File f = new File(baseDir, s);
|
||||
paths.add(f);
|
||||
}
|
||||
}
|
||||
}
|
||||
engine.scan(paths);
|
||||
|
||||
engine.analyzeDependencies();
|
||||
final List<Dependency> dependencies = engine.getDependencies();
|
||||
DatabaseProperties prop = null;
|
||||
CveDB cve = null;
|
||||
try {
|
||||
cve = new CveDB();
|
||||
cve.open();
|
||||
prop = cve.getDatabaseProperties();
|
||||
} catch (DatabaseException ex) {
|
||||
LOGGER.log(Level.FINE, "Unable to retrieve DB Properties", ex);
|
||||
} finally {
|
||||
if (cve != null) {
|
||||
cve.close();
|
||||
}
|
||||
}
|
||||
final ReportGenerator report = new ReportGenerator(applicationName, dependencies, engine.getAnalyzers(), prop);
|
||||
try {
|
||||
report.generateReports(reportDirectory, outputFormat);
|
||||
} catch (IOException ex) {
|
||||
LOGGER.log(Level.SEVERE, "There was an IO error while attempting to generate the report.");
|
||||
LOGGER.log(Level.FINE, null, ex);
|
||||
} catch (Throwable ex) {
|
||||
LOGGER.log(Level.SEVERE, "There was an error while attempting to generate the report.");
|
||||
LOGGER.log(Level.FINE, null, ex);
|
||||
}
|
||||
} catch (DatabaseException ex) {
|
||||
LOGGER.log(Level.SEVERE, "Unable to connect to the dependency-check database; analysis has stopped");
|
||||
LOGGER.log(Level.FINE, "", ex);
|
||||
} finally {
|
||||
if (engine != null) {
|
||||
engine.cleanup();
|
||||
}
|
||||
}
|
||||
final ReportGenerator report = new ReportGenerator(applicationName, dependencies, scanner.getAnalyzers(), prop);
|
||||
try {
|
||||
report.generateReports(reportDirectory, outputFormat);
|
||||
} catch (IOException ex) {
|
||||
Logger.getLogger(App.class.getName()).log(Level.SEVERE, "There was an IO error while attempting to generate the report.");
|
||||
Logger.getLogger(App.class.getName()).log(Level.INFO, null, ex);
|
||||
} catch (Exception ex) {
|
||||
Logger.getLogger(App.class.getName()).log(Level.SEVERE, "There was an error while attempting to generate the report.");
|
||||
Logger.getLogger(App.class.getName()).log(Level.INFO, null, ex);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -137,17 +218,22 @@ public class App {
|
||||
* @param cli a reference to the CLI Parser that contains the command line arguments used to set the corresponding
|
||||
* settings in the core engine.
|
||||
*/
|
||||
private void updateSettings(CliParser cli) {
|
||||
private void populateSettings(CliParser cli) {
|
||||
|
||||
final boolean autoUpdate = cli.isAutoUpdate();
|
||||
final String connectionTimeout = cli.getConnectionTimeout();
|
||||
final String proxyUrl = cli.getProxyUrl();
|
||||
final String proxyServer = cli.getProxyServer();
|
||||
final String proxyPort = cli.getProxyPort();
|
||||
final String proxyUser = cli.getProxyUsername();
|
||||
final String proxyPass = cli.getProxyPassword();
|
||||
final String dataDirectory = cli.getDataDirectory();
|
||||
final File propertiesFile = cli.getPropertiesFile();
|
||||
final String suppressionFile = cli.getSuppressionFile();
|
||||
final boolean jarDisabled = cli.isJarDisabled();
|
||||
final boolean archiveDisabled = cli.isArchiveDisabled();
|
||||
final boolean assemblyDisabled = cli.isAssemblyDisabled();
|
||||
final boolean nuspecDisabled = cli.isNuspecDisabled();
|
||||
final boolean centralDisabled = cli.isCentralDisabled();
|
||||
final boolean nexusDisabled = cli.isNexusDisabled();
|
||||
final String nexusUrl = cli.getNexusUrl();
|
||||
final String databaseDriverName = cli.getDatabaseDriverName();
|
||||
@@ -155,20 +241,26 @@ public class App {
|
||||
final String connectionString = cli.getConnectionString();
|
||||
final String databaseUser = cli.getDatabaseUser();
|
||||
final String databasePassword = cli.getDatabasePassword();
|
||||
final String additionalZipExtensions = cli.getAdditionalZipExtensions();
|
||||
final String pathToMono = cli.getPathToMono();
|
||||
|
||||
if (propertiesFile != null) {
|
||||
try {
|
||||
Settings.mergeProperties(propertiesFile);
|
||||
} catch (FileNotFoundException ex) {
|
||||
final String msg = String.format("Unable to load properties file '%s'", propertiesFile.getPath());
|
||||
Logger.getLogger(App.class.getName()).log(Level.SEVERE, msg);
|
||||
Logger.getLogger(App.class.getName()).log(Level.FINE, null, ex);
|
||||
LOGGER.log(Level.SEVERE, msg);
|
||||
LOGGER.log(Level.FINE, null, ex);
|
||||
} catch (IOException ex) {
|
||||
final String msg = String.format("Unable to find properties file '%s'", propertiesFile.getPath());
|
||||
Logger.getLogger(App.class.getName()).log(Level.SEVERE, msg);
|
||||
Logger.getLogger(App.class.getName()).log(Level.FINE, null, ex);
|
||||
LOGGER.log(Level.SEVERE, msg);
|
||||
LOGGER.log(Level.FINE, null, ex);
|
||||
}
|
||||
}
|
||||
// We have to wait until we've merged the properties before attempting to set whether we use
|
||||
// the proxy for Nexus since it could be disabled in the properties, but not explicitly stated
|
||||
// on the command line
|
||||
final boolean nexusUsesProxy = cli.isNexusUsesProxy();
|
||||
if (dataDirectory != null) {
|
||||
Settings.setString(Settings.KEYS.DATA_DIRECTORY, dataDirectory);
|
||||
} else if (System.getProperty("basedir") != null) {
|
||||
@@ -182,8 +274,8 @@ public class App {
|
||||
Settings.setString(Settings.KEYS.DATA_DIRECTORY, dataDir.getAbsolutePath());
|
||||
}
|
||||
Settings.setBoolean(Settings.KEYS.AUTO_UPDATE, autoUpdate);
|
||||
if (proxyUrl != null && !proxyUrl.isEmpty()) {
|
||||
Settings.setString(Settings.KEYS.PROXY_URL, proxyUrl);
|
||||
if (proxyServer != null && !proxyServer.isEmpty()) {
|
||||
Settings.setString(Settings.KEYS.PROXY_SERVER, proxyServer);
|
||||
}
|
||||
if (proxyPort != null && !proxyPort.isEmpty()) {
|
||||
Settings.setString(Settings.KEYS.PROXY_PORT, proxyPort);
|
||||
@@ -200,11 +292,19 @@ public class App {
|
||||
if (suppressionFile != null && !suppressionFile.isEmpty()) {
|
||||
Settings.setString(Settings.KEYS.SUPPRESSION_FILE, suppressionFile);
|
||||
}
|
||||
|
||||
//File Type Analyzer Settings
|
||||
Settings.setBoolean(Settings.KEYS.ANALYZER_JAR_ENABLED, !jarDisabled);
|
||||
Settings.setBoolean(Settings.KEYS.ANALYZER_ARCHIVE_ENABLED, !archiveDisabled);
|
||||
Settings.setBoolean(Settings.KEYS.ANALYZER_NUSPEC_ENABLED, !nuspecDisabled);
|
||||
Settings.setBoolean(Settings.KEYS.ANALYZER_ASSEMBLY_ENABLED, !assemblyDisabled);
|
||||
|
||||
Settings.setBoolean(Settings.KEYS.ANALYZER_CENTRAL_ENABLED, !centralDisabled);
|
||||
Settings.setBoolean(Settings.KEYS.ANALYZER_NEXUS_ENABLED, !nexusDisabled);
|
||||
if (nexusUrl != null && !nexusUrl.isEmpty()) {
|
||||
Settings.setString(Settings.KEYS.ANALYZER_NEXUS_URL, nexusUrl);
|
||||
}
|
||||
|
||||
Settings.setBoolean(Settings.KEYS.ANALYZER_NEXUS_PROXY, nexusUsesProxy);
|
||||
if (databaseDriverName != null && !databaseDriverName.isEmpty()) {
|
||||
Settings.setString(Settings.KEYS.DB_DRIVER_NAME, databaseDriverName);
|
||||
}
|
||||
@@ -220,5 +320,11 @@ public class App {
|
||||
if (databasePassword != null && !databasePassword.isEmpty()) {
|
||||
Settings.setString(Settings.KEYS.DB_PASSWORD, databasePassword);
|
||||
}
|
||||
if (additionalZipExtensions != null && !additionalZipExtensions.isEmpty()) {
|
||||
Settings.setString(Settings.KEYS.ADDITIONAL_ZIP_EXTENSIONS, additionalZipExtensions);
|
||||
}
|
||||
if (pathToMono != null && !pathToMono.isEmpty()) {
|
||||
Settings.setString(Settings.KEYS.ANALYZER_ASSEMBLY_MONO_PATH, pathToMono);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -15,10 +15,11 @@
|
||||
*
|
||||
* Copyright (c) 2012 Jeremy Long. All Rights Reserved.
|
||||
*/
|
||||
package org.owasp.dependencycheck.cli;
|
||||
package org.owasp.dependencycheck;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.FileNotFoundException;
|
||||
import java.util.logging.Logger;
|
||||
import org.apache.commons.cli.CommandLine;
|
||||
import org.apache.commons.cli.CommandLineParser;
|
||||
import org.apache.commons.cli.HelpFormatter;
|
||||
@@ -29,6 +30,7 @@ import org.apache.commons.cli.Options;
|
||||
import org.apache.commons.cli.ParseException;
|
||||
import org.apache.commons.cli.PosixParser;
|
||||
import org.owasp.dependencycheck.reporting.ReportGenerator.Format;
|
||||
import org.owasp.dependencycheck.utils.InvalidSettingException;
|
||||
import org.owasp.dependencycheck.utils.Settings;
|
||||
|
||||
/**
|
||||
@@ -38,6 +40,10 @@ import org.owasp.dependencycheck.utils.Settings;
|
||||
*/
|
||||
public final class CliParser {
|
||||
|
||||
/**
|
||||
* The logger.
|
||||
*/
|
||||
private static final Logger LOGGER = Logger.getLogger(CliParser.class.getName());
|
||||
/**
|
||||
* The command line.
|
||||
*/
|
||||
@@ -78,19 +84,22 @@ public final class CliParser {
|
||||
/**
|
||||
* Validates that the command line arguments are valid.
|
||||
*
|
||||
* @throws FileNotFoundException if there is a file specified by either the SCAN or CPE command line arguments that
|
||||
* does not exist.
|
||||
* @throws FileNotFoundException if there is a file specified by either the SCAN or CPE command line arguments that does not
|
||||
* exist.
|
||||
* @throws ParseException is thrown if there is an exception parsing the command line.
|
||||
*/
|
||||
private void validateArgs() throws FileNotFoundException, ParseException {
|
||||
if (isRunScan()) {
|
||||
validatePathExists(getScanFiles(), "scan");
|
||||
validatePathExists(getReportDirectory(), "out");
|
||||
if (!line.hasOption(ArgumentName.APP_NAME)) {
|
||||
validatePathExists(getScanFiles(), ARGUMENT.SCAN);
|
||||
validatePathExists(getReportDirectory(), ARGUMENT.OUT);
|
||||
if (getPathToMono() != null) {
|
||||
validatePathExists(getPathToMono(), ARGUMENT.PATH_TO_MONO);
|
||||
}
|
||||
if (!line.hasOption(ARGUMENT.APP_NAME)) {
|
||||
throw new ParseException("Missing 'app' argument; the scan cannot be run without the an application name.");
|
||||
}
|
||||
if (line.hasOption(ArgumentName.OUTPUT_FORMAT)) {
|
||||
final String format = line.getOptionValue(ArgumentName.OUTPUT_FORMAT);
|
||||
if (line.hasOption(ARGUMENT.OUTPUT_FORMAT)) {
|
||||
final String format = line.getOptionValue(ARGUMENT.OUTPUT_FORMAT);
|
||||
try {
|
||||
Format.valueOf(format);
|
||||
} catch (IllegalArgumentException ex) {
|
||||
@@ -103,8 +112,8 @@ public final class CliParser {
|
||||
}
|
||||
|
||||
/**
|
||||
* Validates whether or not the path(s) points at a file that exists; if the path(s) does not point to an existing
|
||||
* file a FileNotFoundException is thrown.
|
||||
* Validates whether or not the path(s) points at a file that exists; if the path(s) does not point to an existing file a
|
||||
* FileNotFoundException is thrown.
|
||||
*
|
||||
* @param paths the paths to validate if they exists
|
||||
* @param optType the option being validated (e.g. scan, out, etc.)
|
||||
@@ -121,14 +130,38 @@ public final class CliParser {
|
||||
* FileNotFoundException is thrown.
|
||||
*
|
||||
* @param path the paths to validate if they exists
|
||||
* @param optType the option being validated (e.g. scan, out, etc.)
|
||||
* @param argumentName the argument being validated (e.g. scan, out, etc.)
|
||||
* @throws FileNotFoundException is thrown if the path being validated does not exist.
|
||||
*/
|
||||
private void validatePathExists(String path, String optType) throws FileNotFoundException {
|
||||
final File f = new File(path);
|
||||
if (!f.exists()) {
|
||||
private void validatePathExists(String path, String argumentName) throws FileNotFoundException {
|
||||
if (path == null) {
|
||||
isValid = false;
|
||||
final String msg = String.format("Invalid '%s' argument: '%s'", optType, path);
|
||||
final String msg = String.format("Invalid '%s' argument: null", argumentName);
|
||||
throw new FileNotFoundException(msg);
|
||||
} else if (!path.contains("*") && !path.contains("?")) {
|
||||
File f = new File(path);
|
||||
if ("o".equalsIgnoreCase(argumentName.substring(0, 1)) && !"ALL".equalsIgnoreCase(this.getReportFormat())) {
|
||||
final String checkPath = path.toLowerCase();
|
||||
if (checkPath.endsWith(".html") || checkPath.endsWith(".xml") || checkPath.endsWith(".htm")) {
|
||||
if (f.getParentFile() == null) {
|
||||
f = new File(".", path);
|
||||
}
|
||||
if (!f.getParentFile().isDirectory()) {
|
||||
isValid = false;
|
||||
final String msg = String.format("Invalid '%s' argument: '%s'", argumentName, path);
|
||||
throw new FileNotFoundException(msg);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
if (!f.exists()) {
|
||||
isValid = false;
|
||||
final String msg = String.format("Invalid '%s' argument: '%s'", argumentName, path);
|
||||
throw new FileNotFoundException(msg);
|
||||
}
|
||||
}
|
||||
} else if (path.startsWith("//") || path.startsWith("\\\\")) {
|
||||
isValid = false;
|
||||
final String msg = String.format("Invalid '%s' argument: '%s'%nUnable to scan paths that start with '//'.", argumentName, path);
|
||||
throw new FileNotFoundException(msg);
|
||||
}
|
||||
}
|
||||
@@ -140,11 +173,10 @@ public final class CliParser {
|
||||
*/
|
||||
@SuppressWarnings("static-access")
|
||||
private Options createCommandLineOptions() {
|
||||
|
||||
final Options options = new Options();
|
||||
addStandardOptions(options);
|
||||
addAdvancedOptions(options);
|
||||
|
||||
addDeprecatedOptions(options);
|
||||
return options;
|
||||
}
|
||||
|
||||
@@ -156,59 +188,62 @@ public final class CliParser {
|
||||
*/
|
||||
@SuppressWarnings("static-access")
|
||||
private void addStandardOptions(final Options options) throws IllegalArgumentException {
|
||||
final Option help = new Option(ArgumentName.HELP_SHORT, ArgumentName.HELP, false,
|
||||
final Option help = new Option(ARGUMENT.HELP_SHORT, ARGUMENT.HELP, false,
|
||||
"Print this message.");
|
||||
|
||||
final Option advancedHelp = OptionBuilder.withLongOpt(ArgumentName.ADVANCED_HELP)
|
||||
final Option advancedHelp = OptionBuilder.withLongOpt(ARGUMENT.ADVANCED_HELP)
|
||||
.withDescription("Print the advanced help message.").create();
|
||||
|
||||
final Option version = new Option(ArgumentName.VERSION_SHORT, ArgumentName.VERSION,
|
||||
final Option version = new Option(ARGUMENT.VERSION_SHORT, ARGUMENT.VERSION,
|
||||
false, "Print the version information.");
|
||||
|
||||
final Option noUpdate = new Option(ArgumentName.DISABLE_AUTO_UPDATE_SHORT, ArgumentName.DISABLE_AUTO_UPDATE,
|
||||
final Option noUpdate = new Option(ARGUMENT.DISABLE_AUTO_UPDATE_SHORT, ARGUMENT.DISABLE_AUTO_UPDATE,
|
||||
false, "Disables the automatic updating of the CPE data.");
|
||||
|
||||
final Option appName = OptionBuilder.withArgName("name").hasArg().withLongOpt(ArgumentName.APP_NAME)
|
||||
final Option appName = OptionBuilder.withArgName("name").hasArg().withLongOpt(ARGUMENT.APP_NAME)
|
||||
.withDescription("The name of the application being scanned. This is a required argument.")
|
||||
.create(ArgumentName.APP_NAME_SHORT);
|
||||
.create(ARGUMENT.APP_NAME_SHORT);
|
||||
|
||||
final Option path = OptionBuilder.withArgName("path").hasArg().withLongOpt(ArgumentName.SCAN)
|
||||
.withDescription("The path to scan - this option can be specified multiple times.")
|
||||
.create(ArgumentName.SCAN_SHORT);
|
||||
final Option path = OptionBuilder.withArgName("path").hasArg().withLongOpt(ARGUMENT.SCAN)
|
||||
.withDescription("The path to scan - this option can be specified multiple times. Ant style"
|
||||
+ " paths are supported (e.g. path/**/*.jar).")
|
||||
.create(ARGUMENT.SCAN_SHORT);
|
||||
|
||||
final Option props = OptionBuilder.withArgName("file").hasArg().withLongOpt(ArgumentName.PROP)
|
||||
final Option excludes = OptionBuilder.withArgName("pattern").hasArg().withLongOpt(ARGUMENT.EXCLUDE)
|
||||
.withDescription("Specify and exclusion pattern. This option can be specified multiple times"
|
||||
+ " and it accepts Ant style excludsions.")
|
||||
.create();
|
||||
|
||||
final Option props = OptionBuilder.withArgName("file").hasArg().withLongOpt(ARGUMENT.PROP)
|
||||
.withDescription("A property file to load.")
|
||||
.create(ArgumentName.PROP_SHORT);
|
||||
.create(ARGUMENT.PROP_SHORT);
|
||||
|
||||
final Option out = OptionBuilder.withArgName("folder").hasArg().withLongOpt(ArgumentName.OUT)
|
||||
.withDescription("The folder to write reports to. This defaults to the current directory.")
|
||||
.create(ArgumentName.OUT_SHORT);
|
||||
final Option out = OptionBuilder.withArgName("path").hasArg().withLongOpt(ARGUMENT.OUT)
|
||||
.withDescription("The folder to write reports to. This defaults to the current directory. "
|
||||
+ "It is possible to set this to a specific file name if the format argument is not set to ALL.")
|
||||
.create(ARGUMENT.OUT_SHORT);
|
||||
|
||||
final Option outputFormat = OptionBuilder.withArgName("format").hasArg().withLongOpt(ArgumentName.OUTPUT_FORMAT)
|
||||
final Option outputFormat = OptionBuilder.withArgName("format").hasArg().withLongOpt(ARGUMENT.OUTPUT_FORMAT)
|
||||
.withDescription("The output format to write to (XML, HTML, VULN, ALL). The default is HTML.")
|
||||
.create(ArgumentName.OUTPUT_FORMAT_SHORT);
|
||||
.create(ARGUMENT.OUTPUT_FORMAT_SHORT);
|
||||
|
||||
final Option verboseLog = OptionBuilder.withArgName("file").hasArg().withLongOpt(ArgumentName.VERBOSE_LOG)
|
||||
final Option verboseLog = OptionBuilder.withArgName("file").hasArg().withLongOpt(ARGUMENT.VERBOSE_LOG)
|
||||
.withDescription("The file path to write verbose logging information.")
|
||||
.create(ArgumentName.VERBOSE_LOG_SHORT);
|
||||
.create(ARGUMENT.VERBOSE_LOG_SHORT);
|
||||
|
||||
final Option suppressionFile = OptionBuilder.withArgName("file").hasArg().withLongOpt(ArgumentName.SUPPRESION_FILE)
|
||||
final Option suppressionFile = OptionBuilder.withArgName("file").hasArg().withLongOpt(ARGUMENT.SUPPRESSION_FILE)
|
||||
.withDescription("The file path to the suppression XML file.")
|
||||
.create();
|
||||
|
||||
final Option disableNexusAnalyzer = OptionBuilder.withLongOpt(ArgumentName.DISABLE_NEXUS)
|
||||
.withDescription("Disable the Nexus Analyzer.")
|
||||
.create();
|
||||
|
||||
final Option nexusUrl = OptionBuilder.withArgName("url").hasArg().withLongOpt(ArgumentName.NEXUS_URL)
|
||||
.withDescription("The url to the Nexus Server.")
|
||||
.create();
|
||||
|
||||
//This is an option group because it can be specified more then once.
|
||||
final OptionGroup og = new OptionGroup();
|
||||
og.addOption(path);
|
||||
|
||||
final OptionGroup exog = new OptionGroup();
|
||||
exog.addOption(excludes);
|
||||
|
||||
options.addOptionGroup(og)
|
||||
.addOptionGroup(exog)
|
||||
.addOption(out)
|
||||
.addOption(outputFormat)
|
||||
.addOption(appName)
|
||||
@@ -218,14 +253,12 @@ public final class CliParser {
|
||||
.addOption(noUpdate)
|
||||
.addOption(props)
|
||||
.addOption(verboseLog)
|
||||
.addOption(suppressionFile)
|
||||
.addOption(disableNexusAnalyzer)
|
||||
.addOption(nexusUrl);
|
||||
.addOption(suppressionFile);
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds the advanced command line options to the given options collection. These are split out for purposes of being
|
||||
* able to display two different help messages.
|
||||
* Adds the advanced command line options to the given options collection. These are split out for purposes of being able to
|
||||
* display two different help messages.
|
||||
*
|
||||
* @param options a collection of command line arguments
|
||||
* @throws IllegalArgumentException thrown if there is an exception
|
||||
@@ -233,48 +266,92 @@ public final class CliParser {
|
||||
@SuppressWarnings("static-access")
|
||||
private void addAdvancedOptions(final Options options) throws IllegalArgumentException {
|
||||
|
||||
final Option data = OptionBuilder.withArgName("path").hasArg().withLongOpt(ArgumentName.DATA_DIRECTORY)
|
||||
final Option data = OptionBuilder.withArgName("path").hasArg().withLongOpt(ARGUMENT.DATA_DIRECTORY)
|
||||
.withDescription("The location of the H2 Database file. This option should generally not be set.")
|
||||
.create(ArgumentName.DATA_DIRECTORY_SHORT);
|
||||
.create(ARGUMENT.DATA_DIRECTORY_SHORT);
|
||||
|
||||
final Option connectionTimeout = OptionBuilder.withArgName("timeout").hasArg().withLongOpt(ArgumentName.CONNECTION_TIMEOUT)
|
||||
final Option connectionTimeout = OptionBuilder.withArgName("timeout").hasArg().withLongOpt(ARGUMENT.CONNECTION_TIMEOUT)
|
||||
.withDescription("The connection timeout (in milliseconds) to use when downloading resources.")
|
||||
.create(ArgumentName.CONNECTION_TIMEOUT_SHORT);
|
||||
.create(ARGUMENT.CONNECTION_TIMEOUT_SHORT);
|
||||
|
||||
final Option proxyUrl = OptionBuilder.withArgName("url").hasArg().withLongOpt(ArgumentName.PROXY_URL)
|
||||
.withDescription("The proxy url to use when downloading resources.")
|
||||
.create(ArgumentName.PROXY_URL_SHORT);
|
||||
final Option proxyServer = OptionBuilder.withArgName("server").hasArg().withLongOpt(ARGUMENT.PROXY_SERVER)
|
||||
.withDescription("The proxy server to use when downloading resources.")
|
||||
.create();
|
||||
|
||||
final Option proxyPort = OptionBuilder.withArgName("port").hasArg().withLongOpt(ArgumentName.PROXY_PORT)
|
||||
final Option proxyPort = OptionBuilder.withArgName("port").hasArg().withLongOpt(ARGUMENT.PROXY_PORT)
|
||||
.withDescription("The proxy port to use when downloading resources.")
|
||||
.create(ArgumentName.PROXY_PORT_SHORT);
|
||||
.create();
|
||||
|
||||
final Option proxyUsername = OptionBuilder.withArgName("user").hasArg().withLongOpt(ArgumentName.PROXY_USERNAME)
|
||||
final Option proxyUsername = OptionBuilder.withArgName("user").hasArg().withLongOpt(ARGUMENT.PROXY_USERNAME)
|
||||
.withDescription("The proxy username to use when downloading resources.")
|
||||
.create();
|
||||
|
||||
final Option proxyPassword = OptionBuilder.withArgName("pass").hasArg().withLongOpt(ArgumentName.PROXY_PASSWORD)
|
||||
final Option proxyPassword = OptionBuilder.withArgName("pass").hasArg().withLongOpt(ARGUMENT.PROXY_PASSWORD)
|
||||
.withDescription("The proxy password to use when downloading resources.")
|
||||
.create();
|
||||
|
||||
final Option connectionString = OptionBuilder.withArgName("connStr").hasArg().withLongOpt(ArgumentName.CONNECTION_STRING)
|
||||
final Option connectionString = OptionBuilder.withArgName("connStr").hasArg().withLongOpt(ARGUMENT.CONNECTION_STRING)
|
||||
.withDescription("The connection string to the database.")
|
||||
.create();
|
||||
final Option dbUser = OptionBuilder.withArgName("user").hasArg().withLongOpt(ArgumentName.DB_NAME)
|
||||
|
||||
final Option dbUser = OptionBuilder.withArgName("user").hasArg().withLongOpt(ARGUMENT.DB_NAME)
|
||||
.withDescription("The username used to connect to the database.")
|
||||
.create();
|
||||
final Option dbPassword = OptionBuilder.withArgName("password").hasArg().withLongOpt(ArgumentName.DB_PASSWORD)
|
||||
|
||||
final Option dbPassword = OptionBuilder.withArgName("password").hasArg().withLongOpt(ARGUMENT.DB_PASSWORD)
|
||||
.withDescription("The password for connecting to the database.")
|
||||
.create();
|
||||
final Option dbDriver = OptionBuilder.withArgName("driver").hasArg().withLongOpt(ArgumentName.DB_DRIVER)
|
||||
|
||||
final Option dbDriver = OptionBuilder.withArgName("driver").hasArg().withLongOpt(ARGUMENT.DB_DRIVER)
|
||||
.withDescription("The database driver name.")
|
||||
.create();
|
||||
final Option dbDriverPath = OptionBuilder.withArgName("path").hasArg().withLongOpt(ArgumentName.DB_DRIVER_PATH)
|
||||
|
||||
final Option dbDriverPath = OptionBuilder.withArgName("path").hasArg().withLongOpt(ARGUMENT.DB_DRIVER_PATH)
|
||||
.withDescription("The path to the database driver; note, this does not need to be set unless the JAR is outside of the classpath.")
|
||||
.create();
|
||||
|
||||
final Option disableJarAnalyzer = OptionBuilder.withLongOpt(ARGUMENT.DISABLE_JAR)
|
||||
.withDescription("Disable the Jar Analyzer.")
|
||||
.create();
|
||||
final Option disableArchiveAnalyzer = OptionBuilder.withLongOpt(ARGUMENT.DISABLE_ARCHIVE)
|
||||
.withDescription("Disable the Archive Analyzer.")
|
||||
.create();
|
||||
final Option disableNuspecAnalyzer = OptionBuilder.withLongOpt(ARGUMENT.DISABLE_NUSPEC)
|
||||
.withDescription("Disable the Nuspec Analyzer.")
|
||||
.create();
|
||||
final Option disableAssemblyAnalyzer = OptionBuilder.withLongOpt(ARGUMENT.DISABLE_ASSEMBLY)
|
||||
.withDescription("Disable the .NET Assembly Analyzer.")
|
||||
.create();
|
||||
|
||||
final Option disableCentralAnalyzer = OptionBuilder.withLongOpt(ARGUMENT.DISABLE_CENTRAL)
|
||||
.withDescription("Disable the Central Analyzer. If this analyzer is disabled it is likely you also want to disable "
|
||||
+ "the Nexus Analyzer.")
|
||||
.create();
|
||||
|
||||
final Option disableNexusAnalyzer = OptionBuilder.withLongOpt(ARGUMENT.DISABLE_NEXUS)
|
||||
.withDescription("Disable the Nexus Analyzer.")
|
||||
.create();
|
||||
|
||||
final Option nexusUrl = OptionBuilder.withArgName("url").hasArg().withLongOpt(ARGUMENT.NEXUS_URL)
|
||||
.withDescription("The url to the Nexus Pro Server. If not set the Nexus Analyzer will be disabled.")
|
||||
.create();
|
||||
|
||||
final Option nexusUsesProxy = OptionBuilder.withArgName("true/false").hasArg().withLongOpt(ARGUMENT.NEXUS_USES_PROXY)
|
||||
.withDescription("Whether or not the configured proxy should be used when connecting to Nexus.")
|
||||
.create();
|
||||
|
||||
final Option additionalZipExtensions = OptionBuilder.withArgName("extensions").hasArg()
|
||||
.withLongOpt(ARGUMENT.ADDITIONAL_ZIP_EXTENSIONS)
|
||||
.withDescription("A comma separated list of additional extensions to be scanned as ZIP files "
|
||||
+ "(ZIP, EAR, WAR are already treated as zip files)")
|
||||
.create();
|
||||
|
||||
final Option pathToMono = OptionBuilder.withArgName("path").hasArg().withLongOpt(ARGUMENT.PATH_TO_MONO)
|
||||
.withDescription("The path to Mono for .NET Assembly analysis on non-windows systems.")
|
||||
.create();
|
||||
|
||||
options.addOption(proxyPort)
|
||||
.addOption(proxyUrl)
|
||||
.addOption(proxyServer)
|
||||
.addOption(proxyUsername)
|
||||
.addOption(proxyPassword)
|
||||
.addOption(connectionTimeout)
|
||||
@@ -283,7 +360,34 @@ public final class CliParser {
|
||||
.addOption(data)
|
||||
.addOption(dbPassword)
|
||||
.addOption(dbDriver)
|
||||
.addOption(dbDriverPath);
|
||||
.addOption(dbDriverPath)
|
||||
.addOption(disableJarAnalyzer)
|
||||
.addOption(disableArchiveAnalyzer)
|
||||
.addOption(disableAssemblyAnalyzer)
|
||||
.addOption(disableNuspecAnalyzer)
|
||||
.addOption(disableCentralAnalyzer)
|
||||
.addOption(disableNexusAnalyzer)
|
||||
.addOption(nexusUrl)
|
||||
.addOption(nexusUsesProxy)
|
||||
.addOption(additionalZipExtensions)
|
||||
.addOption(pathToMono);
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds the deprecated command line options to the given options collection. These are split out for purposes of not including
|
||||
* them in the help message. We need to add the deprecated options so as not to break existing scripts.
|
||||
*
|
||||
* @param options a collection of command line arguments
|
||||
* @throws IllegalArgumentException thrown if there is an exception
|
||||
*/
|
||||
@SuppressWarnings("static-access")
|
||||
private void addDeprecatedOptions(final Options options) throws IllegalArgumentException {
|
||||
|
||||
final Option proxyServer = OptionBuilder.withArgName("url").hasArg().withLongOpt(ARGUMENT.PROXY_URL)
|
||||
.withDescription("The proxy url argument is deprecated, use proxyserver instead.")
|
||||
.create();
|
||||
|
||||
options.addOption(proxyServer);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -292,7 +396,7 @@ public final class CliParser {
|
||||
* @return whether or not the 'version' command line argument was passed in
|
||||
*/
|
||||
public boolean isGetVersion() {
|
||||
return (line != null) && line.hasOption(ArgumentName.VERSION);
|
||||
return (line != null) && line.hasOption(ARGUMENT.VERSION);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -301,7 +405,7 @@ public final class CliParser {
|
||||
* @return whether or not the 'help' command line argument was passed in
|
||||
*/
|
||||
public boolean isGetHelp() {
|
||||
return (line != null) && line.hasOption(ArgumentName.HELP);
|
||||
return (line != null) && line.hasOption(ARGUMENT.HELP);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -310,7 +414,43 @@ public final class CliParser {
|
||||
* @return whether or not the 'scan' command line argument was passed in
|
||||
*/
|
||||
public boolean isRunScan() {
|
||||
return (line != null) && isValid && line.hasOption(ArgumentName.SCAN);
|
||||
return (line != null) && isValid && line.hasOption(ARGUMENT.SCAN);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns true if the disableJar command line argument was specified.
|
||||
*
|
||||
* @return true if the disableJar command line argument was specified; otherwise false
|
||||
*/
|
||||
public boolean isJarDisabled() {
|
||||
return (line != null) && line.hasOption(ARGUMENT.DISABLE_JAR);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns true if the disableArchive command line argument was specified.
|
||||
*
|
||||
* @return true if the disableArchive command line argument was specified; otherwise false
|
||||
*/
|
||||
public boolean isArchiveDisabled() {
|
||||
return (line != null) && line.hasOption(ARGUMENT.DISABLE_ARCHIVE);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns true if the disableNuspec command line argument was specified.
|
||||
*
|
||||
* @return true if the disableNuspec command line argument was specified; otherwise false
|
||||
*/
|
||||
public boolean isNuspecDisabled() {
|
||||
return (line != null) && line.hasOption(ARGUMENT.DISABLE_NUSPEC);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns true if the disableAssembly command line argument was specified.
|
||||
*
|
||||
* @return true if the disableAssembly command line argument was specified; otherwise false
|
||||
*/
|
||||
public boolean isAssemblyDisabled() {
|
||||
return (line != null) && line.hasOption(ARGUMENT.DISABLE_ASSEMBLY);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -319,7 +459,16 @@ public final class CliParser {
|
||||
* @return true if the disableNexus command line argument was specified; otherwise false
|
||||
*/
|
||||
public boolean isNexusDisabled() {
|
||||
return (line != null) && line.hasOption(ArgumentName.DISABLE_NEXUS);
|
||||
return (line != null) && line.hasOption(ARGUMENT.DISABLE_NEXUS);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns true if the disableCentral command line argument was specified.
|
||||
*
|
||||
* @return true if the disableCentral command line argument was specified; otherwise false
|
||||
*/
|
||||
public boolean isCentralDisabled() {
|
||||
return (line != null) && line.hasOption(ARGUMENT.DISABLE_CENTRAL);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -328,10 +477,29 @@ public final class CliParser {
|
||||
* @return the url to the nexus server; if none was specified this will return null;
|
||||
*/
|
||||
public String getNexusUrl() {
|
||||
if (line == null || !line.hasOption(ArgumentName.NEXUS_URL)) {
|
||||
if (line == null || !line.hasOption(ARGUMENT.NEXUS_URL)) {
|
||||
return null;
|
||||
} else {
|
||||
return line.getOptionValue(ArgumentName.NEXUS_URL);
|
||||
return line.getOptionValue(ARGUMENT.NEXUS_URL);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns true if the Nexus Analyzer should use the configured proxy to connect to Nexus; otherwise false is returned.
|
||||
*
|
||||
* @return true if the Nexus Analyzer should use the configured proxy to connect to Nexus; otherwise false
|
||||
*/
|
||||
public boolean isNexusUsesProxy() {
|
||||
// If they didn't specify whether Nexus needs to use the proxy, we should
|
||||
// still honor the property if it's set.
|
||||
if (line == null || !line.hasOption(ARGUMENT.NEXUS_USES_PROXY)) {
|
||||
try {
|
||||
return Settings.getBoolean(Settings.KEYS.ANALYZER_NEXUS_PROXY);
|
||||
} catch (InvalidSettingException ise) {
|
||||
return true;
|
||||
}
|
||||
} else {
|
||||
return Boolean.parseBoolean(line.getOptionValue(ARGUMENT.NEXUS_USES_PROXY));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -342,7 +510,7 @@ public final class CliParser {
|
||||
final HelpFormatter formatter = new HelpFormatter();
|
||||
final Options options = new Options();
|
||||
addStandardOptions(options);
|
||||
if (line != null && line.hasOption(ArgumentName.ADVANCED_HELP)) {
|
||||
if (line != null && line.hasOption(ARGUMENT.ADVANCED_HELP)) {
|
||||
addAdvancedOptions(options);
|
||||
}
|
||||
final String helpMsg = String.format("%n%s"
|
||||
@@ -356,7 +524,6 @@ public final class CliParser {
|
||||
options,
|
||||
"",
|
||||
true);
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -365,7 +532,16 @@ public final class CliParser {
|
||||
* @return the file paths specified on the command line for scan
|
||||
*/
|
||||
public String[] getScanFiles() {
|
||||
return line.getOptionValues(ArgumentName.SCAN);
|
||||
return line.getOptionValues(ARGUMENT.SCAN);
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieves the list of excluded file patterns specified by the 'exclude' argument.
|
||||
*
|
||||
* @return the excluded file patterns
|
||||
*/
|
||||
public String[] getExcludeList() {
|
||||
return line.getOptionValues(ARGUMENT.EXCLUDE);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -374,7 +550,16 @@ public final class CliParser {
|
||||
* @return the path to the reports directory.
|
||||
*/
|
||||
public String getReportDirectory() {
|
||||
return line.getOptionValue(ArgumentName.OUT, ".");
|
||||
return line.getOptionValue(ARGUMENT.OUT, ".");
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the path to Mono for .NET Assembly analysis on non-windows systems.
|
||||
*
|
||||
* @return the path to Mono
|
||||
*/
|
||||
public String getPathToMono() {
|
||||
return line.getOptionValue(ARGUMENT.PATH_TO_MONO);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -383,7 +568,7 @@ public final class CliParser {
|
||||
* @return the output format name.
|
||||
*/
|
||||
public String getReportFormat() {
|
||||
return line.getOptionValue(ArgumentName.OUTPUT_FORMAT, "HTML");
|
||||
return line.getOptionValue(ARGUMENT.OUTPUT_FORMAT, "HTML");
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -392,7 +577,7 @@ public final class CliParser {
|
||||
* @return the application name.
|
||||
*/
|
||||
public String getApplicationName() {
|
||||
return line.getOptionValue(ArgumentName.APP_NAME);
|
||||
return line.getOptionValue(ARGUMENT.APP_NAME);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -401,16 +586,24 @@ public final class CliParser {
|
||||
* @return the connection timeout
|
||||
*/
|
||||
public String getConnectionTimeout() {
|
||||
return line.getOptionValue(ArgumentName.CONNECTION_TIMEOUT);
|
||||
return line.getOptionValue(ARGUMENT.CONNECTION_TIMEOUT);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the proxy url.
|
||||
* Returns the proxy server.
|
||||
*
|
||||
* @return the proxy url
|
||||
* @return the proxy server
|
||||
*/
|
||||
public String getProxyUrl() {
|
||||
return line.getOptionValue(ArgumentName.PROXY_URL);
|
||||
public String getProxyServer() {
|
||||
|
||||
String server = line.getOptionValue(ARGUMENT.PROXY_SERVER);
|
||||
if (server == null) {
|
||||
server = line.getOptionValue(ARGUMENT.PROXY_URL);
|
||||
if (server != null) {
|
||||
LOGGER.warning("An old command line argument 'proxyurl' was detected; use proxyserver instead");
|
||||
}
|
||||
}
|
||||
return server;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -419,7 +612,7 @@ public final class CliParser {
|
||||
* @return the proxy port
|
||||
*/
|
||||
public String getProxyPort() {
|
||||
return line.getOptionValue(ArgumentName.PROXY_PORT);
|
||||
return line.getOptionValue(ARGUMENT.PROXY_PORT);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -428,7 +621,7 @@ public final class CliParser {
|
||||
* @return the proxy username
|
||||
*/
|
||||
public String getProxyUsername() {
|
||||
return line.getOptionValue(ArgumentName.PROXY_USERNAME);
|
||||
return line.getOptionValue(ARGUMENT.PROXY_USERNAME);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -437,7 +630,7 @@ public final class CliParser {
|
||||
* @return the proxy password
|
||||
*/
|
||||
public String getProxyPassword() {
|
||||
return line.getOptionValue(ArgumentName.PROXY_PASSWORD);
|
||||
return line.getOptionValue(ARGUMENT.PROXY_PASSWORD);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -446,7 +639,7 @@ public final class CliParser {
|
||||
* @return the value of dataDirectory
|
||||
*/
|
||||
public String getDataDirectory() {
|
||||
return line.getOptionValue(ArgumentName.DATA_DIRECTORY);
|
||||
return line.getOptionValue(ARGUMENT.DATA_DIRECTORY);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -455,7 +648,7 @@ public final class CliParser {
|
||||
* @return the properties file specified on the command line
|
||||
*/
|
||||
public File getPropertiesFile() {
|
||||
final String path = line.getOptionValue(ArgumentName.PROP);
|
||||
final String path = line.getOptionValue(ARGUMENT.PROP);
|
||||
if (path != null) {
|
||||
return new File(path);
|
||||
}
|
||||
@@ -468,7 +661,7 @@ public final class CliParser {
|
||||
* @return the path to the verbose log file
|
||||
*/
|
||||
public String getVerboseLog() {
|
||||
return line.getOptionValue(ArgumentName.VERBOSE_LOG);
|
||||
return line.getOptionValue(ARGUMENT.VERBOSE_LOG);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -477,7 +670,7 @@ public final class CliParser {
|
||||
* @return the path to the suppression file
|
||||
*/
|
||||
public String getSuppressionFile() {
|
||||
return line.getOptionValue(ArgumentName.SUPPRESION_FILE);
|
||||
return line.getOptionValue(ARGUMENT.SUPPRESSION_FILE);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -488,19 +681,18 @@ public final class CliParser {
|
||||
*/
|
||||
public void printVersionInfo() {
|
||||
final String version = String.format("%s version %s",
|
||||
Settings.getString("application.name", "DependencyCheck"),
|
||||
Settings.getString("application.version", "Unknown"));
|
||||
Settings.getString(Settings.KEYS.APPLICATION_VAME, "dependency-check"),
|
||||
Settings.getString(Settings.KEYS.APPLICATION_VERSION, "Unknown"));
|
||||
System.out.println(version);
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks if the auto update feature has been disabled. If it has been disabled via the command line this will
|
||||
* return false.
|
||||
* Checks if the auto update feature has been disabled. If it has been disabled via the command line this will return false.
|
||||
*
|
||||
* @return if auto-update is allowed.
|
||||
*/
|
||||
public boolean isAutoUpdate() {
|
||||
return (line == null) || !line.hasOption(ArgumentName.DISABLE_AUTO_UPDATE);
|
||||
return (line == null) || !line.hasOption(ARGUMENT.DISABLE_AUTO_UPDATE);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -509,7 +701,7 @@ public final class CliParser {
|
||||
* @return the database driver name if specified; otherwise null is returned
|
||||
*/
|
||||
public String getDatabaseDriverName() {
|
||||
return line.getOptionValue(ArgumentName.DB_DRIVER);
|
||||
return line.getOptionValue(ARGUMENT.DB_DRIVER);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -518,7 +710,7 @@ public final class CliParser {
|
||||
* @return the database driver name if specified; otherwise null is returned
|
||||
*/
|
||||
public String getDatabaseDriverPath() {
|
||||
return line.getOptionValue(ArgumentName.DB_DRIVER_PATH);
|
||||
return line.getOptionValue(ARGUMENT.DB_DRIVER_PATH);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -527,7 +719,7 @@ public final class CliParser {
|
||||
* @return the database connection string if specified; otherwise null is returned
|
||||
*/
|
||||
public String getConnectionString() {
|
||||
return line.getOptionValue(ArgumentName.CONNECTION_STRING);
|
||||
return line.getOptionValue(ARGUMENT.CONNECTION_STRING);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -536,7 +728,7 @@ public final class CliParser {
|
||||
* @return the database database user name if specified; otherwise null is returned
|
||||
*/
|
||||
public String getDatabaseUser() {
|
||||
return line.getOptionValue(ArgumentName.DB_NAME);
|
||||
return line.getOptionValue(ARGUMENT.DB_NAME);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -545,13 +737,22 @@ public final class CliParser {
|
||||
* @return the database database password if specified; otherwise null is returned
|
||||
*/
|
||||
public String getDatabasePassword() {
|
||||
return line.getOptionValue(ArgumentName.DB_PASSWORD);
|
||||
return line.getOptionValue(ARGUMENT.DB_PASSWORD);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the additional Extensions if specified; otherwise null is returned.
|
||||
*
|
||||
* @return the additional Extensions; otherwise null is returned
|
||||
*/
|
||||
public String getAdditionalZipExtensions() {
|
||||
return line.getOptionValue(ARGUMENT.ADDITIONAL_ZIP_EXTENSIONS);
|
||||
}
|
||||
|
||||
/**
|
||||
* A collection of static final strings that represent the possible command line arguments.
|
||||
*/
|
||||
public static class ArgumentName {
|
||||
public static class ARGUMENT {
|
||||
|
||||
/**
|
||||
* The long CLI argument name specifying the directory/file to scan.
|
||||
@@ -613,21 +814,20 @@ public final class CliParser {
|
||||
* The short CLI argument name asking for the version.
|
||||
*/
|
||||
public static final String VERSION = "version";
|
||||
/**
|
||||
* The short CLI argument name indicating the proxy port.
|
||||
*/
|
||||
public static final String PROXY_PORT_SHORT = "p";
|
||||
/**
|
||||
* The CLI argument name indicating the proxy port.
|
||||
*/
|
||||
public static final String PROXY_PORT = "proxyport";
|
||||
/**
|
||||
* The short CLI argument name indicating the proxy url.
|
||||
* The CLI argument name indicating the proxy server.
|
||||
*/
|
||||
public static final String PROXY_URL_SHORT = "u";
|
||||
public static final String PROXY_SERVER = "proxyserver";
|
||||
/**
|
||||
* The CLI argument name indicating the proxy url.
|
||||
*
|
||||
* @deprecated use {@link org.owasp.dependencycheck.cli.CliParser.ArgumentName#PROXY_SERVER} instead
|
||||
*/
|
||||
@Deprecated
|
||||
public static final String PROXY_URL = "proxyurl";
|
||||
/**
|
||||
* The CLI argument name indicating the proxy username.
|
||||
@@ -648,7 +848,7 @@ public final class CliParser {
|
||||
/**
|
||||
* The short CLI argument name for setting the location of an additional properties file.
|
||||
*/
|
||||
public static final String PROP_SHORT = "p";
|
||||
public static final String PROP_SHORT = "P";
|
||||
/**
|
||||
* The CLI argument name for setting the location of an additional properties file.
|
||||
*/
|
||||
@@ -672,7 +872,27 @@ public final class CliParser {
|
||||
/**
|
||||
* The CLI argument name for setting the location of the suppression file.
|
||||
*/
|
||||
public static final String SUPPRESION_FILE = "suppression";
|
||||
public static final String SUPPRESSION_FILE = "suppression";
|
||||
/**
|
||||
* Disables the Jar Analyzer.
|
||||
*/
|
||||
public static final String DISABLE_JAR = "disableJar";
|
||||
/**
|
||||
* Disables the Archive Analyzer.
|
||||
*/
|
||||
public static final String DISABLE_ARCHIVE = "disableArchive";
|
||||
/**
|
||||
* Disables the Assembly Analyzer.
|
||||
*/
|
||||
public static final String DISABLE_ASSEMBLY = "disableAssembly";
|
||||
/**
|
||||
* Disables the Nuspec Analyzer.
|
||||
*/
|
||||
public static final String DISABLE_NUSPEC = "disableNuspec";
|
||||
/**
|
||||
* Disables the Central Analyzer.
|
||||
*/
|
||||
public static final String DISABLE_CENTRAL = "disableCentral";
|
||||
/**
|
||||
* Disables the Nexus Analyzer.
|
||||
*/
|
||||
@@ -681,6 +901,10 @@ public final class CliParser {
|
||||
* The URL of the nexus server.
|
||||
*/
|
||||
public static final String NEXUS_URL = "nexus";
|
||||
/**
|
||||
* Whether or not the defined proxy should be used when connecting to Nexus.
|
||||
*/
|
||||
public static final String NEXUS_USES_PROXY = "nexusUsesProxy";
|
||||
/**
|
||||
* The CLI argument name for setting the connection string.
|
||||
*/
|
||||
@@ -701,5 +925,17 @@ public final class CliParser {
|
||||
* The CLI argument name for setting the path to the database driver; in case it is not on the class path.
|
||||
*/
|
||||
public static final String DB_DRIVER_PATH = "dbDriverPath";
|
||||
/**
|
||||
* The CLI argument name for setting the path to mono for .NET Assembly analysis on non-windows systems.
|
||||
*/
|
||||
public static final String PATH_TO_MONO = "mono";
|
||||
/**
|
||||
* The CLI argument name for setting extra extensions.
|
||||
*/
|
||||
public static final String ADDITIONAL_ZIP_EXTENSIONS = "zipExtensions";
|
||||
/**
|
||||
* Exclude path argument.
|
||||
*/
|
||||
public static final String EXCLUDE = "exclude";
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,61 @@
|
||||
/*
|
||||
* This file is part of dependency-check-cli.
|
||||
*
|
||||
* Licensed under the Apache 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.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*
|
||||
* Copyright (c) 2014 Jeremy Long. All Rights Reserved.
|
||||
*/
|
||||
package org.owasp.dependencycheck;
|
||||
|
||||
/**
|
||||
* Thrown if an invalid path is encountered.
|
||||
*
|
||||
* @author Jeremy Long <jeremy.long@owasp.org>
|
||||
*/
|
||||
class InvalidScanPathException extends Exception {
|
||||
|
||||
/**
|
||||
* Creates a new InvalidScanPathException.
|
||||
*/
|
||||
public InvalidScanPathException() {
|
||||
super();
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new InvalidScanPathException.
|
||||
*
|
||||
* @param msg a message for the exception
|
||||
*/
|
||||
public InvalidScanPathException(String msg) {
|
||||
super(msg);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new InvalidScanPathException.
|
||||
*
|
||||
* @param ex the cause of the exception
|
||||
*/
|
||||
public InvalidScanPathException(Throwable ex) {
|
||||
super(ex);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new InvalidScanPathException.
|
||||
*
|
||||
* @param msg a message for the exception
|
||||
* @param ex the cause of the exception
|
||||
*/
|
||||
public InvalidScanPathException(String msg, Throwable ex) {
|
||||
super(msg, ex);
|
||||
}
|
||||
}
|
||||
@@ -1,12 +0,0 @@
|
||||
/**
|
||||
* <html>
|
||||
* <head>
|
||||
* <title>org.owasp.dependencycheck.cli</title>
|
||||
* </head>
|
||||
* <body>
|
||||
* Includes utility classes such as the CLI Parser,
|
||||
* </body>
|
||||
* </html>
|
||||
*/
|
||||
|
||||
package org.owasp.dependencycheck.cli;
|
||||
@@ -1,30 +1,45 @@
|
||||
Command Line Arguments
|
||||
====================
|
||||
======================
|
||||
|
||||
The following table lists the command line arguments:
|
||||
|
||||
Short | Argument Name | Parameter | Description | Requirement
|
||||
-------|-----------------------|-------------|-------------|------------
|
||||
\-a | \-\-app | \<name\> | The name of the application being scanned. This is a required argument. |
|
||||
\-c | \-\-connectiontimeout | \<timeout\> | The connection timeout (in milliseconds) to use when downloading resources. | Optional
|
||||
\-d | \-\-data | \<path\> | The location of the data directory used to store persistent data. This option should generally not be set. | Optional
|
||||
\-f | \-\-format | \<format\> | The output format to write to (XML, HTML, VULN, ALL). The default is HTML. |
|
||||
\-h | \-\-help | | Print the help message. | Optional
|
||||
\-l | \-\-log | \<file\> | The file path to write verbose logging information. | Optional
|
||||
\-n | \-\-noupdate | | Disables the automatic updating of the CPE data. | Optional
|
||||
\-o | \-\-out | \<folder\> | The folder to write reports to. This defaults to the current directory. | Optional
|
||||
\-p | \-\-proxyport | \<port\> | The proxy port to use when downloading resources. | Optional
|
||||
| \-\-proxypass | \<pass\> | The proxy password to use when downloading resources. | Optional
|
||||
| \-\-proxyuser | \<user\> | The proxy username to use when downloading resources. | Optional
|
||||
\-s | \-\-scan | \<path\> | The path to scan \- this option can be specified multiple times. |
|
||||
| \-\-suppression | \<file\> | The file path to the suppression XML file; used to suppress [false positives](../suppression.html). | Optional
|
||||
\-u | \-\-proxyurl | \<url\> | The proxy url to use when downloading resources. | Optional
|
||||
\-v | \-\-version | | Print the version information. | Optional
|
||||
| \-\-advancedHelp | | Print the advanced help message. | Optional
|
||||
| \-\-connectionString | \<connStr\> | The connection string to the database. | Optional
|
||||
| \-\-dbDriverName | \<driver\> | The database driver name. | Optional
|
||||
| \-\-dbDriverPath | \<path\> | The path to the database driver; note, this does not need to be set unless the JAR is outside of the class path. | Optional
|
||||
| \-\-dbPassword | \<password\>| The password for connecting to the database. | Optional
|
||||
| \-\-dbUser | \<user\> | The username used to connect to the database. | Optional
|
||||
| \-\-disableNexus | | Disable the Nexus Analyzer. | Optional
|
||||
| \-\-nexus | \<url\> | The url to the Nexus Server. | Optional
|
||||
Short | Argument Name | Parameter | Description | Requirement
|
||||
-------|-----------------------|-----------------|-------------|------------
|
||||
\-a | \-\-app | \<name\> | The name of the application being scanned. This is a required argument. | Required
|
||||
\-s | \-\-scan | \<path\> | The path to scan \- this option can be specified multiple times. It is also possible to specify Ant style paths (e.g. directory/**/*.jar). | Required
|
||||
| \-\-exclude | \<pattern\> | The path patterns to exclude from the scan \- this option can be specified multiple times. This accepts Ant style path patterns (e.g. **/exclude/**) . | Optional
|
||||
\-o | \-\-out | \<path\> | The folder to write reports to. This defaults to the current directory. If the format is not set to ALL one could specify a specific file name. | Optional
|
||||
\-f | \-\-format | \<format\> | The output format to write to (XML, HTML, VULN, ALL). The default is HTML. | Required
|
||||
\-l | \-\-log | \<file\> | The file path to write verbose logging information. | Optional
|
||||
\-n | \-\-noupdate | | Disables the automatic updating of the CPE data. | Optional
|
||||
| \-\-suppression | \<file\> | The file path to the suppression XML file; used to suppress [false positives](../suppression.html). | Optional
|
||||
\-h | \-\-help | | Print the help message. | Optional
|
||||
| \-\-advancedHelp | | Print the advanced help message. | Optional
|
||||
\-v | \-\-version | | Print the version information. | Optional
|
||||
|
||||
Advanced Options
|
||||
================
|
||||
Short | Argument Name | Parameter | Description | Default Value
|
||||
-------|-----------------------|-----------------|-----------------------------------------------------------------------------|---------------
|
||||
\-P | \-\-propertyfile | \<file\> | Specifies a file that contains properties to use instead of applicaion defaults. |
|
||||
| \-\-disableArchive | | Sets whether the Archive Analyzer will be used. | false
|
||||
| \-\-zipExtensions | \<strings\> | A comma-separated list of additional file extensions to be treated like a ZIP file, the contents will be extracted and analyzed. |
|
||||
| \-\-disableJar | | Sets whether the Jar Analyzer will be used. | false
|
||||
| \-\-disableCentral | | Sets whether the Central Analyzer will be used. **Disabling this analyzer is not recommended as it could lead to false negatives (e.g. libraries that have vulnerabilities may not be reported correctly).** If this analyzer is being disabled there is a good chance you also want to disable the Nexus Analyzer. | false
|
||||
| \-\-disableNexus | | Sets whether the Nexus Analyzer will be used. Note, this has been superceded by the Central Analyzer. However, you can configure the Nexus URL to utilize an internally hosted Nexus Pro server. | false
|
||||
| \-\-nexus | \<url\> | The url to the Nexus Pro Server. If not set the Nexus Analyzer will be disabled. |
|
||||
| \-\-nexusUsesProxy | \<true\|false\> | Whether or not the defined proxy should be used when connecting to Nexus. | true
|
||||
| \-\-disableNuspec | | Sets whether or not the .NET Nuget Nuspec Analyzer will be used. | false
|
||||
| \-\-disableAssembly | | Sets whether or not the .NET Assembly Analyzer should be used. | false
|
||||
| \-\-pathToMono | \<path\> | The path to Mono for .NET Assembly analysis on non-windows systems. |
|
||||
| \-\-proxyserver | \<server\> | The proxy server to use when downloading resources. |
|
||||
| \-\-proxyport | \<port\> | The proxy port to use when downloading resources. |
|
||||
| \-\-connectiontimeout | \<timeout\> | The connection timeout (in milliseconds) to use when downloading resources. |
|
||||
| \-\-proxypass | \<pass\> | The proxy password to use when downloading resources. |
|
||||
| \-\-proxyuser | \<user\> | The proxy username to use when downloading resources. |
|
||||
| \-\-connectionString | \<connStr\> | The connection string to the database. |
|
||||
| \-\-dbDriverName | \<driver\> | The database driver name. |
|
||||
| \-\-dbDriverPath | \<path\> | The path to the database driver; note, this does not need to be set unless the JAR is outside of the class path. |
|
||||
| \-\-dbPassword | \<password\> | The password for connecting to the database. |
|
||||
| \-\-dbUser | \<user\> | The username used to connect to the database. |
|
||||
\-d | \-\-data | \<path\> | The location of the data directory used to store persistent data. This option should generally not be set. |
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
Installation & Usage
|
||||
--------------------
|
||||
====================
|
||||
Download the dependency-check command line tool [here](http://dl.bintray.com/jeremy-long/owasp/dependency-check-${project.version}-release.zip).
|
||||
Extract the zip file to a location on your computer and put the 'bin' directory into the
|
||||
path environment variable. On \*nix systems you will likely need to make the shell
|
||||
@@ -8,16 +8,18 @@ script executable:
|
||||
$ chmod +777 dependency-check.sh
|
||||
|
||||
To scan a folder on the system you can run:
|
||||
#set( $H = '#' )
|
||||
|
||||
<h3>Windows</h3>
|
||||
$H$H$H Windows
|
||||
dependency-check.bat --app "My App Name" --scan "c:\java\application\lib"
|
||||
|
||||
<h3>\*nix</h3>
|
||||
$H$H$H *nix
|
||||
dependency-check.sh --app "My App Name" --scan "/java/application/lib"
|
||||
|
||||
To view the command line arguments, see the <a href="arguments.html">arguments page</a>, or you can run:
|
||||
<h3>Windows</h3>
|
||||
|
||||
$H$H$H Windows
|
||||
dependency-check.bat --help
|
||||
|
||||
<h3>\*nix</h3>
|
||||
$H$H$H *nix
|
||||
dependency-check.sh --help
|
||||
@@ -15,8 +15,9 @@
|
||||
*
|
||||
* Copyright (c) 2012 Jeremy Long. All Rights Reserved.
|
||||
*/
|
||||
package org.owasp.dependencycheck.cli;
|
||||
package org.owasp.dependencycheck;
|
||||
|
||||
import org.owasp.dependencycheck.CliParser;
|
||||
import java.io.ByteArrayOutputStream;
|
||||
import java.io.File;
|
||||
import java.io.FileNotFoundException;
|
||||
@@ -29,6 +30,7 @@ import org.junit.Assert;
|
||||
import org.junit.Before;
|
||||
import org.junit.BeforeClass;
|
||||
import org.junit.Test;
|
||||
import org.owasp.dependencycheck.utils.Settings;
|
||||
|
||||
/**
|
||||
*
|
||||
@@ -38,10 +40,12 @@ public class CliParserTest {
|
||||
|
||||
@BeforeClass
|
||||
public static void setUpClass() throws Exception {
|
||||
Settings.initialize();
|
||||
}
|
||||
|
||||
@AfterClass
|
||||
public static void tearDownClass() throws Exception {
|
||||
Settings.cleanup(true);
|
||||
}
|
||||
|
||||
@Before
|
||||
@@ -1,223 +0,0 @@
|
||||
<?xml version="1.0"?>
|
||||
<!DOCTYPE module PUBLIC
|
||||
"-//Puppy Crawl//DTD Check Configuration 1.3//EN"
|
||||
"http://www.puppycrawl.com/dtds/configuration_1_3.dtd">
|
||||
|
||||
<module name="Checker">
|
||||
<!--
|
||||
If you set the basedir property below, then all reported file
|
||||
names will be relative to the specified directory. See
|
||||
http://checkstyle.sourceforge.net/5.x/config.html#Checker
|
||||
|
||||
<property name="basedir" value="${basedir}"/>
|
||||
-->
|
||||
|
||||
<property name="severity" value="error"/>
|
||||
|
||||
<module name="SuppressionFilter">
|
||||
<property name="file" value="${checkstyle.suppressions.file}"/>
|
||||
</module>
|
||||
|
||||
<module name="JavadocPackage">
|
||||
<property name="allowLegacy" value="false"/>
|
||||
</module>
|
||||
|
||||
<module name="Translation">
|
||||
<property name="severity" value="warning"/>
|
||||
</module>
|
||||
|
||||
<module name="FileTabCharacter">
|
||||
<property name="eachLine" value="false"/>
|
||||
</module>
|
||||
|
||||
<module name="FileLength">
|
||||
<property name="fileExtensions" value="java"/>
|
||||
</module>
|
||||
|
||||
<module name="NewlineAtEndOfFile">
|
||||
<property name="fileExtensions" value="java"/>
|
||||
<property name="lineSeparator" value="lf"/>
|
||||
</module>
|
||||
|
||||
<module name="RegexpHeader">
|
||||
<property name="headerFile" value="${checkstyle.header.file}"/>
|
||||
<property name="fileExtensions" value="java"/>
|
||||
<property name="id" value="header"/>
|
||||
</module>
|
||||
|
||||
<module name="RegexpSingleline">
|
||||
<property name="format" value="\s+$"/>
|
||||
<property name="minimum" value="0"/>
|
||||
<property name="maximum" value="0"/>
|
||||
</module>
|
||||
|
||||
<module name="TreeWalker">
|
||||
<property name="tabWidth" value="4"/>
|
||||
|
||||
<module name="AvoidStarImport"/>
|
||||
<module name="ConstantName"/>
|
||||
<module name="EmptyBlock"/>
|
||||
<module name="EmptyForIteratorPad"/>
|
||||
<module name="EqualsHashCode"/>
|
||||
<module name="OneStatementPerLine"/>
|
||||
|
||||
<!-- module name="IllegalCatch"/ -->
|
||||
<!--module name="ImportControl">
|
||||
<property name="file" value="${checkstyle.importcontrol.file}"/>
|
||||
</module-->
|
||||
<module name="IllegalImport"/>
|
||||
<module name="IllegalInstantiation"/>
|
||||
<module name="IllegalThrows"/>
|
||||
<module name="InnerAssignment"/>
|
||||
<module name="JavadocType">
|
||||
<property name="authorFormat" value="\S"/>
|
||||
</module>
|
||||
<module name="JavadocMethod">
|
||||
<property name="allowUndeclaredRTE" value="true"/>
|
||||
<property name="allowThrowsTagsForSubclasses" value="true"/>
|
||||
<property name="allowMissingPropertyJavadoc" value="true"/>
|
||||
</module>
|
||||
<module name="JavadocVariable"/>
|
||||
<module name="JavadocStyle">
|
||||
<property name="scope" value="public"/>
|
||||
</module>
|
||||
|
||||
<module name="LeftCurly">
|
||||
<property name="option" value="eol"/>
|
||||
<property name="tokens" value="CLASS_DEF"/>
|
||||
<property name="tokens" value="CTOR_DEF"/>
|
||||
<property name="tokens" value="INTERFACE_DEF"/>
|
||||
<property name="tokens" value="METHOD_DEF"/>
|
||||
<property name="tokens" value="LITERAL_CATCH"/>
|
||||
<property name="tokens" value="LITERAL_DO"/>
|
||||
<property name="tokens" value="LITERAL_ELSE"/>
|
||||
<property name="tokens" value="LITERAL_FINALLY"/>
|
||||
<property name="tokens" value="LITERAL_FOR"/>
|
||||
<property name="tokens" value="LITERAL_IF"/>
|
||||
<property name="tokens" value="LITERAL_SWITCH"/>
|
||||
<property name="tokens" value="LITERAL_SYNCHRONIZED"/>
|
||||
<property name="tokens" value="LITERAL_TRY"/>
|
||||
<property name="tokens" value="LITERAL_WHILE"/>
|
||||
</module>
|
||||
|
||||
<module name="OuterTypeNumber"/>
|
||||
<module name="LineLength">
|
||||
<property name="ignorePattern" value="^ *\* *[^ ]+$"/>
|
||||
<property name="max" value="150"/>
|
||||
</module>
|
||||
|
||||
<module name="MethodCount">
|
||||
<property name="maxTotal" value="40"/>
|
||||
</module>
|
||||
|
||||
<module name="LocalFinalVariableName"/>
|
||||
<module name="LocalVariableName"/>
|
||||
<module name="MemberName">
|
||||
<property name="format" value="^[a-z][a-zA-Z0-9]*$"/>
|
||||
</module>
|
||||
<module name="MethodLength">
|
||||
<property name="max" value="160"/>
|
||||
<property name="countEmpty" value="false"/>
|
||||
</module>
|
||||
<module name="MethodName"/>
|
||||
<module name="MethodParamPad"/>
|
||||
<module name="ModifierOrder"/>
|
||||
<module name="NeedBraces"/>
|
||||
<module name="NoWhitespaceAfter">
|
||||
<property name="tokens" value="ARRAY_INIT"/>
|
||||
<property name="tokens" value="BNOT"/>
|
||||
<property name="tokens" value="DEC"/>
|
||||
<property name="tokens" value="DOT"/>
|
||||
<property name="tokens" value="INC"/>
|
||||
<property name="tokens" value="LNOT"/>
|
||||
<property name="tokens" value="UNARY_MINUS"/>
|
||||
<property name="tokens" value="UNARY_PLUS"/>
|
||||
</module>
|
||||
|
||||
<module name="NoWhitespaceBefore"/>
|
||||
<module name="NoWhitespaceBefore">
|
||||
<property name="tokens" value="DOT"/>
|
||||
<property name="allowLineBreaks" value="true"/>
|
||||
</module>
|
||||
|
||||
<module name="OperatorWrap"/>
|
||||
<module name="OperatorWrap">
|
||||
<property name="tokens" value="ASSIGN"/>
|
||||
<property name="tokens" value="DIV_ASSIGN"/>
|
||||
<property name="tokens" value="PLUS_ASSIGN"/>
|
||||
<property name="tokens" value="MINUS_ASSIGN"/>
|
||||
<property name="tokens" value="STAR_ASSIGN"/>
|
||||
<property name="tokens" value="MOD_ASSIGN"/>
|
||||
<property name="tokens" value="SR_ASSIGN"/>
|
||||
<property name="tokens" value="BSR_ASSIGN"/>
|
||||
<property name="tokens" value="SL_ASSIGN"/>
|
||||
<property name="tokens" value="BXOR_ASSIGN"/>
|
||||
<property name="tokens" value="BOR_ASSIGN"/>
|
||||
<property name="tokens" value="BAND_ASSIGN"/>
|
||||
<property name="option" value="eol"/>
|
||||
</module>
|
||||
<module name="PackageName"/>
|
||||
<module name="ParameterName">
|
||||
<property name="format" value="^[a-z][a-zA-Z0-9]*$"/>
|
||||
</module>
|
||||
<module name="ParameterNumber">
|
||||
<property name="id" value="paramNum"/>
|
||||
</module>
|
||||
<module name="ParenPad"/>
|
||||
<module name="TypecastParenPad"/>
|
||||
<module name="RedundantImport"/>
|
||||
<module name="RedundantModifier"/>
|
||||
<module name="RightCurly">
|
||||
<property name="option" value="same"/>
|
||||
</module>
|
||||
<module name="SimplifyBooleanExpression"/>
|
||||
<module name="SimplifyBooleanReturn"/>
|
||||
<module name="StaticVariableName">
|
||||
<property name="format" value="^[a-z][a-zA-Z0-9]*$"/>
|
||||
</module>
|
||||
<module name="TypeName"/>
|
||||
<module name="UnusedImports"/>
|
||||
<module name="UpperEll"/>
|
||||
<module name="VisibilityModifier"/>
|
||||
<module name="WhitespaceAfter"/>
|
||||
<module name="WhitespaceAround"/>
|
||||
<module name="GenericWhitespace"/>
|
||||
<module name="FinalClass"/>
|
||||
<module name="MissingSwitchDefault"/>
|
||||
<!--module name="MagicNumber"/-->
|
||||
<!--module name="Indentation">
|
||||
<property name="basicOffset" value="4"/>
|
||||
<property name="braceAdjustment" value="0"/>
|
||||
<property name="caseIndent" value="0"/>
|
||||
</module-->
|
||||
<module name="ArrayTrailingComma"/>
|
||||
<module name="FinalLocalVariable"/>
|
||||
<module name="EqualsAvoidNull"/>
|
||||
<module name="ParameterAssignment"/>
|
||||
|
||||
<!-- Generates quite a few errors -->
|
||||
<module name="CyclomaticComplexity">
|
||||
<property name="severity" value="ignore"/>
|
||||
</module>
|
||||
|
||||
<module name="NestedForDepth">
|
||||
<property name="max" value="2"/>
|
||||
</module>
|
||||
<module name="NestedIfDepth">
|
||||
<property name="max" value="4"/>
|
||||
</module>
|
||||
<module name="NestedTryDepth">
|
||||
<property name="max" value="2"/>
|
||||
</module>
|
||||
<!--module name="ExplicitInitialization"/-->
|
||||
<module name="AnnotationUseStyle"/>
|
||||
<module name="MissingDeprecated"/>
|
||||
<module name="MissingOverride">
|
||||
<property name="javaFiveCompatibility" value="true"/>
|
||||
</module>
|
||||
<module name="PackageAnnotation"/>
|
||||
<module name="SuppressWarnings"/>
|
||||
<module name="OuterTypeFilename"/>
|
||||
<module name="HideUtilityClassConstructor"/>
|
||||
</module>
|
||||
</module>
|
||||
@@ -1,18 +0,0 @@
|
||||
^/\*\s*$
|
||||
^ \* This file is part of dependency-check-core\.\s*$
|
||||
^ \*\s*$
|
||||
^ \* Licensed under the Apache License, Version 2\.0 \(the "License"\);\s*$
|
||||
^ \* you may not use this file except in compliance with the License.\s*$
|
||||
^ \* You may obtain a copy of the License at\s*$
|
||||
^ \*\s*$
|
||||
^ \*\s*http://www.apache.org/licenses/LICENSE-2\.0\s*$
|
||||
^ \*\s*$
|
||||
^ \* Unless required by applicable law or agreed to in writing, software\s*$
|
||||
^ \* distributed under the License is distributed on an "AS IS" BASIS,\s*$
|
||||
^ \* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied\.\s*$
|
||||
^ \* See the License for the specific language governing permissions and\s*$
|
||||
^ \* limitations under the License\.\s*$
|
||||
^ \*\s*$
|
||||
^ \* Copyright \(c\) 201[234] (Jeremy Long|Steve Springett)\. All Rights Reserved\.\s*$
|
||||
^ \*/\s*$
|
||||
^package
|
||||
@@ -1,12 +0,0 @@
|
||||
<?xml version="1.0"?>
|
||||
|
||||
<!DOCTYPE suppressions PUBLIC
|
||||
"-//Puppy Crawl//DTD Suppressions 1.0//EN"
|
||||
"http://www.puppycrawl.com/dtds/suppressions_1_0.dtd">
|
||||
|
||||
<suppressions>
|
||||
<suppress checks=".*" files=".*[\\/]package-info\.java" />
|
||||
<suppress checks=".*" files=".*org[\\/]owasp[\\/]dependencycheck[\\/]utils[\\/]Filter.java" />
|
||||
<suppress checks=".*" files=".*org[\\/]owasp[\\/]dependencycheck[\\/]utils[\\/]Checksum.java" />
|
||||
<suppress checks=".*" files=".*[\\/]generated[\\/].*.java" />
|
||||
</suppressions>
|
||||
@@ -15,19 +15,19 @@ limitations under the License.
|
||||
|
||||
Copyright (c) 2012 Jeremy Long. All Rights Reserved.
|
||||
-->
|
||||
|
||||
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
<parent>
|
||||
<groupId>org.owasp</groupId>
|
||||
<artifactId>dependency-check-parent</artifactId>
|
||||
<version>1.1.1</version>
|
||||
<version>1.2.9</version>
|
||||
</parent>
|
||||
|
||||
<artifactId>dependency-check-core</artifactId>
|
||||
<packaging>jar</packaging>
|
||||
|
||||
<name>Dependency-Check Core</name>
|
||||
<description>dependency-check-core is the engine and reporting tool used to identify and report if there are any known, publicly disclosed vulnerabilities in the scanned project's dependencies. The engine extracts meta-data from the dependencies and uses this to do fuzzy key-word matching against the Common Platfrom Enumeration (CPE), if any CPE identifiers are found the associated Common Vulnerability and Exposure (CVE) entries are added to the generated report.</description>
|
||||
<!-- begin copy from http://minds.coremedia.com/2012/09/11/problem-solved-deploy-multi-module-maven-project-site-as-github-pages/ -->
|
||||
<distributionManagement>
|
||||
<site>
|
||||
@@ -93,7 +93,6 @@ Copyright (c) 2012 Jeremy Long. All Rights Reserved.
|
||||
<plugin>
|
||||
<groupId>org.apache.maven.plugins</groupId>
|
||||
<artifactId>maven-dependency-plugin</artifactId>
|
||||
<version>2.8</version>
|
||||
<executions>
|
||||
<execution>
|
||||
<phase>generate-resources</phase>
|
||||
@@ -110,7 +109,6 @@ Copyright (c) 2012 Jeremy Long. All Rights Reserved.
|
||||
<plugin>
|
||||
<groupId>org.apache.maven.plugins</groupId>
|
||||
<artifactId>maven-jar-plugin</artifactId>
|
||||
<version>2.4</version>
|
||||
<executions>
|
||||
<execution>
|
||||
<id>jar</id>
|
||||
@@ -127,23 +125,13 @@ Copyright (c) 2012 Jeremy Long. All Rights Reserved.
|
||||
</goals>
|
||||
</execution>
|
||||
</executions>
|
||||
<configuration>
|
||||
<archive>
|
||||
<manifest>
|
||||
<addDefaultImplementationEntries>true</addDefaultImplementationEntries>
|
||||
</manifest>
|
||||
</archive>
|
||||
<excludes>
|
||||
<exclude>**/checkstyle*</exclude>
|
||||
</excludes>
|
||||
</configuration>
|
||||
</plugin>
|
||||
<plugin>
|
||||
<groupId>org.codehaus.mojo</groupId>
|
||||
<artifactId>cobertura-maven-plugin</artifactId>
|
||||
<version>2.6</version>
|
||||
<configuration>
|
||||
<instrumentation>
|
||||
<!--ignoreTrivial>true</ignoreTrivial-->
|
||||
<ignores>
|
||||
<ignore>.*\$KEYS\.class</ignore>
|
||||
<ignore>.*\$Element\.class</ignore>
|
||||
@@ -191,7 +179,6 @@ Copyright (c) 2012 Jeremy Long. All Rights Reserved.
|
||||
<plugin>
|
||||
<groupId>org.apache.maven.plugins</groupId>
|
||||
<artifactId>maven-surefire-plugin</artifactId>
|
||||
<version>2.16</version>
|
||||
<configuration>
|
||||
<systemProperties>
|
||||
<property>
|
||||
@@ -212,7 +199,6 @@ Copyright (c) 2012 Jeremy Long. All Rights Reserved.
|
||||
<plugin>
|
||||
<groupId>org.apache.maven.plugins</groupId>
|
||||
<artifactId>maven-failsafe-plugin</artifactId>
|
||||
<version>2.16</version>
|
||||
<configuration>
|
||||
<systemProperties>
|
||||
<property>
|
||||
@@ -220,194 +206,168 @@ Copyright (c) 2012 Jeremy Long. All Rights Reserved.
|
||||
<value>${project.build.directory}/data</value>
|
||||
</property>
|
||||
</systemProperties>
|
||||
<includes>
|
||||
<include>**/*IntegrationTest.java</include>
|
||||
</includes>
|
||||
</configuration>
|
||||
<executions>
|
||||
<execution>
|
||||
<goals>
|
||||
<goal>integration-test</goal>
|
||||
<goal>verify</goal>
|
||||
</goals>
|
||||
</execution>
|
||||
</executions>
|
||||
</plugin>
|
||||
<plugin>
|
||||
<groupId>org.apache.maven.plugins</groupId>
|
||||
<artifactId>maven-site-plugin</artifactId>
|
||||
<version>3.3</version>
|
||||
<dependencies>
|
||||
<dependency>
|
||||
<groupId>org.apache.maven.doxia</groupId>
|
||||
<artifactId>doxia-module-markdown</artifactId>
|
||||
<version>1.5</version>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
<configuration>
|
||||
<skipDeploy>true</skipDeploy>
|
||||
<reportPlugins>
|
||||
<plugin>
|
||||
<groupId>org.apache.maven.plugins</groupId>
|
||||
<artifactId>maven-project-info-reports-plugin</artifactId>
|
||||
<version>2.7</version>
|
||||
<reportSets>
|
||||
<reportSet>
|
||||
<reports>
|
||||
<report>index</report>
|
||||
<report>summary</report>
|
||||
<report>license</report>
|
||||
<report>help</report>
|
||||
</reports>
|
||||
</reportSet>
|
||||
</reportSets>
|
||||
</plugin>
|
||||
<plugin>
|
||||
<groupId>org.apache.maven.plugins</groupId>
|
||||
<artifactId>maven-javadoc-plugin</artifactId>
|
||||
<version>2.9.1</version>
|
||||
<reportSets>
|
||||
<reportSet>
|
||||
<id>default</id>
|
||||
<reports>
|
||||
<report>javadoc</report>
|
||||
</reports>
|
||||
</reportSet>
|
||||
</reportSets>
|
||||
</plugin>
|
||||
<plugin>
|
||||
<groupId>org.codehaus.mojo</groupId>
|
||||
<artifactId>versions-maven-plugin</artifactId>
|
||||
<version>2.1</version>
|
||||
<reportSets>
|
||||
<reportSet>
|
||||
<reports>
|
||||
<report>dependency-updates-report</report>
|
||||
<report>plugin-updates-report</report>
|
||||
</reports>
|
||||
</reportSet>
|
||||
</reportSets>
|
||||
</plugin>
|
||||
<plugin>
|
||||
<groupId>org.apache.maven.plugins</groupId>
|
||||
<artifactId>maven-jxr-plugin</artifactId>
|
||||
<version>2.4</version>
|
||||
</plugin>
|
||||
<plugin>
|
||||
<groupId>org.codehaus.mojo</groupId>
|
||||
<artifactId>cobertura-maven-plugin</artifactId>
|
||||
<version>2.6</version>
|
||||
</plugin>
|
||||
<plugin>
|
||||
<groupId>org.apache.maven.plugins</groupId>
|
||||
<artifactId>maven-surefire-report-plugin</artifactId>
|
||||
<version>2.16</version>
|
||||
<reportSets>
|
||||
<reportSet>
|
||||
<reports>
|
||||
<report>report-only</report>
|
||||
</reports>
|
||||
</reportSet>
|
||||
<reportSet>
|
||||
<id>integration-tests</id>
|
||||
<reports>
|
||||
<report>report-only</report>
|
||||
<report>failsafe-report-only</report>
|
||||
</reports>
|
||||
</reportSet>
|
||||
</reportSets>
|
||||
</plugin>
|
||||
<plugin>
|
||||
<groupId>org.codehaus.mojo</groupId>
|
||||
<artifactId>taglist-maven-plugin</artifactId>
|
||||
<version>2.4</version>
|
||||
<configuration>
|
||||
<tagListOptions>
|
||||
<tagClasses>
|
||||
<tagClass>
|
||||
<displayName>Todo Work</displayName>
|
||||
<tags>
|
||||
<tag>
|
||||
<matchString>todo</matchString>
|
||||
<matchType>ignoreCase</matchType>
|
||||
</tag>
|
||||
<tag>
|
||||
<matchString>FIXME</matchString>
|
||||
<matchType>exact</matchType>
|
||||
</tag>
|
||||
</tags>
|
||||
</tagClass>
|
||||
</tagClasses>
|
||||
</tagListOptions>
|
||||
</configuration>
|
||||
</plugin>
|
||||
<plugin>
|
||||
<groupId>org.apache.maven.plugins</groupId>
|
||||
<artifactId>maven-checkstyle-plugin</artifactId>
|
||||
<version>2.11</version>
|
||||
<configuration>
|
||||
<enableRulesSummary>false</enableRulesSummary>
|
||||
<configLocation>${basedir}/config/checkstyle-checks.xml</configLocation>
|
||||
<headerLocation>${basedir}/config/checkstyle-header.txt</headerLocation>
|
||||
<suppressionsLocation>${basedir}/config/checkstyle-suppressions.xml</suppressionsLocation>
|
||||
<suppressionsFileExpression>checkstyle.suppressions.file</suppressionsFileExpression>
|
||||
</configuration>
|
||||
</plugin>
|
||||
<plugin>
|
||||
<groupId>org.apache.maven.plugins</groupId>
|
||||
<artifactId>maven-pmd-plugin</artifactId>
|
||||
<version>3.0.1</version>
|
||||
<configuration>
|
||||
<targetJdk>1.6</targetJdk>
|
||||
<linkXref>true</linkXref>
|
||||
<sourceEncoding>utf-8</sourceEncoding>
|
||||
<excludes>
|
||||
<exclude>**/generated/*.java</exclude>
|
||||
</excludes>
|
||||
</configuration>
|
||||
</plugin>
|
||||
<plugin>
|
||||
<groupId>org.codehaus.mojo</groupId>
|
||||
<artifactId>findbugs-maven-plugin</artifactId>
|
||||
<version>2.5.3</version>
|
||||
</plugin>
|
||||
<dependency>
|
||||
<groupId>org.codehaus.mojo</groupId>
|
||||
<artifactId>javancss-maven-plugin</artifactId>
|
||||
<version>2.0</version>
|
||||
</dependency>
|
||||
</reportPlugins>
|
||||
</configuration>
|
||||
</plugin>
|
||||
<plugin>
|
||||
<groupId>org.apache.maven.plugins</groupId>
|
||||
<artifactId>maven-compiler-plugin</artifactId>
|
||||
<version>3.1</version>
|
||||
<configuration>
|
||||
<showDeprecation>false</showDeprecation>
|
||||
<source>1.6</source>
|
||||
<target>1.6</target>
|
||||
<compilerArgument>-Xlint:unchecked</compilerArgument>
|
||||
</configuration>
|
||||
</plugin>
|
||||
</plugins>
|
||||
</build>
|
||||
<reporting>
|
||||
<plugins>
|
||||
<plugin>
|
||||
<groupId>org.apache.maven.plugins</groupId>
|
||||
<artifactId>maven-javadoc-plugin</artifactId>
|
||||
<version>2.9.1</version>
|
||||
<configuration>
|
||||
<bottom>Copyright© 2012-15 Jeremy Long. All Rights Reserved.</bottom>
|
||||
</configuration>
|
||||
<reportSets>
|
||||
<reportSet>
|
||||
<id>default</id>
|
||||
<reports>
|
||||
<report>javadoc</report>
|
||||
</reports>
|
||||
</reportSet>
|
||||
</reportSets>
|
||||
</plugin>
|
||||
<plugin>
|
||||
<groupId>org.codehaus.mojo</groupId>
|
||||
<artifactId>versions-maven-plugin</artifactId>
|
||||
<version>2.1</version>
|
||||
<reportSets>
|
||||
<reportSet>
|
||||
<reports>
|
||||
<report>dependency-updates-report</report>
|
||||
<report>plugin-updates-report</report>
|
||||
</reports>
|
||||
</reportSet>
|
||||
</reportSets>
|
||||
</plugin>
|
||||
<plugin>
|
||||
<groupId>org.apache.maven.plugins</groupId>
|
||||
<artifactId>maven-jxr-plugin</artifactId>
|
||||
<version>2.4</version>
|
||||
</plugin>
|
||||
<plugin>
|
||||
<groupId>org.codehaus.mojo</groupId>
|
||||
<artifactId>cobertura-maven-plugin</artifactId>
|
||||
<version>2.6</version>
|
||||
</plugin>
|
||||
<plugin>
|
||||
<groupId>org.apache.maven.plugins</groupId>
|
||||
<artifactId>maven-surefire-report-plugin</artifactId>
|
||||
<version>2.16</version>
|
||||
<reportSets>
|
||||
<reportSet>
|
||||
<reports>
|
||||
<report>report-only</report>
|
||||
</reports>
|
||||
</reportSet>
|
||||
<reportSet>
|
||||
<id>integration-tests</id>
|
||||
<reports>
|
||||
<report>report-only</report>
|
||||
<report>failsafe-report-only</report>
|
||||
</reports>
|
||||
</reportSet>
|
||||
</reportSets>
|
||||
</plugin>
|
||||
<plugin>
|
||||
<groupId>org.codehaus.mojo</groupId>
|
||||
<artifactId>taglist-maven-plugin</artifactId>
|
||||
<version>2.4</version>
|
||||
<configuration>
|
||||
<tagListOptions>
|
||||
<tagClasses>
|
||||
<tagClass>
|
||||
<displayName>Todo Work</displayName>
|
||||
<tags>
|
||||
<tag>
|
||||
<matchString>todo</matchString>
|
||||
<matchType>ignoreCase</matchType>
|
||||
</tag>
|
||||
<tag>
|
||||
<matchString>FIXME</matchString>
|
||||
<matchType>exact</matchType>
|
||||
</tag>
|
||||
</tags>
|
||||
</tagClass>
|
||||
</tagClasses>
|
||||
</tagListOptions>
|
||||
</configuration>
|
||||
</plugin>
|
||||
<plugin>
|
||||
<groupId>org.apache.maven.plugins</groupId>
|
||||
<artifactId>maven-checkstyle-plugin</artifactId>
|
||||
<version>2.11</version>
|
||||
<configuration>
|
||||
<enableRulesSummary>false</enableRulesSummary>
|
||||
<enableFilesSummary>false</enableFilesSummary>
|
||||
<configLocation>${basedir}/../src/main/config/checkstyle-checks.xml</configLocation>
|
||||
<headerLocation>${basedir}/../src/main/config/checkstyle-header.txt</headerLocation>
|
||||
<suppressionsLocation>${basedir}/../src/main/config/checkstyle-suppressions.xml</suppressionsLocation>
|
||||
<suppressionsFileExpression>checkstyle.suppressions.file</suppressionsFileExpression>
|
||||
</configuration>
|
||||
</plugin>
|
||||
<plugin>
|
||||
<groupId>org.apache.maven.plugins</groupId>
|
||||
<artifactId>maven-pmd-plugin</artifactId>
|
||||
<version>3.1</version>
|
||||
<configuration>
|
||||
<targetJdk>1.6</targetJdk>
|
||||
<linkXref>true</linkXref>
|
||||
<sourceEncoding>utf-8</sourceEncoding>
|
||||
<excludes>
|
||||
<exclude>**/generated/*.java</exclude>
|
||||
</excludes>
|
||||
<rulesets>
|
||||
<ruleset>../src/main/config/dcrules.xml</ruleset>
|
||||
<ruleset>/rulesets/java/basic.xml</ruleset>
|
||||
<ruleset>/rulesets/java/imports.xml</ruleset>
|
||||
<ruleset>/rulesets/java/unusedcode.xml</ruleset>
|
||||
</rulesets>
|
||||
</configuration>
|
||||
</plugin>
|
||||
<plugin>
|
||||
<groupId>org.codehaus.mojo</groupId>
|
||||
<artifactId>findbugs-maven-plugin</artifactId>
|
||||
<version>2.5.3</version>
|
||||
</plugin>
|
||||
</plugins>
|
||||
</reporting>
|
||||
<dependencies>
|
||||
<!-- Note, to stay compatible with Jenkins installations only JARs compiled to 1.6 can be used -->
|
||||
<dependency>
|
||||
<groupId>org.owasp</groupId>
|
||||
<artifactId>dependency-check-utils</artifactId>
|
||||
<version>${project.parent.version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.apache.lucene</groupId>
|
||||
<artifactId>lucene-test-framework</artifactId>
|
||||
<version>4.3.1</version>
|
||||
<version>${apache.lucene.version}</version>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.jmockit</groupId>
|
||||
<artifactId>jmockit</artifactId>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>com.google.code.findbugs</groupId>
|
||||
<artifactId>annotations</artifactId>
|
||||
<version>2.0.1</version>
|
||||
<version>3.0.0</version>
|
||||
<optional>true</optional>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>commons-cli</groupId>
|
||||
<artifactId>commons-cli</artifactId>
|
||||
<version>1.2</version>
|
||||
<groupId>org.apache.commons</groupId>
|
||||
<artifactId>commons-compress</artifactId>
|
||||
<version>1.9</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>commons-io</groupId>
|
||||
@@ -417,76 +377,32 @@ Copyright (c) 2012 Jeremy Long. All Rights Reserved.
|
||||
<dependency>
|
||||
<groupId>commons-lang</groupId>
|
||||
<artifactId>commons-lang</artifactId>
|
||||
<version>2.5</version>
|
||||
<version>2.6</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.apache.lucene</groupId>
|
||||
<artifactId>lucene-core</artifactId>
|
||||
<version>4.5.1</version>
|
||||
<version>${apache.lucene.version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.apache.lucene</groupId>
|
||||
<artifactId>lucene-analyzers-common</artifactId>
|
||||
<version>4.5.1</version>
|
||||
<version>${apache.lucene.version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.apache.lucene</groupId>
|
||||
<artifactId>lucene-queryparser</artifactId>
|
||||
<version>4.5.1</version>
|
||||
<version>${apache.lucene.version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.apache.velocity</groupId>
|
||||
<artifactId>velocity</artifactId>
|
||||
<version>1.7</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.apache.velocity</groupId>
|
||||
<artifactId>velocity-tools</artifactId>
|
||||
<version>2.0</version>
|
||||
<!-- very limited use of the velocity-tools, not all of the dependencies are needed-->
|
||||
<exclusions>
|
||||
<exclusion>
|
||||
<groupId>commons-chain</groupId>
|
||||
<artifactId>commons-chain</artifactId>
|
||||
</exclusion>
|
||||
<exclusion>
|
||||
<groupId>javax.servlet</groupId>
|
||||
<artifactId>servlet-api</artifactId>
|
||||
</exclusion>
|
||||
<exclusion>
|
||||
<groupId>commons-validator</groupId>
|
||||
<artifactId>commons-validator</artifactId>
|
||||
</exclusion>
|
||||
<exclusion>
|
||||
<groupId>dom4j</groupId>
|
||||
<artifactId>dom4j</artifactId>
|
||||
</exclusion>
|
||||
<exclusion>
|
||||
<groupId>sslext</groupId>
|
||||
<artifactId>sslext</artifactId>
|
||||
</exclusion>
|
||||
<exclusion>
|
||||
<groupId>org.apache.struts</groupId>
|
||||
<artifactId>struts-core</artifactId>
|
||||
</exclusion>
|
||||
<exclusion>
|
||||
<groupId>antlr</groupId>
|
||||
<artifactId>antlr</artifactId>
|
||||
</exclusion>
|
||||
<exclusion>
|
||||
<groupId>org.apache.struts</groupId>
|
||||
<artifactId>struts-taglib</artifactId>
|
||||
</exclusion>
|
||||
<exclusion>
|
||||
<groupId>org.apache.struts</groupId>
|
||||
<artifactId>struts-tiles</artifactId>
|
||||
</exclusion>
|
||||
</exclusions>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>com.h2database</groupId>
|
||||
<artifactId>h2</artifactId>
|
||||
<version>1.3.172</version>
|
||||
<version>1.3.176</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.jsoup</groupId>
|
||||
@@ -494,11 +410,6 @@ Copyright (c) 2012 Jeremy Long. All Rights Reserved.
|
||||
<version>1.7.2</version>
|
||||
<type>jar</type>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.apache.commons</groupId>
|
||||
<artifactId>commons-compress</artifactId>
|
||||
<version>1.5</version>
|
||||
</dependency>
|
||||
<!-- The following dependencies are only used during testing -->
|
||||
<dependency>
|
||||
<groupId>org.apache.maven.scm</groupId>
|
||||
@@ -514,6 +425,13 @@ Copyright (c) 2012 Jeremy Long. All Rights Reserved.
|
||||
<scope>provided</scope>
|
||||
<optional>true</optional>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.springframework.security</groupId>
|
||||
<artifactId>spring-security-web</artifactId>
|
||||
<version>3.0.0.RELEASE</version>
|
||||
<scope>provided</scope>
|
||||
<optional>true</optional>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>com.hazelcast</groupId>
|
||||
<artifactId>hazelcast</artifactId>
|
||||
@@ -580,6 +498,27 @@ Copyright (c) 2012 Jeremy Long. All Rights Reserved.
|
||||
<scope>provided</scope>
|
||||
<optional>true</optional>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.apache.openjpa</groupId>
|
||||
<artifactId>openjpa</artifactId>
|
||||
<version>2.0.1</version>
|
||||
<scope>provided</scope>
|
||||
<optional>true</optional>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>com.google.inject</groupId>
|
||||
<artifactId>guice</artifactId>
|
||||
<version>3.0</version>
|
||||
<scope>provided</scope>
|
||||
<optional>true</optional>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.springframework.retry</groupId>
|
||||
<artifactId>spring-retry</artifactId>
|
||||
<version>1.1.0.RELEASE</version>
|
||||
<scope>provided</scope>
|
||||
<optional>true</optional>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
<profiles>
|
||||
<profile>
|
||||
@@ -595,7 +534,7 @@ Copyright (c) 2012 Jeremy Long. All Rights Reserved.
|
||||
<plugin>
|
||||
<groupId>org.apache.maven.plugins</groupId>
|
||||
<artifactId>maven-surefire-plugin</artifactId>
|
||||
<version>2.16</version>
|
||||
<version>2.18.1</version>
|
||||
<configuration>
|
||||
<skip>true</skip>
|
||||
</configuration>
|
||||
@@ -603,7 +542,7 @@ Copyright (c) 2012 Jeremy Long. All Rights Reserved.
|
||||
<plugin>
|
||||
<groupId>org.apache.maven.plugins</groupId>
|
||||
<artifactId>maven-failsafe-plugin</artifactId>
|
||||
<version>2.16</version>
|
||||
<version>2.18.1</version>
|
||||
<configuration>
|
||||
<systemProperties>
|
||||
<property>
|
||||
@@ -635,5 +574,115 @@ Copyright (c) 2012 Jeremy Long. All Rights Reserved.
|
||||
</plugins>
|
||||
</build>
|
||||
</profile>
|
||||
<profile>
|
||||
<!-- The following profile adds additional
|
||||
dependencies that are only used during testing.
|
||||
Additionally, these are only added when using "allTests" to
|
||||
make the build slightly faster in most cases. -->
|
||||
<id>False Positive Tests</id>
|
||||
<activation>
|
||||
<property>
|
||||
<name>allTests</name>
|
||||
</property>
|
||||
</activation>
|
||||
<dependencies>
|
||||
<dependency>
|
||||
<groupId>org.apache.xmlgraphics</groupId>
|
||||
<artifactId>batik-util</artifactId>
|
||||
<version>1.7</version>
|
||||
<scope>provided</scope>
|
||||
<optional>true</optional>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>com.thoughtworks.xstream</groupId>
|
||||
<artifactId>xstream</artifactId>
|
||||
<version>1.4.2</version>
|
||||
<scope>provided</scope>
|
||||
<optional>true</optional>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.apache.ws.security</groupId>
|
||||
<artifactId>wss4j</artifactId>
|
||||
<version>1.5.7</version>
|
||||
<scope>provided</scope>
|
||||
<optional>true</optional>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>com.ganyo</groupId>
|
||||
<artifactId>gcm-server</artifactId>
|
||||
<version>1.0.2</version>
|
||||
<scope>provided</scope>
|
||||
<optional>true</optional>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.python</groupId>
|
||||
<artifactId>jython-standalone</artifactId>
|
||||
<version>2.7-b1</version>
|
||||
<scope>provided</scope>
|
||||
<optional>true</optional>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.jruby</groupId>
|
||||
<artifactId>jruby-complete</artifactId>
|
||||
<version>1.7.4</version>
|
||||
<scope>provided</scope>
|
||||
<optional>true</optional>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.jruby</groupId>
|
||||
<artifactId>jruby</artifactId>
|
||||
<version>1.6.3</version>
|
||||
<scope>provided</scope>
|
||||
<optional>true</optional>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.glassfish.jersey.core</groupId>
|
||||
<artifactId>jersey-client</artifactId>
|
||||
<version>2.12</version>
|
||||
<scope>provided</scope>
|
||||
<optional>true</optional>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>com.sun.jersey</groupId>
|
||||
<artifactId>jersey-client</artifactId>
|
||||
<version>1.11.1</version>
|
||||
<scope>provided</scope>
|
||||
<optional>true</optional>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>com.sun.faces</groupId>
|
||||
<artifactId>jsf-impl</artifactId>
|
||||
<version>2.2.8-02</version>
|
||||
<scope>provided</scope>
|
||||
<optional>true</optional>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>com.google.inject</groupId>
|
||||
<artifactId>guice</artifactId>
|
||||
<version>3.0</version>
|
||||
<scope>provided</scope>
|
||||
<optional>true</optional>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.opensaml</groupId>
|
||||
<artifactId>xmltooling</artifactId>
|
||||
<version>1.4.1</version>
|
||||
<scope>provided</scope>
|
||||
<optional>true</optional>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.springframework</groupId>
|
||||
<artifactId>spring-webmvc</artifactId>
|
||||
<version>3.2.12.RELEASE</version>
|
||||
<scope>provided</scope>
|
||||
<optional>true</optional>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
</profile>
|
||||
</profiles>
|
||||
<properties>
|
||||
<!-- new versions of lucene are compiled with JDK 1.7 and cannot be used ubiquitously in Jenkins
|
||||
this, we cannot upgrade beyond 4.7.2 -->
|
||||
<apache.lucene.version>4.7.2</apache.lucene.version>
|
||||
</properties>
|
||||
</project>
|
||||
|
||||
@@ -26,12 +26,12 @@ import java.util.List;
|
||||
import java.util.Set;
|
||||
import java.util.logging.Level;
|
||||
import java.util.logging.Logger;
|
||||
import org.owasp.dependencycheck.analyzer.AnalysisException;
|
||||
import org.owasp.dependencycheck.analyzer.AnalysisPhase;
|
||||
import org.owasp.dependencycheck.analyzer.Analyzer;
|
||||
import org.owasp.dependencycheck.analyzer.AnalyzerService;
|
||||
import org.owasp.dependencycheck.data.cpe.CpeMemoryIndex;
|
||||
import org.owasp.dependencycheck.data.cpe.IndexException;
|
||||
import org.owasp.dependencycheck.analyzer.FileTypeAnalyzer;
|
||||
import org.owasp.dependencycheck.analyzer.exception.AnalysisException;
|
||||
import org.owasp.dependencycheck.data.nvdcve.ConnectionFactory;
|
||||
import org.owasp.dependencycheck.data.nvdcve.CveDB;
|
||||
import org.owasp.dependencycheck.data.nvdcve.DatabaseException;
|
||||
import org.owasp.dependencycheck.data.update.CachedWebDataSource;
|
||||
@@ -55,52 +55,81 @@ public class Engine {
|
||||
/**
|
||||
* The list of dependencies.
|
||||
*/
|
||||
private final List<Dependency> dependencies;
|
||||
private List<Dependency> dependencies = new ArrayList<Dependency>();
|
||||
/**
|
||||
* A Map of analyzers grouped by Analysis phase.
|
||||
*/
|
||||
private final EnumMap<AnalysisPhase, List<Analyzer>> analyzers;
|
||||
private EnumMap<AnalysisPhase, List<Analyzer>> analyzers = new EnumMap<AnalysisPhase, List<Analyzer>>(AnalysisPhase.class);
|
||||
|
||||
/**
|
||||
* A set of extensions supported by the analyzers.
|
||||
* A Map of analyzers grouped by Analysis phase.
|
||||
*/
|
||||
private final Set<String> extensions;
|
||||
private Set<FileTypeAnalyzer> fileTypeAnalyzers = new HashSet<FileTypeAnalyzer>();
|
||||
|
||||
/**
|
||||
* The ClassLoader to use when dynamically loading Analyzer and Update services.
|
||||
*/
|
||||
private ClassLoader serviceClassLoader = Thread.currentThread().getContextClassLoader();
|
||||
/**
|
||||
* The Logger for use throughout the class.
|
||||
*/
|
||||
private static final Logger LOGGER = Logger.getLogger(Engine.class.getName());
|
||||
|
||||
/**
|
||||
* Creates a new Engine.
|
||||
*
|
||||
* @throws DatabaseException thrown if there is an error connecting to the database
|
||||
*/
|
||||
public Engine() {
|
||||
this.extensions = new HashSet<String>();
|
||||
this.dependencies = new ArrayList<Dependency>();
|
||||
this.analyzers = new EnumMap<AnalysisPhase, List<Analyzer>>(AnalysisPhase.class);
|
||||
public Engine() throws DatabaseException {
|
||||
initializeEngine();
|
||||
}
|
||||
|
||||
boolean autoUpdate = true;
|
||||
try {
|
||||
autoUpdate = Settings.getBoolean(Settings.KEYS.AUTO_UPDATE);
|
||||
} catch (InvalidSettingException ex) {
|
||||
Logger.getLogger(Engine.class.getName()).log(Level.FINE, "Invalid setting for auto-update; using true.");
|
||||
}
|
||||
if (autoUpdate) {
|
||||
doUpdates();
|
||||
}
|
||||
/**
|
||||
* Creates a new Engine.
|
||||
*
|
||||
* @param serviceClassLoader a reference the class loader being used
|
||||
* @throws DatabaseException thrown if there is an error connecting to the database
|
||||
*/
|
||||
public Engine(ClassLoader serviceClassLoader) throws DatabaseException {
|
||||
this.serviceClassLoader = serviceClassLoader;
|
||||
initializeEngine();
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new Engine using the specified classloader to dynamically load Analyzer and Update services.
|
||||
*
|
||||
* @throws DatabaseException thrown if there is an error connecting to the database
|
||||
*/
|
||||
protected final void initializeEngine() throws DatabaseException {
|
||||
ConnectionFactory.initialize();
|
||||
loadAnalyzers();
|
||||
}
|
||||
|
||||
/**
|
||||
* Properly cleans up resources allocated during analysis.
|
||||
*/
|
||||
public void cleanup() {
|
||||
ConnectionFactory.cleanup();
|
||||
}
|
||||
|
||||
/**
|
||||
* Loads the analyzers specified in the configuration file (or system properties).
|
||||
*/
|
||||
private void loadAnalyzers() {
|
||||
|
||||
if (!analyzers.isEmpty()) {
|
||||
return;
|
||||
}
|
||||
for (AnalysisPhase phase : AnalysisPhase.values()) {
|
||||
analyzers.put(phase, new ArrayList<Analyzer>());
|
||||
}
|
||||
|
||||
final AnalyzerService service = AnalyzerService.getInstance();
|
||||
final AnalyzerService service = new AnalyzerService(serviceClassLoader);
|
||||
final Iterator<Analyzer> iterator = service.getAnalyzers();
|
||||
while (iterator.hasNext()) {
|
||||
final Analyzer a = iterator.next();
|
||||
analyzers.get(a.getAnalysisPhase()).add(a);
|
||||
if (a.getSupportedExtensions() != null) {
|
||||
extensions.addAll(a.getSupportedExtensions());
|
||||
if (a instanceof FileTypeAnalyzer) {
|
||||
this.fileTypeAnalyzers.add((FileTypeAnalyzer) a);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -124,151 +153,212 @@ public class Engine {
|
||||
return dependencies;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the dependencies.
|
||||
*
|
||||
* @param dependencies the dependencies
|
||||
*/
|
||||
public void setDependencies(List<Dependency> dependencies) {
|
||||
this.dependencies = dependencies;
|
||||
}
|
||||
|
||||
/**
|
||||
* Scans an array of files or directories. If a directory is specified, it will be scanned recursively. Any
|
||||
* dependencies identified are added to the dependency collection.
|
||||
*
|
||||
* @since v0.3.2.5
|
||||
* @param paths an array of paths to files or directories to be analyzed
|
||||
* @return the list of dependencies scanned
|
||||
*
|
||||
* @param paths an array of paths to files or directories to be analyzed.
|
||||
* @since v0.3.2.5
|
||||
*/
|
||||
public void scan(String[] paths) {
|
||||
public List<Dependency> scan(String[] paths) {
|
||||
final List<Dependency> deps = new ArrayList<Dependency>();
|
||||
for (String path : paths) {
|
||||
final File file = new File(path);
|
||||
scan(file);
|
||||
final List<Dependency> d = scan(file);
|
||||
if (d != null) {
|
||||
deps.addAll(d);
|
||||
}
|
||||
}
|
||||
return deps;
|
||||
}
|
||||
|
||||
/**
|
||||
* Scans a given file or directory. If a directory is specified, it will be scanned recursively. Any dependencies
|
||||
* identified are added to the dependency collection.
|
||||
*
|
||||
* @param path the path to a file or directory to be analyzed.
|
||||
* @param path the path to a file or directory to be analyzed
|
||||
* @return the list of dependencies scanned
|
||||
*/
|
||||
public void scan(String path) {
|
||||
public List<Dependency> scan(String path) {
|
||||
final File file = new File(path);
|
||||
scan(file);
|
||||
return scan(file);
|
||||
}
|
||||
|
||||
/**
|
||||
* Scans an array of files or directories. If a directory is specified, it will be scanned recursively. Any
|
||||
* dependencies identified are added to the dependency collection.
|
||||
*
|
||||
* @since v0.3.2.5
|
||||
*
|
||||
* @param files an array of paths to files or directories to be analyzed.
|
||||
* @return the list of dependencies
|
||||
*
|
||||
* @since v0.3.2.5
|
||||
*/
|
||||
public void scan(File[] files) {
|
||||
public List<Dependency> scan(File[] files) {
|
||||
final List<Dependency> deps = new ArrayList<Dependency>();
|
||||
for (File file : files) {
|
||||
scan(file);
|
||||
final List<Dependency> d = scan(file);
|
||||
if (d != null) {
|
||||
deps.addAll(d);
|
||||
}
|
||||
}
|
||||
return deps;
|
||||
}
|
||||
|
||||
/**
|
||||
* Scans a list of files or directories. If a directory is specified, it will be scanned recursively. Any
|
||||
* dependencies identified are added to the dependency collection.
|
||||
*
|
||||
* @since v0.3.2.5
|
||||
* @param files a set of paths to files or directories to be analyzed
|
||||
* @return the list of dependencies scanned
|
||||
*
|
||||
* @param files a set of paths to files or directories to be analyzed.
|
||||
* @since v0.3.2.5
|
||||
*/
|
||||
public void scan(Set<File> files) {
|
||||
public List<Dependency> scan(Set<File> files) {
|
||||
final List<Dependency> deps = new ArrayList<Dependency>();
|
||||
for (File file : files) {
|
||||
scan(file);
|
||||
final List<Dependency> d = scan(file);
|
||||
if (d != null) {
|
||||
deps.addAll(d);
|
||||
}
|
||||
}
|
||||
return deps;
|
||||
}
|
||||
|
||||
/**
|
||||
* Scans a list of files or directories. If a directory is specified, it will be scanned recursively. Any
|
||||
* dependencies identified are added to the dependency collection.
|
||||
*
|
||||
* @since v0.3.2.5
|
||||
* @param files a set of paths to files or directories to be analyzed
|
||||
* @return the list of dependencies scanned
|
||||
*
|
||||
* @param files a set of paths to files or directories to be analyzed.
|
||||
* @since v0.3.2.5
|
||||
*/
|
||||
public void scan(List<File> files) {
|
||||
public List<Dependency> scan(List<File> files) {
|
||||
final List<Dependency> deps = new ArrayList<Dependency>();
|
||||
for (File file : files) {
|
||||
scan(file);
|
||||
final List<Dependency> d = scan(file);
|
||||
if (d != null) {
|
||||
deps.addAll(d);
|
||||
}
|
||||
}
|
||||
return deps;
|
||||
}
|
||||
|
||||
/**
|
||||
* Scans a given file or directory. If a directory is specified, it will be scanned recursively. Any dependencies
|
||||
* identified are added to the dependency collection.
|
||||
*
|
||||
* @param file the path to a file or directory to be analyzed
|
||||
* @return the list of dependencies scanned
|
||||
*
|
||||
* @since v0.3.2.4
|
||||
*
|
||||
* @param file the path to a file or directory to be analyzed.
|
||||
*/
|
||||
public void scan(File file) {
|
||||
public List<Dependency> scan(File file) {
|
||||
if (file.exists()) {
|
||||
if (file.isDirectory()) {
|
||||
scanDirectory(file);
|
||||
return scanDirectory(file);
|
||||
} else {
|
||||
scanFile(file);
|
||||
final Dependency d = scanFile(file);
|
||||
if (d != null) {
|
||||
final List<Dependency> deps = new ArrayList<Dependency>();
|
||||
deps.add(d);
|
||||
return deps;
|
||||
}
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Recursively scans files and directories. Any dependencies identified are added to the dependency collection.
|
||||
*
|
||||
* @param dir the directory to scan.
|
||||
* @param dir the directory to scan
|
||||
* @return the list of Dependency objects scanned
|
||||
*/
|
||||
protected void scanDirectory(File dir) {
|
||||
protected List<Dependency> scanDirectory(File dir) {
|
||||
final File[] files = dir.listFiles();
|
||||
final List<Dependency> deps = new ArrayList<Dependency>();
|
||||
if (files != null) {
|
||||
for (File f : files) {
|
||||
if (f.isDirectory()) {
|
||||
scanDirectory(f);
|
||||
final List<Dependency> d = scanDirectory(f);
|
||||
if (d != null) {
|
||||
deps.addAll(d);
|
||||
}
|
||||
} else {
|
||||
scanFile(f);
|
||||
final Dependency d = scanFile(f);
|
||||
deps.add(d);
|
||||
}
|
||||
}
|
||||
}
|
||||
return deps;
|
||||
}
|
||||
|
||||
/**
|
||||
* Scans a specified file. If a dependency is identified it is added to the dependency collection.
|
||||
*
|
||||
* @param file The file to scan.
|
||||
* @param file The file to scan
|
||||
* @return the scanned dependency
|
||||
*/
|
||||
protected void scanFile(File file) {
|
||||
protected Dependency scanFile(File file) {
|
||||
if (!file.isFile()) {
|
||||
final String msg = String.format("Path passed to scanFile(File) is not a file: %s. Skipping the file.", file.toString());
|
||||
Logger.getLogger(Engine.class.getName()).log(Level.FINE, msg);
|
||||
return;
|
||||
LOGGER.log(Level.FINE, msg);
|
||||
return null;
|
||||
}
|
||||
final String fileName = file.getName();
|
||||
final String extension = FileUtils.getFileExtension(fileName);
|
||||
Dependency dependency = null;
|
||||
if (extension != null) {
|
||||
if (extensions.contains(extension)) {
|
||||
final Dependency dependency = new Dependency(file);
|
||||
if (supportsExtension(extension)) {
|
||||
dependency = new Dependency(file);
|
||||
dependencies.add(dependency);
|
||||
}
|
||||
} else {
|
||||
final String msg = String.format("No file extension found on file '%s'. The file was not analyzed.",
|
||||
file.toString());
|
||||
Logger.getLogger(Engine.class.getName()).log(Level.FINEST, msg);
|
||||
final String msg = String.format("No file extension found on file '%s'. The file was not analyzed.", file.toString());
|
||||
LOGGER.log(Level.FINE, msg);
|
||||
}
|
||||
return dependency;
|
||||
}
|
||||
|
||||
/**
|
||||
* Runs the analyzers against all of the dependencies.
|
||||
*/
|
||||
public void analyzeDependencies() {
|
||||
boolean autoUpdate = true;
|
||||
try {
|
||||
autoUpdate = Settings.getBoolean(Settings.KEYS.AUTO_UPDATE);
|
||||
} catch (InvalidSettingException ex) {
|
||||
LOGGER.log(Level.FINE, "Invalid setting for auto-update; using true.");
|
||||
}
|
||||
if (autoUpdate) {
|
||||
doUpdates();
|
||||
}
|
||||
|
||||
//need to ensure that data exists
|
||||
try {
|
||||
ensureDataExists();
|
||||
} catch (NoDataException ex) {
|
||||
final String msg = String.format("%s%n%nUnable to continue dependency-check analysis.", ex.getMessage());
|
||||
Logger.getLogger(Engine.class.getName()).log(Level.SEVERE, msg);
|
||||
Logger.getLogger(Engine.class.getName()).log(Level.FINE, null, ex);
|
||||
LOGGER.log(Level.SEVERE, msg);
|
||||
LOGGER.log(Level.FINE, null, ex);
|
||||
return;
|
||||
} catch (DatabaseException ex) {
|
||||
final String msg = String.format("%s%n%nUnable to continue dependency-check analysis.", ex.getMessage());
|
||||
Logger.getLogger(Engine.class.getName()).log(Level.SEVERE, msg);
|
||||
Logger.getLogger(Engine.class.getName()).log(Level.FINE, null, ex);
|
||||
LOGGER.log(Level.SEVERE, msg);
|
||||
LOGGER.log(Level.FINE, null, ex);
|
||||
return;
|
||||
|
||||
}
|
||||
@@ -277,74 +367,54 @@ public class Engine {
|
||||
+ "----------------------------------------------------%n"
|
||||
+ "BEGIN ANALYSIS%n"
|
||||
+ "----------------------------------------------------");
|
||||
Logger.getLogger(Engine.class.getName()).log(Level.FINE, logHeader);
|
||||
Logger.getLogger(Engine.class.getName()).log(Level.INFO, "Analysis Starting");
|
||||
|
||||
//phase one initialize
|
||||
for (AnalysisPhase phase : AnalysisPhase.values()) {
|
||||
final List<Analyzer> analyzerList = analyzers.get(phase);
|
||||
for (Analyzer a : analyzerList) {
|
||||
try {
|
||||
final String msg = String.format("Initializing %s", a.getName());
|
||||
Logger.getLogger(Engine.class.getName()).log(Level.FINE, msg);
|
||||
a.initialize();
|
||||
} catch (Exception ex) {
|
||||
final String msg = String.format("Exception occurred initializing %s.", a.getName());
|
||||
Logger.getLogger(Engine.class.getName()).log(Level.SEVERE, msg);
|
||||
Logger.getLogger(Engine.class.getName()).log(Level.INFO, null, ex);
|
||||
try {
|
||||
a.close();
|
||||
} catch (Exception ex1) {
|
||||
Logger.getLogger(Engine.class.getName()).log(Level.FINEST, null, ex1);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
LOGGER.log(Level.FINE, logHeader);
|
||||
LOGGER.log(Level.INFO, "Analysis Starting");
|
||||
|
||||
// analysis phases
|
||||
for (AnalysisPhase phase : AnalysisPhase.values()) {
|
||||
final List<Analyzer> analyzerList = analyzers.get(phase);
|
||||
|
||||
for (Analyzer a : analyzerList) {
|
||||
a = initializeAnalyzer(a);
|
||||
|
||||
/* need to create a copy of the collection because some of the
|
||||
* analyzers may modify it. This prevents ConcurrentModificationExceptions.
|
||||
* This is okay for adds/deletes because it happens per analyzer.
|
||||
*/
|
||||
final String msg = String.format("Begin Analyzer '%s'", a.getName());
|
||||
Logger.getLogger(Engine.class.getName()).log(Level.FINE, msg);
|
||||
LOGGER.log(Level.FINE, msg);
|
||||
final Set<Dependency> dependencySet = new HashSet<Dependency>();
|
||||
dependencySet.addAll(dependencies);
|
||||
for (Dependency d : dependencySet) {
|
||||
if (a.supportsExtension(d.getFileExtension())) {
|
||||
boolean shouldAnalyze = true;
|
||||
if (a instanceof FileTypeAnalyzer) {
|
||||
final FileTypeAnalyzer fAnalyzer = (FileTypeAnalyzer) a;
|
||||
shouldAnalyze = fAnalyzer.supportsExtension(d.getFileExtension());
|
||||
}
|
||||
if (shouldAnalyze) {
|
||||
final String msgFile = String.format("Begin Analysis of '%s'", d.getActualFilePath());
|
||||
Logger.getLogger(Engine.class.getName()).log(Level.FINE, msgFile);
|
||||
LOGGER.log(Level.FINE, msgFile);
|
||||
try {
|
||||
a.analyze(d, this);
|
||||
} catch (AnalysisException ex) {
|
||||
d.addAnalysisException(ex);
|
||||
final String exMsg = String.format("An error occurred while analyzing '%s'.", d.getActualFilePath());
|
||||
LOGGER.log(Level.WARNING, exMsg);
|
||||
LOGGER.log(Level.FINE, "", ex);
|
||||
} catch (Throwable ex) {
|
||||
final String axMsg = String.format("An unexpected error occurred during analysis of '%s'", d.getActualFilePath());
|
||||
final AnalysisException ax = new AnalysisException(axMsg, ex);
|
||||
d.addAnalysisException(ax);
|
||||
Logger.getLogger(Engine.class.getName()).log(Level.SEVERE, axMsg);
|
||||
Logger.getLogger(Engine.class.getName()).log(Level.FINE, axMsg, ex);
|
||||
//final AnalysisException ax = new AnalysisException(axMsg, ex);
|
||||
LOGGER.log(Level.WARNING, axMsg);
|
||||
LOGGER.log(Level.FINE, "", ex);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//close/cleanup
|
||||
for (AnalysisPhase phase : AnalysisPhase.values()) {
|
||||
final List<Analyzer> analyzerList = analyzers.get(phase);
|
||||
|
||||
for (Analyzer a : analyzerList) {
|
||||
final String msg = String.format("Closing Analyzer '%s'", a.getName());
|
||||
Logger.getLogger(Engine.class.getName()).log(Level.FINE, msg);
|
||||
try {
|
||||
a.close();
|
||||
} catch (Exception ex) {
|
||||
Logger.getLogger(Engine.class.getName()).log(Level.FINEST, null, ex);
|
||||
}
|
||||
closeAnalyzer(a);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -352,27 +422,67 @@ public class Engine {
|
||||
+ "----------------------------------------------------%n"
|
||||
+ "END ANALYSIS%n"
|
||||
+ "----------------------------------------------------");
|
||||
Logger.getLogger(Engine.class.getName()).log(Level.FINE, logFooter);
|
||||
Logger.getLogger(Engine.class.getName()).log(Level.INFO, "Analysis Complete");
|
||||
LOGGER.log(Level.FINE, logFooter);
|
||||
LOGGER.log(Level.INFO, "Analysis Complete");
|
||||
}
|
||||
|
||||
/**
|
||||
* Initializes the given analyzer.
|
||||
*
|
||||
* @param analyzer the analyzer to initialize
|
||||
* @return the initialized analyzer
|
||||
*/
|
||||
protected Analyzer initializeAnalyzer(Analyzer analyzer) {
|
||||
try {
|
||||
final String msg = String.format("Initializing %s", analyzer.getName());
|
||||
LOGGER.log(Level.FINE, msg);
|
||||
analyzer.initialize();
|
||||
} catch (Throwable ex) {
|
||||
final String msg = String.format("Exception occurred initializing %s.", analyzer.getName());
|
||||
LOGGER.log(Level.SEVERE, msg);
|
||||
LOGGER.log(Level.FINE, null, ex);
|
||||
try {
|
||||
analyzer.close();
|
||||
} catch (Throwable ex1) {
|
||||
LOGGER.log(Level.FINEST, null, ex1);
|
||||
}
|
||||
}
|
||||
return analyzer;
|
||||
}
|
||||
|
||||
/**
|
||||
* Closes the given analyzer.
|
||||
*
|
||||
* @param analyzer the analyzer to close
|
||||
*/
|
||||
protected void closeAnalyzer(Analyzer analyzer) {
|
||||
final String msg = String.format("Closing Analyzer '%s'", analyzer.getName());
|
||||
LOGGER.log(Level.FINE, msg);
|
||||
try {
|
||||
analyzer.close();
|
||||
} catch (Throwable ex) {
|
||||
LOGGER.log(Level.FINEST, null, ex);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Cycles through the cached web data sources and calls update on all of them.
|
||||
*/
|
||||
private void doUpdates() {
|
||||
final UpdateService service = UpdateService.getInstance();
|
||||
LOGGER.info("Checking for updates");
|
||||
final UpdateService service = new UpdateService(serviceClassLoader);
|
||||
final Iterator<CachedWebDataSource> iterator = service.getDataSources();
|
||||
while (iterator.hasNext()) {
|
||||
final CachedWebDataSource source = iterator.next();
|
||||
try {
|
||||
source.update();
|
||||
} catch (UpdateException ex) {
|
||||
Logger.getLogger(Engine.class.getName()).log(Level.WARNING,
|
||||
LOGGER.log(Level.WARNING,
|
||||
"Unable to update Cached Web DataSource, using local data instead. Results may not include recent vulnerabilities.");
|
||||
Logger.getLogger(Engine.class.getName()).log(Level.FINE,
|
||||
String.format("Unable to update details for %s", source.getClass().getName()), ex);
|
||||
LOGGER.log(Level.FINE, String.format("Unable to update details for %s", source.getClass().getName()), ex);
|
||||
}
|
||||
}
|
||||
LOGGER.info("Check for updates complete");
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -399,15 +509,22 @@ public class Engine {
|
||||
if (ext == null) {
|
||||
return false;
|
||||
}
|
||||
for (AnalysisPhase phase : AnalysisPhase.values()) {
|
||||
final List<Analyzer> analyzerList = analyzers.get(phase);
|
||||
for (Analyzer a : analyzerList) {
|
||||
if (a.getSupportedExtensions() != null && a.supportsExtension(ext)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
boolean scan = false;
|
||||
for (FileTypeAnalyzer a : this.fileTypeAnalyzers) {
|
||||
/* note, we can't break early on this loop as the analyzers need to know if
|
||||
they have files to work on prior to initialization */
|
||||
scan |= a.supportsExtension(ext);
|
||||
}
|
||||
return false;
|
||||
return scan;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the set of file type analyzers.
|
||||
*
|
||||
* @return the set of file type analyzers
|
||||
*/
|
||||
public Set<FileTypeAnalyzer> getFileTypeAnalyzers() {
|
||||
return this.fileTypeAnalyzers;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -417,22 +534,16 @@ public class Engine {
|
||||
* @throws DatabaseException thrown if there is an exception opening the database
|
||||
*/
|
||||
private void ensureDataExists() throws NoDataException, DatabaseException {
|
||||
final CpeMemoryIndex cpe = CpeMemoryIndex.getInstance();
|
||||
final CveDB cve = new CveDB();
|
||||
|
||||
try {
|
||||
cve.open();
|
||||
cpe.open(cve);
|
||||
} catch (IndexException ex) {
|
||||
throw new NoDataException(ex.getMessage(), ex);
|
||||
if (!cve.dataExists()) {
|
||||
throw new NoDataException("No documents exist");
|
||||
}
|
||||
} catch (DatabaseException ex) {
|
||||
throw new NoDataException(ex.getMessage(), ex);
|
||||
} finally {
|
||||
cve.close();
|
||||
}
|
||||
if (cpe.numDocs() <= 0) {
|
||||
cpe.close();
|
||||
throw new NoDataException("No documents exist");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,13 @@
|
||||
/**
|
||||
* <html>
|
||||
* <head>
|
||||
* <title>org.owasp.dependencycheck.agent</title>
|
||||
* </head>
|
||||
* <body>
|
||||
* The agent package holds an agent API that can be used by other applications that have information about dependencies;
|
||||
* but would rather implement something in their code directly rather then spawn a process to run the entire
|
||||
* dependency-check engine. This basically provides programmatic access to running a scan.
|
||||
* </body>
|
||||
* </html>
|
||||
*/
|
||||
package org.owasp.dependencycheck.agent;
|
||||
@@ -17,33 +17,12 @@
|
||||
*/
|
||||
package org.owasp.dependencycheck.analyzer;
|
||||
|
||||
import java.util.Collections;
|
||||
import java.util.HashSet;
|
||||
import java.util.Set;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author Jeremy Long <jeremy.long@owasp.org>
|
||||
*/
|
||||
public abstract class AbstractAnalyzer implements Analyzer {
|
||||
|
||||
/**
|
||||
* Utility method to help in the creation of the extensions set. This constructs a new Set that can be used in a
|
||||
* final static declaration.<br/><br/>
|
||||
*
|
||||
* This implementation was copied from
|
||||
* http://stackoverflow.com/questions/2041778/initialize-java-hashset-values-by-construction
|
||||
*
|
||||
* @param strings a list of strings to add to the set.
|
||||
* @return a Set of strings.
|
||||
*/
|
||||
protected static Set<String> newHashSet(String... strings) {
|
||||
final Set<String> set = new HashSet<String>();
|
||||
|
||||
Collections.addAll(set, strings);
|
||||
return set;
|
||||
}
|
||||
|
||||
/**
|
||||
* The initialize method does nothing for this Analyzer.
|
||||
*
|
||||
|
||||
@@ -0,0 +1,237 @@
|
||||
/*
|
||||
* This file is part of dependency-check-core.
|
||||
*
|
||||
* Licensed under the Apache 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.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*
|
||||
* Copyright (c) 2014 Jeremy Long. All Rights Reserved.
|
||||
*/
|
||||
package org.owasp.dependencycheck.analyzer;
|
||||
|
||||
import java.util.Collections;
|
||||
import java.util.HashSet;
|
||||
import java.util.Set;
|
||||
import java.util.logging.Level;
|
||||
import java.util.logging.Logger;
|
||||
import org.owasp.dependencycheck.Engine;
|
||||
import org.owasp.dependencycheck.analyzer.exception.AnalysisException;
|
||||
import org.owasp.dependencycheck.dependency.Dependency;
|
||||
import org.owasp.dependencycheck.utils.InvalidSettingException;
|
||||
import org.owasp.dependencycheck.utils.Settings;
|
||||
|
||||
/**
|
||||
* The base FileTypeAnalyzer that all analyzers that have specific file types they analyze should extend.
|
||||
*
|
||||
* @author Jeremy Long <jeremy.long@owasp.org>
|
||||
*/
|
||||
public abstract class AbstractFileTypeAnalyzer extends AbstractAnalyzer implements FileTypeAnalyzer {
|
||||
|
||||
//<editor-fold defaultstate="collapsed" desc="Constructor">
|
||||
/**
|
||||
* Base constructor that all children must call. This checks the configuration to determine if the analyzer is
|
||||
* enabled.
|
||||
*/
|
||||
public AbstractFileTypeAnalyzer() {
|
||||
reset();
|
||||
}
|
||||
//</editor-fold>
|
||||
|
||||
//<editor-fold defaultstate="collapsed" desc="Field definitions">
|
||||
/**
|
||||
* The logger.
|
||||
*/
|
||||
private static final Logger LOGGER = Logger.getLogger(AbstractFileTypeAnalyzer.class.getName());
|
||||
/**
|
||||
* Whether the file type analyzer detected any files it needs to analyze.
|
||||
*/
|
||||
private boolean filesMatched = false;
|
||||
|
||||
/**
|
||||
* Get the value of filesMatched. A flag indicating whether the scan included any file types this analyzer supports.
|
||||
*
|
||||
* @return the value of filesMatched
|
||||
*/
|
||||
protected boolean isFilesMatched() {
|
||||
return filesMatched;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the value of filesMatched. A flag indicating whether the scan included any file types this analyzer supports.
|
||||
*
|
||||
* @param filesMatched new value of filesMatched
|
||||
*/
|
||||
protected void setFilesMatched(boolean filesMatched) {
|
||||
this.filesMatched = filesMatched;
|
||||
}
|
||||
|
||||
/**
|
||||
* A flag indicating whether or not the analyzer is enabled.
|
||||
*/
|
||||
private boolean enabled = true;
|
||||
|
||||
/**
|
||||
* Get the value of enabled.
|
||||
*
|
||||
* @return the value of enabled
|
||||
*/
|
||||
public boolean isEnabled() {
|
||||
return enabled;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the value of enabled.
|
||||
*
|
||||
* @param enabled new value of enabled
|
||||
*/
|
||||
public void setEnabled(boolean enabled) {
|
||||
this.enabled = enabled;
|
||||
}
|
||||
//</editor-fold>
|
||||
|
||||
//<editor-fold defaultstate="collapsed" desc="Abstract methods children must implement">
|
||||
/**
|
||||
* <p>
|
||||
* Returns a list of supported file extensions. An example would be an analyzer that inspected java jar files. The
|
||||
* getSupportedExtensions function would return a set with a single element "jar".</p>
|
||||
*
|
||||
* <p>
|
||||
* <b>Note:</b> when implementing this the extensions returned MUST be lowercase.</p>
|
||||
*
|
||||
* @return The file extensions supported by this analyzer.
|
||||
*
|
||||
* <p>
|
||||
* If the analyzer returns null it will not cause additional files to be analyzed but will be executed against every
|
||||
* file loaded</p>
|
||||
*/
|
||||
protected abstract Set<String> getSupportedExtensions();
|
||||
|
||||
/**
|
||||
* Initializes the file type analyzer.
|
||||
*
|
||||
* @throws Exception thrown if there is an exception during initialization
|
||||
*/
|
||||
protected abstract void initializeFileTypeAnalyzer() throws Exception;
|
||||
|
||||
/**
|
||||
* Analyzes a given dependency. If the dependency is an archive, such as a WAR or EAR, the contents are extracted,
|
||||
* scanned, and added to the list of dependencies within the engine.
|
||||
*
|
||||
* @param dependency the dependency to analyze
|
||||
* @param engine the engine scanning
|
||||
* @throws AnalysisException thrown if there is an analysis exception
|
||||
*/
|
||||
protected abstract void analyzeFileType(Dependency dependency, Engine engine) throws AnalysisException;
|
||||
|
||||
/**
|
||||
* <p>
|
||||
* Returns the setting key to determine if the analyzer is enabled.</p>
|
||||
*
|
||||
* @return the key for the analyzer's enabled property
|
||||
*/
|
||||
protected abstract String getAnalyzerEnabledSettingKey();
|
||||
|
||||
//</editor-fold>
|
||||
//<editor-fold defaultstate="collapsed" desc="Final implementations for the Analyzer interface">
|
||||
/**
|
||||
* Initializes the analyzer.
|
||||
*
|
||||
* @throws Exception thrown if there is an exception during initialization
|
||||
*/
|
||||
@Override
|
||||
public final void initialize() throws Exception {
|
||||
if (filesMatched) {
|
||||
initializeFileTypeAnalyzer();
|
||||
} else {
|
||||
enabled = false;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Resets the enabled flag on the analyzer.
|
||||
*/
|
||||
@Override
|
||||
public final void reset() {
|
||||
final String key = getAnalyzerEnabledSettingKey();
|
||||
try {
|
||||
enabled = Settings.getBoolean(key, true);
|
||||
} catch (InvalidSettingException ex) {
|
||||
String msg = String.format("Invalid setting for property '%s'", key);
|
||||
LOGGER.log(Level.WARNING, msg);
|
||||
LOGGER.log(Level.FINE, "", ex);
|
||||
msg = String.format("%s has been disabled", getName());
|
||||
LOGGER.log(Level.WARNING, msg);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Analyzes a given dependency. If the dependency is an archive, such as a WAR or EAR, the contents are extracted,
|
||||
* scanned, and added to the list of dependencies within the engine.
|
||||
*
|
||||
* @param dependency the dependency to analyze
|
||||
* @param engine the engine scanning
|
||||
* @throws AnalysisException thrown if there is an analysis exception
|
||||
*/
|
||||
@Override
|
||||
public final void analyze(Dependency dependency, Engine engine) throws AnalysisException {
|
||||
if (enabled) {
|
||||
analyzeFileType(dependency, engine);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns whether or not this analyzer can process the given extension.
|
||||
*
|
||||
* @param extension the file extension to test for support.
|
||||
* @return whether or not the specified file extension is supported by this analyzer.
|
||||
*/
|
||||
@Override
|
||||
public final boolean supportsExtension(String extension) {
|
||||
if (!enabled) {
|
||||
return false;
|
||||
}
|
||||
final Set<String> ext = getSupportedExtensions();
|
||||
if (ext == null) {
|
||||
final String msg = String.format("The '%s' analyzer is misconfigured and does not have any file extensions;"
|
||||
+ " it will be disabled", getName());
|
||||
LOGGER.log(Level.SEVERE, msg);
|
||||
return false;
|
||||
} else {
|
||||
final boolean match = ext.contains(extension);
|
||||
if (match) {
|
||||
filesMatched = match;
|
||||
}
|
||||
return match;
|
||||
}
|
||||
}
|
||||
//</editor-fold>
|
||||
|
||||
//<editor-fold defaultstate="collapsed" desc="Static utility methods">
|
||||
/**
|
||||
* <p>
|
||||
* Utility method to help in the creation of the extensions set. This constructs a new Set that can be used in a
|
||||
* final static declaration.</p>
|
||||
*
|
||||
* <p>
|
||||
* This implementation was copied from
|
||||
* http://stackoverflow.com/questions/2041778/initialize-java-hashset-values-by-construction</p>
|
||||
*
|
||||
* @param strings a list of strings to add to the set.
|
||||
* @return a Set of strings.
|
||||
*/
|
||||
protected static Set<String> newHashSet(String... strings) {
|
||||
final Set<String> set = new HashSet<String>();
|
||||
|
||||
Collections.addAll(set, strings);
|
||||
return set;
|
||||
}
|
||||
//</editor-fold>
|
||||
}
|
||||
@@ -18,13 +18,21 @@
|
||||
package org.owasp.dependencycheck.analyzer;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.net.MalformedURLException;
|
||||
import java.net.URL;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
import java.util.logging.Level;
|
||||
import java.util.logging.Logger;
|
||||
import java.util.regex.Pattern;
|
||||
import org.owasp.dependencycheck.suppression.SuppressionParseException;
|
||||
import org.owasp.dependencycheck.suppression.SuppressionParser;
|
||||
import org.owasp.dependencycheck.suppression.SuppressionRule;
|
||||
import org.owasp.dependencycheck.utils.DownloadFailedException;
|
||||
import org.owasp.dependencycheck.utils.Downloader;
|
||||
import org.owasp.dependencycheck.utils.FileUtils;
|
||||
import org.owasp.dependencycheck.utils.Settings;
|
||||
|
||||
/**
|
||||
@@ -34,6 +42,11 @@ import org.owasp.dependencycheck.utils.Settings;
|
||||
*/
|
||||
public abstract class AbstractSuppressionAnalyzer extends AbstractAnalyzer {
|
||||
|
||||
/**
|
||||
* The Logger for use throughout the class
|
||||
*/
|
||||
private static final Logger LOGGER = Logger.getLogger(AbstractSuppressionAnalyzer.class.getName());
|
||||
|
||||
//<editor-fold defaultstate="collapsed" desc="All standard implementation details of Analyzer">
|
||||
/**
|
||||
* Returns a list of file EXTENSIONS supported by this analyzer.
|
||||
@@ -44,17 +57,6 @@ public abstract class AbstractSuppressionAnalyzer extends AbstractAnalyzer {
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns whether or not this analyzer can process the given extension.
|
||||
*
|
||||
* @param extension the file extension to test for support.
|
||||
* @return whether or not the specified file extension is supported by this analyzer.
|
||||
*/
|
||||
@Override
|
||||
public boolean supportsExtension(String extension) {
|
||||
return true;
|
||||
}
|
||||
|
||||
//</editor-fold>
|
||||
/**
|
||||
* The initialize method loads the suppression XML file.
|
||||
@@ -66,6 +68,7 @@ public abstract class AbstractSuppressionAnalyzer extends AbstractAnalyzer {
|
||||
super.initialize();
|
||||
loadSuppressionData();
|
||||
}
|
||||
|
||||
/**
|
||||
* The list of suppression rules
|
||||
*/
|
||||
@@ -95,18 +98,81 @@ public abstract class AbstractSuppressionAnalyzer extends AbstractAnalyzer {
|
||||
* @throws SuppressionParseException thrown if the XML cannot be parsed.
|
||||
*/
|
||||
private void loadSuppressionData() throws SuppressionParseException {
|
||||
final File file = Settings.getFile(Settings.KEYS.SUPPRESSION_FILE);
|
||||
if (file != null) {
|
||||
final SuppressionParser parser = new SuppressionParser();
|
||||
try {
|
||||
rules = parser.parseSuppressionRules(file);
|
||||
} catch (SuppressionParseException ex) {
|
||||
final String msg = String.format("Unable to parse suppression xml file '%s'", file.getPath());
|
||||
Logger.getLogger(AbstractSuppressionAnalyzer.class.getName()).log(Level.WARNING, msg);
|
||||
Logger.getLogger(AbstractSuppressionAnalyzer.class.getName()).log(Level.WARNING, ex.getMessage());
|
||||
Logger.getLogger(AbstractSuppressionAnalyzer.class.getName()).log(Level.FINE, null, ex);
|
||||
throw ex;
|
||||
final SuppressionParser parser = new SuppressionParser();
|
||||
File file = null;
|
||||
try {
|
||||
rules = parser.parseSuppressionRules(this.getClass().getClassLoader().getResourceAsStream("dependencycheck-base-suppression.xml"));
|
||||
} catch (SuppressionParseException ex) {
|
||||
LOGGER.log(Level.FINE, "Unable to parse the base suppression data file", ex);
|
||||
}
|
||||
final String suppressionFilePath = Settings.getString(Settings.KEYS.SUPPRESSION_FILE);
|
||||
if (suppressionFilePath == null) {
|
||||
return;
|
||||
}
|
||||
boolean deleteTempFile = false;
|
||||
try {
|
||||
final Pattern uriRx = Pattern.compile("^(https?|file)\\:.*", Pattern.CASE_INSENSITIVE);
|
||||
if (uriRx.matcher(suppressionFilePath).matches()) {
|
||||
deleteTempFile = true;
|
||||
file = FileUtils.getTempFile("suppression", "xml");
|
||||
final URL url = new URL(suppressionFilePath);
|
||||
try {
|
||||
Downloader.fetchFile(url, file, false);
|
||||
} catch (DownloadFailedException ex) {
|
||||
Downloader.fetchFile(url, file, true);
|
||||
}
|
||||
} else {
|
||||
file = new File(suppressionFilePath);
|
||||
if (!file.exists()) {
|
||||
final InputStream suppressionsFromClasspath = this.getClass().getClassLoader().getResourceAsStream(suppressionFilePath);
|
||||
if (suppressionsFromClasspath != null) {
|
||||
deleteTempFile = true;
|
||||
file = FileUtils.getTempFile("suppression", "xml");
|
||||
try {
|
||||
org.apache.commons.io.FileUtils.copyInputStreamToFile(suppressionsFromClasspath, file);
|
||||
} catch (IOException ex) {
|
||||
throwSuppressionParseException("Unable to locate suppressions file in classpath", ex);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (file != null) {
|
||||
try {
|
||||
//rules = parser.parseSuppressionRules(file);
|
||||
rules.addAll(parser.parseSuppressionRules(file));
|
||||
LOGGER.log(Level.FINE, rules.size() + " suppression rules were loaded.");
|
||||
} catch (SuppressionParseException ex) {
|
||||
final String msg = String.format("Unable to parse suppression xml file '%s'", file.getPath());
|
||||
LOGGER.log(Level.WARNING, msg);
|
||||
LOGGER.log(Level.WARNING, ex.getMessage());
|
||||
LOGGER.log(Level.FINE, "", ex);
|
||||
throw ex;
|
||||
}
|
||||
}
|
||||
} catch (DownloadFailedException ex) {
|
||||
throwSuppressionParseException("Unable to fetch the configured suppression file", ex);
|
||||
} catch (MalformedURLException ex) {
|
||||
throwSuppressionParseException("Configured suppression file has an invalid URL", ex);
|
||||
} catch (IOException ex) {
|
||||
throwSuppressionParseException("Unable to create temp file for suppressions", ex);
|
||||
} finally {
|
||||
if (deleteTempFile && file != null) {
|
||||
FileUtils.delete(file);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Utility method to throw parse exceptions.
|
||||
*
|
||||
* @param message the exception message
|
||||
* @param exception the cause of the exception
|
||||
* @throws SuppressionParseException throws the generated SuppressionParseException
|
||||
*/
|
||||
private void throwSuppressionParseException(String message, Exception exception) throws SuppressionParseException {
|
||||
LOGGER.log(Level.WARNING, message);
|
||||
LOGGER.log(Level.FINE, "", exception);
|
||||
throw new SuppressionParseException(message, exception);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -17,8 +17,8 @@
|
||||
*/
|
||||
package org.owasp.dependencycheck.analyzer;
|
||||
|
||||
import java.util.Set;
|
||||
import org.owasp.dependencycheck.Engine;
|
||||
import org.owasp.dependencycheck.analyzer.exception.AnalysisException;
|
||||
import org.owasp.dependencycheck.dependency.Dependency;
|
||||
|
||||
/**
|
||||
@@ -41,22 +41,6 @@ public interface Analyzer {
|
||||
*/
|
||||
void analyze(Dependency dependency, Engine engine) throws AnalysisException;
|
||||
|
||||
/**
|
||||
* <p>
|
||||
* Returns a list of supported file extensions. An example would be an analyzer that inspected java jar files. The
|
||||
* getSupportedExtensions function would return a set with a single element "jar".</p>
|
||||
*
|
||||
* <p>
|
||||
* <b>Note:</b> when implementing this the extensions returned MUST be lowercase.</p>
|
||||
*
|
||||
* @return The file extensions supported by this analyzer.
|
||||
*
|
||||
* <p>
|
||||
* If the analyzer returns null it will not cause additional files to be analyzed but will be executed against every
|
||||
* file loaded</p>
|
||||
*/
|
||||
Set<String> getSupportedExtensions();
|
||||
|
||||
/**
|
||||
* Returns the name of the analyzer.
|
||||
*
|
||||
@@ -64,14 +48,6 @@ public interface Analyzer {
|
||||
*/
|
||||
String getName();
|
||||
|
||||
/**
|
||||
* Returns whether or not this analyzer can process the given extension.
|
||||
*
|
||||
* @param extension the file extension to test for support.
|
||||
* @return whether or not the specified file extension is supported by this analyzer.
|
||||
*/
|
||||
boolean supportsExtension(String extension);
|
||||
|
||||
/**
|
||||
* Returns the phase that the analyzer is intended to run in.
|
||||
*
|
||||
|
||||
@@ -21,15 +21,13 @@ import java.util.Iterator;
|
||||
import java.util.ServiceLoader;
|
||||
|
||||
/**
|
||||
* The Analyzer Service Loader. This class loads all services that implement
|
||||
* org.owasp.dependencycheck.analyzer.Analyzer.
|
||||
*
|
||||
* @author Jeremy Long <jeremy.long@owasp.org>
|
||||
*/
|
||||
public final class AnalyzerService {
|
||||
public class AnalyzerService {
|
||||
|
||||
/**
|
||||
* The analyzer service singleton.
|
||||
*/
|
||||
private static AnalyzerService service;
|
||||
/**
|
||||
* The service loader for analyzers.
|
||||
*/
|
||||
@@ -37,21 +35,11 @@ public final class AnalyzerService {
|
||||
|
||||
/**
|
||||
* Creates a new instance of AnalyzerService.
|
||||
*/
|
||||
private AnalyzerService() {
|
||||
loader = ServiceLoader.load(Analyzer.class);
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieve the singleton instance of AnalyzerService.
|
||||
*
|
||||
* @return a singleton AnalyzerService.
|
||||
* @param classLoader the ClassLoader to use when dynamically loading Analyzer and Update services
|
||||
*/
|
||||
public static synchronized AnalyzerService getInstance() {
|
||||
if (service == null) {
|
||||
service = new AnalyzerService();
|
||||
}
|
||||
return service;
|
||||
public AnalyzerService(ClassLoader classLoader) {
|
||||
loader = ServiceLoader.load(Analyzer.class, classLoader);
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -25,7 +25,9 @@ import java.io.FileNotFoundException;
|
||||
import java.io.FileOutputStream;
|
||||
import java.io.IOException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.Collections;
|
||||
import java.util.Enumeration;
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
@@ -34,13 +36,17 @@ import java.util.logging.Logger;
|
||||
import org.apache.commons.compress.archivers.ArchiveEntry;
|
||||
import org.apache.commons.compress.archivers.ArchiveInputStream;
|
||||
import org.apache.commons.compress.archivers.tar.TarArchiveInputStream;
|
||||
import org.apache.commons.compress.archivers.zip.ZipArchiveEntry;
|
||||
import org.apache.commons.compress.archivers.zip.ZipArchiveInputStream;
|
||||
import org.apache.commons.compress.archivers.zip.ZipFile;
|
||||
import org.apache.commons.compress.compressors.CompressorInputStream;
|
||||
import org.apache.commons.compress.compressors.gzip.GzipCompressorInputStream;
|
||||
import org.apache.commons.compress.compressors.gzip.GzipUtils;
|
||||
import org.h2.store.fs.FileUtils;
|
||||
import org.owasp.dependencycheck.Engine;
|
||||
import org.owasp.dependencycheck.analyzer.exception.AnalysisException;
|
||||
import org.owasp.dependencycheck.analyzer.exception.ArchiveExtractionException;
|
||||
import org.owasp.dependencycheck.dependency.Dependency;
|
||||
import org.owasp.dependencycheck.utils.FileUtils;
|
||||
import org.owasp.dependencycheck.utils.Settings;
|
||||
|
||||
/**
|
||||
@@ -50,8 +56,12 @@ import org.owasp.dependencycheck.utils.Settings;
|
||||
*
|
||||
* @author Jeremy Long <jeremy.long@owasp.org>
|
||||
*/
|
||||
public class ArchiveAnalyzer extends AbstractAnalyzer implements Analyzer {
|
||||
public class ArchiveAnalyzer extends AbstractFileTypeAnalyzer {
|
||||
|
||||
/**
|
||||
* The logger.
|
||||
*/
|
||||
private static final Logger LOGGER = Logger.getLogger(ArchiveAnalyzer.class.getName());
|
||||
/**
|
||||
* The buffer size to use when extracting files from the archive.
|
||||
*/
|
||||
@@ -72,6 +82,7 @@ public class ArchiveAnalyzer extends AbstractAnalyzer implements Analyzer {
|
||||
* Tracks the current scan/extraction depth for nested archives.
|
||||
*/
|
||||
private int scanDepth = 0;
|
||||
|
||||
//<editor-fold defaultstate="collapsed" desc="All standard implementation details of Analyzer">
|
||||
/**
|
||||
* The name of the analyzer.
|
||||
@@ -84,13 +95,25 @@ public class ArchiveAnalyzer extends AbstractAnalyzer implements Analyzer {
|
||||
/**
|
||||
* The set of things we can handle with Zip methods
|
||||
*/
|
||||
private static final Set<String> ZIPPABLES = newHashSet("zip", "ear", "war", "nupkg");
|
||||
private static final Set<String> ZIPPABLES = newHashSet("zip", "ear", "war", "jar", "sar", "apk", "nupkg");
|
||||
/**
|
||||
* The set of file extensions supported by this analyzer.
|
||||
* The set of file extensions supported by this analyzer. Note for developers, any additions to this list will need
|
||||
* to be explicitly handled in extractFiles().
|
||||
*/
|
||||
private static final Set<String> EXTENSIONS = newHashSet("tar", "gz", "tgz");
|
||||
|
||||
/**
|
||||
* The set of file extensions to remove from the engine's collection of dependencies.
|
||||
*/
|
||||
private static final Set<String> REMOVE_FROM_ANALYSIS = newHashSet("zip", "tar", "gz", "tgz"); //TODO add nupkg, apk, sar?
|
||||
|
||||
static {
|
||||
EXTENSIONS.addAll(ZIPPABLES);
|
||||
final String additionalZipExt = Settings.getString(Settings.KEYS.ADDITIONAL_ZIP_EXTENSIONS);
|
||||
if (additionalZipExt != null) {
|
||||
final Set<String> ext = new HashSet<String>(Arrays.asList(additionalZipExt));
|
||||
ZIPPABLES.addAll(ext);
|
||||
}
|
||||
EXTENSIONS.addAll(ZIPPABLES);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -98,6 +121,7 @@ public class ArchiveAnalyzer extends AbstractAnalyzer implements Analyzer {
|
||||
*
|
||||
* @return a list of file EXTENSIONS supported by this analyzer.
|
||||
*/
|
||||
@Override
|
||||
public Set<String> getSupportedExtensions() {
|
||||
return EXTENSIONS;
|
||||
}
|
||||
@@ -107,44 +131,40 @@ public class ArchiveAnalyzer extends AbstractAnalyzer implements Analyzer {
|
||||
*
|
||||
* @return the name of the analyzer.
|
||||
*/
|
||||
@Override
|
||||
public String getName() {
|
||||
return ANALYZER_NAME;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns whether or not this analyzer can process the given extension.
|
||||
*
|
||||
* @param extension the file extension to test for support.
|
||||
* @return whether or not the specified file extension is supported by this analyzer.
|
||||
*/
|
||||
public boolean supportsExtension(String extension) {
|
||||
return EXTENSIONS.contains(extension);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the phase that the analyzer is intended to run in.
|
||||
*
|
||||
* @return the phase that the analyzer is intended to run in.
|
||||
*/
|
||||
@Override
|
||||
public AnalysisPhase getAnalysisPhase() {
|
||||
return ANALYSIS_PHASE;
|
||||
}
|
||||
//</editor-fold>
|
||||
|
||||
/**
|
||||
* Returns the key used in the properties file to reference the analyzer's enabled property.
|
||||
*
|
||||
* @return the analyzer's enabled property setting key
|
||||
*/
|
||||
@Override
|
||||
protected String getAnalyzerEnabledSettingKey() {
|
||||
return Settings.KEYS.ANALYZER_ARCHIVE_ENABLED;
|
||||
}
|
||||
|
||||
/**
|
||||
* The initialize method does nothing for this Analyzer.
|
||||
*
|
||||
* @throws Exception is thrown if there is an exception deleting or creating temporary files
|
||||
*/
|
||||
@Override
|
||||
public void initialize() throws Exception {
|
||||
public void initializeFileTypeAnalyzer() throws Exception {
|
||||
final File baseDir = Settings.getTempDirectory();
|
||||
if (!baseDir.exists()) {
|
||||
if (!baseDir.mkdirs()) {
|
||||
final String msg = String.format("Unable to make a temporary folder '%s'", baseDir.getPath());
|
||||
throw new AnalysisException(msg);
|
||||
}
|
||||
}
|
||||
tempFileLocation = File.createTempFile("check", "tmp", baseDir);
|
||||
if (!tempFileLocation.delete()) {
|
||||
final String msg = String.format("Unable to delete temporary file '%s'.", tempFileLocation.getAbsolutePath());
|
||||
@@ -157,14 +177,18 @@ public class ArchiveAnalyzer extends AbstractAnalyzer implements Analyzer {
|
||||
}
|
||||
|
||||
/**
|
||||
* The close method does nothing for this Analyzer.
|
||||
* The close method deletes any temporary files and directories created during analysis.
|
||||
*
|
||||
* @throws Exception thrown if there is an exception deleting temporary files
|
||||
*/
|
||||
@Override
|
||||
public void close() throws Exception {
|
||||
if (tempFileLocation != null && tempFileLocation.exists()) {
|
||||
FileUtils.deleteRecursive(tempFileLocation.getAbsolutePath(), true);
|
||||
LOGGER.log(Level.FINE, "Attempting to delete temporary files");
|
||||
final boolean success = FileUtils.delete(tempFileLocation);
|
||||
if (!success && tempFileLocation != null && tempFileLocation.exists() && tempFileLocation.list().length > 0) {
|
||||
LOGGER.log(Level.WARNING, "Failed to delete some temporary files, see the log for more details");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -177,15 +201,15 @@ public class ArchiveAnalyzer extends AbstractAnalyzer implements Analyzer {
|
||||
* @throws AnalysisException thrown if there is an analysis exception
|
||||
*/
|
||||
@Override
|
||||
public void analyze(Dependency dependency, Engine engine) throws AnalysisException {
|
||||
public void analyzeFileType(Dependency dependency, Engine engine) throws AnalysisException {
|
||||
final File f = new File(dependency.getActualFilePath());
|
||||
final File tmpDir = getNextTempDirectory();
|
||||
extractFiles(f, tmpDir, engine);
|
||||
|
||||
//make a copy
|
||||
final List<Dependency> dependencies = new ArrayList<Dependency>(engine.getDependencies());
|
||||
List<Dependency> dependencies = new ArrayList<Dependency>(engine.getDependencies());
|
||||
engine.scan(tmpDir);
|
||||
final List<Dependency> newDependencies = engine.getDependencies();
|
||||
List<Dependency> newDependencies = engine.getDependencies();
|
||||
if (dependencies.size() != newDependencies.size()) {
|
||||
//get the new dependencies
|
||||
final Set<Dependency> dependencySet = new HashSet<Dependency>();
|
||||
@@ -197,9 +221,8 @@ public class ArchiveAnalyzer extends AbstractAnalyzer implements Analyzer {
|
||||
final String displayPath = String.format("%s%s",
|
||||
dependency.getFilePath(),
|
||||
d.getActualFilePath().substring(tmpDir.getAbsolutePath().length()));
|
||||
final String displayName = String.format("%s%s%s",
|
||||
final String displayName = String.format("%s: %s",
|
||||
dependency.getFileName(),
|
||||
File.separator,
|
||||
d.getFileName());
|
||||
d.setFilePath(displayPath);
|
||||
d.setFileName(displayName);
|
||||
@@ -213,6 +236,40 @@ public class ArchiveAnalyzer extends AbstractAnalyzer implements Analyzer {
|
||||
}
|
||||
}
|
||||
}
|
||||
if (this.REMOVE_FROM_ANALYSIS.contains(dependency.getFileExtension())) {
|
||||
if ("zip".equals(dependency.getFileExtension()) && isZipFileActuallyJarFile(dependency)) {
|
||||
final File tdir = getNextTempDirectory();
|
||||
final String fileName = dependency.getFileName();
|
||||
|
||||
LOGGER.info(String.format("The zip file '%s' appears to be a JAR file, making a copy and analyzing it as a JAR.", fileName));
|
||||
|
||||
final File tmpLoc = new File(tdir, fileName.substring(0, fileName.length() - 3) + "jar");
|
||||
try {
|
||||
org.apache.commons.io.FileUtils.copyFile(tdir, tmpLoc);
|
||||
dependencies = new ArrayList<Dependency>(engine.getDependencies());
|
||||
engine.scan(tmpLoc);
|
||||
newDependencies = engine.getDependencies();
|
||||
if (dependencies.size() != newDependencies.size()) {
|
||||
//get the new dependencies
|
||||
final Set<Dependency> dependencySet = new HashSet<Dependency>();
|
||||
dependencySet.addAll(newDependencies);
|
||||
dependencySet.removeAll(dependencies);
|
||||
if (dependencySet.size() != 1) {
|
||||
LOGGER.info("Deep copy of ZIP to JAR file resulted in more then one dependency?");
|
||||
}
|
||||
for (Dependency d : dependencySet) {
|
||||
//fix the dependency's display name and path
|
||||
d.setFilePath(dependency.getFilePath());
|
||||
d.setDisplayFileName(dependency.getFileName());
|
||||
}
|
||||
}
|
||||
} catch (IOException ex) {
|
||||
final String msg = String.format("Unable to perform deep copy on '%s'", dependency.getActualFile().getPath());
|
||||
LOGGER.log(Level.FINE, msg, ex);
|
||||
}
|
||||
}
|
||||
engine.getDependencies().remove(dependency);
|
||||
}
|
||||
Collections.sort(engine.getDependencies());
|
||||
}
|
||||
|
||||
@@ -253,10 +310,10 @@ public class ArchiveAnalyzer extends AbstractAnalyzer implements Analyzer {
|
||||
try {
|
||||
fis = new FileInputStream(archive);
|
||||
} catch (FileNotFoundException ex) {
|
||||
Logger.getLogger(ArchiveAnalyzer.class.getName()).log(Level.INFO, null, ex);
|
||||
LOGGER.log(Level.FINE, null, ex);
|
||||
throw new AnalysisException("Archive file was not found.", ex);
|
||||
}
|
||||
final String archiveExt = org.owasp.dependencycheck.utils.FileUtils.getFileExtension(archive.getName()).toLowerCase();
|
||||
final String archiveExt = FileUtils.getFileExtension(archive.getName()).toLowerCase();
|
||||
try {
|
||||
if (ZIPPABLES.contains(archiveExt)) {
|
||||
extractArchive(new ZipArchiveInputStream(new BufferedInputStream(fis)), destination, engine);
|
||||
@@ -264,24 +321,24 @@ public class ArchiveAnalyzer extends AbstractAnalyzer implements Analyzer {
|
||||
extractArchive(new TarArchiveInputStream(new BufferedInputStream(fis)), destination, engine);
|
||||
} else if ("gz".equals(archiveExt) || "tgz".equals(archiveExt)) {
|
||||
final String uncompressedName = GzipUtils.getUncompressedFilename(archive.getName());
|
||||
final String uncompressedExt = org.owasp.dependencycheck.utils.FileUtils.getFileExtension(uncompressedName).toLowerCase();
|
||||
final String uncompressedExt = FileUtils.getFileExtension(uncompressedName).toLowerCase();
|
||||
if (engine.supportsExtension(uncompressedExt)) {
|
||||
decompressFile(new GzipCompressorInputStream(new BufferedInputStream(fis)), new File(destination, uncompressedName));
|
||||
}
|
||||
}
|
||||
} catch (ArchiveExtractionException ex) {
|
||||
final String msg = String.format("Exception extracting archive '%s'.", archive.getName());
|
||||
Logger.getLogger(ArchiveAnalyzer.class.getName()).log(Level.WARNING, msg);
|
||||
Logger.getLogger(ArchiveAnalyzer.class.getName()).log(Level.FINE, null, ex);
|
||||
LOGGER.log(Level.WARNING, msg);
|
||||
LOGGER.log(Level.FINE, null, ex);
|
||||
} catch (IOException ex) {
|
||||
final String msg = String.format("Exception reading archive '%s'.", archive.getName());
|
||||
Logger.getLogger(ArchiveAnalyzer.class.getName()).log(Level.WARNING, msg);
|
||||
Logger.getLogger(ArchiveAnalyzer.class.getName()).log(Level.FINE, null, ex);
|
||||
LOGGER.log(Level.WARNING, msg);
|
||||
LOGGER.log(Level.FINE, null, ex);
|
||||
} finally {
|
||||
try {
|
||||
fis.close();
|
||||
} catch (IOException ex) {
|
||||
Logger.getLogger(ArchiveAnalyzer.class.getName()).log(Level.FINEST, null, ex);
|
||||
LOGGER.log(Level.FINE, null, ex);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -308,10 +365,12 @@ public class ArchiveAnalyzer extends AbstractAnalyzer implements Analyzer {
|
||||
}
|
||||
} else {
|
||||
final File file = new File(destination, entry.getName());
|
||||
final String ext = org.owasp.dependencycheck.utils.FileUtils.getFileExtension(file.getName());
|
||||
final String ext = FileUtils.getFileExtension(file.getName());
|
||||
if (engine.supportsExtension(ext)) {
|
||||
final String extracting = String.format("Extracting '%s'", file.getPath());
|
||||
LOGGER.fine(extracting);
|
||||
BufferedOutputStream bos = null;
|
||||
FileOutputStream fos;
|
||||
FileOutputStream fos = null;
|
||||
try {
|
||||
final File parent = file.getParentFile();
|
||||
if (!parent.isDirectory()) {
|
||||
@@ -323,19 +382,17 @@ public class ArchiveAnalyzer extends AbstractAnalyzer implements Analyzer {
|
||||
fos = new FileOutputStream(file);
|
||||
bos = new BufferedOutputStream(fos, BUFFER_SIZE);
|
||||
int count;
|
||||
final byte data[] = new byte[BUFFER_SIZE];
|
||||
final byte[] data = new byte[BUFFER_SIZE];
|
||||
while ((count = input.read(data, 0, BUFFER_SIZE)) != -1) {
|
||||
bos.write(data, 0, count);
|
||||
}
|
||||
bos.flush();
|
||||
} catch (FileNotFoundException ex) {
|
||||
Logger.getLogger(ArchiveAnalyzer.class
|
||||
.getName()).log(Level.FINE, null, ex);
|
||||
LOGGER.log(Level.FINE, null, ex);
|
||||
final String msg = String.format("Unable to find file '%s'.", file.getName());
|
||||
throw new AnalysisException(msg, ex);
|
||||
} catch (IOException ex) {
|
||||
Logger.getLogger(ArchiveAnalyzer.class
|
||||
.getName()).log(Level.FINE, null, ex);
|
||||
LOGGER.log(Level.FINE, null, ex);
|
||||
final String msg = String.format("IO Exception while parsing file '%s'.", file.getName());
|
||||
throw new AnalysisException(msg, ex);
|
||||
} finally {
|
||||
@@ -343,8 +400,14 @@ public class ArchiveAnalyzer extends AbstractAnalyzer implements Analyzer {
|
||||
try {
|
||||
bos.close();
|
||||
} catch (IOException ex) {
|
||||
Logger.getLogger(ArchiveAnalyzer.class
|
||||
.getName()).log(Level.FINEST, null, ex);
|
||||
LOGGER.log(Level.FINEST, null, ex);
|
||||
}
|
||||
}
|
||||
if (fos != null) {
|
||||
try {
|
||||
fos.close();
|
||||
} catch (IOException ex) {
|
||||
LOGGER.log(Level.FINEST, null, ex);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -360,7 +423,7 @@ public class ArchiveAnalyzer extends AbstractAnalyzer implements Analyzer {
|
||||
try {
|
||||
input.close();
|
||||
} catch (IOException ex) {
|
||||
Logger.getLogger(ArchiveAnalyzer.class.getName()).log(Level.FINEST, null, ex);
|
||||
LOGGER.log(Level.FINEST, null, ex);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -374,6 +437,8 @@ public class ArchiveAnalyzer extends AbstractAnalyzer implements Analyzer {
|
||||
* @throws ArchiveExtractionException thrown if there is an exception decompressing the file
|
||||
*/
|
||||
private void decompressFile(CompressorInputStream inputStream, File outputFile) throws ArchiveExtractionException {
|
||||
final String msg = String.format("Decompressing '%s'", outputFile.getPath());
|
||||
LOGGER.fine(msg);
|
||||
FileOutputStream out = null;
|
||||
try {
|
||||
out = new FileOutputStream(outputFile);
|
||||
@@ -383,19 +448,53 @@ public class ArchiveAnalyzer extends AbstractAnalyzer implements Analyzer {
|
||||
out.write(buffer, 0, n);
|
||||
}
|
||||
} catch (FileNotFoundException ex) {
|
||||
Logger.getLogger(ArchiveAnalyzer.class.getName()).log(Level.FINE, null, ex);
|
||||
LOGGER.log(Level.FINE, null, ex);
|
||||
throw new ArchiveExtractionException(ex);
|
||||
} catch (IOException ex) {
|
||||
Logger.getLogger(ArchiveAnalyzer.class.getName()).log(Level.FINE, null, ex);
|
||||
LOGGER.log(Level.FINE, null, ex);
|
||||
throw new ArchiveExtractionException(ex);
|
||||
} finally {
|
||||
if (out != null) {
|
||||
try {
|
||||
out.close();
|
||||
} catch (IOException ex) {
|
||||
Logger.getLogger(ArchiveAnalyzer.class.getName()).log(Level.FINEST, null, ex);
|
||||
LOGGER.log(Level.FINEST, null, ex);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Attempts to determine if a zip file is actually a JAR file.
|
||||
*
|
||||
* @param dependency the dependency to check
|
||||
* @return true if the dependency appears to be a JAR file; otherwise false
|
||||
*/
|
||||
private boolean isZipFileActuallyJarFile(Dependency dependency) {
|
||||
boolean isJar = false;
|
||||
ZipFile zip = null;
|
||||
try {
|
||||
zip = new ZipFile(dependency.getActualFilePath());
|
||||
if (zip.getEntry("META-INF/MANIFEST.MF") != null
|
||||
|| zip.getEntry("META-INF/maven") != null) {
|
||||
final Enumeration<ZipArchiveEntry> entries = zip.getEntries();
|
||||
while (entries.hasMoreElements()) {
|
||||
final ZipArchiveEntry entry = entries.nextElement();
|
||||
if (!entry.isDirectory()) {
|
||||
final String name = entry.getName().toLowerCase();
|
||||
if (name.endsWith(".class")) {
|
||||
isJar = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
} catch (IOException ex) {
|
||||
LOGGER.log(Level.FINE, String.format("Unable to unzip zip file '%s'", dependency.getFilePath()), ex);
|
||||
} finally {
|
||||
ZipFile.closeQuietly(zip);
|
||||
}
|
||||
|
||||
return isJar;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,325 @@
|
||||
/*
|
||||
* This file is part of dependency-check-core.
|
||||
*
|
||||
* Licensed under the Apache 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.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*
|
||||
* Copyright (c) 2012 Jeremy Long. All Rights Reserved.
|
||||
*/
|
||||
package org.owasp.dependencycheck.analyzer;
|
||||
|
||||
import java.io.BufferedReader;
|
||||
import java.io.File;
|
||||
import java.io.FileOutputStream;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.io.InputStreamReader;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
import java.util.logging.Level;
|
||||
import java.util.logging.Logger;
|
||||
import javax.xml.parsers.DocumentBuilder;
|
||||
import javax.xml.parsers.DocumentBuilderFactory;
|
||||
import javax.xml.xpath.XPath;
|
||||
import javax.xml.xpath.XPathExpressionException;
|
||||
import javax.xml.xpath.XPathFactory;
|
||||
import org.owasp.dependencycheck.Engine;
|
||||
import org.owasp.dependencycheck.analyzer.exception.AnalysisException;
|
||||
import org.owasp.dependencycheck.dependency.Confidence;
|
||||
import org.owasp.dependencycheck.dependency.Dependency;
|
||||
import org.owasp.dependencycheck.dependency.Evidence;
|
||||
import org.owasp.dependencycheck.utils.Settings;
|
||||
import org.w3c.dom.Document;
|
||||
import org.xml.sax.SAXException;
|
||||
|
||||
/**
|
||||
* Analyzer for getting company, product, and version information from a .NET assembly.
|
||||
*
|
||||
* @author colezlaw
|
||||
*
|
||||
*/
|
||||
public class AssemblyAnalyzer extends AbstractFileTypeAnalyzer {
|
||||
|
||||
/**
|
||||
* The analyzer name
|
||||
*/
|
||||
private static final String ANALYZER_NAME = "Assembly Analyzer";
|
||||
/**
|
||||
* The analysis phase
|
||||
*/
|
||||
private static final AnalysisPhase ANALYSIS_PHASE = AnalysisPhase.INFORMATION_COLLECTION;
|
||||
/**
|
||||
* The list of supported extensions
|
||||
*/
|
||||
private static final Set<String> SUPPORTED_EXTENSIONS = newHashSet("dll", "exe");
|
||||
/**
|
||||
* The temp value for GrokAssembly.exe
|
||||
*/
|
||||
private File grokAssemblyExe = null;
|
||||
/**
|
||||
* The DocumentBuilder for parsing the XML
|
||||
*/
|
||||
private DocumentBuilder builder;
|
||||
/**
|
||||
* Logger
|
||||
*/
|
||||
private static final Logger LOGGER = Logger.getLogger(AssemblyAnalyzer.class.getName(), "dependencycheck-resources");
|
||||
|
||||
/**
|
||||
* Builds the beginnings of a List for ProcessBuilder
|
||||
*
|
||||
* @return the list of arguments to begin populating the ProcessBuilder
|
||||
*/
|
||||
private List<String> buildArgumentList() {
|
||||
// Use file.separator as a wild guess as to whether this is Windows
|
||||
final List<String> args = new ArrayList<String>();
|
||||
if (!"\\".equals(System.getProperty("file.separator"))) {
|
||||
if (Settings.getString(Settings.KEYS.ANALYZER_ASSEMBLY_MONO_PATH) != null) {
|
||||
args.add(Settings.getString(Settings.KEYS.ANALYZER_ASSEMBLY_MONO_PATH));
|
||||
} else {
|
||||
args.add("mono");
|
||||
}
|
||||
}
|
||||
args.add(grokAssemblyExe.getPath());
|
||||
|
||||
return args;
|
||||
}
|
||||
|
||||
/**
|
||||
* Performs the analysis on a single Dependency.
|
||||
*
|
||||
* @param dependency the dependency to analyze
|
||||
* @param engine the engine to perform the analysis under
|
||||
* @throws AnalysisException if anything goes sideways
|
||||
*/
|
||||
@Override
|
||||
public void analyzeFileType(Dependency dependency, Engine engine)
|
||||
throws AnalysisException {
|
||||
if (grokAssemblyExe == null) {
|
||||
LOGGER.warning("analyzer.AssemblyAnalyzer.notdeployed");
|
||||
return;
|
||||
}
|
||||
|
||||
final List<String> args = buildArgumentList();
|
||||
args.add(dependency.getActualFilePath());
|
||||
final ProcessBuilder pb = new ProcessBuilder(args);
|
||||
BufferedReader rdr = null;
|
||||
Document doc = null;
|
||||
try {
|
||||
final Process proc = pb.start();
|
||||
// Try evacuating the error stream
|
||||
rdr = new BufferedReader(new InputStreamReader(proc.getErrorStream(), "UTF-8"));
|
||||
String line = null;
|
||||
// CHECKSTYLE:OFF
|
||||
while (rdr.ready() && (line = rdr.readLine()) != null) {
|
||||
LOGGER.log(Level.WARNING, "analyzer.AssemblyAnalyzer.grokassembly.stderr", line);
|
||||
}
|
||||
// CHECKSTYLE:ON
|
||||
int rc = 0;
|
||||
doc = builder.parse(proc.getInputStream());
|
||||
|
||||
try {
|
||||
rc = proc.waitFor();
|
||||
} catch (InterruptedException ie) {
|
||||
return;
|
||||
}
|
||||
if (rc == 3) {
|
||||
LOGGER.log(Level.FINE, "analyzer.AssemblyAnalyzer.notassembly", dependency.getActualFilePath());
|
||||
return;
|
||||
} else if (rc != 0) {
|
||||
LOGGER.log(Level.WARNING, "analyzer.AssemblyAnalyzer.grokassembly.rc", rc);
|
||||
}
|
||||
|
||||
final XPath xpath = XPathFactory.newInstance().newXPath();
|
||||
|
||||
// First, see if there was an error
|
||||
final String error = xpath.evaluate("/assembly/error", doc);
|
||||
if (error != null && !"".equals(error)) {
|
||||
throw new AnalysisException(error);
|
||||
}
|
||||
|
||||
final String version = xpath.evaluate("/assembly/version", doc);
|
||||
if (version != null) {
|
||||
dependency.getVersionEvidence().addEvidence(new Evidence("grokassembly", "version",
|
||||
version, Confidence.HIGHEST));
|
||||
}
|
||||
|
||||
final String vendor = xpath.evaluate("/assembly/company", doc);
|
||||
if (vendor != null) {
|
||||
dependency.getVendorEvidence().addEvidence(new Evidence("grokassembly", "vendor",
|
||||
vendor, Confidence.HIGH));
|
||||
}
|
||||
|
||||
final String product = xpath.evaluate("/assembly/product", doc);
|
||||
if (product != null) {
|
||||
dependency.getProductEvidence().addEvidence(new Evidence("grokassembly", "product",
|
||||
product, Confidence.HIGH));
|
||||
}
|
||||
|
||||
} catch (IOException ioe) {
|
||||
throw new AnalysisException(ioe);
|
||||
} catch (SAXException saxe) {
|
||||
throw new AnalysisException("Couldn't parse GrokAssembly result", saxe);
|
||||
} catch (XPathExpressionException xpe) {
|
||||
// This shouldn't happen
|
||||
throw new AnalysisException(xpe);
|
||||
} finally {
|
||||
if (rdr != null) {
|
||||
try {
|
||||
rdr.close();
|
||||
} catch (IOException ex) {
|
||||
LOGGER.log(Level.FINEST, "ignore", ex);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Initialize the analyzer. In this case, extract GrokAssembly.exe to a temporary location.
|
||||
*
|
||||
* @throws Exception if anything goes wrong
|
||||
*/
|
||||
@Override
|
||||
public void initializeFileTypeAnalyzer() throws Exception {
|
||||
final File tempFile = File.createTempFile("GKA", ".exe", Settings.getTempDirectory());
|
||||
FileOutputStream fos = null;
|
||||
InputStream is = null;
|
||||
try {
|
||||
fos = new FileOutputStream(tempFile);
|
||||
is = AssemblyAnalyzer.class.getClassLoader().getResourceAsStream("GrokAssembly.exe");
|
||||
final byte[] buff = new byte[4096];
|
||||
int bread = -1;
|
||||
while ((bread = is.read(buff)) >= 0) {
|
||||
fos.write(buff, 0, bread);
|
||||
}
|
||||
grokAssemblyExe = tempFile;
|
||||
// Set the temp file to get deleted when we're done
|
||||
grokAssemblyExe.deleteOnExit();
|
||||
LOGGER.log(Level.FINE, "analyzer.AssemblyAnalyzer.grokassembly.deployed", grokAssemblyExe.getPath());
|
||||
} catch (IOException ioe) {
|
||||
this.setEnabled(false);
|
||||
LOGGER.log(Level.WARNING, "analyzer.AssemblyAnalyzer.grokassembly.notdeployed", ioe.getMessage());
|
||||
throw new AnalysisException("Could not extract GrokAssembly.exe", ioe);
|
||||
} finally {
|
||||
if (fos != null) {
|
||||
try {
|
||||
fos.close();
|
||||
} catch (Throwable e) {
|
||||
LOGGER.fine("Error closing output stream");
|
||||
}
|
||||
}
|
||||
if (is != null) {
|
||||
try {
|
||||
is.close();
|
||||
} catch (Throwable e) {
|
||||
LOGGER.fine("Error closing input stream");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Now, need to see if GrokAssembly actually runs from this location.
|
||||
final List<String> args = buildArgumentList();
|
||||
BufferedReader rdr = null;
|
||||
try {
|
||||
final ProcessBuilder pb = new ProcessBuilder(args);
|
||||
final Process p = pb.start();
|
||||
// Try evacuating the error stream
|
||||
rdr = new BufferedReader(new InputStreamReader(p.getErrorStream(), "UTF-8"));
|
||||
// CHECKSTYLE:OFF
|
||||
while (rdr.ready() && rdr.readLine() != null) {
|
||||
// We expect this to complain
|
||||
}
|
||||
// CHECKSTYLE:ON
|
||||
final Document doc = DocumentBuilderFactory.newInstance().newDocumentBuilder().parse(p.getInputStream());
|
||||
final XPath xpath = XPathFactory.newInstance().newXPath();
|
||||
final String error = xpath.evaluate("/assembly/error", doc);
|
||||
if (p.waitFor() != 1 || error == null || "".equals(error)) {
|
||||
LOGGER.warning("An error occurred with the .NET AssemblyAnalyzer, please see the log for more details.");
|
||||
LOGGER.fine("GrokAssembly.exe is not working properly");
|
||||
grokAssemblyExe = null;
|
||||
this.setEnabled(false);
|
||||
throw new AnalysisException("Could not execute .NET AssemblyAnalyzer");
|
||||
}
|
||||
} catch (Throwable e) {
|
||||
if (e instanceof AnalysisException) {
|
||||
throw (AnalysisException) e;
|
||||
} else {
|
||||
LOGGER.warning("analyzer.AssemblyAnalyzer.grokassembly.initialization.failed");
|
||||
LOGGER.log(Level.FINE, "analyzer.AssemblyAnalyzer.grokassembly.initialization.message", e.getMessage());
|
||||
this.setEnabled(false);
|
||||
throw new AnalysisException("An error occured with the .NET AssemblyAnalyzer", e);
|
||||
}
|
||||
} finally {
|
||||
if (rdr != null) {
|
||||
try {
|
||||
rdr.close();
|
||||
} catch (IOException ex) {
|
||||
LOGGER.log(Level.FINEST, "ignore", ex);
|
||||
}
|
||||
}
|
||||
}
|
||||
builder = DocumentBuilderFactory.newInstance().newDocumentBuilder();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void close() throws Exception {
|
||||
super.close();
|
||||
try {
|
||||
if (grokAssemblyExe != null && !grokAssemblyExe.delete()) {
|
||||
grokAssemblyExe.deleteOnExit();
|
||||
}
|
||||
} catch (SecurityException se) {
|
||||
LOGGER.fine("analyzer.AssemblyAnalyzer.grokassembly.notdeleted");
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the set of extensions supported by this analyzer.
|
||||
*
|
||||
* @return the list of supported extensions
|
||||
*/
|
||||
@Override
|
||||
public Set<String> getSupportedExtensions() {
|
||||
return SUPPORTED_EXTENSIONS;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets this analyzer's name.
|
||||
*
|
||||
* @return the analyzer name
|
||||
*/
|
||||
@Override
|
||||
public String getName() {
|
||||
return ANALYZER_NAME;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the phase this analyzer runs under.
|
||||
*
|
||||
* @return the phase this runs under
|
||||
*/
|
||||
@Override
|
||||
public AnalysisPhase getAnalysisPhase() {
|
||||
return ANALYSIS_PHASE;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the key used in the properties file to reference the analyzer's enabled property.
|
||||
*
|
||||
* @return the analyzer's enabled property setting key
|
||||
*/
|
||||
@Override
|
||||
protected String getAnalyzerEnabledSettingKey() {
|
||||
return Settings.KEYS.ANALYZER_ASSEMBLY_ENABLED;
|
||||
}
|
||||
}
|
||||
@@ -33,6 +33,7 @@ import org.apache.lucene.queryparser.classic.ParseException;
|
||||
import org.apache.lucene.search.ScoreDoc;
|
||||
import org.apache.lucene.search.TopDocs;
|
||||
import org.owasp.dependencycheck.Engine;
|
||||
import org.owasp.dependencycheck.analyzer.exception.AnalysisException;
|
||||
import org.owasp.dependencycheck.data.cpe.CpeMemoryIndex;
|
||||
import org.owasp.dependencycheck.data.cpe.Fields;
|
||||
import org.owasp.dependencycheck.data.cpe.IndexEntry;
|
||||
@@ -50,13 +51,17 @@ import org.owasp.dependencycheck.utils.DependencyVersion;
|
||||
import org.owasp.dependencycheck.utils.DependencyVersionUtil;
|
||||
|
||||
/**
|
||||
* CPEAnalyzer is a utility class that takes a project dependency and attempts to discern if there is an associated CPE.
|
||||
* It uses the evidence contained within the dependency to search the Lucene index.
|
||||
* CPEAnalyzer is a utility class that takes a project dependency and attempts to discern if there is an associated CPE. It uses
|
||||
* the evidence contained within the dependency to search the Lucene index.
|
||||
*
|
||||
* @author Jeremy Long <jeremy.long@owasp.org>
|
||||
*/
|
||||
public class CPEAnalyzer implements Analyzer {
|
||||
|
||||
/**
|
||||
* The Logger.
|
||||
*/
|
||||
private static final Logger LOGGER = Logger.getLogger(CPEAnalyzer.class.getName());
|
||||
/**
|
||||
* The maximum number of query results to return.
|
||||
*/
|
||||
@@ -86,23 +91,58 @@ public class CPEAnalyzer implements Analyzer {
|
||||
*/
|
||||
private CveDB cve;
|
||||
|
||||
/**
|
||||
* The URL to perform a search of the NVD CVE data at NIST.
|
||||
*/
|
||||
public static final String NVD_SEARCH_URL = "https://web.nvd.nist.gov/view/vuln/search-results?adv_search=true&cves=on&cpe_version=%s";
|
||||
|
||||
/**
|
||||
* Returns the name of this analyzer.
|
||||
*
|
||||
* @return the name of this analyzer.
|
||||
*/
|
||||
@Override
|
||||
public String getName() {
|
||||
return "CPE Analyzer";
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the analysis phase that this analyzer should run in.
|
||||
*
|
||||
* @return the analysis phase that this analyzer should run in.
|
||||
*/
|
||||
@Override
|
||||
public AnalysisPhase getAnalysisPhase() {
|
||||
return AnalysisPhase.IDENTIFIER_ANALYSIS;
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates the CPE Lucene Index.
|
||||
*
|
||||
* @throws Exception is thrown if there is an issue opening the index.
|
||||
*/
|
||||
@Override
|
||||
public void initialize() throws Exception {
|
||||
this.open();
|
||||
}
|
||||
|
||||
/**
|
||||
* Opens the data source.
|
||||
*
|
||||
* @throws IOException when the Lucene directory to be queried does not exist or is corrupt.
|
||||
* @throws DatabaseException when the database throws an exception. This usually occurs when the database is in use
|
||||
* by another process.
|
||||
* @throws DatabaseException when the database throws an exception. This usually occurs when the database is in use by another
|
||||
* process.
|
||||
*/
|
||||
public void open() throws IOException, DatabaseException {
|
||||
Logger.getLogger(CPEAnalyzer.class.getName()).log(Level.FINE, "Opening the CVE Database");
|
||||
LOGGER.log(Level.FINE, "Opening the CVE Database");
|
||||
cve = new CveDB();
|
||||
cve.open();
|
||||
Logger.getLogger(CPEAnalyzer.class.getName()).log(Level.FINE, "Creating the Lucene CPE Index");
|
||||
LOGGER.log(Level.FINE, "Creating the Lucene CPE Index");
|
||||
cpe = CpeMemoryIndex.getInstance();
|
||||
try {
|
||||
cpe.open(cve);
|
||||
} catch (IndexException ex) {
|
||||
Logger.getLogger(CPEAnalyzer.class.getName()).log(Level.FINE, "IndexException", ex);
|
||||
LOGGER.log(Level.FINE, "IndexException", ex);
|
||||
throw new DatabaseException(ex);
|
||||
}
|
||||
}
|
||||
@@ -121,8 +161,8 @@ public class CPEAnalyzer implements Analyzer {
|
||||
}
|
||||
|
||||
/**
|
||||
* Searches the data store of CPE entries, trying to identify the CPE for the given dependency based on the evidence
|
||||
* contained within. The dependency passed in is updated with any identified CPE values.
|
||||
* Searches the data store of CPE entries, trying to identify the CPE for the given dependency based on the evidence contained
|
||||
* within. The dependency passed in is updated with any identified CPE values.
|
||||
*
|
||||
* @param dependency the dependency to search for CPE entries on.
|
||||
* @throws CorruptIndexException is thrown when the Lucene index is corrupt.
|
||||
@@ -130,47 +170,45 @@ public class CPEAnalyzer implements Analyzer {
|
||||
* @throws ParseException is thrown when the Lucene query cannot be parsed.
|
||||
*/
|
||||
protected void determineCPE(Dependency dependency) throws CorruptIndexException, IOException, ParseException {
|
||||
Confidence confidence = Confidence.HIGHEST;
|
||||
|
||||
String vendors = addEvidenceWithoutDuplicateTerms("", dependency.getVendorEvidence(), confidence);
|
||||
String products = addEvidenceWithoutDuplicateTerms("", dependency.getProductEvidence(), confidence);
|
||||
/* bug fix for #40 - version evidence is not showing up as "used" in the reports if there is no
|
||||
* CPE identified. As such, we are "using" the evidence and ignoring the results. */
|
||||
addEvidenceWithoutDuplicateTerms("", dependency.getVersionEvidence(), confidence);
|
||||
|
||||
int ctr = 0;
|
||||
do {
|
||||
if (!vendors.isEmpty() && !products.isEmpty()) {
|
||||
final List<IndexEntry> entries = searchCPE(vendors, products, dependency.getProductEvidence().getWeighting(),
|
||||
dependency.getVendorEvidence().getWeighting());
|
||||
|
||||
for (IndexEntry e : entries) {
|
||||
if (verifyEntry(e, dependency)) {
|
||||
final String vendor = e.getVendor();
|
||||
final String product = e.getProduct();
|
||||
determineIdentifiers(dependency, vendor, product);
|
||||
}
|
||||
}
|
||||
}
|
||||
confidence = reduceConfidence(confidence);
|
||||
//TODO test dojo-war against this. we shold get dojo-toolkit:dojo-toolkit AND dojo-toolkit:toolkit
|
||||
String vendors = "";
|
||||
String products = "";
|
||||
for (Confidence confidence : Confidence.values()) {
|
||||
if (dependency.getVendorEvidence().contains(confidence)) {
|
||||
vendors = addEvidenceWithoutDuplicateTerms(vendors, dependency.getVendorEvidence(), confidence);
|
||||
LOGGER.fine(String.format("vendor search: %s", vendors));
|
||||
}
|
||||
if (dependency.getProductEvidence().contains(confidence)) {
|
||||
products = addEvidenceWithoutDuplicateTerms(products, dependency.getProductEvidence(), confidence);
|
||||
LOGGER.fine(String.format("product search: %s", products));
|
||||
}
|
||||
/* bug fix for #40 - version evidence is not showing up as "used" in the reports if there is no
|
||||
* CPE identified. As such, we are "using" the evidence and ignoring the results. */
|
||||
if (dependency.getVersionEvidence().contains(confidence)) {
|
||||
addEvidenceWithoutDuplicateTerms("", dependency.getVersionEvidence(), confidence);
|
||||
if (!vendors.isEmpty() && !products.isEmpty()) {
|
||||
final List<IndexEntry> entries = searchCPE(vendors, products, dependency.getProductEvidence().getWeighting(),
|
||||
dependency.getVendorEvidence().getWeighting());
|
||||
if (entries == null) {
|
||||
continue;
|
||||
}
|
||||
boolean identifierAdded = false;
|
||||
for (IndexEntry e : entries) {
|
||||
LOGGER.fine(String.format("Verifying entry: %s", e.toString()));
|
||||
if (verifyEntry(e, dependency)) {
|
||||
final String vendor = e.getVendor();
|
||||
final String product = e.getProduct();
|
||||
LOGGER.fine(String.format("identified vendor/product: %s/%s", vendor, product));
|
||||
identifierAdded |= determineIdentifiers(dependency, vendor, product, confidence);
|
||||
}
|
||||
}
|
||||
if (identifierAdded) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
} while ((++ctr) < 4);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the text created by concatenating the text and the values from the EvidenceCollection (filtered for a
|
||||
* specific confidence). This attempts to prevent duplicate terms from being added.<br/<br/> Note, if the evidence
|
||||
* is longer then 200 characters it will be truncated.
|
||||
* Returns the text created by concatenating the text and the values from the EvidenceCollection (filtered for a specific
|
||||
* confidence). This attempts to prevent duplicate terms from being added.<br/<br/> Note, if the evidence is longer then 200
|
||||
* characters it will be truncated.
|
||||
*
|
||||
* @param text the base text.
|
||||
* @param ec an EvidenceCollection
|
||||
@@ -199,71 +237,55 @@ public class CPEAnalyzer implements Analyzer {
|
||||
return sb.toString().trim();
|
||||
}
|
||||
|
||||
/**
|
||||
* Reduces the given confidence by one level. This returns LOW if the confidence passed in is not HIGH.
|
||||
*
|
||||
* @param c the confidence to reduce.
|
||||
* @return One less then the confidence passed in.
|
||||
*/
|
||||
private Confidence reduceConfidence(final Confidence c) {
|
||||
if (c == Confidence.HIGHEST) {
|
||||
return Confidence.HIGH;
|
||||
} else if (c == Confidence.HIGH) {
|
||||
return Confidence.MEDIUM;
|
||||
} else {
|
||||
return Confidence.LOW;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* <p>
|
||||
* Searches the Lucene CPE index to identify possible CPE entries associated with the supplied vendor, product, and
|
||||
* version.</p>
|
||||
*
|
||||
* <p>
|
||||
* If either the vendorWeightings or productWeightings lists have been populated this data is used to add weighting
|
||||
* factors to the search.</p>
|
||||
* If either the vendorWeightings or productWeightings lists have been populated this data is used to add weighting factors to
|
||||
* the search.</p>
|
||||
*
|
||||
* @param vendor the text used to search the vendor field
|
||||
* @param product the text used to search the product field
|
||||
* @param vendorWeightings a list of strings to use to add weighting factors to the vendor field
|
||||
* @param productWeightings Adds a list of strings that will be used to add weighting factors to the product search
|
||||
* @return a list of possible CPE values
|
||||
* @throws CorruptIndexException when the Lucene index is corrupt
|
||||
* @throws IOException when the Lucene index is not found
|
||||
* @throws ParseException when the generated query is not valid
|
||||
*/
|
||||
protected List<IndexEntry> searchCPE(String vendor, String product,
|
||||
Set<String> vendorWeightings, Set<String> productWeightings)
|
||||
throws CorruptIndexException, IOException, ParseException {
|
||||
final ArrayList<IndexEntry> ret = new ArrayList<IndexEntry>(MAX_QUERY_RESULTS);
|
||||
Set<String> vendorWeightings, Set<String> productWeightings) {
|
||||
|
||||
final List<IndexEntry> ret = new ArrayList<IndexEntry>(MAX_QUERY_RESULTS);
|
||||
|
||||
final String searchString = buildSearch(vendor, product, vendorWeightings, productWeightings);
|
||||
if (searchString == null) {
|
||||
return ret;
|
||||
}
|
||||
|
||||
final TopDocs docs = cpe.search(searchString, MAX_QUERY_RESULTS);
|
||||
for (ScoreDoc d : docs.scoreDocs) {
|
||||
if (d.score >= 0.08) {
|
||||
final Document doc = cpe.getDocument(d.doc);
|
||||
final IndexEntry entry = new IndexEntry();
|
||||
entry.setVendor(doc.get(Fields.VENDOR));
|
||||
entry.setProduct(doc.get(Fields.PRODUCT));
|
||||
// if (d.score < 0.08) {
|
||||
// System.out.print(entry.getVendor());
|
||||
// System.out.print(":");
|
||||
// System.out.print(entry.getProduct());
|
||||
// System.out.print(":");
|
||||
// System.out.println(d.score);
|
||||
// }
|
||||
entry.setSearchScore(d.score);
|
||||
if (!ret.contains(entry)) {
|
||||
ret.add(entry);
|
||||
try {
|
||||
final TopDocs docs = cpe.search(searchString, MAX_QUERY_RESULTS);
|
||||
for (ScoreDoc d : docs.scoreDocs) {
|
||||
if (d.score >= 0.08) {
|
||||
final Document doc = cpe.getDocument(d.doc);
|
||||
final IndexEntry entry = new IndexEntry();
|
||||
entry.setVendor(doc.get(Fields.VENDOR));
|
||||
entry.setProduct(doc.get(Fields.PRODUCT));
|
||||
entry.setSearchScore(d.score);
|
||||
if (!ret.contains(entry)) {
|
||||
ret.add(entry);
|
||||
}
|
||||
}
|
||||
}
|
||||
return ret;
|
||||
} catch (ParseException ex) {
|
||||
final String msg = String.format("Unable to parse: %s", searchString);
|
||||
LOGGER.log(Level.WARNING, "An error occured querying the CPE data. See the log for more details.");
|
||||
LOGGER.log(Level.INFO, msg, ex);
|
||||
} catch (IOException ex) {
|
||||
final String msg = String.format("IO Error with search string: %s", searchString);
|
||||
LOGGER.log(Level.WARNING, "An error occured reading CPE data. See the log for more details.");
|
||||
LOGGER.log(Level.INFO, msg, ex);
|
||||
}
|
||||
return ret;
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -271,8 +293,8 @@ public class CPEAnalyzer implements Analyzer {
|
||||
* Builds a Lucene search string by properly escaping data and constructing a valid search query.</p>
|
||||
*
|
||||
* <p>
|
||||
* If either the possibleVendor or possibleProducts lists have been populated this data is used to add weighting
|
||||
* factors to the search string generated.</p>
|
||||
* If either the possibleVendor or possibleProducts lists have been populated this data is used to add weighting factors to
|
||||
* the search string generated.</p>
|
||||
*
|
||||
* @param vendor text to search the vendor field
|
||||
* @param product text to search the product field
|
||||
@@ -298,9 +320,8 @@ public class CPEAnalyzer implements Analyzer {
|
||||
}
|
||||
|
||||
/**
|
||||
* This method constructs a Lucene query for a given field. The searchText is split into separate words and if the
|
||||
* word is within the list of weighted words then an additional weighting is applied to the term as it is appended
|
||||
* into the query.
|
||||
* This method constructs a Lucene query for a given field. The searchText is split into separate words and if the word is
|
||||
* within the list of weighted words then an additional weighting is applied to the term as it is appended into the query.
|
||||
*
|
||||
* @param sb a StringBuilder that the query text will be appended to.
|
||||
* @param field the field within the Lucene index that the query is searching.
|
||||
@@ -371,8 +392,8 @@ public class CPEAnalyzer implements Analyzer {
|
||||
}
|
||||
|
||||
/**
|
||||
* Ensures that the CPE Identified matches the dependency. This validates that the product, vendor, and version
|
||||
* information for the CPE are contained within the dependencies evidence.
|
||||
* Ensures that the CPE Identified matches the dependency. This validates that the product, vendor, and version information
|
||||
* for the CPE are contained within the dependencies evidence.
|
||||
*
|
||||
* @param entry a CPE entry.
|
||||
* @param dependency the dependency that the CPE entries could be for.
|
||||
@@ -461,72 +482,28 @@ public class CPEAnalyzer implements Analyzer {
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns true because this analyzer supports all dependency types.
|
||||
*
|
||||
* @return true.
|
||||
*/
|
||||
@Override
|
||||
public Set<String> getSupportedExtensions() {
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the name of this analyzer.
|
||||
*
|
||||
* @return the name of this analyzer.
|
||||
*/
|
||||
@Override
|
||||
public String getName() {
|
||||
return "CPE Analyzer";
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns true because this analyzer supports all dependency types.
|
||||
*
|
||||
* @param extension the file extension of the dependency being analyzed.
|
||||
* @return true.
|
||||
*/
|
||||
@Override
|
||||
public boolean supportsExtension(String extension) {
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the analysis phase that this analyzer should run in.
|
||||
*
|
||||
* @return the analysis phase that this analyzer should run in.
|
||||
*/
|
||||
@Override
|
||||
public AnalysisPhase getAnalysisPhase() {
|
||||
return AnalysisPhase.IDENTIFIER_ANALYSIS;
|
||||
}
|
||||
|
||||
/**
|
||||
* Opens the CPE Lucene Index.
|
||||
*
|
||||
* @throws Exception is thrown if there is an issue opening the index.
|
||||
*/
|
||||
@Override
|
||||
public void initialize() throws Exception {
|
||||
this.open();
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieves a list of CPE values from the CveDB based on the vendor and product passed in. The list is then
|
||||
* validated to find only CPEs that are valid for the given dependency. It is possible that the CPE identified is a
|
||||
* best effort "guess" based on the vendor, product, and version information.
|
||||
* Retrieves a list of CPE values from the CveDB based on the vendor and product passed in. The list is then validated to find
|
||||
* only CPEs that are valid for the given dependency. It is possible that the CPE identified is a best effort "guess" based on
|
||||
* the vendor, product, and version information.
|
||||
*
|
||||
* @param dependency the Dependency being analyzed
|
||||
* @param vendor the vendor for the CPE being analyzed
|
||||
* @param product the product for the CPE being analyzed
|
||||
* @param currentConfidence the current confidence being used during analysis
|
||||
* @return <code>true</code> if an identifier was added to the dependency; otherwise <code>false</code>
|
||||
* @throws UnsupportedEncodingException is thrown if UTF-8 is not supported
|
||||
*/
|
||||
private void determineIdentifiers(Dependency dependency, String vendor, String product) throws UnsupportedEncodingException {
|
||||
protected boolean determineIdentifiers(Dependency dependency, String vendor, String product,
|
||||
Confidence currentConfidence) throws UnsupportedEncodingException {
|
||||
final Set<VulnerableSoftware> cpes = cve.getCPEs(vendor, product);
|
||||
DependencyVersion bestGuess = new DependencyVersion("-");
|
||||
Confidence bestGuessConf = null;
|
||||
boolean hasBroadMatch = false;
|
||||
final List<IdentifierMatch> collected = new ArrayList<IdentifierMatch>();
|
||||
for (Confidence conf : Confidence.values()) {
|
||||
// if (conf.compareTo(currentConfidence) > 0) {
|
||||
// break;
|
||||
// }
|
||||
for (Evidence evidence : dependency.getVersionEvidence().iterator(conf)) {
|
||||
final DependencyVersion evVer = DependencyVersionUtil.parseVersion(evidence.getValue());
|
||||
if (evVer == null) {
|
||||
@@ -539,9 +516,13 @@ public class CPEAnalyzer implements Analyzer {
|
||||
} else {
|
||||
dbVer = DependencyVersionUtil.parseVersion(vs.getVersion());
|
||||
}
|
||||
if (dbVer == null //special case, no version specified - everything is vulnerable
|
||||
|| evVer.equals(dbVer)) { //yeah! exact match
|
||||
final String url = String.format("http://web.nvd.nist.gov/view/vuln/search?cpe=%s", URLEncoder.encode(vs.getName(), "UTF-8"));
|
||||
if (dbVer == null) { //special case, no version specified - everything is vulnerable
|
||||
hasBroadMatch = true;
|
||||
final String url = String.format(NVD_SEARCH_URL, URLEncoder.encode(vs.getName(), "UTF-8"));
|
||||
final IdentifierMatch match = new IdentifierMatch("cpe", vs.getName(), url, IdentifierConfidence.BROAD_MATCH, conf);
|
||||
collected.add(match);
|
||||
} else if (evVer.equals(dbVer)) { //yeah! exact match
|
||||
final String url = String.format(NVD_SEARCH_URL, URLEncoder.encode(vs.getName(), "UTF-8"));
|
||||
final IdentifierMatch match = new IdentifierMatch("cpe", vs.getName(), url, IdentifierConfidence.EXACT_MATCH, conf);
|
||||
collected.add(match);
|
||||
} else {
|
||||
@@ -566,7 +547,11 @@ public class CPEAnalyzer implements Analyzer {
|
||||
}
|
||||
}
|
||||
final String cpeName = String.format("cpe:/a:%s:%s:%s", vendor, product, bestGuess.toString());
|
||||
final String url = null; //String.format("http://web.nvd.nist.gov/view/vuln/search?cpe=%s", URLEncoder.encode(cpeName, "UTF-8"));
|
||||
String url = null;
|
||||
if (hasBroadMatch) { //if we have a broad match we can add the URL to the best guess.
|
||||
final String cpeUrlName = String.format("cpe:/a:%s:%s", vendor, product);
|
||||
url = String.format(NVD_SEARCH_URL, URLEncoder.encode(cpeUrlName, "UTF-8"));
|
||||
}
|
||||
if (bestGuessConf == null) {
|
||||
bestGuessConf = Confidence.LOW;
|
||||
}
|
||||
@@ -576,6 +561,7 @@ public class CPEAnalyzer implements Analyzer {
|
||||
Collections.sort(collected);
|
||||
final IdentifierConfidence bestIdentifierQuality = collected.get(0).getConfidence();
|
||||
final Confidence bestEvidenceQuality = collected.get(0).getEvidenceConfidence();
|
||||
boolean identifierAdded = false;
|
||||
for (IdentifierMatch m : collected) {
|
||||
if (bestIdentifierQuality.equals(m.getConfidence())
|
||||
&& bestEvidenceQuality.equals(m.getEvidenceConfidence())) {
|
||||
@@ -586,8 +572,10 @@ public class CPEAnalyzer implements Analyzer {
|
||||
i.setConfidence(bestEvidenceQuality);
|
||||
}
|
||||
dependency.addIdentifier(i);
|
||||
identifierAdded = true;
|
||||
}
|
||||
}
|
||||
return identifierAdded;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -602,7 +590,12 @@ public class CPEAnalyzer implements Analyzer {
|
||||
/**
|
||||
* A best guess for the CPE.
|
||||
*/
|
||||
BEST_GUESS
|
||||
BEST_GUESS,
|
||||
/**
|
||||
* The entire vendor/product group must be added (without a guess at version) because there is a CVE with a VS that only
|
||||
* specifies vendor/product.
|
||||
*/
|
||||
BROAD_MATCH
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -748,8 +741,7 @@ public class CPEAnalyzer implements Analyzer {
|
||||
//</editor-fold>
|
||||
|
||||
/**
|
||||
* Standard implementation of compareTo that compares identifier confidence, evidence confidence, and then the
|
||||
* identifier.
|
||||
* Standard implementation of compareTo that compares identifier confidence, evidence confidence, and then the identifier.
|
||||
*
|
||||
* @param o the IdentifierMatch to compare to
|
||||
* @return the natural ordering of IdentifierMatch
|
||||
|
||||
@@ -0,0 +1,243 @@
|
||||
/*
|
||||
* This file is part of dependency-check-core.
|
||||
*
|
||||
* Licensed under the Apache 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.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*
|
||||
* Copyright (c) 2014 Jeremy Long. All Rights Reserved.
|
||||
*/
|
||||
package org.owasp.dependencycheck.analyzer;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.FileNotFoundException;
|
||||
import java.io.IOException;
|
||||
import java.net.URL;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
import java.util.logging.Level;
|
||||
import java.util.logging.Logger;
|
||||
import org.apache.commons.io.FileUtils;
|
||||
import org.owasp.dependencycheck.Engine;
|
||||
import org.owasp.dependencycheck.analyzer.exception.AnalysisException;
|
||||
import org.owasp.dependencycheck.data.central.CentralSearch;
|
||||
import org.owasp.dependencycheck.data.nexus.MavenArtifact;
|
||||
import org.owasp.dependencycheck.dependency.Confidence;
|
||||
import org.owasp.dependencycheck.dependency.Dependency;
|
||||
import org.owasp.dependencycheck.dependency.Evidence;
|
||||
import org.owasp.dependencycheck.jaxb.pom.PomUtils;
|
||||
import org.owasp.dependencycheck.utils.DownloadFailedException;
|
||||
import org.owasp.dependencycheck.utils.Downloader;
|
||||
import org.owasp.dependencycheck.utils.InvalidSettingException;
|
||||
import org.owasp.dependencycheck.utils.Settings;
|
||||
|
||||
/**
|
||||
* Analyzer which will attempt to locate a dependency, and the GAV information, by querying Central for the dependency's SHA-1
|
||||
* digest.
|
||||
*
|
||||
* @author colezlaw
|
||||
*/
|
||||
public class CentralAnalyzer extends AbstractFileTypeAnalyzer {
|
||||
|
||||
/**
|
||||
* The logger.
|
||||
*/
|
||||
private static final Logger LOGGER = Logger.getLogger(CentralAnalyzer.class.getName());
|
||||
|
||||
/**
|
||||
* The name of the analyzer.
|
||||
*/
|
||||
private static final String ANALYZER_NAME = "Central Analyzer";
|
||||
|
||||
/**
|
||||
* The phase in which this analyzer runs.
|
||||
*/
|
||||
private static final AnalysisPhase ANALYSIS_PHASE = AnalysisPhase.INFORMATION_COLLECTION;
|
||||
|
||||
/**
|
||||
* The types of files on which this will work.
|
||||
*/
|
||||
private static final Set<String> SUPPORTED_EXTENSIONS = newHashSet("jar");
|
||||
|
||||
/**
|
||||
* The analyzer should be disabled if there are errors, so this is a flag to determine if such an error has occurred.
|
||||
*/
|
||||
private boolean errorFlag = false;
|
||||
|
||||
/**
|
||||
* The searcher itself.
|
||||
*/
|
||||
private CentralSearch searcher;
|
||||
/**
|
||||
* Utility to read POM files.
|
||||
*/
|
||||
private PomUtils pomUtil = new PomUtils();
|
||||
/**
|
||||
* Field indicating if the analyzer is enabled.
|
||||
*/
|
||||
private final boolean enabled = checkEnabled();
|
||||
|
||||
/**
|
||||
* Determine whether to enable this analyzer or not.
|
||||
*
|
||||
* @return whether the analyzer should be enabled
|
||||
*/
|
||||
@Override
|
||||
public boolean isEnabled() {
|
||||
return enabled;
|
||||
}
|
||||
|
||||
/**
|
||||
* Determines if this analyzer is enabled.
|
||||
*
|
||||
* @return <code>true</code> if the analyzer is enabled; otherwise <code>false</code>
|
||||
*/
|
||||
private boolean checkEnabled() {
|
||||
boolean retval = false;
|
||||
|
||||
try {
|
||||
if (Settings.getBoolean(Settings.KEYS.ANALYZER_CENTRAL_ENABLED)) {
|
||||
if (!Settings.getBoolean(Settings.KEYS.ANALYZER_NEXUS_ENABLED)
|
||||
|| NexusAnalyzer.DEFAULT_URL.equals(Settings.getString(Settings.KEYS.ANALYZER_NEXUS_URL))) {
|
||||
LOGGER.fine("Enabling the Central analyzer");
|
||||
retval = true;
|
||||
} else {
|
||||
LOGGER.info("Nexus analyzer is enabled, disabling the Central Analyzer");
|
||||
}
|
||||
} else {
|
||||
LOGGER.info("Central analyzer disabled");
|
||||
}
|
||||
} catch (InvalidSettingException ise) {
|
||||
LOGGER.warning("Invalid setting. Disabling the Central analyzer");
|
||||
}
|
||||
return retval;
|
||||
}
|
||||
|
||||
/**
|
||||
* Initializes the analyzer once before any analysis is performed.
|
||||
*
|
||||
* @throws Exception if there's an error during initialization
|
||||
*/
|
||||
@Override
|
||||
public void initializeFileTypeAnalyzer() throws Exception {
|
||||
LOGGER.fine("Initializing Central analyzer");
|
||||
LOGGER.fine(String.format("Central analyzer enabled: %s", isEnabled()));
|
||||
if (isEnabled()) {
|
||||
final String searchUrl = Settings.getString(Settings.KEYS.ANALYZER_CENTRAL_URL);
|
||||
LOGGER.fine(String.format("Central Analyzer URL: %s", searchUrl));
|
||||
searcher = new CentralSearch(new URL(searchUrl));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the analyzer's name.
|
||||
*
|
||||
* @return the name of the analyzer
|
||||
*/
|
||||
@Override
|
||||
public String getName() {
|
||||
return ANALYZER_NAME;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the key used in the properties file to to reference the analyzer's enabled property.
|
||||
*
|
||||
* @return the analyzer's enabled property setting key.
|
||||
*/
|
||||
@Override
|
||||
protected String getAnalyzerEnabledSettingKey() {
|
||||
return Settings.KEYS.ANALYZER_CENTRAL_ENABLED;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the analysis phase under which the analyzer runs.
|
||||
*
|
||||
* @return the phase under which the analyzer runs
|
||||
*/
|
||||
@Override
|
||||
public AnalysisPhase getAnalysisPhase() {
|
||||
return ANALYSIS_PHASE;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the extensions for which this Analyzer runs.
|
||||
*
|
||||
* @return the extensions for which this Analyzer runs
|
||||
*/
|
||||
@Override
|
||||
public Set<String> getSupportedExtensions() {
|
||||
return SUPPORTED_EXTENSIONS;
|
||||
}
|
||||
|
||||
/**
|
||||
* Performs the analysis.
|
||||
*
|
||||
* @param dependency the dependency to analyze
|
||||
* @param engine the engine
|
||||
* @throws AnalysisException when there's an exception during analysis
|
||||
*/
|
||||
@Override
|
||||
public void analyzeFileType(Dependency dependency, Engine engine) throws AnalysisException {
|
||||
if (errorFlag || !isEnabled()) {
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
final List<MavenArtifact> mas = searcher.searchSha1(dependency.getSha1sum());
|
||||
final Confidence confidence = mas.size() > 1 ? Confidence.HIGH : Confidence.HIGHEST;
|
||||
for (MavenArtifact ma : mas) {
|
||||
LOGGER.fine(String.format("Central analyzer found artifact (%s) for dependency (%s)", ma.toString(), dependency.getFileName()));
|
||||
dependency.addAsEvidence("central", ma, confidence);
|
||||
boolean pomAnalyzed = false;
|
||||
for (Evidence e : dependency.getVendorEvidence()) {
|
||||
if ("pom".equals(e.getSource())) {
|
||||
pomAnalyzed = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (!pomAnalyzed && ma.getPomUrl() != null) {
|
||||
File pomFile = null;
|
||||
try {
|
||||
final File baseDir = Settings.getTempDirectory();
|
||||
pomFile = File.createTempFile("pom", ".xml", baseDir);
|
||||
if (!pomFile.delete()) {
|
||||
final String msg = String.format("Unable to fetch pom.xml for %s from Central; "
|
||||
+ "this could result in undetected CPE/CVEs.", dependency.getFileName());
|
||||
LOGGER.warning(msg);
|
||||
LOGGER.fine("Unable to delete temp file");
|
||||
}
|
||||
LOGGER.fine(String.format("Downloading %s", ma.getPomUrl()));
|
||||
Downloader.fetchFile(new URL(ma.getPomUrl()), pomFile);
|
||||
pomUtil.analyzePOM(dependency, pomFile);
|
||||
|
||||
} catch (DownloadFailedException ex) {
|
||||
final String msg = String.format("Unable to download pom.xml for %s from Central; "
|
||||
+ "this could result in undetected CPE/CVEs.", dependency.getFileName());
|
||||
LOGGER.warning(msg);
|
||||
} finally {
|
||||
if (pomFile != null && !FileUtils.deleteQuietly(pomFile)) {
|
||||
pomFile.deleteOnExit();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
} catch (IllegalArgumentException iae) {
|
||||
LOGGER.info(String.format("invalid sha1-hash on %s", dependency.getFileName()));
|
||||
} catch (FileNotFoundException fnfe) {
|
||||
LOGGER.fine(String.format("Artifact not found in repository: '%s", dependency.getFileName()));
|
||||
} catch (IOException ioe) {
|
||||
LOGGER.log(Level.FINE, "Could not connect to Central search", ioe);
|
||||
errorFlag = true;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -17,6 +17,7 @@
|
||||
*/
|
||||
package org.owasp.dependencycheck.analyzer;
|
||||
|
||||
import org.owasp.dependencycheck.analyzer.exception.AnalysisException;
|
||||
import org.owasp.dependencycheck.Engine;
|
||||
import org.owasp.dependencycheck.dependency.Dependency;
|
||||
import org.owasp.dependencycheck.suppression.SuppressionRule;
|
||||
@@ -29,7 +30,7 @@ import org.owasp.dependencycheck.suppression.SuppressionRule;
|
||||
*/
|
||||
public class CpeSuppressionAnalyzer extends AbstractSuppressionAnalyzer {
|
||||
|
||||
//<editor-fold defaultstate="collapsed" desc="All standard implmentation details of Analyzer">
|
||||
//<editor-fold defaultstate="collapsed" desc="All standard implementation details of Analyzer">
|
||||
/**
|
||||
* The name of the analyzer.
|
||||
*/
|
||||
|
||||
@@ -27,6 +27,7 @@ import java.util.logging.Logger;
|
||||
import java.util.regex.Matcher;
|
||||
import java.util.regex.Pattern;
|
||||
import org.owasp.dependencycheck.Engine;
|
||||
import org.owasp.dependencycheck.analyzer.exception.AnalysisException;
|
||||
import org.owasp.dependencycheck.dependency.Dependency;
|
||||
import org.owasp.dependencycheck.dependency.Identifier;
|
||||
import org.owasp.dependencycheck.utils.DependencyVersion;
|
||||
@@ -35,9 +36,9 @@ import org.owasp.dependencycheck.utils.LogUtils;
|
||||
|
||||
/**
|
||||
* <p>
|
||||
* This analyzer ensures dependencies that should be grouped together, to remove excess noise from the report, are
|
||||
* grouped. An example would be Spring, Spring Beans, Spring MVC, etc. If they are all for the same version and have the
|
||||
* same relative path then these should be grouped into a single dependency under the core/main library.</p>
|
||||
* This analyzer ensures dependencies that should be grouped together, to remove excess noise from the report, are grouped. An
|
||||
* example would be Spring, Spring Beans, Spring MVC, etc. If they are all for the same version and have the same relative path
|
||||
* then these should be grouped into a single dependency under the core/main library.</p>
|
||||
* <p>
|
||||
* Note, this grouping only works on dependencies with identified CVE entries</p>
|
||||
*
|
||||
@@ -45,21 +46,22 @@ import org.owasp.dependencycheck.utils.LogUtils;
|
||||
*/
|
||||
public class DependencyBundlingAnalyzer extends AbstractAnalyzer implements Analyzer {
|
||||
|
||||
/**
|
||||
* The Logger.
|
||||
*/
|
||||
private static final Logger LOGGER = Logger.getLogger(DependencyBundlingAnalyzer.class.getName());
|
||||
|
||||
//<editor-fold defaultstate="collapsed" desc="Constants and Member Variables">
|
||||
/**
|
||||
* A pattern for obtaining the first part of a filename.
|
||||
*/
|
||||
private static final Pattern STARTING_TEXT_PATTERN = Pattern.compile("^[a-zA-Z]*");
|
||||
private static final Pattern STARTING_TEXT_PATTERN = Pattern.compile("^[a-zA-Z0-9]*");
|
||||
/**
|
||||
* a flag indicating if this analyzer has run. This analyzer only runs once.
|
||||
*/
|
||||
private boolean analyzed = false;
|
||||
//</editor-fold>
|
||||
//<editor-fold defaultstate="collapsed" desc="All standard implementation details of Analyzer">
|
||||
/**
|
||||
* The set of file extensions supported by this analyzer.
|
||||
*/
|
||||
private static final Set<String> EXTENSIONS = null;
|
||||
/**
|
||||
* The name of the analyzer.
|
||||
*/
|
||||
@@ -69,15 +71,6 @@ public class DependencyBundlingAnalyzer extends AbstractAnalyzer implements Anal
|
||||
*/
|
||||
private static final AnalysisPhase ANALYSIS_PHASE = AnalysisPhase.PRE_FINDING_ANALYSIS;
|
||||
|
||||
/**
|
||||
* Returns a list of file EXTENSIONS supported by this analyzer.
|
||||
*
|
||||
* @return a list of file EXTENSIONS supported by this analyzer.
|
||||
*/
|
||||
public Set<String> getSupportedExtensions() {
|
||||
return EXTENSIONS;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the name of the analyzer.
|
||||
*
|
||||
@@ -87,16 +80,6 @@ public class DependencyBundlingAnalyzer extends AbstractAnalyzer implements Anal
|
||||
return ANALYZER_NAME;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns whether or not this analyzer can process the given extension.
|
||||
*
|
||||
* @param extension the file extension to test for support
|
||||
* @return whether or not the specified file extension is supported by this analyzer.
|
||||
*/
|
||||
public boolean supportsExtension(String extension) {
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the phase that the analyzer is intended to run in.
|
||||
*
|
||||
@@ -108,8 +91,8 @@ public class DependencyBundlingAnalyzer extends AbstractAnalyzer implements Anal
|
||||
//</editor-fold>
|
||||
|
||||
/**
|
||||
* Analyzes a set of dependencies. If they have been found to have the same base path and the same set of
|
||||
* identifiers they are likely related. The related dependencies are bundled into a single reportable item.
|
||||
* Analyzes a set of dependencies. If they have been found to have the same base path and the same set of identifiers they are
|
||||
* likely related. The related dependencies are bundled into a single reportable item.
|
||||
*
|
||||
* @param ignore this analyzer ignores the dependency being analyzed
|
||||
* @param engine the engine that is scanning the dependencies
|
||||
@@ -124,30 +107,34 @@ public class DependencyBundlingAnalyzer extends AbstractAnalyzer implements Anal
|
||||
//for (Dependency nextDependency : engine.getDependencies()) {
|
||||
while (mainIterator.hasNext()) {
|
||||
final Dependency dependency = mainIterator.next();
|
||||
if (mainIterator.hasNext()) {
|
||||
if (mainIterator.hasNext() && !dependenciesToRemove.contains(dependency)) {
|
||||
final ListIterator<Dependency> subIterator = engine.getDependencies().listIterator(mainIterator.nextIndex());
|
||||
while (subIterator.hasNext()) {
|
||||
final Dependency nextDependency = subIterator.next();
|
||||
if (isShadedJar(dependency, nextDependency)) {
|
||||
if (dependency.getFileName().toLowerCase().endsWith("pom.xml")) {
|
||||
dependenciesToRemove.add(dependency);
|
||||
} else {
|
||||
dependenciesToRemove.add(nextDependency);
|
||||
}
|
||||
} else if (hashesMatch(dependency, nextDependency)) {
|
||||
if (isCore(dependency, nextDependency)) {
|
||||
if (hashesMatch(dependency, nextDependency)) {
|
||||
if (firstPathIsShortest(dependency.getFilePath(), nextDependency.getFilePath())) {
|
||||
mergeDependencies(dependency, nextDependency, dependenciesToRemove);
|
||||
} else {
|
||||
mergeDependencies(nextDependency, dependency, dependenciesToRemove);
|
||||
break; //since we merged into the next dependency - skip forward to the next in mainIterator
|
||||
}
|
||||
} else if (isShadedJar(dependency, nextDependency)) {
|
||||
if (dependency.getFileName().toLowerCase().endsWith("pom.xml")) {
|
||||
mergeDependencies(nextDependency, dependency, dependenciesToRemove);
|
||||
nextDependency.getRelatedDependencies().remove(dependency);
|
||||
break;
|
||||
} else {
|
||||
mergeDependencies(dependency, nextDependency, dependenciesToRemove);
|
||||
nextDependency.getRelatedDependencies().remove(nextDependency);
|
||||
}
|
||||
} else if (cpeIdentifiersMatch(dependency, nextDependency)
|
||||
&& hasSameBasePath(dependency, nextDependency)
|
||||
&& fileNameMatch(dependency, nextDependency)) {
|
||||
|
||||
if (isCore(dependency, nextDependency)) {
|
||||
mergeDependencies(dependency, nextDependency, dependenciesToRemove);
|
||||
} else {
|
||||
mergeDependencies(nextDependency, dependency, dependenciesToRemove);
|
||||
break; //since we merged into the next dependency - skip forward to the next in mainIterator
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -155,9 +142,7 @@ public class DependencyBundlingAnalyzer extends AbstractAnalyzer implements Anal
|
||||
}
|
||||
//removing dependencies here as ensuring correctness and avoiding ConcurrentUpdateExceptions
|
||||
// was difficult because of the inner iterator.
|
||||
for (Dependency d : dependenciesToRemove) {
|
||||
engine.getDependencies().remove(d);
|
||||
}
|
||||
engine.getDependencies().removeAll(dependenciesToRemove);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -165,10 +150,10 @@ public class DependencyBundlingAnalyzer extends AbstractAnalyzer implements Anal
|
||||
* Adds the relatedDependency to the dependency's related dependencies.
|
||||
*
|
||||
* @param dependency the main dependency
|
||||
* @param relatedDependency a collection of dependencies to be removed from the main analysis loop, this is the
|
||||
* source of dependencies to remove
|
||||
* @param dependenciesToRemove a collection of dependencies that will be removed from the main analysis loop, this
|
||||
* function adds to this collection
|
||||
* @param relatedDependency a collection of dependencies to be removed from the main analysis loop, this is the source of
|
||||
* dependencies to remove
|
||||
* @param dependenciesToRemove a collection of dependencies that will be removed from the main analysis loop, this function
|
||||
* adds to this collection
|
||||
*/
|
||||
private void mergeDependencies(final Dependency dependency, final Dependency relatedDependency, final Set<Dependency> dependenciesToRemove) {
|
||||
dependency.addRelatedDependency(relatedDependency);
|
||||
@@ -177,12 +162,14 @@ public class DependencyBundlingAnalyzer extends AbstractAnalyzer implements Anal
|
||||
dependency.addRelatedDependency(i.next());
|
||||
i.remove();
|
||||
}
|
||||
if (dependency.getSha1sum().equals(relatedDependency.getSha1sum())) {
|
||||
dependency.addAllProjectReferences(relatedDependency.getProjectReferences());
|
||||
}
|
||||
dependenciesToRemove.add(relatedDependency);
|
||||
}
|
||||
|
||||
/**
|
||||
* Attempts to trim a maven repo to a common base path. This is typically
|
||||
* [drive]\[repo_location]\repository\[path1]\[path2].
|
||||
* Attempts to trim a maven repo to a common base path. This is typically [drive]\[repo_location]\repository\[path1]\[path2].
|
||||
*
|
||||
* @param path the path to trim
|
||||
* @return a string representing the base path.
|
||||
@@ -218,25 +205,8 @@ public class DependencyBundlingAnalyzer extends AbstractAnalyzer implements Anal
|
||||
|| dependency2 == null || dependency2.getFileName() == null) {
|
||||
return false;
|
||||
}
|
||||
String fileName1 = dependency1.getFileName();
|
||||
String fileName2 = dependency2.getFileName();
|
||||
|
||||
//update to deal with archive analyzer, the starting name maybe the same
|
||||
// as this is incorrectly looking at the starting path
|
||||
final File one = new File(fileName1);
|
||||
final File two = new File(fileName2);
|
||||
final String oneParent = one.getParent();
|
||||
final String twoParent = two.getParent();
|
||||
if (oneParent != null) {
|
||||
if (oneParent.equals(twoParent)) {
|
||||
fileName1 = one.getName();
|
||||
fileName2 = two.getName();
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
} else if (twoParent != null) {
|
||||
return false;
|
||||
}
|
||||
final String fileName1 = dependency1.getActualFile().getName();
|
||||
final String fileName2 = dependency2.getActualFile().getName();
|
||||
|
||||
//version check
|
||||
final DependencyVersion version1 = DependencyVersionUtil.parseVersion(fileName1);
|
||||
@@ -284,15 +254,17 @@ public class DependencyBundlingAnalyzer extends AbstractAnalyzer implements Anal
|
||||
}
|
||||
if (cpeCount1 > 0 && cpeCount1 == cpeCount2) {
|
||||
for (Identifier i : dependency1.getIdentifiers()) {
|
||||
matches |= dependency2.getIdentifiers().contains(i);
|
||||
if (!matches) {
|
||||
break;
|
||||
if ("cpe".equals(i.getType())) {
|
||||
matches |= dependency2.getIdentifiers().contains(i);
|
||||
if (!matches) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
if (LogUtils.isVerboseLoggingEnabled()) {
|
||||
final String msg = String.format("IdentifiersMatch=%s (%s, %s)", matches, dependency1.getFileName(), dependency2.getFileName());
|
||||
Logger.getLogger(DependencyBundlingAnalyzer.class.getName()).log(Level.FINE, msg);
|
||||
LOGGER.log(Level.FINE, msg);
|
||||
}
|
||||
return matches;
|
||||
}
|
||||
@@ -335,8 +307,8 @@ public class DependencyBundlingAnalyzer extends AbstractAnalyzer implements Anal
|
||||
}
|
||||
|
||||
/**
|
||||
* This is likely a very broken attempt at determining if the 'left' dependency is the 'core' library in comparison
|
||||
* to the 'right' library.
|
||||
* This is likely a very broken attempt at determining if the 'left' dependency is the 'core' library in comparison to the
|
||||
* 'right' library.
|
||||
*
|
||||
* @param left the dependency to test
|
||||
* @param right the dependency to test against
|
||||
@@ -355,6 +327,10 @@ public class DependencyBundlingAnalyzer extends AbstractAnalyzer implements Anal
|
||||
|| !rightName.contains("core") && leftName.contains("core")
|
||||
|| !rightName.contains("kernel") && leftName.contains("kernel")) {
|
||||
returnVal = true;
|
||||
// } else if (leftName.matches(".*struts2\\-core.*") && rightName.matches(".*xwork\\-core.*")) {
|
||||
// returnVal = true;
|
||||
// } else if (rightName.matches(".*struts2\\-core.*") && leftName.matches(".*xwork\\-core.*")) {
|
||||
// returnVal = false;
|
||||
} else {
|
||||
/*
|
||||
* considered splitting the names up and comparing the components,
|
||||
@@ -363,13 +339,13 @@ public class DependencyBundlingAnalyzer extends AbstractAnalyzer implements Anal
|
||||
* be shorter:
|
||||
* axis2-saaj-1.4.1.jar
|
||||
* axis2-1.4.1.jar <-----
|
||||
* axis2-kernal-1.4.1.jar
|
||||
* axis2-kernel-1.4.1.jar
|
||||
*/
|
||||
returnVal = leftName.length() <= rightName.length();
|
||||
}
|
||||
if (LogUtils.isVerboseLoggingEnabled()) {
|
||||
final String msg = String.format("IsCore=%s (%s, %s)", returnVal, left.getFileName(), right.getFileName());
|
||||
Logger.getLogger(DependencyBundlingAnalyzer.class.getName()).log(Level.FINE, msg);
|
||||
LOGGER.log(Level.FINE, msg);
|
||||
}
|
||||
return returnVal;
|
||||
}
|
||||
@@ -389,13 +365,12 @@ public class DependencyBundlingAnalyzer extends AbstractAnalyzer implements Anal
|
||||
}
|
||||
|
||||
/**
|
||||
* Determines if the jar is shaded and the created pom.xml identified the same CPE as the jar - if so, the pom.xml
|
||||
* dependency should be removed.
|
||||
* Determines if the jar is shaded and the created pom.xml identified the same CPE as the jar - if so, the pom.xml dependency
|
||||
* should be removed.
|
||||
*
|
||||
* @param dependency a dependency to check
|
||||
* @param nextDependency another dependency to check
|
||||
* @return true if on of the dependencies is a pom.xml and the identifiers between the two collections match;
|
||||
* otherwise false
|
||||
* @return true if on of the dependencies is a pom.xml and the identifiers between the two collections match; otherwise false
|
||||
*/
|
||||
private boolean isShadedJar(Dependency dependency, Dependency nextDependency) {
|
||||
final String mainName = dependency.getFileName().toLowerCase();
|
||||
@@ -407,4 +382,43 @@ public class DependencyBundlingAnalyzer extends AbstractAnalyzer implements Anal
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Determines which path is shortest; if path lengths are equal then we use compareTo of the string method to determine if the
|
||||
* first path is smaller.
|
||||
*
|
||||
* @param left the first path to compare
|
||||
* @param right the second path to compare
|
||||
* @return <code>true</code> if the leftPath is the shortest; otherwise <code>false</code>
|
||||
*/
|
||||
protected boolean firstPathIsShortest(String left, String right) {
|
||||
final String leftPath = left.replace('\\', '/');
|
||||
final String rightPath = right.replace('\\', '/');
|
||||
|
||||
final int leftCount = countChar(leftPath, '/');
|
||||
final int rightCount = countChar(rightPath, '/');
|
||||
if (leftCount == rightCount) {
|
||||
return leftPath.compareTo(rightPath) <= 0;
|
||||
} else {
|
||||
return leftCount < rightCount;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Counts the number of times the character is present in the string.
|
||||
*
|
||||
* @param string the string to count the characters in
|
||||
* @param c the character to count
|
||||
* @return the number of times the character is present in the string
|
||||
*/
|
||||
private int countChar(String string, char c) {
|
||||
int count = 0;
|
||||
final int max = string.length();
|
||||
for (int i = 0; i < max; i++) {
|
||||
if (c == string.charAt(i)) {
|
||||
count++;
|
||||
}
|
||||
}
|
||||
return count;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -30,6 +30,7 @@ import java.util.logging.Logger;
|
||||
import java.util.regex.Matcher;
|
||||
import java.util.regex.Pattern;
|
||||
import org.owasp.dependencycheck.Engine;
|
||||
import org.owasp.dependencycheck.analyzer.exception.AnalysisException;
|
||||
import org.owasp.dependencycheck.dependency.Dependency;
|
||||
import org.owasp.dependencycheck.dependency.Identifier;
|
||||
import org.owasp.dependencycheck.dependency.VulnerableSoftware;
|
||||
@@ -41,11 +42,11 @@ import org.owasp.dependencycheck.dependency.VulnerableSoftware;
|
||||
*/
|
||||
public class FalsePositiveAnalyzer extends AbstractAnalyzer {
|
||||
|
||||
//<editor-fold defaultstate="collapsed" desc="All standard implmentation details of Analyzer">
|
||||
/**
|
||||
* The set of file extensions supported by this analyzer.
|
||||
* The Logger.
|
||||
*/
|
||||
private static final Set<String> EXTENSIONS = null;
|
||||
private static final Logger LOGGER = Logger.getLogger(FalsePositiveAnalyzer.class.getName());
|
||||
//<editor-fold defaultstate="collapsed" desc="All standard implementation details of Analyzer">
|
||||
/**
|
||||
* The name of the analyzer.
|
||||
*/
|
||||
@@ -55,15 +56,6 @@ public class FalsePositiveAnalyzer extends AbstractAnalyzer {
|
||||
*/
|
||||
private static final AnalysisPhase ANALYSIS_PHASE = AnalysisPhase.POST_IDENTIFIER_ANALYSIS;
|
||||
|
||||
/**
|
||||
* Returns a list of file EXTENSIONS supported by this analyzer.
|
||||
*
|
||||
* @return a list of file EXTENSIONS supported by this analyzer.
|
||||
*/
|
||||
public Set<String> getSupportedExtensions() {
|
||||
return EXTENSIONS;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the name of the analyzer.
|
||||
*
|
||||
@@ -73,16 +65,6 @@ public class FalsePositiveAnalyzer extends AbstractAnalyzer {
|
||||
return ANALYZER_NAME;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns whether or not this analyzer can process the given extension.
|
||||
*
|
||||
* @param extension the file extension to test for support
|
||||
* @return whether or not the specified file extension is supported by this analyzer.
|
||||
*/
|
||||
public boolean supportsExtension(String extension) {
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the phase that the analyzer is intended to run in.
|
||||
*
|
||||
@@ -104,11 +86,46 @@ public class FalsePositiveAnalyzer extends AbstractAnalyzer {
|
||||
public void analyze(Dependency dependency, Engine engine) throws AnalysisException {
|
||||
removeJreEntries(dependency);
|
||||
removeBadMatches(dependency);
|
||||
removeBadSpringMatches(dependency);
|
||||
removeWrongVersionMatches(dependency);
|
||||
removeSpuriousCPE(dependency);
|
||||
removeDuplicativeEntriesFromJar(dependency, engine);
|
||||
addFalseNegativeCPEs(dependency);
|
||||
}
|
||||
|
||||
/**
|
||||
* Removes inaccurate matches on springframework CPEs.
|
||||
*
|
||||
* @param dependency the dependency to test for and remove known inaccurate CPE matches
|
||||
*/
|
||||
private void removeBadSpringMatches(Dependency dependency) {
|
||||
String mustContain = null;
|
||||
for (Identifier i : dependency.getIdentifiers()) {
|
||||
if ("maven".contains(i.getType())) {
|
||||
if (i.getValue() != null && i.getValue().startsWith("org.springframework.")) {
|
||||
final int endPoint = i.getValue().indexOf(":", 19);
|
||||
if (endPoint >= 0) {
|
||||
mustContain = i.getValue().substring(19, endPoint).toLowerCase();
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
if (mustContain != null) {
|
||||
final Iterator<Identifier> itr = dependency.getIdentifiers().iterator();
|
||||
while (itr.hasNext()) {
|
||||
final Identifier i = itr.next();
|
||||
if ("cpe".contains(i.getType())
|
||||
&& i.getValue() != null
|
||||
&& i.getValue().startsWith("cpe:/a:springsource:")
|
||||
&& !i.getValue().toLowerCase().contains(mustContain)) {
|
||||
itr.remove();
|
||||
//dependency.getIdentifiers().remove(i);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* <p>
|
||||
* Intended to remove spurious CPE entries. By spurious we mean duplicate, less specific CPE entries.</p>
|
||||
@@ -154,8 +171,7 @@ public class FalsePositiveAnalyzer extends AbstractAnalyzer {
|
||||
final String nextVersion = nextCpe.getVersion();
|
||||
if (currentVersion == null && nextVersion == null) {
|
||||
//how did we get here?
|
||||
Logger.getLogger(FalsePositiveAnalyzer.class
|
||||
.getName()).log(Level.FINE, "currentVersion and nextVersion are both null?");
|
||||
LOGGER.log(Level.FINE, "currentVersion and nextVersion are both null?");
|
||||
} else if (currentVersion == null && nextVersion != null) {
|
||||
dependency.getIdentifiers().remove(currentId);
|
||||
} else if (nextVersion == null && currentVersion != null) {
|
||||
@@ -178,12 +194,21 @@ public class FalsePositiveAnalyzer extends AbstractAnalyzer {
|
||||
* Regex to identify core java libraries and a few other commonly misidentified ones.
|
||||
*/
|
||||
public static final Pattern CORE_JAVA = Pattern.compile("^cpe:/a:(sun|oracle|ibm):(j2[ems]e|"
|
||||
+ "java(_platfrom_micro_edition|_runtime_environment|_se|virtual_machine|se_development_kit|fx)?|"
|
||||
+ "jdk|jre|jsf|jsse)($|:.*)");
|
||||
+ "java(_platform_micro_edition|_runtime_environment|_se|virtual_machine|se_development_kit|fx)?|"
|
||||
+ "jdk|jre|jsse)($|:.*)");
|
||||
|
||||
/**
|
||||
* Regex to identify core jsf libraries.
|
||||
*/
|
||||
public static final Pattern CORE_JAVA_JSF = Pattern.compile("^cpe:/a:(sun|oracle|ibm):jsf($|:.*)");
|
||||
/**
|
||||
* Regex to identify core java library files. This is currently incomplete.
|
||||
*/
|
||||
public static final Pattern CORE_FILES = Pattern.compile("^((alt[-])?rt|jsf[-].*|jsse|jfxrt|jfr|jce|javaws|deploy|charsets)\\.jar$");
|
||||
public static final Pattern CORE_FILES = Pattern.compile("(^|/)((alt[-])?rt|jsse|jfxrt|jfr|jce|javaws|deploy|charsets)\\.jar$");
|
||||
/**
|
||||
* Regex to identify core jsf java library files. This is currently incomplete.
|
||||
*/
|
||||
public static final Pattern CORE_JSF_FILES = Pattern.compile("(^|/)jsf[-][^/]*\\.jar$");
|
||||
|
||||
/**
|
||||
* Removes any CPE entries for the JDK/JRE unless the filename ends with rt.jar
|
||||
@@ -200,27 +225,11 @@ public class FalsePositiveAnalyzer extends AbstractAnalyzer {
|
||||
if (coreCPE.matches() && !coreFiles.matches()) {
|
||||
itr.remove();
|
||||
}
|
||||
|
||||
//replacecd with the regex above.
|
||||
// if (("cpe:/a:sun:java".equals(i.getValue())
|
||||
// || "cpe:/a:oracle:java".equals(i.getValue())
|
||||
// || "cpe:/a:ibm:java".equals(i.getValue())
|
||||
// || "cpe:/a:sun:j2se".equals(i.getValue())
|
||||
// || "cpe:/a:oracle:j2se".equals(i.getValue())
|
||||
// || i.getValue().startsWith("cpe:/a:sun:java:")
|
||||
// || i.getValue().startsWith("cpe:/a:sun:j2se:")
|
||||
// || i.getValue().startsWith("cpe:/a:sun:java:jre")
|
||||
// || i.getValue().startsWith("cpe:/a:sun:java:jdk")
|
||||
// || i.getValue().startsWith("cpe:/a:sun:java_se")
|
||||
// || i.getValue().startsWith("cpe:/a:oracle:java_se")
|
||||
// || i.getValue().startsWith("cpe:/a:oracle:java:")
|
||||
// || i.getValue().startsWith("cpe:/a:oracle:j2se:")
|
||||
// || i.getValue().startsWith("cpe:/a:oracle:jre")
|
||||
// || i.getValue().startsWith("cpe:/a:oracle:jdk")
|
||||
// || i.getValue().startsWith("cpe:/a:ibm:java:"))
|
||||
// && !dependency.getFileName().toLowerCase().endsWith("rt.jar")) {
|
||||
// itr.remove();
|
||||
// }
|
||||
final Matcher coreJsfCPE = CORE_JAVA_JSF.matcher(i.getValue());
|
||||
final Matcher coreJsfFiles = CORE_JSF_FILES.matcher(dependency.getFileName());
|
||||
if (coreJsfCPE.matches() && !coreJsfFiles.matches()) {
|
||||
itr.remove();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -239,7 +248,7 @@ public class FalsePositiveAnalyzer extends AbstractAnalyzer {
|
||||
try {
|
||||
cpe.parseName(value);
|
||||
} catch (UnsupportedEncodingException ex) {
|
||||
Logger.getLogger(FalsePositiveAnalyzer.class.getName()).log(Level.FINEST, null, ex);
|
||||
LOGGER.log(Level.FINEST, null, ex);
|
||||
return null;
|
||||
}
|
||||
return cpe;
|
||||
@@ -264,23 +273,48 @@ public class FalsePositiveAnalyzer extends AbstractAnalyzer {
|
||||
//Set<Evidence> artifactId = dependency.getVendorEvidence().getEvidence("pom", "artifactid");
|
||||
while (itr.hasNext()) {
|
||||
final Identifier i = itr.next();
|
||||
//TODO move this startswith expression to a configuration file?
|
||||
//TODO move this startsWith expression to a configuration file?
|
||||
if ("cpe".equals(i.getType())) {
|
||||
if ((i.getValue().matches(".*c\\+\\+.*")
|
||||
|| i.getValue().startsWith("cpe:/a:jquery:jquery")
|
||||
|| i.getValue().startsWith("cpe:/a:prototypejs:prototype")
|
||||
|| i.getValue().startsWith("cpe:/a:yahoo:yui")
|
||||
|| i.getValue().startsWith("cpe:/a:file:file")
|
||||
|| i.getValue().startsWith("cpe:/a:mozilla:mozilla")
|
||||
|| i.getValue().startsWith("cpe:/a:cvs:cvs")
|
||||
|| i.getValue().startsWith("cpe:/a:ftp:ftp")
|
||||
|| i.getValue().startsWith("cpe:/a:ssh:ssh"))
|
||||
|| i.getValue().startsWith("cpe:/a:tcp:tcp")
|
||||
|| i.getValue().startsWith("cpe:/a:ssh:ssh")
|
||||
|| i.getValue().startsWith("cpe:/a:lookup:lookup"))
|
||||
&& (dependency.getFileName().toLowerCase().endsWith(".jar")
|
||||
|| dependency.getFileName().toLowerCase().endsWith("pom.xml")
|
||||
|| dependency.getFileName().toLowerCase().endsWith(".dll")
|
||||
|| dependency.getFileName().toLowerCase().endsWith(".exe")
|
||||
|| dependency.getFileName().toLowerCase().endsWith(".nuspec")
|
||||
|| dependency.getFileName().toLowerCase().endsWith(".nupkg"))) {
|
||||
itr.remove();
|
||||
} else if ((i.getValue().startsWith("cpe:/a:jquery:jquery")
|
||||
|| i.getValue().startsWith("cpe:/a:prototypejs:prototype")
|
||||
|| i.getValue().startsWith("cpe:/a:yahoo:yui"))
|
||||
&& (dependency.getFileName().toLowerCase().endsWith(".jar")
|
||||
|| dependency.getFileName().toLowerCase().endsWith("pom.xml")
|
||||
|| dependency.getFileName().toLowerCase().endsWith(".dll")
|
||||
|| dependency.getFileName().toLowerCase().endsWith(".exe"))) {
|
||||
itr.remove();
|
||||
} else if ((i.getValue().startsWith("cpe:/a:microsoft:excel")
|
||||
|| i.getValue().startsWith("cpe:/a:microsoft:word")
|
||||
|| i.getValue().startsWith("cpe:/a:microsoft:visio")
|
||||
|| i.getValue().startsWith("cpe:/a:microsoft:powerpoint")
|
||||
|| i.getValue().startsWith("cpe:/a:microsoft:office"))
|
||||
&& (dependency.getFileName().toLowerCase().endsWith(".jar")
|
||||
|| dependency.getFileName().toLowerCase().endsWith("pom.xml"))) {
|
||||
itr.remove();
|
||||
} else if (i.getValue().startsWith("cpe:/a:apache:maven")
|
||||
&& !dependency.getFileName().toLowerCase().matches("maven-core-[\\d\\.]+\\.jar")) {
|
||||
itr.remove();
|
||||
} else if (i.getValue().startsWith("cpe:/a:m-core:m-core")
|
||||
&& !dependency.getEvidenceUsed().containsUsedString("m-core")) {
|
||||
itr.remove();
|
||||
} else if (i.getValue().startsWith("cpe:/a:jboss:jboss")
|
||||
&& !dependency.getFileName().toLowerCase().matches("jboss-?[\\d\\.-]+(GA)?\\.jar")) {
|
||||
itr.remove();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -327,6 +361,7 @@ public class FalsePositiveAnalyzer extends AbstractAnalyzer {
|
||||
* @param dependency the dependency being analyzed
|
||||
*/
|
||||
private void addFalseNegativeCPEs(Dependency dependency) {
|
||||
//TODO move this to the hint analyzer
|
||||
final Iterator<Identifier> itr = dependency.getIdentifiers().iterator();
|
||||
while (itr.hasNext()) {
|
||||
final Identifier i = itr.next();
|
||||
@@ -342,21 +377,92 @@ public class FalsePositiveAnalyzer extends AbstractAnalyzer {
|
||||
try {
|
||||
dependency.addIdentifier("cpe",
|
||||
newCpe,
|
||||
String.format("http://web.nvd.nist.gov/view/vuln/search?cpe=%s", URLEncoder.encode(newCpe, "UTF-8")));
|
||||
String.format(CPEAnalyzer.NVD_SEARCH_URL, URLEncoder.encode(newCpe, "UTF-8")));
|
||||
dependency.addIdentifier("cpe",
|
||||
newCpe2,
|
||||
String.format("http://web.nvd.nist.gov/view/vuln/search?cpe=%s", URLEncoder.encode(newCpe2, "UTF-8")));
|
||||
String.format(CPEAnalyzer.NVD_SEARCH_URL, URLEncoder.encode(newCpe2, "UTF-8")));
|
||||
dependency.addIdentifier("cpe",
|
||||
newCpe3,
|
||||
String.format("http://web.nvd.nist.gov/view/vuln/search?cpe=%s", URLEncoder.encode(newCpe3, "UTF-8")));
|
||||
String.format(CPEAnalyzer.NVD_SEARCH_URL, URLEncoder.encode(newCpe3, "UTF-8")));
|
||||
dependency.addIdentifier("cpe",
|
||||
newCpe4,
|
||||
String.format("http://web.nvd.nist.gov/view/vuln/search?cpe=%s", URLEncoder.encode(newCpe4, "UTF-8")));
|
||||
String.format(CPEAnalyzer.NVD_SEARCH_URL, URLEncoder.encode(newCpe4, "UTF-8")));
|
||||
} catch (UnsupportedEncodingException ex) {
|
||||
Logger.getLogger(FalsePositiveAnalyzer.class
|
||||
.getName()).log(Level.FINE, null, ex);
|
||||
LOGGER.log(Level.FINE, null, ex);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Removes duplicate entries identified that are contained within JAR files. These occasionally crop up due to POM
|
||||
* entries or other types of files (such as DLLs and EXEs) being contained within the JAR.
|
||||
*
|
||||
* @param dependency the dependency that might be a duplicate
|
||||
* @param engine the engine used to scan all dependencies
|
||||
*/
|
||||
private void removeDuplicativeEntriesFromJar(Dependency dependency, Engine engine) {
|
||||
if (dependency.getFileName().toLowerCase().endsWith("pom.xml")
|
||||
|| "dll".equals(dependency.getFileExtension())
|
||||
|| "exe".equals(dependency.getFileExtension())) {
|
||||
String parentPath = dependency.getFilePath().toLowerCase();
|
||||
if (parentPath.contains(".jar")) {
|
||||
parentPath = parentPath.substring(0, parentPath.indexOf(".jar") + 4);
|
||||
final Dependency parent = findDependency(parentPath, engine.getDependencies());
|
||||
if (parent != null) {
|
||||
boolean remove = false;
|
||||
for (Identifier i : dependency.getIdentifiers()) {
|
||||
if ("cpe".equals(i.getType())) {
|
||||
final String trimmedCPE = trimCpeToVendor(i.getValue());
|
||||
for (Identifier parentId : parent.getIdentifiers()) {
|
||||
if ("cpe".equals(parentId.getType()) && parentId.getValue().startsWith(trimmedCPE)) {
|
||||
remove |= true;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (!remove) { //we can escape early
|
||||
return;
|
||||
}
|
||||
}
|
||||
if (remove) {
|
||||
engine.getDependencies().remove(dependency);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieves a given dependency, based on a given path, from a list of dependencies.
|
||||
*
|
||||
* @param dependencyPath the path of the dependency to return
|
||||
* @param dependencies the collection of dependencies to search
|
||||
* @return the dependency object for the given path, otherwise null
|
||||
*/
|
||||
private Dependency findDependency(String dependencyPath, List<Dependency> dependencies) {
|
||||
for (Dependency d : dependencies) {
|
||||
if (d.getFilePath().equalsIgnoreCase(dependencyPath)) {
|
||||
return d;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Takes a full CPE and returns the CPE trimmed to include only vendor and product.
|
||||
*
|
||||
* @param value the CPE value to trim
|
||||
* @return a CPE value that only includes the vendor and product
|
||||
*/
|
||||
private String trimCpeToVendor(String value) {
|
||||
//cpe:/a:jruby:jruby:1.0.8
|
||||
final int pos1 = value.indexOf(":", 7); //right of vendor
|
||||
final int pos2 = value.indexOf(":", pos1 + 1); //right of product
|
||||
if (pos2 < 0) {
|
||||
return value;
|
||||
} else {
|
||||
return value.substring(0, pos2);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -18,8 +18,8 @@
|
||||
package org.owasp.dependencycheck.analyzer;
|
||||
|
||||
import java.io.File;
|
||||
import java.util.Set;
|
||||
import org.owasp.dependencycheck.Engine;
|
||||
import org.owasp.dependencycheck.analyzer.exception.AnalysisException;
|
||||
import org.owasp.dependencycheck.dependency.Confidence;
|
||||
import org.owasp.dependencycheck.dependency.Dependency;
|
||||
import org.owasp.dependencycheck.utils.DependencyVersion;
|
||||
@@ -33,7 +33,7 @@ import org.owasp.dependencycheck.utils.DependencyVersionUtil;
|
||||
*/
|
||||
public class FileNameAnalyzer extends AbstractAnalyzer implements Analyzer {
|
||||
|
||||
//<editor-fold defaultstate="collapsed" desc="All standard implmentation details of Analyzer">
|
||||
//<editor-fold defaultstate="collapsed" desc="All standard implementation details of Analyzer">
|
||||
/**
|
||||
* The name of the analyzer.
|
||||
*/
|
||||
@@ -42,19 +42,6 @@ public class FileNameAnalyzer extends AbstractAnalyzer implements Analyzer {
|
||||
* The phase that this analyzer is intended to run in.
|
||||
*/
|
||||
private static final AnalysisPhase ANALYSIS_PHASE = AnalysisPhase.INFORMATION_COLLECTION;
|
||||
/**
|
||||
* The set of file extensions supported by this analyzer.
|
||||
*/
|
||||
private static final Set<String> EXTENSIONS = null;
|
||||
|
||||
/**
|
||||
* Returns a list of file EXTENSIONS supported by this analyzer.
|
||||
*
|
||||
* @return a list of file EXTENSIONS supported by this analyzer.
|
||||
*/
|
||||
public Set<String> getSupportedExtensions() {
|
||||
return EXTENSIONS;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the name of the analyzer.
|
||||
@@ -65,16 +52,6 @@ public class FileNameAnalyzer extends AbstractAnalyzer implements Analyzer {
|
||||
return ANALYZER_NAME;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns whether or not this analyzer can process the given extension.
|
||||
*
|
||||
* @param extension the file extension to test for support.
|
||||
* @return whether or not the specified file extension is supported by this analyzer.
|
||||
*/
|
||||
public boolean supportsExtension(String extension) {
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the phase that the analyzer is intended to run in.
|
||||
*
|
||||
@@ -96,7 +73,7 @@ public class FileNameAnalyzer extends AbstractAnalyzer implements Analyzer {
|
||||
public void analyze(Dependency dependency, Engine engine) throws AnalysisException {
|
||||
|
||||
//strip any path information that may get added by ArchiveAnalyzer, etc.
|
||||
final File f = new File(dependency.getFileName());
|
||||
final File f = dependency.getActualFile();
|
||||
String fileName = f.getName();
|
||||
|
||||
//remove file extension
|
||||
|
||||
@@ -0,0 +1,39 @@
|
||||
/*
|
||||
* This file is part of dependency-check-core.
|
||||
*
|
||||
* Licensed under the Apache 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.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*
|
||||
* Copyright (c) 2014 Jeremy Long. All Rights Reserved.
|
||||
*/
|
||||
package org.owasp.dependencycheck.analyzer;
|
||||
|
||||
/**
|
||||
* An Analyzer that scans specific file types.
|
||||
*
|
||||
* @author Jeremy Long <jeremy.long@owasp.org>
|
||||
*/
|
||||
public interface FileTypeAnalyzer extends Analyzer {
|
||||
|
||||
/**
|
||||
* Returns whether or not this analyzer can process the given extension.
|
||||
*
|
||||
* @param extension the file extension to test for support.
|
||||
* @return whether or not the specified file extension is supported by this analyzer.
|
||||
*/
|
||||
boolean supportsExtension(String extension);
|
||||
|
||||
/**
|
||||
* Resets the analyzers state.
|
||||
*/
|
||||
void reset();
|
||||
}
|
||||
@@ -19,8 +19,10 @@ package org.owasp.dependencycheck.analyzer;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Iterator;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
import org.owasp.dependencycheck.Engine;
|
||||
import org.owasp.dependencycheck.analyzer.exception.AnalysisException;
|
||||
import org.owasp.dependencycheck.dependency.Confidence;
|
||||
import org.owasp.dependencycheck.dependency.Dependency;
|
||||
import org.owasp.dependencycheck.dependency.Evidence;
|
||||
@@ -31,7 +33,7 @@ import org.owasp.dependencycheck.dependency.Evidence;
|
||||
*/
|
||||
public class HintAnalyzer extends AbstractAnalyzer implements Analyzer {
|
||||
|
||||
//<editor-fold defaultstate="collapsed" desc="All standard implmentation details of Analyzer">
|
||||
//<editor-fold defaultstate="collapsed" desc="All standard implementation details of Analyzer">
|
||||
/**
|
||||
* The name of the analyzer.
|
||||
*/
|
||||
@@ -40,52 +42,31 @@ public class HintAnalyzer extends AbstractAnalyzer implements Analyzer {
|
||||
* The phase that this analyzer is intended to run in.
|
||||
*/
|
||||
private static final AnalysisPhase ANALYSIS_PHASE = AnalysisPhase.PRE_IDENTIFIER_ANALYSIS;
|
||||
/**
|
||||
* The set of file extensions supported by this analyzer.
|
||||
*/
|
||||
private static final Set<String> EXTENSIONS = null;
|
||||
|
||||
/**
|
||||
* Returns a list of file EXTENSIONS supported by this analyzer.
|
||||
*
|
||||
* @return a list of file EXTENSIONS supported by this analyzer.
|
||||
*/
|
||||
public Set<String> getSupportedExtensions() {
|
||||
return EXTENSIONS;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the name of the analyzer.
|
||||
*
|
||||
* @return the name of the analyzer.
|
||||
*/
|
||||
@Override
|
||||
public String getName() {
|
||||
return ANALYZER_NAME;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns whether or not this analyzer can process the given extension.
|
||||
*
|
||||
* @param extension the file extension to test for support.
|
||||
* @return whether or not the specified file extension is supported by this analyzer.
|
||||
*/
|
||||
public boolean supportsExtension(String extension) {
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the phase that the analyzer is intended to run in.
|
||||
*
|
||||
* @return the phase that the analyzer is intended to run in.
|
||||
*/
|
||||
@Override
|
||||
public AnalysisPhase getAnalysisPhase() {
|
||||
return ANALYSIS_PHASE;
|
||||
}
|
||||
//</editor-fold>
|
||||
|
||||
/**
|
||||
* The HintAnalyzer uses knowledge about a dependency to add additional information to help in identification of
|
||||
* identifiers or vulnerabilities.
|
||||
* The HintAnalyzer uses knowledge about a dependency to add additional information to help in identification of identifiers
|
||||
* or vulnerabilities.
|
||||
*
|
||||
* @param dependency The dependency being analyzed
|
||||
* @param engine The scanning engine
|
||||
@@ -104,24 +85,39 @@ public class HintAnalyzer extends AbstractAnalyzer implements Analyzer {
|
||||
Confidence.HIGH);
|
||||
|
||||
final Evidence springTest3 = new Evidence("Manifest",
|
||||
"Implementation-Title",
|
||||
"spring-core",
|
||||
Confidence.HIGH);
|
||||
|
||||
final Evidence springTest4 = new Evidence("Manifest",
|
||||
"Bundle-Vendor",
|
||||
"SpringSource",
|
||||
Confidence.HIGH);
|
||||
|
||||
Set<Evidence> evidence = dependency.getProductEvidence().getEvidence();
|
||||
if (evidence.contains(springTest1) || evidence.contains(springTest2)) {
|
||||
dependency.getProductEvidence().addEvidence("hint analyzer", "product", "springsource_spring_framework", Confidence.HIGH);
|
||||
final Evidence springTest5 = new Evidence("jar",
|
||||
"package name",
|
||||
"springframework",
|
||||
Confidence.LOW);
|
||||
|
||||
//springsource/vware problem
|
||||
final Set<Evidence> product = dependency.getProductEvidence().getEvidence();
|
||||
final Set<Evidence> vendor = dependency.getVendorEvidence().getEvidence();
|
||||
|
||||
if (product.contains(springTest1) || product.contains(springTest2) || product.contains(springTest3)
|
||||
|| (dependency.getFileName().contains("spring") && (product.contains(springTest5) || vendor.contains(springTest5)))) {
|
||||
dependency.getProductEvidence().addEvidence("hint analyzer", "product", "springsource spring framework", Confidence.HIGH);
|
||||
dependency.getVendorEvidence().addEvidence("hint analyzer", "vendor", "SpringSource", Confidence.HIGH);
|
||||
dependency.getVendorEvidence().addEvidence("hint analyzer", "vendor", "vmware", Confidence.HIGH);
|
||||
}
|
||||
|
||||
evidence = dependency.getVendorEvidence().getEvidence();
|
||||
if (evidence.contains(springTest3)) {
|
||||
if (vendor.contains(springTest4)) {
|
||||
dependency.getProductEvidence().addEvidence("hint analyzer", "product", "springsource_spring_framework", Confidence.HIGH);
|
||||
dependency.getVendorEvidence().addEvidence("hint analyzer", "vendor", "vmware", Confidence.HIGH);
|
||||
}
|
||||
|
||||
//sun/oracle problem
|
||||
final Iterator<Evidence> itr = dependency.getVendorEvidence().iterator();
|
||||
final ArrayList<Evidence> newEntries = new ArrayList<Evidence>();
|
||||
final List<Evidence> newEntries = new ArrayList<Evidence>();
|
||||
while (itr.hasNext()) {
|
||||
final Evidence e = itr.next();
|
||||
if ("sun".equalsIgnoreCase(e.getValue(false))) {
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -27,17 +27,24 @@ import java.util.logging.Level;
|
||||
import java.util.logging.Logger;
|
||||
import java.util.regex.Pattern;
|
||||
import org.owasp.dependencycheck.Engine;
|
||||
import org.owasp.dependencycheck.analyzer.exception.AnalysisException;
|
||||
import org.owasp.dependencycheck.dependency.Dependency;
|
||||
import org.owasp.dependencycheck.utils.Settings;
|
||||
|
||||
/**
|
||||
*
|
||||
* Used to analyze a JavaScript file to gather information to aid in identification of a CPE identifier.
|
||||
*
|
||||
* @author Jeremy Long (jeremy.long@owasp.org)
|
||||
* @author Jeremy Long <jeremy.long@owasp.org>
|
||||
*/
|
||||
public class JavaScriptAnalyzer extends AbstractAnalyzer implements Analyzer {
|
||||
public class JavaScriptAnalyzer extends AbstractFileTypeAnalyzer {
|
||||
|
||||
//<editor-fold defaultstate="collapsed" desc="All standard implmentation details of Analyzer">
|
||||
/**
|
||||
* The logger.
|
||||
*/
|
||||
private static final Logger LOGGER = Logger.getLogger(JavaScriptAnalyzer.class.getName());
|
||||
|
||||
//<editor-fold defaultstate="collapsed" desc="All standard implementation details of Analyzer">
|
||||
/**
|
||||
* The name of the analyzer.
|
||||
*/
|
||||
@@ -71,17 +78,6 @@ public class JavaScriptAnalyzer extends AbstractAnalyzer implements Analyzer {
|
||||
return ANALYZER_NAME;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns whether or not this analyzer can process the given extension.
|
||||
*
|
||||
* @param extension the file extension to test for support.
|
||||
* @return whether or not the specified file extension is supported by this analyzer.
|
||||
*/
|
||||
@Override
|
||||
public boolean supportsExtension(String extension) {
|
||||
return EXTENSIONS.contains(extension);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the phase that the analyzer is intended to run in.
|
||||
*
|
||||
@@ -92,6 +88,15 @@ public class JavaScriptAnalyzer extends AbstractAnalyzer implements Analyzer {
|
||||
return ANALYSIS_PHASE;
|
||||
}
|
||||
//</editor-fold>
|
||||
/**
|
||||
* Returns the key used in the properties file to reference the analyzer's enabled property.
|
||||
*
|
||||
* @return the analyzer's enabled property setting key
|
||||
*/
|
||||
@Override
|
||||
protected String getAnalyzerEnabledSettingKey() {
|
||||
return Settings.KEYS.ANALYZER_JAVASCRIPT_ENABLED;
|
||||
}
|
||||
|
||||
/**
|
||||
* Loads a specified JavaScript file and collects information from the copyright information contained within.
|
||||
@@ -101,8 +106,8 @@ public class JavaScriptAnalyzer extends AbstractAnalyzer implements Analyzer {
|
||||
* @throws AnalysisException is thrown if there is an error reading the JavaScript file.
|
||||
*/
|
||||
@Override
|
||||
public void analyze(Dependency dependency, Engine engine) throws AnalysisException {
|
||||
BufferedReader fin = null;;
|
||||
public void analyzeFileType(Dependency dependency, Engine engine) throws AnalysisException {
|
||||
BufferedReader fin = null;
|
||||
try {
|
||||
// /\*([^\*][^/]|[\r\n\f])+?\*/
|
||||
final Pattern extractComments = Pattern.compile("(/\\*([^*]|[\\r\\n]|(\\*+([^*/]|[\\r\\n])))*\\*+/)|(//.*)", Pattern.MULTILINE);
|
||||
@@ -117,15 +122,20 @@ public class JavaScriptAnalyzer extends AbstractAnalyzer implements Analyzer {
|
||||
final String msg = String.format("Dependency file not found: '%s'", dependency.getActualFilePath());
|
||||
throw new AnalysisException(msg, ex);
|
||||
} catch (IOException ex) {
|
||||
Logger.getLogger(JavaScriptAnalyzer.class.getName()).log(Level.SEVERE, null, ex);
|
||||
LOGGER.log(Level.SEVERE, null, ex);
|
||||
} finally {
|
||||
if (fin != null) {
|
||||
try {
|
||||
fin.close();
|
||||
} catch (IOException ex) {
|
||||
Logger.getLogger(JavaScriptAnalyzer.class.getName()).log(Level.FINEST, null, ex);
|
||||
LOGGER.log(Level.FINEST, null, ex);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void initializeFileTypeAnalyzer() throws Exception {
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@@ -17,6 +17,7 @@
|
||||
*/
|
||||
package org.owasp.dependencycheck.analyzer;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.FileNotFoundException;
|
||||
import java.io.IOException;
|
||||
import java.net.MalformedURLException;
|
||||
@@ -24,11 +25,18 @@ import java.net.URL;
|
||||
import java.util.Set;
|
||||
import java.util.logging.Level;
|
||||
import java.util.logging.Logger;
|
||||
import org.apache.commons.io.FileUtils;
|
||||
import org.owasp.dependencycheck.Engine;
|
||||
import org.owasp.dependencycheck.analyzer.exception.AnalysisException;
|
||||
import org.owasp.dependencycheck.data.nexus.MavenArtifact;
|
||||
import org.owasp.dependencycheck.data.nexus.NexusSearch;
|
||||
import org.owasp.dependencycheck.dependency.Confidence;
|
||||
import org.owasp.dependencycheck.dependency.Dependency;
|
||||
import org.owasp.dependencycheck.dependency.Evidence;
|
||||
import org.owasp.dependencycheck.jaxb.pom.PomUtils;
|
||||
import org.owasp.dependencycheck.utils.InvalidSettingException;
|
||||
import org.owasp.dependencycheck.utils.DownloadFailedException;
|
||||
import org.owasp.dependencycheck.utils.Downloader;
|
||||
import org.owasp.dependencycheck.utils.Settings;
|
||||
|
||||
/**
|
||||
@@ -45,20 +53,25 @@ import org.owasp.dependencycheck.utils.Settings;
|
||||
*
|
||||
* @author colezlaw
|
||||
*/
|
||||
public class NexusAnalyzer extends AbstractAnalyzer {
|
||||
public class NexusAnalyzer extends AbstractFileTypeAnalyzer {
|
||||
|
||||
/**
|
||||
* The logger
|
||||
* The default URL - this will be used by the CentralAnalyzer to determine whether to enable this.
|
||||
*/
|
||||
public static final String DEFAULT_URL = "https://repository.sonatype.org/service/local/";
|
||||
|
||||
/**
|
||||
* The logger.
|
||||
*/
|
||||
private static final Logger LOGGER = Logger.getLogger(NexusAnalyzer.class.getName());
|
||||
|
||||
/**
|
||||
* The name of the analyzer
|
||||
* The name of the analyzer.
|
||||
*/
|
||||
private static final String ANALYZER_NAME = "Nexus Analyzer";
|
||||
|
||||
/**
|
||||
* The phase in which the analyzer runs
|
||||
* The phase in which the analyzer runs.
|
||||
*/
|
||||
private static final AnalysisPhase ANALYSIS_PHASE = AnalysisPhase.INFORMATION_COLLECTION;
|
||||
|
||||
@@ -67,36 +80,79 @@ public class NexusAnalyzer extends AbstractAnalyzer {
|
||||
*/
|
||||
private static final Set<String> SUPPORTED_EXTENSIONS = newHashSet("jar");
|
||||
|
||||
/**
|
||||
* Whether this is actually enabled. Will get set during initialization.
|
||||
*/
|
||||
private boolean enabled = false;
|
||||
|
||||
/**
|
||||
* The Nexus Search to be set up for this analyzer.
|
||||
*/
|
||||
private NexusSearch searcher;
|
||||
|
||||
/**
|
||||
* Field indicating if the analyzer is enabled.
|
||||
*/
|
||||
private final boolean enabled = checkEnabled();
|
||||
/**
|
||||
* Field for doing POM work
|
||||
*/
|
||||
private final PomUtils pomUtil = new PomUtils();
|
||||
|
||||
/**
|
||||
* Determines if this analyzer is enabled
|
||||
*
|
||||
* @return <code>true</code> if the analyzer is enabled; otherwise <code>false</code>
|
||||
*/
|
||||
private boolean checkEnabled() {
|
||||
/* Enable this analyzer ONLY if the Nexus URL has been set to something
|
||||
other than the default one (if it's the default one, we'll use the
|
||||
central one) and it's enabled by the user.
|
||||
*/
|
||||
boolean retval = false;
|
||||
try {
|
||||
if ((!DEFAULT_URL.equals(Settings.getString(Settings.KEYS.ANALYZER_NEXUS_URL)))
|
||||
&& Settings.getBoolean(Settings.KEYS.ANALYZER_NEXUS_ENABLED)) {
|
||||
LOGGER.info("Enabling Nexus analyzer");
|
||||
retval = true;
|
||||
} else {
|
||||
LOGGER.fine("Nexus analyzer disabled, using Central instead");
|
||||
}
|
||||
} catch (InvalidSettingException ise) {
|
||||
LOGGER.warning("Invalid setting. Disabling Nexus analyzer");
|
||||
}
|
||||
|
||||
return retval;
|
||||
}
|
||||
|
||||
/**
|
||||
* Determine whether to enable this analyzer or not.
|
||||
*
|
||||
* @return whether the analyzer should be enabled
|
||||
*/
|
||||
@Override
|
||||
public boolean isEnabled() {
|
||||
return enabled;
|
||||
}
|
||||
|
||||
/**
|
||||
* Initializes the analyzer once before any analysis is performed.
|
||||
*
|
||||
* @throws Exception if there's an error during initialization
|
||||
*/
|
||||
@Override
|
||||
public void initialize() throws Exception {
|
||||
enabled = Settings.getBoolean(Settings.KEYS.ANALYZER_NEXUS_ENABLED);
|
||||
public void initializeFileTypeAnalyzer() throws Exception {
|
||||
LOGGER.fine("Initializing Nexus Analyzer");
|
||||
LOGGER.fine(String.format("Nexus Analyzer enabled: %s", enabled));
|
||||
if (enabled) {
|
||||
LOGGER.fine(String.format("Nexus Analyzer enabled: %s", isEnabled()));
|
||||
if (isEnabled()) {
|
||||
final String searchUrl = Settings.getString(Settings.KEYS.ANALYZER_NEXUS_URL);
|
||||
LOGGER.fine(String.format("Nexus Analyzer URL: %s", searchUrl));
|
||||
try {
|
||||
searcher = new NexusSearch(new URL(searchUrl));
|
||||
if (!searcher.preflightRequest()) {
|
||||
LOGGER.warning("There was an issue getting Nexus status. Disabling analyzer.");
|
||||
setEnabled(false);
|
||||
}
|
||||
} catch (MalformedURLException mue) {
|
||||
// I know that initialize can throw an exception, but we'll
|
||||
// just disable the analyzer if the URL isn't valid
|
||||
LOGGER.warning(String.format("Property %s not a valid URL. Nexus Analyzer disabled", searchUrl));
|
||||
enabled = false;
|
||||
setEnabled(false);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -111,6 +167,16 @@ public class NexusAnalyzer extends AbstractAnalyzer {
|
||||
return ANALYZER_NAME;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the key used in the properties file to reference the analyzer's enabled property.
|
||||
*
|
||||
* @return the analyzer's enabled property setting key
|
||||
*/
|
||||
@Override
|
||||
protected String getAnalyzerEnabledSettingKey() {
|
||||
return Settings.KEYS.ANALYZER_NEXUS_ENABLED;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the analysis phase under which the analyzer runs.
|
||||
*
|
||||
@@ -131,17 +197,6 @@ public class NexusAnalyzer extends AbstractAnalyzer {
|
||||
return SUPPORTED_EXTENSIONS;
|
||||
}
|
||||
|
||||
/**
|
||||
* Determines whether the incoming extension is supported.
|
||||
*
|
||||
* @param extension the extension to check for support
|
||||
* @return whether the extension is supported
|
||||
*/
|
||||
@Override
|
||||
public boolean supportsExtension(String extension) {
|
||||
return SUPPORTED_EXTENSIONS.contains(extension);
|
||||
}
|
||||
|
||||
/**
|
||||
* Performs the analysis.
|
||||
*
|
||||
@@ -150,32 +205,51 @@ public class NexusAnalyzer extends AbstractAnalyzer {
|
||||
* @throws AnalysisException when there's an exception during analysis
|
||||
*/
|
||||
@Override
|
||||
public void analyze(Dependency dependency, Engine engine) throws AnalysisException {
|
||||
// Make a quick exit if this analyzer is disabled
|
||||
if (!enabled) {
|
||||
public void analyzeFileType(Dependency dependency, Engine engine) throws AnalysisException {
|
||||
if (!isEnabled()) {
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
final MavenArtifact ma = searcher.searchSha1(dependency.getSha1sum());
|
||||
if (ma.getGroupId() != null && !"".equals(ma.getGroupId())) {
|
||||
dependency.getVendorEvidence().addEvidence("nexus", "groupid", ma.getGroupId(), Confidence.HIGH);
|
||||
dependency.addAsEvidence("nexus", ma, Confidence.HIGH);
|
||||
boolean pomAnalyzed = false;
|
||||
LOGGER.fine("POM URL " + ma.getPomUrl());
|
||||
for (Evidence e : dependency.getVendorEvidence()) {
|
||||
if ("pom".equals(e.getSource())) {
|
||||
pomAnalyzed = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (ma.getArtifactId() != null && !"".equals(ma.getArtifactId())) {
|
||||
dependency.getProductEvidence().addEvidence("nexus", "artifactid", ma.getArtifactId(), Confidence.HIGH);
|
||||
}
|
||||
if (ma.getVersion() != null && !"".equals(ma.getVersion())) {
|
||||
dependency.getVersionEvidence().addEvidence("nexus", "version", ma.getVersion(), Confidence.HIGH);
|
||||
}
|
||||
if (ma.getArtifactUrl() != null && !"".equals(ma.getArtifactUrl())) {
|
||||
dependency.addIdentifier("maven", ma.toString(), ma.getArtifactUrl(), Confidence.HIGHEST);
|
||||
if (!pomAnalyzed && ma.getPomUrl() != null) {
|
||||
File pomFile = null;
|
||||
try {
|
||||
final File baseDir = Settings.getTempDirectory();
|
||||
pomFile = File.createTempFile("pom", ".xml", baseDir);
|
||||
if (!pomFile.delete()) {
|
||||
final String msg = String.format("Unable to fetch pom.xml for %s from Nexus repository; "
|
||||
+ "this could result in undetected CPE/CVEs.", dependency.getFileName());
|
||||
LOGGER.warning(msg);
|
||||
LOGGER.fine("Unable to delete temp file");
|
||||
}
|
||||
LOGGER.fine(String.format("Downloading %s", ma.getPomUrl()));
|
||||
Downloader.fetchFile(new URL(ma.getPomUrl()), pomFile);
|
||||
pomUtil.analyzePOM(dependency, pomFile);
|
||||
} catch (DownloadFailedException ex) {
|
||||
final String msg = String.format("Unable to download pom.xml for %s from Nexus repository; "
|
||||
+ "this could result in undetected CPE/CVEs.", dependency.getFileName());
|
||||
LOGGER.warning(msg);
|
||||
} finally {
|
||||
if (pomFile != null && !FileUtils.deleteQuietly(pomFile)) {
|
||||
pomFile.deleteOnExit();
|
||||
}
|
||||
}
|
||||
}
|
||||
} catch (IllegalArgumentException iae) {
|
||||
//dependency.addAnalysisException(new AnalysisException("Invalid SHA-1"));
|
||||
LOGGER.info(String.format("invalid sha-1 hash on %s", dependency.getFileName()));
|
||||
} catch (FileNotFoundException fnfe) {
|
||||
//dependency.addAnalysisException(new AnalysisException("Artifact not found on repository"));
|
||||
LOGGER.fine(String.format("Artificat not found in repository '%s'", dependency.getFileName()));
|
||||
LOGGER.fine(String.format("Artifact not found in repository '%s'", dependency.getFileName()));
|
||||
LOGGER.log(Level.FINE, fnfe.getMessage(), fnfe);
|
||||
} catch (IOException ioe) {
|
||||
//dependency.addAnalysisException(new AnalysisException("Could not connect to repository", ioe));
|
||||
@@ -183,5 +257,3 @@ public class NexusAnalyzer extends AbstractAnalyzer {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// vim: cc=120:sw=4:ts=4:sts=4
|
||||
|
||||
@@ -18,36 +18,40 @@
|
||||
package org.owasp.dependencycheck.analyzer;
|
||||
|
||||
import java.io.FileInputStream;
|
||||
import java.io.FileNotFoundException;
|
||||
import java.io.IOException;
|
||||
import java.util.Set;
|
||||
import java.util.logging.Level;
|
||||
import java.util.logging.Logger;
|
||||
|
||||
import org.owasp.dependencycheck.Engine;
|
||||
import org.owasp.dependencycheck.analyzer.exception.AnalysisException;
|
||||
import org.owasp.dependencycheck.data.nuget.NugetPackage;
|
||||
import org.owasp.dependencycheck.data.nuget.NuspecParseException;
|
||||
import org.owasp.dependencycheck.data.nuget.NuspecParser;
|
||||
import org.owasp.dependencycheck.data.nuget.XPathNuspecParser;
|
||||
import org.owasp.dependencycheck.dependency.Confidence;
|
||||
import org.owasp.dependencycheck.dependency.Dependency;
|
||||
import org.owasp.dependencycheck.utils.Settings;
|
||||
|
||||
/**
|
||||
* Analyzer which will parse a Nuspec file to gather module information.
|
||||
*
|
||||
* @author colezlaw
|
||||
*/
|
||||
public class NuspecAnalyzer extends AbstractAnalyzer {
|
||||
public class NuspecAnalyzer extends AbstractFileTypeAnalyzer {
|
||||
|
||||
/**
|
||||
* The logger
|
||||
* The logger.
|
||||
*/
|
||||
private static final Logger LOGGER = Logger.getLogger(NuspecAnalyzer.class.getName());
|
||||
|
||||
/**
|
||||
* The name of the analyzer
|
||||
* The name of the analyzer.
|
||||
*/
|
||||
private static final String ANALYZER_NAME = "Nuspec Analyzer";
|
||||
|
||||
/**
|
||||
* The phase in which the analyzer runs
|
||||
* The phase in which the analyzer runs.
|
||||
*/
|
||||
private static final AnalysisPhase ANALYSIS_PHASE = AnalysisPhase.INFORMATION_COLLECTION;
|
||||
|
||||
@@ -62,7 +66,7 @@ public class NuspecAnalyzer extends AbstractAnalyzer {
|
||||
* @throws Exception if there's an error during initialization
|
||||
*/
|
||||
@Override
|
||||
public void initialize() throws Exception {
|
||||
public void initializeFileTypeAnalyzer() throws Exception {
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -75,6 +79,16 @@ public class NuspecAnalyzer extends AbstractAnalyzer {
|
||||
return ANALYZER_NAME;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the key used in the properties file to reference the analyzer's enabled property.
|
||||
*
|
||||
* @return the analyzer's enabled property setting key
|
||||
*/
|
||||
@Override
|
||||
protected String getAnalyzerEnabledSettingKey() {
|
||||
return Settings.KEYS.ANALYZER_NUSPEC_ENABLED;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the analysis phase under which the analyzer runs.
|
||||
*
|
||||
@@ -95,17 +109,6 @@ public class NuspecAnalyzer extends AbstractAnalyzer {
|
||||
return SUPPORTED_EXTENSIONS;
|
||||
}
|
||||
|
||||
/**
|
||||
* Determines whether the incoming extension is supported.
|
||||
*
|
||||
* @param extension the extension to check for support
|
||||
* @return whether the extension is supported
|
||||
*/
|
||||
@Override
|
||||
public boolean supportsExtension(String extension) {
|
||||
return SUPPORTED_EXTENSIONS.contains(extension);
|
||||
}
|
||||
|
||||
/**
|
||||
* Performs the analysis.
|
||||
*
|
||||
@@ -114,8 +117,8 @@ public class NuspecAnalyzer extends AbstractAnalyzer {
|
||||
* @throws AnalysisException when there's an exception during analysis
|
||||
*/
|
||||
@Override
|
||||
public void analyze(Dependency dependency, Engine engine) throws AnalysisException {
|
||||
LOGGER.log(Level.INFO, "Checking Nuspec file {0}", dependency.toString());
|
||||
public void analyzeFileType(Dependency dependency, Engine engine) throws AnalysisException {
|
||||
LOGGER.log(Level.FINE, "Checking Nuspec file {0}", dependency.toString());
|
||||
try {
|
||||
final NuspecParser parser = new XPathNuspecParser();
|
||||
NugetPackage np = null;
|
||||
@@ -123,9 +126,17 @@ public class NuspecAnalyzer extends AbstractAnalyzer {
|
||||
try {
|
||||
fis = new FileInputStream(dependency.getActualFilePath());
|
||||
np = parser.parse(fis);
|
||||
} catch (NuspecParseException ex) {
|
||||
throw new AnalysisException(ex);
|
||||
} catch (FileNotFoundException ex) {
|
||||
throw new AnalysisException(ex);
|
||||
} finally {
|
||||
if (fis != null) {
|
||||
try { fis.close(); } catch (Exception e) { }
|
||||
try {
|
||||
fis.close();
|
||||
} catch (IOException e) {
|
||||
LOGGER.fine("Error closing input stream");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -138,10 +149,8 @@ public class NuspecAnalyzer extends AbstractAnalyzer {
|
||||
if (np.getTitle() != null) {
|
||||
dependency.getProductEvidence().addEvidence("nuspec", "title", np.getTitle(), Confidence.MEDIUM);
|
||||
}
|
||||
} catch (Exception e) {
|
||||
} catch (Throwable e) {
|
||||
throw new AnalysisException(e);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// vim: cc=120:sw=4:ts=4:sts=4
|
||||
|
||||
@@ -20,8 +20,8 @@ package org.owasp.dependencycheck.analyzer;
|
||||
import java.io.IOException;
|
||||
import java.sql.SQLException;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
import org.owasp.dependencycheck.Engine;
|
||||
import org.owasp.dependencycheck.analyzer.exception.AnalysisException;
|
||||
import org.owasp.dependencycheck.data.nvdcve.CveDB;
|
||||
import org.owasp.dependencycheck.data.nvdcve.DatabaseException;
|
||||
import org.owasp.dependencycheck.dependency.Dependency;
|
||||
@@ -61,6 +61,7 @@ public class NvdCveAnalyzer implements Analyzer {
|
||||
/**
|
||||
* Closes the data source.
|
||||
*/
|
||||
@Override
|
||||
public void close() {
|
||||
cveDB.close();
|
||||
cveDB = null;
|
||||
@@ -95,6 +96,7 @@ public class NvdCveAnalyzer implements Analyzer {
|
||||
* @param engine The analysis engine
|
||||
* @throws AnalysisException is thrown if there is an issue analyzing the dependency
|
||||
*/
|
||||
@Override
|
||||
public void analyze(Dependency dependency, Engine engine) throws AnalysisException {
|
||||
for (Identifier id : dependency.getIdentifiers()) {
|
||||
if ("cpe".equals(id.getType())) {
|
||||
@@ -107,15 +109,17 @@ public class NvdCveAnalyzer implements Analyzer {
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns true because this analyzer supports all dependency types.
|
||||
*
|
||||
* @return true.
|
||||
*/
|
||||
public Set<String> getSupportedExtensions() {
|
||||
return null;
|
||||
for (Identifier id : dependency.getSuppressedIdentifiers()) {
|
||||
if ("cpe".equals(id.getType())) {
|
||||
try {
|
||||
final String value = id.getValue();
|
||||
final List<Vulnerability> vulns = cveDB.getVulnerabilities(value);
|
||||
dependency.getSuppressedVulnerabilities().addAll(vulns);
|
||||
} catch (DatabaseException ex) {
|
||||
throw new AnalysisException(ex);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -123,34 +127,27 @@ public class NvdCveAnalyzer implements Analyzer {
|
||||
*
|
||||
* @return the name of this analyzer.
|
||||
*/
|
||||
@Override
|
||||
public String getName() {
|
||||
return "NVD CVE Analyzer";
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns true because this analyzer supports all dependency types.
|
||||
*
|
||||
* @param extension the file extension of the dependency being analyzed.
|
||||
* @return true.
|
||||
*/
|
||||
public boolean supportsExtension(String extension) {
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the analysis phase that this analyzer should run in.
|
||||
*
|
||||
* @return the analysis phase that this analyzer should run in.
|
||||
*/
|
||||
@Override
|
||||
public AnalysisPhase getAnalysisPhase() {
|
||||
return AnalysisPhase.FINDING_ANALYSIS;
|
||||
}
|
||||
|
||||
/**
|
||||
* Opens the NVD CVE Lucene Index.
|
||||
* Opens the database used to gather NVD CVE data.
|
||||
*
|
||||
* @throws Exception is thrown if there is an issue opening the index.
|
||||
*/
|
||||
@Override
|
||||
public void initialize() throws Exception {
|
||||
this.open();
|
||||
}
|
||||
|
||||
@@ -17,6 +17,7 @@
|
||||
*/
|
||||
package org.owasp.dependencycheck.analyzer;
|
||||
|
||||
import org.owasp.dependencycheck.analyzer.exception.AnalysisException;
|
||||
import org.owasp.dependencycheck.Engine;
|
||||
import org.owasp.dependencycheck.dependency.Dependency;
|
||||
import org.owasp.dependencycheck.suppression.SuppressionRule;
|
||||
|
||||
@@ -15,7 +15,7 @@
|
||||
*
|
||||
* Copyright (c) 2012 Jeremy Long. All Rights Reserved.
|
||||
*/
|
||||
package org.owasp.dependencycheck.analyzer;
|
||||
package org.owasp.dependencycheck.analyzer.exception;
|
||||
|
||||
/**
|
||||
* An exception thrown when the analysis of a dependency fails.
|
||||
@@ -15,7 +15,7 @@
|
||||
*
|
||||
* Copyright (c) 2013 Jeremy Long. All Rights Reserved.
|
||||
*/
|
||||
package org.owasp.dependencycheck.analyzer;
|
||||
package org.owasp.dependencycheck.analyzer.exception;
|
||||
|
||||
/**
|
||||
* An exception thrown when files in an archive cannot be extracted.
|
||||
@@ -0,0 +1,12 @@
|
||||
/**
|
||||
* <html>
|
||||
* <head>
|
||||
* <title>org.owasp.dependencycheck.analyzer.exception</title>
|
||||
* </head>
|
||||
* <body>
|
||||
* <p>
|
||||
* A collection of exception classes used within the analyzers.</p>
|
||||
* </body>
|
||||
* </html>
|
||||
*/
|
||||
package org.owasp.dependencycheck.analyzer.exception;
|
||||
@@ -0,0 +1,161 @@
|
||||
/*
|
||||
* This file is part of dependency-check-core.
|
||||
*
|
||||
* Licensed under the Apache 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.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*
|
||||
* Copyright (c) 2014 Jeremy Long. All Rights Reserved.
|
||||
*/
|
||||
package org.owasp.dependencycheck.data.central;
|
||||
|
||||
import java.io.FileNotFoundException;
|
||||
import java.io.IOException;
|
||||
import java.net.HttpURLConnection;
|
||||
import java.net.URL;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.logging.Logger;
|
||||
import javax.xml.parsers.DocumentBuilder;
|
||||
import javax.xml.parsers.DocumentBuilderFactory;
|
||||
import javax.xml.xpath.XPath;
|
||||
import javax.xml.xpath.XPathConstants;
|
||||
import javax.xml.xpath.XPathFactory;
|
||||
import org.owasp.dependencycheck.data.nexus.MavenArtifact;
|
||||
import org.owasp.dependencycheck.utils.Settings;
|
||||
import org.owasp.dependencycheck.utils.URLConnectionFactory;
|
||||
import org.w3c.dom.Document;
|
||||
import org.w3c.dom.NodeList;
|
||||
|
||||
/**
|
||||
* Class of methods to search Maven Central via Central.
|
||||
*
|
||||
* @author colezlaw
|
||||
*/
|
||||
public class CentralSearch {
|
||||
|
||||
/**
|
||||
* The URL for the Central service
|
||||
*/
|
||||
private final URL rootURL;
|
||||
|
||||
/**
|
||||
* Whether to use the Proxy when making requests
|
||||
*/
|
||||
private boolean useProxy;
|
||||
|
||||
/**
|
||||
* Used for logging.
|
||||
*/
|
||||
private static final Logger LOGGER = Logger.getLogger(CentralSearch.class.getName());
|
||||
|
||||
/**
|
||||
* Creates a NexusSearch for the given repository URL.
|
||||
*
|
||||
* @param rootURL the URL of the repository on which searches should execute. Only parameters are added to this (so it should
|
||||
* end in /select)
|
||||
*/
|
||||
public CentralSearch(URL rootURL) {
|
||||
this.rootURL = rootURL;
|
||||
if (null != Settings.getString(Settings.KEYS.PROXY_SERVER)) {
|
||||
useProxy = true;
|
||||
LOGGER.fine("Using proxy");
|
||||
} else {
|
||||
useProxy = false;
|
||||
LOGGER.fine("Not using proxy");
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Searches the configured Central URL for the given sha1 hash. If the artifact is found, a <code>MavenArtifact</code> is
|
||||
* populated with the GAV.
|
||||
*
|
||||
* @param sha1 the SHA-1 hash string for which to search
|
||||
* @return the populated Maven GAV.
|
||||
* @throws IOException if it's unable to connect to the specified repository or if the specified artifact is not found.
|
||||
*/
|
||||
public List<MavenArtifact> searchSha1(String sha1) throws IOException {
|
||||
if (null == sha1 || !sha1.matches("^[0-9A-Fa-f]{40}$")) {
|
||||
throw new IllegalArgumentException("Invalid SHA1 format");
|
||||
}
|
||||
|
||||
final URL url = new URL(rootURL + String.format("?q=1:\"%s\"&wt=xml", sha1));
|
||||
|
||||
LOGGER.fine(String.format("Searching Central url %s", url.toString()));
|
||||
|
||||
// Determine if we need to use a proxy. The rules:
|
||||
// 1) If the proxy is set, AND the setting is set to true, use the proxy
|
||||
// 2) Otherwise, don't use the proxy (either the proxy isn't configured,
|
||||
// or proxy is specifically set to false)
|
||||
final HttpURLConnection conn = URLConnectionFactory.createHttpURLConnection(url, useProxy);
|
||||
|
||||
conn.setDoOutput(true);
|
||||
|
||||
// JSON would be more elegant, but there's not currently a dependency
|
||||
// on JSON, so don't want to add one just for this
|
||||
conn.addRequestProperty("Accept", "application/xml");
|
||||
conn.connect();
|
||||
|
||||
if (conn.getResponseCode() == 200) {
|
||||
boolean missing = false;
|
||||
try {
|
||||
final DocumentBuilder builder = DocumentBuilderFactory
|
||||
.newInstance().newDocumentBuilder();
|
||||
final Document doc = builder.parse(conn.getInputStream());
|
||||
final XPath xpath = XPathFactory.newInstance().newXPath();
|
||||
final String numFound = xpath.evaluate("/response/result/@numFound", doc);
|
||||
if ("0".equals(numFound)) {
|
||||
missing = true;
|
||||
} else {
|
||||
final ArrayList<MavenArtifact> result = new ArrayList<MavenArtifact>();
|
||||
final NodeList docs = (NodeList) xpath.evaluate("/response/result/doc", doc, XPathConstants.NODESET);
|
||||
for (int i = 0; i < docs.getLength(); i++) {
|
||||
final String g = xpath.evaluate("./str[@name='g']", docs.item(i));
|
||||
LOGGER.finest(String.format("GroupId: %s", g));
|
||||
final String a = xpath.evaluate("./str[@name='a']", docs.item(i));
|
||||
LOGGER.finest(String.format("ArtifactId: %s", a));
|
||||
final String v = xpath.evaluate("./str[@name='v']", docs.item(i));
|
||||
final NodeList atts = (NodeList) xpath.evaluate("./arr[@name='ec']/str", docs.item(i), XPathConstants.NODESET);
|
||||
boolean pomAvailable = false;
|
||||
boolean jarAvailable = false;
|
||||
for (int x = 0; x < atts.getLength(); x++) {
|
||||
final String tmp = xpath.evaluate(".", atts.item(x));
|
||||
if (".pom".equals(tmp)) {
|
||||
pomAvailable = true;
|
||||
} else if (".jar".equals(tmp)) {
|
||||
jarAvailable = true;
|
||||
}
|
||||
}
|
||||
LOGGER.finest(String.format("Version: %s", v));
|
||||
result.add(new MavenArtifact(g, a, v, jarAvailable, pomAvailable));
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
} catch (Throwable e) {
|
||||
// Anything else is jacked up XML stuff that we really can't recover
|
||||
// from well
|
||||
throw new IOException(e.getMessage(), e);
|
||||
}
|
||||
|
||||
if (missing) {
|
||||
throw new FileNotFoundException("Artifact not found in Central");
|
||||
}
|
||||
} else {
|
||||
final String msg = String.format("Could not connect to Central received response code: %d %s",
|
||||
conn.getResponseCode(), conn.getResponseMessage());
|
||||
LOGGER.fine(msg);
|
||||
throw new IOException(msg);
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,14 @@
|
||||
/**
|
||||
* <html>
|
||||
* <head>
|
||||
* <title>org.owasp.dependencycheck.data.central</title>
|
||||
* </head>
|
||||
* <body>
|
||||
* <p>
|
||||
* Contains classes related to searching Maven Central.</p>
|
||||
* <p>
|
||||
* These are used to abstract Maven Central searching away from OWASP Dependency Check so they can be reused elsewhere.</p>
|
||||
* </body>
|
||||
* </html>
|
||||
*/
|
||||
package org.owasp.dependencycheck.data.central;
|
||||
@@ -18,10 +18,9 @@
|
||||
package org.owasp.dependencycheck.data.cpe;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.sql.ResultSet;
|
||||
import java.sql.SQLException;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
import java.util.logging.Level;
|
||||
import java.util.logging.Logger;
|
||||
import org.apache.lucene.analysis.Analyzer;
|
||||
@@ -45,19 +44,25 @@ import org.owasp.dependencycheck.data.lucene.FieldAnalyzer;
|
||||
import org.owasp.dependencycheck.data.lucene.LuceneUtils;
|
||||
import org.owasp.dependencycheck.data.lucene.SearchFieldAnalyzer;
|
||||
import org.owasp.dependencycheck.data.nvdcve.CveDB;
|
||||
import org.owasp.dependencycheck.data.nvdcve.DatabaseException;
|
||||
import org.owasp.dependencycheck.utils.Pair;
|
||||
|
||||
/**
|
||||
* An in memory lucene index that contains the vendor/product combinations from the CPE (application) identifiers within
|
||||
* the NVD CVE data.
|
||||
* An in memory lucene index that contains the vendor/product combinations from the CPE (application) identifiers within the NVD
|
||||
* CVE data.
|
||||
*
|
||||
* @author Jeremy Long <jeremy.long@owasp.org>
|
||||
*/
|
||||
public final class CpeMemoryIndex {
|
||||
|
||||
/**
|
||||
* The logger.
|
||||
*/
|
||||
private static final Logger LOGGER = Logger.getLogger(CpeMemoryIndex.class.getName());
|
||||
/**
|
||||
* singleton instance.
|
||||
*/
|
||||
private static CpeMemoryIndex instance = new CpeMemoryIndex();
|
||||
private static final CpeMemoryIndex INSTANCE = new CpeMemoryIndex();
|
||||
|
||||
/**
|
||||
* private constructor for singleton.
|
||||
@@ -71,7 +76,7 @@ public final class CpeMemoryIndex {
|
||||
* @return the instance of the CpeMemoryIndex
|
||||
*/
|
||||
public static CpeMemoryIndex getInstance() {
|
||||
return instance;
|
||||
return INSTANCE;
|
||||
}
|
||||
/**
|
||||
* The in memory Lucene index.
|
||||
@@ -109,18 +114,20 @@ public final class CpeMemoryIndex {
|
||||
* @throws IndexException thrown if there is an error creating the index
|
||||
*/
|
||||
public void open(CveDB cve) throws IndexException {
|
||||
if (!openState) {
|
||||
index = new RAMDirectory();
|
||||
buildIndex(cve);
|
||||
try {
|
||||
indexReader = DirectoryReader.open(index);
|
||||
} catch (IOException ex) {
|
||||
throw new IndexException(ex);
|
||||
synchronized (INSTANCE) {
|
||||
if (!openState) {
|
||||
index = new RAMDirectory();
|
||||
buildIndex(cve);
|
||||
try {
|
||||
indexReader = DirectoryReader.open(index);
|
||||
} catch (IOException ex) {
|
||||
throw new IndexException(ex);
|
||||
}
|
||||
indexSearcher = new IndexSearcher(indexReader);
|
||||
searchingAnalyzer = createSearchingAnalyzer();
|
||||
queryParser = new QueryParser(LuceneUtils.CURRENT_VERSION, Fields.DOCUMENT_KEY, searchingAnalyzer);
|
||||
openState = true;
|
||||
}
|
||||
indexSearcher = new IndexSearcher(indexReader);
|
||||
searchingAnalyzer = createSearchingAnalyzer();
|
||||
queryParser = new QueryParser(LuceneUtils.CURRENT_VERSION, Fields.DOCUMENT_KEY, searchingAnalyzer);
|
||||
openState = true;
|
||||
}
|
||||
}
|
||||
/**
|
||||
@@ -156,7 +163,7 @@ public final class CpeMemoryIndex {
|
||||
*/
|
||||
@SuppressWarnings("unchecked")
|
||||
private Analyzer createSearchingAnalyzer() {
|
||||
final Map fieldAnalyzers = new HashMap();
|
||||
final Map<String, Analyzer> fieldAnalyzers = new HashMap<String, Analyzer>();
|
||||
fieldAnalyzers.put(Fields.DOCUMENT_KEY, new KeywordAnalyzer());
|
||||
productSearchFieldAnalyzer = new SearchFieldAnalyzer(LuceneUtils.CURRENT_VERSION);
|
||||
vendorSearchFieldAnalyzer = new SearchFieldAnalyzer(LuceneUtils.CURRENT_VERSION);
|
||||
@@ -196,7 +203,7 @@ public final class CpeMemoryIndex {
|
||||
try {
|
||||
indexReader.close();
|
||||
} catch (IOException ex) {
|
||||
Logger.getLogger(CpeMemoryIndex.class.getName()).log(Level.FINEST, null, ex);
|
||||
LOGGER.log(Level.FINEST, null, ex);
|
||||
}
|
||||
indexReader = null;
|
||||
}
|
||||
@@ -210,7 +217,7 @@ public final class CpeMemoryIndex {
|
||||
}
|
||||
|
||||
/**
|
||||
* Builds the lucene index based off of the data within the CveDB.
|
||||
* Builds the CPE Lucene Index based off of the data within the CveDB.
|
||||
*
|
||||
* @param cve the data base containing the CPE data
|
||||
* @throws IndexException thrown if there is an issue creating the index
|
||||
@@ -222,16 +229,13 @@ public final class CpeMemoryIndex {
|
||||
analyzer = createIndexingAnalyzer();
|
||||
final IndexWriterConfig conf = new IndexWriterConfig(LuceneUtils.CURRENT_VERSION, analyzer);
|
||||
indexWriter = new IndexWriter(index, conf);
|
||||
final ResultSet rs = cve.getVendorProductList();
|
||||
if (rs == null) {
|
||||
throw new IndexException("No data exists");
|
||||
}
|
||||
try {
|
||||
while (rs.next()) {
|
||||
saveEntry(rs.getString(1), rs.getString(2), indexWriter);
|
||||
final Set<Pair<String, String>> data = cve.getVendorProductList();
|
||||
for (Pair<String, String> pair : data) {
|
||||
saveEntry(pair.getLeft(), pair.getRight(), indexWriter);
|
||||
}
|
||||
} catch (SQLException ex) {
|
||||
Logger.getLogger(CpeMemoryIndex.class.getName()).log(Level.FINE, null, ex);
|
||||
} catch (DatabaseException ex) {
|
||||
LOGGER.log(Level.FINE, null, ex);
|
||||
throw new IndexException("Error reading CPE data", ex);
|
||||
}
|
||||
} catch (CorruptIndexException ex) {
|
||||
|
||||
@@ -22,7 +22,7 @@ package org.owasp.dependencycheck.data.cpe;
|
||||
*
|
||||
* @author Jeremy Long <jeremy.long@owasp.org>
|
||||
*/
|
||||
public abstract class Fields {
|
||||
public final class Fields {
|
||||
|
||||
/**
|
||||
* The key for the name document id.
|
||||
@@ -36,7 +36,10 @@ public abstract class Fields {
|
||||
* The key for the product field.
|
||||
*/
|
||||
public static final String PRODUCT = "product";
|
||||
|
||||
/**
|
||||
* The key for the version field.
|
||||
* Private constructor as this is more of an enumeration rather then a full class.
|
||||
*/
|
||||
private Fields() {
|
||||
}
|
||||
}
|
||||
|
||||
@@ -30,6 +30,11 @@ import java.util.logging.Logger;
|
||||
*/
|
||||
public final class CweDB {
|
||||
|
||||
/**
|
||||
* The Logger.
|
||||
*/
|
||||
private static final Logger LOGGER = Logger.getLogger(CweDB.class.getName());
|
||||
|
||||
/**
|
||||
* Empty private constructor as this is a utility class.
|
||||
*/
|
||||
@@ -52,19 +57,21 @@ public final class CweDB {
|
||||
final String filePath = "data/cwe.hashmap.serialized";
|
||||
final InputStream input = CweDB.class.getClassLoader().getResourceAsStream(filePath);
|
||||
oin = new ObjectInputStream(input);
|
||||
return (HashMap<String, String>) oin.readObject();
|
||||
@SuppressWarnings("unchecked")
|
||||
final HashMap<String, String> ret = (HashMap<String, String>) oin.readObject();
|
||||
return ret;
|
||||
} catch (ClassNotFoundException ex) {
|
||||
Logger.getLogger(CweDB.class.getName()).log(Level.WARNING, "Unable to load CWE data. This should not be an issue.");
|
||||
Logger.getLogger(CweDB.class.getName()).log(Level.FINE, null, ex);
|
||||
LOGGER.log(Level.WARNING, "Unable to load CWE data. This should not be an issue.");
|
||||
LOGGER.log(Level.FINE, null, ex);
|
||||
} catch (IOException ex) {
|
||||
Logger.getLogger(CweDB.class.getName()).log(Level.WARNING, "Unable to load CWE data due to an IO Error. This should not be an issue.");
|
||||
Logger.getLogger(CweDB.class.getName()).log(Level.FINE, null, ex);
|
||||
LOGGER.log(Level.WARNING, "Unable to load CWE data due to an IO Error. This should not be an issue.");
|
||||
LOGGER.log(Level.FINE, null, ex);
|
||||
} finally {
|
||||
if (oin != null) {
|
||||
try {
|
||||
oin.close();
|
||||
} catch (IOException ex) {
|
||||
Logger.getLogger(CweDB.class.getName()).log(Level.FINEST, null, ex);
|
||||
LOGGER.log(Level.FINEST, null, ex);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -72,7 +72,7 @@ public abstract class AbstractTokenizingFilter extends TokenFilter {
|
||||
* @return whether or not a new term was added
|
||||
*/
|
||||
protected boolean addTerm() {
|
||||
final boolean termAdded = tokens.size() > 0;
|
||||
final boolean termAdded = !tokens.isEmpty();
|
||||
if (termAdded) {
|
||||
final String term = tokens.pop();
|
||||
clearAttributes();
|
||||
|
||||
@@ -29,8 +29,8 @@ import org.apache.lucene.util.Version;
|
||||
|
||||
/**
|
||||
* <p>
|
||||
* A Lucene Analyzer that utilizes the WhitespaceTokenizer, WordDelimiterFilter, LowerCaseFilter, and StopFilter. The
|
||||
* intended purpose of this Analyzer is to index the CPE fields vendor and product.</p>
|
||||
* A Lucene Analyzer that utilizes the WhitespaceTokenizer, WordDelimiterFilter, LowerCaseFilter, and StopFilter. The intended
|
||||
* purpose of this Analyzer is to index the CPE fields vendor and product.</p>
|
||||
*
|
||||
* @author Jeremy Long <jeremy.long@owasp.org>
|
||||
*/
|
||||
|
||||
@@ -17,6 +17,7 @@
|
||||
*/
|
||||
package org.owasp.dependencycheck.data.lucene;
|
||||
|
||||
import edu.umd.cs.findbugs.annotations.SuppressFBWarnings;
|
||||
import org.apache.lucene.util.Version;
|
||||
|
||||
/**
|
||||
@@ -28,10 +29,10 @@ import org.apache.lucene.util.Version;
|
||||
public final class LuceneUtils {
|
||||
|
||||
/**
|
||||
* The current version of Lucene being used. Declaring this one place so an upgrade doesn't require hunting through
|
||||
* the code base.
|
||||
* The current version of Lucene being used. Declaring this one place so an upgrade doesn't require hunting through the code
|
||||
* base.
|
||||
*/
|
||||
public static final Version CURRENT_VERSION = Version.LUCENE_45;
|
||||
public static final Version CURRENT_VERSION = Version.LUCENE_47;
|
||||
|
||||
/**
|
||||
* Private constructor as this is a utility class.
|
||||
@@ -46,7 +47,7 @@ public final class LuceneUtils {
|
||||
* @param text the data to be escaped
|
||||
*/
|
||||
@SuppressWarnings("fallthrough")
|
||||
@edu.umd.cs.findbugs.annotations.SuppressWarnings(
|
||||
@SuppressFBWarnings(
|
||||
value = "SF_SWITCH_NO_DEFAULT",
|
||||
justification = "The switch below does have a default.")
|
||||
public static void appendEscapedLuceneQuery(StringBuilder buf,
|
||||
|
||||
@@ -39,8 +39,7 @@ public class SearchFieldAnalyzer extends Analyzer {
|
||||
*/
|
||||
private final Version version;
|
||||
/**
|
||||
* A local reference to the TokenPairConcatenatingFilter so that we can clear any left over state if this analyzer
|
||||
* is re-used.
|
||||
* A local reference to the TokenPairConcatenatingFilter so that we can clear any left over state if this analyzer is re-used.
|
||||
*/
|
||||
private TokenPairConcatenatingFilter concatenatingFilter;
|
||||
|
||||
@@ -85,8 +84,7 @@ public class SearchFieldAnalyzer extends Analyzer {
|
||||
|
||||
/**
|
||||
* <p>
|
||||
* Resets the analyzer and clears any internal state data that may have been left-over from previous uses of the
|
||||
* analyzer.</p>
|
||||
* Resets the analyzer and clears any internal state data that may have been left-over from previous uses of the analyzer.</p>
|
||||
* <p>
|
||||
* <b>If this analyzer is re-used this method must be called between uses.</b></p>
|
||||
*/
|
||||
|
||||
@@ -1,72 +0,0 @@
|
||||
/*
|
||||
* This file is part of dependency-check-core.
|
||||
*
|
||||
* Licensed under the Apache 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.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*
|
||||
* Copyright (c) 2012 Jeremy Long. All Rights Reserved.
|
||||
*/
|
||||
package org.owasp.dependencycheck.data.lucene;
|
||||
|
||||
import java.io.Reader;
|
||||
import org.apache.lucene.analysis.Analyzer;
|
||||
import org.apache.lucene.analysis.TokenStream;
|
||||
import org.apache.lucene.analysis.Tokenizer;
|
||||
import org.apache.lucene.analysis.core.LowerCaseFilter;
|
||||
import org.apache.lucene.analysis.core.WhitespaceTokenizer;
|
||||
import org.apache.lucene.util.Version;
|
||||
|
||||
/**
|
||||
* SearchVersionAnalyzer is a Lucene Analyzer used to analyze version information.
|
||||
*
|
||||
* @author Jeremy Long <jeremy.long@owasp.org>
|
||||
* @deprecated version information is no longer stored in lucene
|
||||
*/
|
||||
@Deprecated
|
||||
public class SearchVersionAnalyzer extends Analyzer {
|
||||
//TODO consider implementing payloads/custom attributes...
|
||||
// use custom attributes for major, minor, x, x, x, rcx
|
||||
// these can then be used to weight the score for searches on the version.
|
||||
// see http://lucene.apache.org/core/3_6_1/api/core/org/apache/lucene/analysis/package-summary.html#package_description
|
||||
// look at this article to implement
|
||||
// http://www.codewrecks.com/blog/index.php/2012/08/25/index-your-blog-using-tags-and-lucene-net/
|
||||
|
||||
/**
|
||||
* The Lucene Version used.
|
||||
*/
|
||||
private final Version version;
|
||||
|
||||
/**
|
||||
* Creates a new SearchVersionAnalyzer.
|
||||
*
|
||||
* @param version the Lucene version
|
||||
*/
|
||||
public SearchVersionAnalyzer(Version version) {
|
||||
this.version = version;
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates the TokenStreamComponents
|
||||
*
|
||||
* @param fieldName the field name being analyzed
|
||||
* @param reader the reader containing the input
|
||||
* @return the TokenStreamComponents
|
||||
*/
|
||||
@Override
|
||||
protected TokenStreamComponents createComponents(String fieldName, Reader reader) {
|
||||
final Tokenizer source = new WhitespaceTokenizer(version, reader);
|
||||
TokenStream stream = source;
|
||||
stream = new LowerCaseFilter(version, stream);
|
||||
stream = new VersionTokenizingFilter(stream);
|
||||
return new TokenStreamComponents(source, stream);
|
||||
}
|
||||
}
|
||||
@@ -92,7 +92,7 @@ public final class TokenPairConcatenatingFilter extends TokenFilter {
|
||||
|
||||
//if we have a previousTerm - write it out as its own token concatenated
|
||||
// with the current word (if one is available).
|
||||
if (previousWord != null && words.size() > 0) {
|
||||
if (previousWord != null && !words.isEmpty()) {
|
||||
final String word = words.getFirst();
|
||||
clearAttributes();
|
||||
termAtt.append(previousWord).append(word);
|
||||
@@ -100,7 +100,7 @@ public final class TokenPairConcatenatingFilter extends TokenFilter {
|
||||
return true;
|
||||
}
|
||||
//if we have words, write it out as a single token
|
||||
if (words.size() > 0) {
|
||||
if (!words.isEmpty()) {
|
||||
final String word = words.removeFirst();
|
||||
clearAttributes();
|
||||
termAtt.append(word);
|
||||
|
||||
@@ -36,7 +36,10 @@ import org.owasp.dependencycheck.utils.UrlStringUtils;
|
||||
* @author Jeremy Long <jeremy.long@owasp.org>
|
||||
*/
|
||||
public final class UrlTokenizingFilter extends AbstractTokenizingFilter {
|
||||
|
||||
/**
|
||||
* The logger.
|
||||
*/
|
||||
private static final Logger LOGGER = Logger.getLogger(UrlTokenizingFilter.class.getName());
|
||||
/**
|
||||
* Constructs a new VersionTokenizingFilter.
|
||||
*
|
||||
@@ -57,7 +60,7 @@ public final class UrlTokenizingFilter extends AbstractTokenizingFilter {
|
||||
public boolean incrementToken() throws IOException {
|
||||
final LinkedList<String> tokens = getTokens();
|
||||
final CharTermAttribute termAtt = getTermAtt();
|
||||
if (tokens.size() == 0 && input.incrementToken()) {
|
||||
if (tokens.isEmpty() && input.incrementToken()) {
|
||||
final String text = new String(termAtt.buffer(), 0, termAtt.length());
|
||||
if (UrlStringUtils.containsUrl(text)) {
|
||||
final String[] parts = text.split("\\s");
|
||||
@@ -67,7 +70,7 @@ public final class UrlTokenizingFilter extends AbstractTokenizingFilter {
|
||||
final List<String> data = UrlStringUtils.extractImportantUrlData(part);
|
||||
tokens.addAll(data);
|
||||
} catch (MalformedURLException ex) {
|
||||
Logger.getLogger(UrlTokenizingFilter.class.getName()).log(Level.INFO, "error parsing " + part, ex);
|
||||
LOGGER.log(Level.FINE, "error parsing " + part, ex);
|
||||
tokens.add(part);
|
||||
}
|
||||
} else {
|
||||
|
||||
@@ -1,71 +0,0 @@
|
||||
/*
|
||||
* This file is part of dependency-check-core.
|
||||
*
|
||||
* Licensed under the Apache 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.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*
|
||||
* Copyright (c) 2012 Jeremy Long. All Rights Reserved.
|
||||
*/
|
||||
package org.owasp.dependencycheck.data.lucene;
|
||||
|
||||
import java.io.Reader;
|
||||
import org.apache.lucene.analysis.Analyzer;
|
||||
import org.apache.lucene.analysis.TokenStream;
|
||||
import org.apache.lucene.analysis.Tokenizer;
|
||||
import org.apache.lucene.analysis.core.LowerCaseFilter;
|
||||
import org.apache.lucene.analysis.core.WhitespaceTokenizer;
|
||||
import org.apache.lucene.util.Version;
|
||||
|
||||
/**
|
||||
* VersionAnalyzer is a Lucene Analyzer used to analyze version information.
|
||||
*
|
||||
* @author Jeremy Long <jeremy.long@owasp.org>
|
||||
* @deprecated version information is no longer stored in lucene
|
||||
*/
|
||||
@Deprecated
|
||||
public class VersionAnalyzer extends Analyzer {
|
||||
//TODO consider implementing payloads/custom attributes...
|
||||
// use custom attributes for major, minor, x, x, x, rcx
|
||||
// these can then be used to weight the score for searches on the version.
|
||||
// see http://lucene.apache.org/core/3_6_1/api/core/org/apache/lucene/analysis/package-summary.html#package_description
|
||||
// look at this article to implement
|
||||
// http://www.codewrecks.com/blog/index.php/2012/08/25/index-your-blog-using-tags-and-lucene-net/
|
||||
|
||||
/**
|
||||
* The Lucene Version used.
|
||||
*/
|
||||
private final Version version;
|
||||
|
||||
/**
|
||||
* Creates a new VersionAnalyzer.
|
||||
*
|
||||
* @param version the Lucene version
|
||||
*/
|
||||
public VersionAnalyzer(Version version) {
|
||||
this.version = version;
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates the TokenStreamComponents
|
||||
*
|
||||
* @param fieldName the field name being analyzed
|
||||
* @param reader the reader containing the input
|
||||
* @return the TokenStreamComponents
|
||||
*/
|
||||
@Override
|
||||
protected TokenStreamComponents createComponents(String fieldName, Reader reader) {
|
||||
final Tokenizer source = new WhitespaceTokenizer(version, reader);
|
||||
TokenStream stream = source;
|
||||
stream = new LowerCaseFilter(version, stream);
|
||||
return new TokenStreamComponents(source, stream);
|
||||
}
|
||||
}
|
||||
@@ -1,98 +0,0 @@
|
||||
/*
|
||||
* This file is part of dependency-check-core.
|
||||
*
|
||||
* Licensed under the Apache 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.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*
|
||||
* Copyright (c) 2012 Jeremy Long. All Rights Reserved.
|
||||
*/
|
||||
package org.owasp.dependencycheck.data.lucene;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.LinkedList;
|
||||
import org.apache.lucene.analysis.TokenStream;
|
||||
import org.apache.lucene.analysis.tokenattributes.CharTermAttribute;
|
||||
|
||||
/**
|
||||
* <p>
|
||||
* Takes a TokenStream and splits or adds tokens to correctly index version numbers.</p>
|
||||
* <p>
|
||||
* <b>Example:</b> "3.0.0.RELEASE" -> "3 3.0 3.0.0 RELEASE 3.0.0.RELEASE".</p>
|
||||
*
|
||||
* @author Jeremy Long <jeremy.long@owasp.org>
|
||||
* @deprecated version information is no longer stored in lucene
|
||||
*/
|
||||
@Deprecated
|
||||
public final class VersionTokenizingFilter extends AbstractTokenizingFilter {
|
||||
|
||||
/**
|
||||
* Constructs a new VersionTokenizingFilter.
|
||||
*
|
||||
* @param stream the TokenStream that this filter will process
|
||||
*/
|
||||
public VersionTokenizingFilter(TokenStream stream) {
|
||||
super(stream);
|
||||
}
|
||||
|
||||
/**
|
||||
* Increments the underlying TokenStream and sets CharTermAttributes to construct an expanded set of tokens by
|
||||
* concatenating tokens with the previous token.
|
||||
*
|
||||
* @return whether or not we have hit the end of the TokenStream
|
||||
* @throws IOException is thrown when an IOException occurs
|
||||
*/
|
||||
@Override
|
||||
public boolean incrementToken() throws IOException {
|
||||
final LinkedList<String> tokens = getTokens();
|
||||
final CharTermAttribute termAtt = getTermAtt();
|
||||
if (tokens.size() == 0 && input.incrementToken()) {
|
||||
final String version = new String(termAtt.buffer(), 0, termAtt.length());
|
||||
final String[] toAnalyze = version.split("[_-]");
|
||||
//ensure we analyze the whole string as one too
|
||||
analyzeVersion(version);
|
||||
for (String str : toAnalyze) {
|
||||
analyzeVersion(str);
|
||||
}
|
||||
}
|
||||
return addTerm();
|
||||
}
|
||||
|
||||
/**
|
||||
* <p>
|
||||
* Analyzes the version and adds several copies of the version as different tokens. For example, the version 1.2.7
|
||||
* would create the tokens 1 1.2 1.2.7. This is useful in discovering the correct version - sometimes a maintenance
|
||||
* or build number will throw off the version identification.</p>
|
||||
*
|
||||
* <p>
|
||||
* expected format:&nbps;major.minor[.maintenance[.build]]</p>
|
||||
*
|
||||
* @param version the version to analyze
|
||||
*/
|
||||
private void analyzeVersion(String version) {
|
||||
//todo should we also be splitting on dash or underscore? we would need
|
||||
// to incorporate the dash or underscore back in...
|
||||
final LinkedList<String> tokens = getTokens();
|
||||
final String[] versionParts = version.split("\\.");
|
||||
String dottedVersion = null;
|
||||
for (String current : versionParts) {
|
||||
if (!current.matches("^/d+$")) {
|
||||
tokens.add(current);
|
||||
}
|
||||
if (dottedVersion == null) {
|
||||
dottedVersion = current;
|
||||
} else {
|
||||
dottedVersion = dottedVersion + "." + current;
|
||||
}
|
||||
tokens.add(dottedVersion);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -24,6 +24,11 @@ package org.owasp.dependencycheck.data.nexus;
|
||||
*/
|
||||
public class MavenArtifact {
|
||||
|
||||
/**
|
||||
* The base URL for download artifacts from Central.
|
||||
*/
|
||||
private static final String CENTRAL_CONTENT_URL = "http://search.maven.org/remotecontent?filepath=";
|
||||
|
||||
/**
|
||||
* The groupId
|
||||
*/
|
||||
@@ -43,6 +48,10 @@ public class MavenArtifact {
|
||||
* The artifact url. This may change depending on which Nexus server the search took place.
|
||||
*/
|
||||
private String artifactUrl;
|
||||
/**
|
||||
* The url to download the POM from.
|
||||
*/
|
||||
private String pomUrl;
|
||||
|
||||
/**
|
||||
* Creates an empty MavenArtifact.
|
||||
@@ -58,9 +67,34 @@ public class MavenArtifact {
|
||||
* @param version the version
|
||||
*/
|
||||
public MavenArtifact(String groupId, String artifactId, String version) {
|
||||
setGroupId(groupId);
|
||||
setArtifactId(artifactId);
|
||||
setVersion(version);
|
||||
this.groupId = groupId;
|
||||
this.artifactId = artifactId;
|
||||
this.version = version;
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a MavenArtifact with the given attributes.
|
||||
*
|
||||
* @param groupId the groupId
|
||||
* @param artifactId the artifactId
|
||||
* @param version the version
|
||||
* @param jarAvailable if the jar file is available from central
|
||||
* @param pomAvailable if the pom file is available from central
|
||||
*/
|
||||
public MavenArtifact(String groupId, String artifactId, String version, boolean jarAvailable, boolean pomAvailable) {
|
||||
this.groupId = groupId;
|
||||
this.artifactId = artifactId;
|
||||
this.version = version;
|
||||
if (jarAvailable) {
|
||||
//org/springframework/spring-core/3.2.0.RELEASE/spring-core-3.2.0.RELEASE.pom
|
||||
this.artifactUrl = this.CENTRAL_CONTENT_URL + groupId.replace('.', '/') + "/" + artifactId.replace('.', '/') + "/"
|
||||
+ version + "/" + artifactId + "-" + version + ".jar";
|
||||
}
|
||||
if (pomAvailable) {
|
||||
//org/springframework/spring-core/3.2.0.RELEASE/spring-core-3.2.0.RELEASE.pom
|
||||
this.pomUrl = this.CENTRAL_CONTENT_URL + groupId.replace('.', '/') + "/" + artifactId.replace('.', '/') + "/"
|
||||
+ version + "/" + artifactId + "-" + version + ".pom";
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -72,10 +106,10 @@ public class MavenArtifact {
|
||||
* @param url the artifactLink url
|
||||
*/
|
||||
public MavenArtifact(String groupId, String artifactId, String version, String url) {
|
||||
setGroupId(groupId);
|
||||
setArtifactId(artifactId);
|
||||
setVersion(version);
|
||||
setArtifactUrl(url);
|
||||
this.groupId = groupId;
|
||||
this.artifactId = artifactId;
|
||||
this.version = version;
|
||||
this.artifactUrl = url;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -159,6 +193,25 @@ public class MavenArtifact {
|
||||
public String getArtifactUrl() {
|
||||
return artifactUrl;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the value of pomUrl.
|
||||
*
|
||||
* @return the value of pomUrl
|
||||
*/
|
||||
public String getPomUrl() {
|
||||
return pomUrl;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the value of pomUrl.
|
||||
*
|
||||
* @param pomUrl new value of pomUrl
|
||||
*/
|
||||
public void setPomUrl(String pomUrl) {
|
||||
this.pomUrl = pomUrl;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
// vim: cc=120:sw=4:ts=4:sts=4
|
||||
|
||||
@@ -19,13 +19,17 @@ package org.owasp.dependencycheck.data.nexus;
|
||||
|
||||
import java.io.FileNotFoundException;
|
||||
import java.io.IOException;
|
||||
import java.net.HttpURLConnection;
|
||||
import java.net.URL;
|
||||
import java.net.URLConnection;
|
||||
import java.util.logging.Level;
|
||||
import java.util.logging.Logger;
|
||||
import javax.xml.parsers.DocumentBuilder;
|
||||
import javax.xml.parsers.DocumentBuilderFactory;
|
||||
import javax.xml.xpath.XPath;
|
||||
import javax.xml.xpath.XPathFactory;
|
||||
import org.owasp.dependencycheck.utils.InvalidSettingException;
|
||||
import org.owasp.dependencycheck.utils.Settings;
|
||||
import org.owasp.dependencycheck.utils.URLConnectionFactory;
|
||||
import org.w3c.dom.Document;
|
||||
|
||||
/**
|
||||
@@ -40,40 +44,64 @@ public class NexusSearch {
|
||||
*/
|
||||
private final URL rootURL;
|
||||
|
||||
/**
|
||||
* Whether to use the Proxy when making requests
|
||||
*/
|
||||
private boolean useProxy;
|
||||
|
||||
/**
|
||||
* Used for logging.
|
||||
*/
|
||||
private static final Logger LOGGER = Logger.getLogger(NexusSearch.class.getName());
|
||||
private static final Logger LOGGER = Logger.getLogger(NexusSearch.class
|
||||
.getName());
|
||||
|
||||
/**
|
||||
* Creates a NexusSearch for the given repository URL.
|
||||
*
|
||||
* @param rootURL the root URL of the repository on which searches should execute. full URL's are calculated
|
||||
* relative to this URL, so it should end with a /
|
||||
* @param rootURL the root URL of the repository on which searches should execute. full URL's are calculated relative to this
|
||||
* URL, so it should end with a /
|
||||
*/
|
||||
public NexusSearch(URL rootURL) {
|
||||
this.rootURL = rootURL;
|
||||
try {
|
||||
if (null != Settings.getString(Settings.KEYS.PROXY_SERVER)
|
||||
&& Settings.getBoolean(Settings.KEYS.ANALYZER_NEXUS_PROXY)) {
|
||||
useProxy = true;
|
||||
LOGGER.fine("Using proxy");
|
||||
} else {
|
||||
useProxy = false;
|
||||
LOGGER.fine("Not using proxy");
|
||||
}
|
||||
} catch (InvalidSettingException ise) {
|
||||
useProxy = false;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Searches the configured Nexus repository for the given sha1 hash. If the artifact is found, a
|
||||
* <code>MavenArtifact</code> is populated with the coordinate information.
|
||||
* Searches the configured Nexus repository for the given sha1 hash. If the artifact is found, a <code>MavenArtifact</code> is
|
||||
* populated with the coordinate information.
|
||||
*
|
||||
* @param sha1 The SHA-1 hash string for which to search
|
||||
* @return the populated Maven coordinates
|
||||
* @throws IOException if it's unable to connect to the specified repositor or if the specified artifact is not
|
||||
* found.
|
||||
* @throws IOException if it's unable to connect to the specified repository or if the specified artifact is not found.
|
||||
*/
|
||||
public MavenArtifact searchSha1(String sha1) throws IOException {
|
||||
if (null == sha1 || !sha1.matches("^[0-9A-Fa-f]{40}$")) {
|
||||
throw new IllegalArgumentException("Invalid SHA1 format");
|
||||
}
|
||||
|
||||
final URL url = new URL(rootURL, String.format("identify/sha1/%s", sha1.toLowerCase()));
|
||||
final URL url = new URL(rootURL, String.format("identify/sha1/%s",
|
||||
sha1.toLowerCase()));
|
||||
|
||||
LOGGER.fine(String.format("Searching Nexus url %s", url.toString()));
|
||||
|
||||
final URLConnection conn = url.openConnection();
|
||||
// Determine if we need to use a proxy. The rules:
|
||||
// 1) If the proxy is set, AND the setting is set to true, use the proxy
|
||||
// 2) Otherwise, don't use the proxy (either the proxy isn't configured,
|
||||
// or proxy is specifically
|
||||
// set to false
|
||||
final HttpURLConnection conn = URLConnectionFactory.createHttpURLConnection(url, useProxy);
|
||||
|
||||
conn.setDoOutput(true);
|
||||
|
||||
// JSON would be more elegant, but there's not currently a dependency
|
||||
@@ -81,23 +109,79 @@ public class NexusSearch {
|
||||
conn.addRequestProperty("Accept", "application/xml");
|
||||
conn.connect();
|
||||
|
||||
if (conn.getResponseCode() == 200) {
|
||||
try {
|
||||
final DocumentBuilder builder = DocumentBuilderFactory
|
||||
.newInstance().newDocumentBuilder();
|
||||
final Document doc = builder.parse(conn.getInputStream());
|
||||
final XPath xpath = XPathFactory.newInstance().newXPath();
|
||||
final String groupId = xpath
|
||||
.evaluate(
|
||||
"/org.sonatype.nexus.rest.model.NexusArtifact/groupId",
|
||||
doc);
|
||||
final String artifactId = xpath.evaluate(
|
||||
"/org.sonatype.nexus.rest.model.NexusArtifact/artifactId",
|
||||
doc);
|
||||
final String version = xpath
|
||||
.evaluate(
|
||||
"/org.sonatype.nexus.rest.model.NexusArtifact/version",
|
||||
doc);
|
||||
final String link = xpath
|
||||
.evaluate(
|
||||
"/org.sonatype.nexus.rest.model.NexusArtifact/artifactLink",
|
||||
doc);
|
||||
final String pomLink = xpath
|
||||
.evaluate(
|
||||
"/org.sonatype.nexus.rest.model.NexusArtifact/pomLink",
|
||||
doc);
|
||||
final MavenArtifact ma = new MavenArtifact(groupId, artifactId, version);
|
||||
if (link != null && !"".equals(link)) {
|
||||
ma.setArtifactUrl(link);
|
||||
}
|
||||
if (pomLink != null && !"".equals(pomLink)) {
|
||||
ma.setPomUrl(pomLink);
|
||||
}
|
||||
return ma;
|
||||
} catch (Throwable e) {
|
||||
// Anything else is jacked-up XML stuff that we really can't recover
|
||||
// from well
|
||||
throw new IOException(e.getMessage(), e);
|
||||
}
|
||||
} else if (conn.getResponseCode() == 404) {
|
||||
throw new FileNotFoundException("Artifact not found in Nexus");
|
||||
} else {
|
||||
final String msg = String.format("Could not connect to Nexus received response code: %d %s",
|
||||
conn.getResponseCode(), conn.getResponseMessage());
|
||||
LOGGER.fine(msg);
|
||||
throw new IOException(msg);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Do a preflight request to see if the repository is actually working.
|
||||
*
|
||||
* @return whether the repository is listening and returns the /status URL correctly
|
||||
*/
|
||||
public boolean preflightRequest() {
|
||||
try {
|
||||
final HttpURLConnection conn = URLConnectionFactory.createHttpURLConnection(new URL(rootURL, "status"), useProxy);
|
||||
conn.addRequestProperty("Accept", "application/xml");
|
||||
conn.connect();
|
||||
if (conn.getResponseCode() != 200) {
|
||||
LOGGER.log(Level.WARNING, "Expected 200 result from Nexus, got {0}", conn.getResponseCode());
|
||||
return false;
|
||||
}
|
||||
final DocumentBuilder builder = DocumentBuilderFactory.newInstance().newDocumentBuilder();
|
||||
final Document doc = builder.parse(conn.getInputStream());
|
||||
final XPath xpath = XPathFactory.newInstance().newXPath();
|
||||
final String groupId = xpath.evaluate("/org.sonatype.nexus.rest.model.NexusArtifact/groupId", doc);
|
||||
final String artifactId = xpath.evaluate("/org.sonatype.nexus.rest.model.NexusArtifact/artifactId", doc);
|
||||
final String version = xpath.evaluate("/org.sonatype.nexus.rest.model.NexusArtifact/version", doc);
|
||||
final String link = xpath.evaluate("/org.sonatype.nexus.rest.model.NexusArtifact/artifactLink", doc);
|
||||
return new MavenArtifact(groupId, artifactId, version, link);
|
||||
} catch (FileNotFoundException fnfe) {
|
||||
// This is what we get when the SHA1 they sent doesn't exist in Nexus. This
|
||||
// is useful upstream for recovery, so we just re-throw it
|
||||
throw fnfe;
|
||||
} catch (Exception e) {
|
||||
// Anything else is jacked-up XML stuff that we really can't recover from well
|
||||
throw new IOException(e.getMessage(), e);
|
||||
if (!"status".equals(doc.getDocumentElement().getNodeName())) {
|
||||
LOGGER.log(Level.WARNING, "Expected root node name of status, got {0}", doc.getDocumentElement().getNodeName());
|
||||
return false;
|
||||
}
|
||||
} catch (Throwable e) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -23,6 +23,7 @@ package org.owasp.dependencycheck.data.nuget;
|
||||
* @author colezlaw
|
||||
*/
|
||||
public class NuspecParseException extends Exception {
|
||||
|
||||
/**
|
||||
* The serialVersionUID
|
||||
*/
|
||||
@@ -31,20 +32,19 @@ public class NuspecParseException extends Exception {
|
||||
/**
|
||||
* Constructs a new exception with <code>null</code> as its detail message.
|
||||
*
|
||||
* The cause is not initialized, and may subsequently be initialized by a call
|
||||
* to {@link java.lang.Throwable#initCause(java.lang.Throwable)}.
|
||||
* The cause is not initialized, and may subsequently be initialized by a call to
|
||||
* {@link java.lang.Throwable#initCause(java.lang.Throwable)}.
|
||||
*/
|
||||
public NuspecParseException() {
|
||||
super();
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructs a new exception with the specified detail message. The cause is
|
||||
* not initialized, and may subsequently be initialized by a call to
|
||||
* {@link java.lang.Throwable#initCause(java.lang.Throwable).
|
||||
* Constructs a new exception with the specified detail message. The cause is not initialized, and may subsequently
|
||||
* be initialized by a call to {@link java.lang.Throwable#initCause(java.lang.Throwable)}.
|
||||
*
|
||||
* @param message the detail message. The detail message is saved for later retrieval
|
||||
* by the {@link java.lang.Throwable#getMessage()} method.
|
||||
* @param message the detail message. The detail message is saved for later retrieval by the
|
||||
* {@link java.lang.Throwable#getMessage()} method.
|
||||
*/
|
||||
public NuspecParseException(String message) {
|
||||
super(message);
|
||||
@@ -56,11 +56,10 @@ public class NuspecParseException extends Exception {
|
||||
* Note that the detail message associated with <code>cause</code> is <em>not</em>
|
||||
* automatically incorporated in this exception's detail message.
|
||||
*
|
||||
* @param message the detail message (whcih is saved for later retrieval by the
|
||||
* @param message the detail message (which is saved for later retrieval by the
|
||||
* {@link java.lang.Throwable#getMessage()} method.
|
||||
* @param cause the cause (which is saved for later retrieval by the
|
||||
* {@link java.lang.Throwable#getCause()} method). (A <code>null</code> value is permitted,
|
||||
* and indicates that the cause is nonexistent or unknown).
|
||||
* @param cause the cause (which is saved for later retrieval by the {@link java.lang.Throwable#getCause()} method).
|
||||
* (A <code>null</code> value is permitted, and indicates that the cause is nonexistent or unknown).
|
||||
*/
|
||||
public NuspecParseException(String message, Throwable cause) {
|
||||
super(message, cause);
|
||||
|
||||
@@ -22,7 +22,7 @@ import java.io.InputStream;
|
||||
/**
|
||||
* Interface defining methods for parsing a Nuspec file.
|
||||
*
|
||||
* @author willstranathan
|
||||
* @author colezlaw
|
||||
*
|
||||
*/
|
||||
public interface NuspecParser {
|
||||
|
||||
@@ -18,21 +18,20 @@
|
||||
package org.owasp.dependencycheck.data.nuget;
|
||||
|
||||
import java.io.InputStream;
|
||||
|
||||
import javax.xml.parsers.DocumentBuilderFactory;
|
||||
import javax.xml.xpath.XPath;
|
||||
import javax.xml.xpath.XPathConstants;
|
||||
import javax.xml.xpath.XPathFactory;
|
||||
|
||||
import org.w3c.dom.Document;
|
||||
import org.w3c.dom.Node;
|
||||
|
||||
/**
|
||||
* Parse a Nuspec file using XPath.
|
||||
*
|
||||
* @author willstranathan
|
||||
* @author colezlaw
|
||||
*/
|
||||
public class XPathNuspecParser implements NuspecParser {
|
||||
|
||||
/**
|
||||
* Gets the string value of a node or null if it's not present
|
||||
*
|
||||
@@ -71,11 +70,11 @@ public class XPathNuspecParser implements NuspecParser {
|
||||
nuspec.setId(xpath.evaluate("/package/metadata/id", d));
|
||||
nuspec.setVersion(xpath.evaluate("/package/metadata/version", d));
|
||||
nuspec.setAuthors(xpath.evaluate("/package/metadata/authors", d));
|
||||
nuspec.setOwners(getOrNull((Node) xpath.evaluate("/package/metadata/owners", d, XPathConstants.NODE)));
|
||||
nuspec.setLicenseUrl(getOrNull((Node) xpath.evaluate("/package/metadata/licenseUrl", d, XPathConstants.NODE)));
|
||||
nuspec.setTitle(getOrNull((Node) xpath.evaluate("/package/metadata/title", d, XPathConstants.NODE)));
|
||||
nuspec.setOwners(getOrNull((Node) xpath.evaluate("/package/metadata/owners", d, XPathConstants.NODE)));
|
||||
nuspec.setLicenseUrl(getOrNull((Node) xpath.evaluate("/package/metadata/licenseUrl", d, XPathConstants.NODE)));
|
||||
nuspec.setTitle(getOrNull((Node) xpath.evaluate("/package/metadata/title", d, XPathConstants.NODE)));
|
||||
return nuspec;
|
||||
} catch (Exception e) {
|
||||
} catch (Throwable e) {
|
||||
throw new NuspecParseException("Unable to parse nuspec", e);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -24,6 +24,7 @@ import java.io.InputStream;
|
||||
import java.io.InputStreamReader;
|
||||
import java.sql.CallableStatement;
|
||||
import java.sql.Connection;
|
||||
import java.sql.Driver;
|
||||
import java.sql.DriverManager;
|
||||
import java.sql.ResultSet;
|
||||
import java.sql.SQLException;
|
||||
@@ -42,14 +43,34 @@ import org.owasp.dependencycheck.utils.Settings;
|
||||
*/
|
||||
public final class ConnectionFactory {
|
||||
|
||||
/**
|
||||
* The Logger.
|
||||
*/
|
||||
private static final Logger LOGGER = Logger.getLogger(ConnectionFactory.class.getName());
|
||||
/**
|
||||
* The version of the current DB Schema.
|
||||
*/
|
||||
public static final String DB_SCHEMA_VERSION = "2.9";
|
||||
public static final String DB_SCHEMA_VERSION = Settings.getString(Settings.KEYS.DB_VERSION);
|
||||
/**
|
||||
* Resource location for SQL file used to create the database schema.
|
||||
*/
|
||||
public static final String DB_STRUCTURE_RESOURCE = "data/initialize.sql";
|
||||
/**
|
||||
* The database driver used to connect to the database.
|
||||
*/
|
||||
private static Driver driver = null;
|
||||
/**
|
||||
* The database connection string.
|
||||
*/
|
||||
private static String connectionString = null;
|
||||
/**
|
||||
* The username to connect to the database.
|
||||
*/
|
||||
private static String userName = null;
|
||||
/**
|
||||
* The password for the database.
|
||||
*/
|
||||
private static String password = null;
|
||||
|
||||
/**
|
||||
* Private constructor for this factory class; no instance is ever needed.
|
||||
@@ -58,117 +79,160 @@ public final class ConnectionFactory {
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructs a new database connection object per the database configuration. This will load the appropriate
|
||||
* database driver, via the DriverManager, if configured.
|
||||
* Initializes the connection factory. Ensuring that the appropriate drivers are loaded and that a connection can be
|
||||
* made successfully.
|
||||
*
|
||||
* @return a database connection object
|
||||
* @throws DatabaseException thrown if there is an exception loading the database connection
|
||||
* @throws DatabaseException thrown if we are unable to connect to the database
|
||||
*/
|
||||
public static Connection getConnection() throws DatabaseException {
|
||||
public static synchronized void initialize() throws DatabaseException {
|
||||
//this only needs to be called once.
|
||||
if (connectionString != null) {
|
||||
return;
|
||||
}
|
||||
Connection conn = null;
|
||||
try {
|
||||
Logger.getLogger(CveDB.class.getName()).log(Level.FINE, "Loading database connection");
|
||||
|
||||
final String connStr = getConnectionString();
|
||||
final String user = Settings.getString(Settings.KEYS.DB_USER, "dcuser");
|
||||
//yes, yes - hard-coded password - only if there isn't one in the properties file.
|
||||
final String pass = Settings.getString(Settings.KEYS.DB_PASSWORD, "DC-Pass1337!");
|
||||
Logger.getLogger(CveDB.class.getName()).log(Level.FINE, "Connection String: {0}", connStr);
|
||||
Logger.getLogger(CveDB.class.getName()).log(Level.FINE, "Database User: {0}", user);
|
||||
boolean createTables = false;
|
||||
if (connStr.startsWith("jdbc:h2:file:")) { //H2
|
||||
createTables = needToCreateDatabaseStructure();
|
||||
Logger.getLogger(CveDB.class.getName()).log(Level.FINE, "Need to create DB Structure: {0}", createTables);
|
||||
}
|
||||
//load the driver if necessary
|
||||
final String driverName = Settings.getString(Settings.KEYS.DB_DRIVER_NAME, "");
|
||||
if (!driverName.isEmpty()) { //likely need to load the correct driver
|
||||
Logger.getLogger(CveDB.class.getName()).log(Level.FINE, "Loading driver: {0}", driverName);
|
||||
LOGGER.log(Level.FINE, "Loading driver: {0}", driverName);
|
||||
final String driverPath = Settings.getString(Settings.KEYS.DB_DRIVER_PATH, "");
|
||||
if (!driverPath.isEmpty()) { //ugh, driver is not on classpath?
|
||||
Logger.getLogger(CveDB.class.getName()).log(Level.FINE, "Loading driver from: {0}", driverPath);
|
||||
DriverLoader.load(driverName, driverPath);
|
||||
try {
|
||||
if (!driverPath.isEmpty()) {
|
||||
LOGGER.log(Level.FINE, "Loading driver from: {0}", driverPath);
|
||||
driver = DriverLoader.load(driverName, driverPath);
|
||||
} else {
|
||||
driver = DriverLoader.load(driverName);
|
||||
}
|
||||
} catch (DriverLoadException ex) {
|
||||
LOGGER.log(Level.FINE, "Unable to load database driver", ex);
|
||||
throw new DatabaseException("Unable to load database driver");
|
||||
}
|
||||
}
|
||||
userName = Settings.getString(Settings.KEYS.DB_USER, "dcuser");
|
||||
//yes, yes - hard-coded password - only if there isn't one in the properties file.
|
||||
password = Settings.getString(Settings.KEYS.DB_PASSWORD, "DC-Pass1337!");
|
||||
try {
|
||||
connectionString = Settings.getConnectionString(
|
||||
Settings.KEYS.DB_CONNECTION_STRING,
|
||||
Settings.KEYS.DB_FILE_NAME,
|
||||
Settings.KEYS.DB_VERSION);
|
||||
} catch (IOException ex) {
|
||||
LOGGER.log(Level.FINE,
|
||||
"Unable to retrieve the database connection string", ex);
|
||||
throw new DatabaseException("Unable to retrieve the database connection string");
|
||||
}
|
||||
boolean shouldCreateSchema = false;
|
||||
try {
|
||||
if (connectionString.startsWith("jdbc:h2:file:")) { //H2
|
||||
shouldCreateSchema = !h2DataFileExists();
|
||||
LOGGER.log(Level.FINE, "Need to create DB Structure: {0}", shouldCreateSchema);
|
||||
}
|
||||
} catch (IOException ioex) {
|
||||
LOGGER.log(Level.FINE, "Unable to verify database exists", ioex);
|
||||
throw new DatabaseException("Unable to verify database exists");
|
||||
}
|
||||
LOGGER.log(Level.FINE, "Loading database connection");
|
||||
LOGGER.log(Level.FINE, "Connection String: {0}", connectionString);
|
||||
LOGGER.log(Level.FINE, "Database User: {0}", userName);
|
||||
|
||||
try {
|
||||
conn = DriverManager.getConnection(connectionString, userName, password);
|
||||
} catch (SQLException ex) {
|
||||
if (ex.getMessage().contains("java.net.UnknownHostException") && connectionString.contains("AUTO_SERVER=TRUE;")) {
|
||||
connectionString = connectionString.replace("AUTO_SERVER=TRUE;", "");
|
||||
try {
|
||||
conn = DriverManager.getConnection(connectionString, userName, password);
|
||||
Settings.setString(Settings.KEYS.DB_CONNECTION_STRING, connectionString);
|
||||
LOGGER.log(Level.FINE,
|
||||
"Unable to start the database in server mode; reverting to single user mode");
|
||||
} catch (SQLException sqlex) {
|
||||
LOGGER.log(Level.FINE, "Unable to connect to the database", ex);
|
||||
throw new DatabaseException("Unable to connect to the database");
|
||||
}
|
||||
} else {
|
||||
DriverLoader.load(driverName);
|
||||
LOGGER.log(Level.FINE, "Unable to connect to the database", ex);
|
||||
throw new DatabaseException("Unable to connect to the database");
|
||||
}
|
||||
}
|
||||
|
||||
//JDBC4 drivers don't need this call.
|
||||
//Class.forName("org.h2.Driver");
|
||||
conn = DriverManager.getConnection(connStr, user, pass);
|
||||
if (createTables) {
|
||||
if (shouldCreateSchema) {
|
||||
try {
|
||||
createTables(conn);
|
||||
} catch (DatabaseException ex) {
|
||||
Logger.getLogger(ConnectionFactory.class.getName()).log(Level.FINE, null, ex);
|
||||
} catch (DatabaseException dex) {
|
||||
LOGGER.log(Level.FINE, null, dex);
|
||||
throw new DatabaseException("Unable to create the database structure");
|
||||
}
|
||||
} else {
|
||||
try {
|
||||
ensureSchemaVersion(conn);
|
||||
} catch (DatabaseException ex) {
|
||||
Logger.getLogger(ConnectionFactory.class.getName()).log(Level.FINE, null, ex);
|
||||
} catch (DatabaseException dex) {
|
||||
LOGGER.log(Level.FINE, null, dex);
|
||||
throw new DatabaseException("Database schema does not match this version of dependency-check");
|
||||
}
|
||||
}
|
||||
} catch (IOException ex) {
|
||||
Logger.getLogger(ConnectionFactory.class.getName()).log(Level.FINE, null, ex);
|
||||
throw new DatabaseException("Unable to load database");
|
||||
} catch (DriverLoadException ex) {
|
||||
Logger.getLogger(ConnectionFactory.class.getName()).log(Level.FINE, null, ex);
|
||||
throw new DatabaseException("Unable to load database driver");
|
||||
} finally {
|
||||
if (conn != null) {
|
||||
try {
|
||||
conn.close();
|
||||
} catch (SQLException ex) {
|
||||
LOGGER.log(Level.FINE, "An error occurred closing the connection", ex);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Cleans up resources and unloads any registered database drivers. This needs to be called to ensure the driver is
|
||||
* unregistered prior to the finalize method being called as during shutdown the class loader used to load the
|
||||
* driver may be unloaded prior to the driver being de-registered.
|
||||
*/
|
||||
public static synchronized void cleanup() {
|
||||
if (driver != null) {
|
||||
try {
|
||||
DriverManager.deregisterDriver(driver);
|
||||
} catch (SQLException ex) {
|
||||
LOGGER.log(Level.FINE, "An error occurred unloading the database driver", ex);
|
||||
} catch (Throwable unexpected) {
|
||||
LOGGER.log(Level.FINE,
|
||||
"An unexpected throwable occurred unloading the database driver", unexpected);
|
||||
}
|
||||
driver = null;
|
||||
}
|
||||
connectionString = null;
|
||||
userName = null;
|
||||
password = null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructs a new database connection object per the database configuration.
|
||||
*
|
||||
* @return a database connection object
|
||||
* @throws DatabaseException thrown if there is an exception loading the database connection
|
||||
*/
|
||||
public static Connection getConnection() throws DatabaseException {
|
||||
initialize();
|
||||
Connection conn = null;
|
||||
try {
|
||||
conn = DriverManager.getConnection(connectionString, userName, password);
|
||||
} catch (SQLException ex) {
|
||||
Logger.getLogger(ConnectionFactory.class.getName()).log(Level.FINE, null, ex);
|
||||
LOGGER.log(Level.FINE, null, ex);
|
||||
throw new DatabaseException("Unable to connect to the database");
|
||||
}
|
||||
return conn;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the configured connection string. If using the embedded H2 database this function will also ensure the
|
||||
* data directory exists and if not create it.
|
||||
*
|
||||
* @return the connection string
|
||||
* @throws IOException thrown the data directory cannot be created
|
||||
*/
|
||||
private static String getConnectionString() throws IOException {
|
||||
final String connStr = Settings.getString(Settings.KEYS.DB_CONNECTION_STRING, "jdbc:h2:file:%s;AUTO_SERVER=TRUE");
|
||||
if (connStr.contains("%s")) {
|
||||
final String directory = getDataDirectory().getCanonicalPath();
|
||||
final File dataFile = new File(directory, "cve." + DB_SCHEMA_VERSION);
|
||||
Logger.getLogger(ConnectionFactory.class.getName()).log(Level.FINE, String.format("File path for H2 file: '%s'", dataFile.toString()));
|
||||
return String.format(connStr, dataFile.getAbsolutePath());
|
||||
}
|
||||
return connStr;
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieves the directory that the JAR file exists in so that we can ensure we always use a common data directory
|
||||
* for the embedded H2 database. This is public solely for some unit tests; otherwise this should be private.
|
||||
*
|
||||
* @return the data directory to store data files
|
||||
* @throws IOException is thrown if an IOException occurs of course...
|
||||
*/
|
||||
public static File getDataDirectory() throws IOException {
|
||||
final File path = Settings.getDataFile(Settings.KEYS.DATA_DIRECTORY);
|
||||
if (!path.exists()) {
|
||||
if (!path.mkdirs()) {
|
||||
throw new IOException("Unable to create NVD CVE Data directory");
|
||||
}
|
||||
}
|
||||
return path;
|
||||
}
|
||||
|
||||
/**
|
||||
* Determines if the H2 database file exists. If it does not exist then the data structure will need to be created.
|
||||
*
|
||||
* @return true if the H2 database file does not exist; otherwise false
|
||||
* @throws IOException thrown if the data directory does not exist and cannot be created
|
||||
*/
|
||||
private static boolean needToCreateDatabaseStructure() throws IOException {
|
||||
final File dir = getDataDirectory();
|
||||
final String name = String.format("cve.%s.h2.db", DB_SCHEMA_VERSION);
|
||||
final File file = new File(dir, name);
|
||||
return !file.exists();
|
||||
private static boolean h2DataFileExists() throws IOException {
|
||||
final File dir = Settings.getDataDirectory();
|
||||
final String name = Settings.getString(Settings.KEYS.DB_FILE_NAME);
|
||||
final String fileName = String.format(name, DB_SCHEMA_VERSION);
|
||||
final File file = new File(dir, fileName);
|
||||
return file.exists();
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -178,7 +242,7 @@ public final class ConnectionFactory {
|
||||
* @throws DatabaseException thrown if there is a Database Exception
|
||||
*/
|
||||
private static void createTables(Connection conn) throws DatabaseException {
|
||||
Logger.getLogger(ConnectionFactory.class.getName()).log(Level.FINE, "Creating database structure");
|
||||
LOGGER.log(Level.FINE, "Creating database structure");
|
||||
InputStream is;
|
||||
InputStreamReader reader;
|
||||
BufferedReader in = null;
|
||||
@@ -196,7 +260,7 @@ public final class ConnectionFactory {
|
||||
statement = conn.createStatement();
|
||||
statement.execute(sb.toString());
|
||||
} catch (SQLException ex) {
|
||||
Logger.getLogger(ConnectionFactory.class.getName()).log(Level.FINE, null, ex);
|
||||
LOGGER.log(Level.FINE, null, ex);
|
||||
throw new DatabaseException("Unable to create database statement", ex);
|
||||
} finally {
|
||||
DBUtils.closeStatement(statement);
|
||||
@@ -208,7 +272,7 @@ public final class ConnectionFactory {
|
||||
try {
|
||||
in.close();
|
||||
} catch (IOException ex) {
|
||||
Logger.getLogger(ConnectionFactory.class.getName()).log(Level.FINEST, null, ex);
|
||||
LOGGER.log(Level.FINEST, null, ex);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -235,7 +299,7 @@ public final class ConnectionFactory {
|
||||
throw new DatabaseException("Database schema is missing");
|
||||
}
|
||||
} catch (SQLException ex) {
|
||||
Logger.getLogger(ConnectionFactory.class.getName()).log(Level.FINE, null, ex);
|
||||
LOGGER.log(Level.FINE, null, ex);
|
||||
throw new DatabaseException("Unable to check the database schema version");
|
||||
} finally {
|
||||
DBUtils.closeResultSet(rs);
|
||||
|
||||
@@ -17,6 +17,7 @@
|
||||
*/
|
||||
package org.owasp.dependencycheck.data.nvdcve;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.UnsupportedEncodingException;
|
||||
import java.sql.Connection;
|
||||
import java.sql.PreparedStatement;
|
||||
@@ -24,8 +25,10 @@ import java.sql.ResultSet;
|
||||
import java.sql.SQLException;
|
||||
import java.sql.Statement;
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Map.Entry;
|
||||
import java.util.Properties;
|
||||
import java.util.Set;
|
||||
@@ -38,6 +41,8 @@ import org.owasp.dependencycheck.dependency.VulnerableSoftware;
|
||||
import org.owasp.dependencycheck.utils.DBUtils;
|
||||
import org.owasp.dependencycheck.utils.DependencyVersion;
|
||||
import org.owasp.dependencycheck.utils.DependencyVersionUtil;
|
||||
import org.owasp.dependencycheck.utils.Pair;
|
||||
import org.owasp.dependencycheck.utils.Settings;
|
||||
|
||||
/**
|
||||
* The database holding information about the NVD CVE data.
|
||||
@@ -46,14 +51,18 @@ import org.owasp.dependencycheck.utils.DependencyVersionUtil;
|
||||
*/
|
||||
public class CveDB {
|
||||
|
||||
/**
|
||||
* The logger.
|
||||
*/
|
||||
private static final Logger LOGGER = Logger.getLogger(CveDB.class.getName());
|
||||
/**
|
||||
* Database connection
|
||||
*/
|
||||
private Connection conn;
|
||||
|
||||
/**
|
||||
* Creates a new CveDB object and opens the database connection. Note, the connection must be closed by the caller
|
||||
* by calling the close method.
|
||||
* Creates a new CveDB object and opens the database connection. Note, the connection must be closed by the caller by calling
|
||||
* the close method.
|
||||
*
|
||||
* @throws DatabaseException thrown if there is an exception opening the database.
|
||||
*/
|
||||
@@ -82,7 +91,9 @@ public class CveDB {
|
||||
* @throws DatabaseException thrown if there is an error opening the database connection
|
||||
*/
|
||||
public final void open() throws DatabaseException {
|
||||
conn = ConnectionFactory.getConnection();
|
||||
if (!isOpen()) {
|
||||
conn = ConnectionFactory.getConnection();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -94,8 +105,12 @@ public class CveDB {
|
||||
conn.close();
|
||||
} catch (SQLException ex) {
|
||||
final String msg = "There was an error attempting to close the CveDB, see the log for more details.";
|
||||
Logger.getLogger(DBUtils.class.getName()).log(Level.SEVERE, msg);
|
||||
Logger.getLogger(DBUtils.class.getName()).log(Level.FINE, null, ex);
|
||||
LOGGER.log(Level.SEVERE, msg);
|
||||
LOGGER.log(Level.FINE, null, ex);
|
||||
} catch (Throwable ex) {
|
||||
final String msg = "There was an exception attempting to close the CveDB, see the log for more details.";
|
||||
LOGGER.log(Level.SEVERE, msg);
|
||||
LOGGER.log(Level.FINE, null, ex);
|
||||
}
|
||||
conn = null;
|
||||
}
|
||||
@@ -128,7 +143,9 @@ public class CveDB {
|
||||
* @throws Throwable thrown if there is a problem
|
||||
*/
|
||||
@Override
|
||||
@SuppressWarnings("FinalizeDeclaration")
|
||||
protected void finalize() throws Throwable {
|
||||
LOGGER.log(Level.FINE, "Entering finalize");
|
||||
close();
|
||||
super.finalize();
|
||||
}
|
||||
@@ -159,8 +176,8 @@ public class CveDB {
|
||||
*/
|
||||
private static final String DELETE_VULNERABILITY = "DELETE FROM vulnerability WHERE id = ?";
|
||||
/**
|
||||
* SQL Statement to cleanup orphan entries. Yes, the db schema could be a little tighter, but what we have works
|
||||
* well to keep the data file size down a bit.
|
||||
* SQL Statement to cleanup orphan entries. Yes, the db schema could be a little tighter, but what we have works well to keep
|
||||
* the data file size down a bit.
|
||||
*/
|
||||
private static final String CLEANUP_ORPHANS = "DELETE FROM CpeEntry WHERE id not in (SELECT CPEEntryId FROM Software); ";
|
||||
/**
|
||||
@@ -197,7 +214,8 @@ public class CveDB {
|
||||
private static final String SELECT_CVE_FROM_SOFTWARE = "SELECT cve, cpe, previousVersion "
|
||||
+ "FROM software INNER JOIN vulnerability ON vulnerability.id = software.cveId "
|
||||
+ "INNER JOIN cpeEntry ON cpeEntry.id = software.cpeEntryId "
|
||||
+ "WHERE vendor = ? AND product = ?";
|
||||
+ "WHERE vendor = ? AND product = ? "
|
||||
+ "ORDER BY cve, cpe"; //, previousVersion
|
||||
//unfortunately, the version info is too complicated to do in a select. Need to filter this afterwards
|
||||
// + " AND (version = '-' OR previousVersion IS NOT NULL OR version=?)";
|
||||
//
|
||||
@@ -237,6 +255,7 @@ public class CveDB {
|
||||
/**
|
||||
* SQL Statement to retrieve a property from the database.
|
||||
*/
|
||||
@SuppressWarnings("unused")
|
||||
private static final String SELECT_PROPERTY = "SELECT id, value FROM properties WHERE id = ?";
|
||||
/**
|
||||
* SQL Statement to insert a new property.
|
||||
@@ -249,12 +268,13 @@ public class CveDB {
|
||||
/**
|
||||
* SQL Statement to delete a property.
|
||||
*/
|
||||
@SuppressWarnings("unused")
|
||||
private static final String DELETE_PROPERTY = "DELETE FROM properties WHERE id = ?";
|
||||
|
||||
//</editor-fold>
|
||||
/**
|
||||
* Searches the CPE entries in the database and retrieves all entries for a given vendor and product combination.
|
||||
* The returned list will include all versions of the product that are registered in the NVD CVE data.
|
||||
* Searches the CPE entries in the database and retrieves all entries for a given vendor and product combination. The returned
|
||||
* list will include all versions of the product that are registered in the NVD CVE data.
|
||||
*
|
||||
* @param vendor the identified vendor name of the dependency being analyzed
|
||||
* @param product the identified name of the product of the dependency being analyzed
|
||||
@@ -277,8 +297,8 @@ public class CveDB {
|
||||
}
|
||||
} catch (SQLException ex) {
|
||||
final String msg = "An unexpected SQL Exception occurred; please see the verbose log for more details.";
|
||||
Logger.getLogger(CveDB.class.getName()).log(Level.SEVERE, msg);
|
||||
Logger.getLogger(CveDB.class.getName()).log(Level.FINE, null, ex);
|
||||
LOGGER.log(Level.SEVERE, msg);
|
||||
LOGGER.log(Level.FINE, null, ex);
|
||||
} finally {
|
||||
DBUtils.closeResultSet(rs);
|
||||
DBUtils.closeStatement(ps);
|
||||
@@ -289,19 +309,27 @@ public class CveDB {
|
||||
/**
|
||||
* Returns the entire list of vendor/product combinations.
|
||||
*
|
||||
* @return the entire list of vendor/product combinations.
|
||||
* @return the entire list of vendor/product combinations
|
||||
* @throws DatabaseException thrown when there is an error retrieving the data from the DB
|
||||
*/
|
||||
public ResultSet getVendorProductList() {
|
||||
public Set<Pair<String, String>> getVendorProductList() throws DatabaseException {
|
||||
final Set<Pair<String, String>> data = new HashSet<Pair<String, String>>();
|
||||
ResultSet rs = null;
|
||||
PreparedStatement ps = null;
|
||||
try {
|
||||
final PreparedStatement ps = getConnection().prepareStatement(SELECT_VENDOR_PRODUCT_LIST);
|
||||
ps = getConnection().prepareStatement(SELECT_VENDOR_PRODUCT_LIST);
|
||||
rs = ps.executeQuery();
|
||||
while (rs.next()) {
|
||||
data.add(new Pair<String, String>(rs.getString(1), rs.getString(2)));
|
||||
}
|
||||
} catch (SQLException ex) {
|
||||
final String msg = "An unexpected SQL Exception occurred; please see the verbose log for more details.";
|
||||
Logger.getLogger(CveDB.class.getName()).log(Level.SEVERE, msg);
|
||||
Logger.getLogger(CveDB.class.getName()).log(Level.FINE, null, ex);
|
||||
} // can't close the statement in the PS as the resultset is returned, closing PS would close the resultset
|
||||
return rs;
|
||||
throw new DatabaseException(msg, ex);
|
||||
} finally {
|
||||
DBUtils.closeResultSet(rs);
|
||||
DBUtils.closeStatement(ps);
|
||||
}
|
||||
return data;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -321,8 +349,8 @@ public class CveDB {
|
||||
}
|
||||
} catch (SQLException ex) {
|
||||
final String msg = "An unexpected SQL Exception occurred; please see the verbose log for more details.";
|
||||
Logger.getLogger(CveDB.class.getName()).log(Level.SEVERE, msg);
|
||||
Logger.getLogger(CveDB.class.getName()).log(Level.FINE, null, ex);
|
||||
LOGGER.log(Level.SEVERE, msg);
|
||||
LOGGER.log(Level.FINE, null, ex);
|
||||
} finally {
|
||||
DBUtils.closeStatement(ps);
|
||||
DBUtils.closeResultSet(rs);
|
||||
@@ -343,8 +371,8 @@ public class CveDB {
|
||||
updateProperty = getConnection().prepareStatement(UPDATE_PROPERTY);
|
||||
insertProperty = getConnection().prepareStatement(INSERT_PROPERTY);
|
||||
} catch (SQLException ex) {
|
||||
Logger.getLogger(CveDB.class.getName()).log(Level.WARNING, "Unable to save properties to the database");
|
||||
Logger.getLogger(CveDB.class.getName()).log(Level.FINE, "Unable to save properties to the database", ex);
|
||||
LOGGER.log(Level.WARNING, "Unable to save properties to the database");
|
||||
LOGGER.log(Level.FINE, "Unable to save properties to the database", ex);
|
||||
return;
|
||||
}
|
||||
for (Entry<Object, Object> entry : props.entrySet()) {
|
||||
@@ -359,8 +387,8 @@ public class CveDB {
|
||||
}
|
||||
} catch (SQLException ex) {
|
||||
final String msg = String.format("Unable to save property '%s' with a value of '%s' to the database", key, value);
|
||||
Logger.getLogger(CveDB.class.getName()).log(Level.WARNING, msg);
|
||||
Logger.getLogger(CveDB.class.getName()).log(Level.FINE, null, ex);
|
||||
LOGGER.log(Level.WARNING, msg);
|
||||
LOGGER.log(Level.FINE, null, ex);
|
||||
}
|
||||
}
|
||||
} finally {
|
||||
@@ -382,8 +410,8 @@ public class CveDB {
|
||||
try {
|
||||
updateProperty = getConnection().prepareStatement(UPDATE_PROPERTY);
|
||||
} catch (SQLException ex) {
|
||||
Logger.getLogger(CveDB.class.getName()).log(Level.WARNING, "Unable to save properties to the database");
|
||||
Logger.getLogger(CveDB.class.getName()).log(Level.FINE, "Unable to save properties to the database", ex);
|
||||
LOGGER.log(Level.WARNING, "Unable to save properties to the database");
|
||||
LOGGER.log(Level.FINE, "Unable to save properties to the database", ex);
|
||||
return;
|
||||
}
|
||||
try {
|
||||
@@ -393,8 +421,8 @@ public class CveDB {
|
||||
try {
|
||||
insertProperty = getConnection().prepareStatement(INSERT_PROPERTY);
|
||||
} catch (SQLException ex) {
|
||||
Logger.getLogger(CveDB.class.getName()).log(Level.WARNING, "Unable to save properties to the database");
|
||||
Logger.getLogger(CveDB.class.getName()).log(Level.FINE, "Unable to save properties to the database", ex);
|
||||
LOGGER.log(Level.WARNING, "Unable to save properties to the database");
|
||||
LOGGER.log(Level.FINE, "Unable to save properties to the database", ex);
|
||||
return;
|
||||
}
|
||||
insertProperty.setString(1, key);
|
||||
@@ -403,8 +431,8 @@ public class CveDB {
|
||||
}
|
||||
} catch (SQLException ex) {
|
||||
final String msg = String.format("Unable to save property '%s' with a value of '%s' to the database", key, value);
|
||||
Logger.getLogger(CveDB.class.getName()).log(Level.WARNING, msg);
|
||||
Logger.getLogger(CveDB.class.getName()).log(Level.FINE, null, ex);
|
||||
LOGGER.log(Level.WARNING, msg);
|
||||
LOGGER.log(Level.FINE, null, ex);
|
||||
}
|
||||
} finally {
|
||||
DBUtils.closeStatement(updateProperty);
|
||||
@@ -425,36 +453,47 @@ public class CveDB {
|
||||
try {
|
||||
cpe.parseName(cpeStr);
|
||||
} catch (UnsupportedEncodingException ex) {
|
||||
Logger.getLogger(CveDB.class.getName()).log(Level.FINEST, null, ex);
|
||||
LOGGER.log(Level.FINEST, null, ex);
|
||||
}
|
||||
final DependencyVersion detectedVersion = parseDependencyVersion(cpe);
|
||||
final List<Vulnerability> vulnerabilities = new ArrayList<Vulnerability>();
|
||||
|
||||
PreparedStatement ps;
|
||||
final HashSet<String> cveEntries = new HashSet<String>();
|
||||
try {
|
||||
ps = getConnection().prepareStatement(SELECT_CVE_FROM_SOFTWARE);
|
||||
ps.setString(1, cpe.getVendor());
|
||||
ps.setString(2, cpe.getProduct());
|
||||
rs = ps.executeQuery();
|
||||
String currentCVE = "";
|
||||
|
||||
final Map<String, Boolean> vulnSoftware = new HashMap<String, Boolean>();
|
||||
while (rs.next()) {
|
||||
final String cveId = rs.getString(1);
|
||||
if (!currentCVE.equals(cveId)) { //check for match and add
|
||||
final Entry<String, Boolean> matchedCPE = getMatchingSoftware(vulnSoftware, cpe.getVendor(), cpe.getProduct(), detectedVersion);
|
||||
if (matchedCPE != null) {
|
||||
final Vulnerability v = getVulnerability(currentCVE);
|
||||
v.setMatchedCPE(matchedCPE.getKey(), matchedCPE.getValue() ? "Y" : null);
|
||||
vulnerabilities.add(v);
|
||||
}
|
||||
vulnSoftware.clear();
|
||||
currentCVE = cveId;
|
||||
}
|
||||
|
||||
final String cpeId = rs.getString(2);
|
||||
final String previous = rs.getString(3);
|
||||
if (!cveEntries.contains(cveId) && isAffected(cpe.getVendor(), cpe.getProduct(), detectedVersion, cpeId, previous)) {
|
||||
cveEntries.add(cveId);
|
||||
final Vulnerability v = getVulnerability(cveId);
|
||||
v.setMatchedCPE(cpeId, previous);
|
||||
vulnerabilities.add(v);
|
||||
}
|
||||
final Boolean p = previous != null && !previous.isEmpty();
|
||||
vulnSoftware.put(cpeId, p);
|
||||
}
|
||||
//remember to process the last set of CVE/CPE entries
|
||||
final Entry<String, Boolean> matchedCPE = getMatchingSoftware(vulnSoftware, cpe.getVendor(), cpe.getProduct(), detectedVersion);
|
||||
if (matchedCPE != null) {
|
||||
final Vulnerability v = getVulnerability(currentCVE);
|
||||
v.setMatchedCPE(matchedCPE.getKey(), matchedCPE.getValue() ? "Y" : null);
|
||||
vulnerabilities.add(v);
|
||||
}
|
||||
DBUtils.closeResultSet(rs);
|
||||
DBUtils.closeStatement(ps);
|
||||
// for (String cve : cveEntries) {
|
||||
// final Vulnerability v = getVulnerability(cve);
|
||||
// vulnerabilities.add(v);
|
||||
// }
|
||||
|
||||
} catch (SQLException ex) {
|
||||
throw new DatabaseException("Exception retrieving vulnerability for " + cpeStr, ex);
|
||||
} finally {
|
||||
@@ -663,7 +702,7 @@ public class CveDB {
|
||||
|
||||
} catch (SQLException ex) {
|
||||
final String msg = String.format("Error updating '%s'", vuln.getName());
|
||||
Logger.getLogger(CveDB.class.getName()).log(Level.FINE, null, ex);
|
||||
LOGGER.log(Level.FINE, null, ex);
|
||||
throw new DatabaseException(msg, ex);
|
||||
} finally {
|
||||
DBUtils.closeStatement(selectVulnerabilityId);
|
||||
@@ -680,8 +719,45 @@ public class CveDB {
|
||||
}
|
||||
|
||||
/**
|
||||
* It is possible that orphaned rows may be generated during database updates. This should be called after all
|
||||
* updates have been completed to ensure orphan entries are removed.
|
||||
* Checks to see if data exists so that analysis can be performed.
|
||||
*
|
||||
* @return <code>true</code> if data exists; otherwise <code>false</code>
|
||||
*/
|
||||
public boolean dataExists() {
|
||||
Statement cs = null;
|
||||
ResultSet rs = null;
|
||||
try {
|
||||
cs = conn.createStatement();
|
||||
rs = cs.executeQuery("SELECT COUNT(*) records FROM cpeEntry");
|
||||
if (rs.next()) {
|
||||
if (rs.getInt(1) > 0) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
} catch (SQLException ex) {
|
||||
String dd;
|
||||
try {
|
||||
dd = Settings.getDataDirectory().getAbsolutePath();
|
||||
} catch (IOException ex1) {
|
||||
dd = Settings.getString(Settings.KEYS.DATA_DIRECTORY);
|
||||
}
|
||||
final String msg = String.format("Unable to access the local database.%n%nEnsure that '%s' is a writable directory. "
|
||||
+ "If the problem persist try deleting the files in '%s' and running %s again. If the problem continues, please "
|
||||
+ "create a log file (see documentation at http://jeremylong.github.io/DependencyCheck/) and open a ticket at "
|
||||
+ "https://github.com/jeremylong/DependencyCheck/issues and include the log file.%n%n",
|
||||
dd, dd, Settings.getString(Settings.KEYS.APPLICATION_VAME));
|
||||
LOGGER.log(Level.SEVERE, msg);
|
||||
LOGGER.log(Level.FINE, "", ex);
|
||||
} finally {
|
||||
DBUtils.closeResultSet(rs);
|
||||
DBUtils.closeStatement(cs);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* It is possible that orphaned rows may be generated during database updates. This should be called after all updates have
|
||||
* been completed to ensure orphan entries are removed.
|
||||
*/
|
||||
public void cleanupDatabase() {
|
||||
PreparedStatement ps = null;
|
||||
@@ -692,52 +768,88 @@ public class CveDB {
|
||||
}
|
||||
} catch (SQLException ex) {
|
||||
final String msg = "An unexpected SQL Exception occurred; please see the verbose log for more details.";
|
||||
Logger.getLogger(CveDB.class.getName()).log(Level.SEVERE, msg);
|
||||
Logger.getLogger(CveDB.class.getName()).log(Level.FINE, null, ex);
|
||||
LOGGER.log(Level.SEVERE, msg);
|
||||
LOGGER.log(Level.FINE, null, ex);
|
||||
} finally {
|
||||
DBUtils.closeStatement(ps);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Determines if the given identifiedVersion is affected by the given cpeId and previous version flag. A non-null,
|
||||
* non-empty string passed to the previous version argument indicates that all previous versions are affected.
|
||||
* Determines if the given identifiedVersion is affected by the given cpeId and previous version flag. A non-null, non-empty
|
||||
* string passed to the previous version argument indicates that all previous versions are affected.
|
||||
*
|
||||
* @param vendor the vendor of the dependency being analyzed
|
||||
* @param product the product name of the dependency being analyzed
|
||||
* @param vulnerableSoftware a map of the vulnerable software with a boolean indicating if all previous versions are affected
|
||||
* @param identifiedVersion the identified version of the dependency being analyzed
|
||||
* @param cpeId the cpe identifier of software that has a known vulnerability
|
||||
* @param previous a flag indicating if previous versions of the product are vulnerable
|
||||
* @return true if the identified version is affected, otherwise false
|
||||
*/
|
||||
private boolean isAffected(String vendor, String product, DependencyVersion identifiedVersion, String cpeId, String previous) {
|
||||
boolean affected = false;
|
||||
final boolean isStruts = "apache".equals(vendor) && "struts".equals(product);
|
||||
final DependencyVersion v = parseDependencyVersion(cpeId);
|
||||
final boolean prevAffected = previous != null && !previous.isEmpty();
|
||||
if (identifiedVersion == null || "-".equals(identifiedVersion.toString())) {
|
||||
if (v == null || "-".equals(v.toString())) {
|
||||
affected = true;
|
||||
Entry<String, Boolean> getMatchingSoftware(Map<String, Boolean> vulnerableSoftware, String vendor, String product,
|
||||
DependencyVersion identifiedVersion) {
|
||||
|
||||
final boolean isVersionTwoADifferentProduct = "apache".equals(vendor) && "struts".equals(product);
|
||||
|
||||
final Set<String> majorVersionsAffectingAllPrevious = new HashSet<String>();
|
||||
final boolean matchesAnyPrevious = identifiedVersion == null || "-".equals(identifiedVersion.toString());
|
||||
String majorVersionMatch = null;
|
||||
for (Entry<String, Boolean> entry : vulnerableSoftware.entrySet()) {
|
||||
final DependencyVersion v = parseDependencyVersion(entry.getKey());
|
||||
if (v == null || "-".equals(v.toString())) { //all versions
|
||||
return entry;
|
||||
}
|
||||
} else if (identifiedVersion.equals(v) || (prevAffected && identifiedVersion.compareTo(v) < 0)) {
|
||||
if (isStruts) { //struts 2 vulns don't affect struts 1
|
||||
if (identifiedVersion.getVersionParts().get(0).equals(v.getVersionParts().get(0))) {
|
||||
affected = true;
|
||||
if (entry.getValue()) {
|
||||
if (matchesAnyPrevious) {
|
||||
return entry;
|
||||
}
|
||||
} else {
|
||||
affected = true;
|
||||
if (identifiedVersion != null && identifiedVersion.getVersionParts().get(0).equals(v.getVersionParts().get(0))) {
|
||||
majorVersionMatch = v.getVersionParts().get(0);
|
||||
}
|
||||
majorVersionsAffectingAllPrevious.add(v.getVersionParts().get(0));
|
||||
}
|
||||
}
|
||||
/*
|
||||
* TODO consider utilizing the matchThreeVersion method to get additional results. However, this
|
||||
* might also introduce false positives.
|
||||
*/
|
||||
return affected;
|
||||
if (matchesAnyPrevious) {
|
||||
return null;
|
||||
}
|
||||
|
||||
final boolean canSkipVersions = majorVersionMatch != null && majorVersionsAffectingAllPrevious.size() > 1;
|
||||
//yes, we are iterating over this twice. The first time we are skipping versions those that affect all versions
|
||||
//then later we process those that affect all versions. This could be done with sorting...
|
||||
for (Entry<String, Boolean> entry : vulnerableSoftware.entrySet()) {
|
||||
if (!entry.getValue()) {
|
||||
final DependencyVersion v = parseDependencyVersion(entry.getKey());
|
||||
//this can't dereference a null 'majorVersionMatch' as canSkipVersions accounts for this.
|
||||
if (canSkipVersions && !majorVersionMatch.equals(v.getVersionParts().get(0))) {
|
||||
continue;
|
||||
}
|
||||
//this can't dereference a null 'identifiedVersion' because if it was null we would have exited
|
||||
//in the above loop or just after loop (if matchesAnyPrevious return null).
|
||||
if (identifiedVersion.equals(v)) {
|
||||
return entry;
|
||||
}
|
||||
}
|
||||
}
|
||||
for (Entry<String, Boolean> entry : vulnerableSoftware.entrySet()) {
|
||||
if (entry.getValue()) {
|
||||
final DependencyVersion v = parseDependencyVersion(entry.getKey());
|
||||
//this can't dereference a null 'majorVersionMatch' as canSkipVersions accounts for this.
|
||||
if (canSkipVersions && !majorVersionMatch.equals(v.getVersionParts().get(0))) {
|
||||
continue;
|
||||
}
|
||||
//this can't dereference a null 'identifiedVersion' because if it was null we would have exited
|
||||
//in the above loop or just after loop (if matchesAnyPrevious return null).
|
||||
if (entry.getValue() && identifiedVersion.compareTo(v) <= 0) {
|
||||
if (!(isVersionTwoADifferentProduct && !identifiedVersion.getVersionParts().get(0).equals(v.getVersionParts().get(0)))) {
|
||||
return entry;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Parses the version (including revision) from a CPE identifier. If no version is identified then a '-' is
|
||||
* returned.
|
||||
* Parses the version (including revision) from a CPE identifier. If no version is identified then a '-' is returned.
|
||||
*
|
||||
* @param cpeStr a cpe identifier
|
||||
* @return a dependency version
|
||||
@@ -748,7 +860,7 @@ public class CveDB {
|
||||
cpe.parseName(cpeStr);
|
||||
} catch (UnsupportedEncodingException ex) {
|
||||
//never going to happen.
|
||||
Logger.getLogger(CveDB.class.getName()).log(Level.FINEST, null, ex);
|
||||
LOGGER.log(Level.FINEST, null, ex);
|
||||
}
|
||||
return parseDependencyVersion(cpe);
|
||||
}
|
||||
@@ -761,9 +873,9 @@ public class CveDB {
|
||||
*/
|
||||
private DependencyVersion parseDependencyVersion(VulnerableSoftware cpe) {
|
||||
DependencyVersion cpeVersion;
|
||||
if (cpe.getVersion() != null && cpe.getVersion().length() > 0) {
|
||||
if (cpe.getVersion() != null && !cpe.getVersion().isEmpty()) {
|
||||
String versionText;
|
||||
if (cpe.getRevision() != null && cpe.getRevision().length() > 0) {
|
||||
if (cpe.getRevision() != null && !cpe.getRevision().isEmpty()) {
|
||||
versionText = String.format("%s.%s", cpe.getVersion(), cpe.getRevision());
|
||||
} else {
|
||||
versionText = cpe.getVersion();
|
||||
|
||||
@@ -17,7 +17,6 @@
|
||||
*/
|
||||
package org.owasp.dependencycheck.data.nvdcve;
|
||||
|
||||
import com.hazelcast.logging.Logger;
|
||||
import java.text.DateFormat;
|
||||
import java.text.SimpleDateFormat;
|
||||
import java.util.Date;
|
||||
@@ -26,6 +25,7 @@ import java.util.Map.Entry;
|
||||
import java.util.Properties;
|
||||
import java.util.TreeMap;
|
||||
import java.util.logging.Level;
|
||||
import java.util.logging.Logger;
|
||||
import org.owasp.dependencycheck.data.update.NvdCveInfo;
|
||||
import org.owasp.dependencycheck.data.update.exception.UpdateException;
|
||||
|
||||
@@ -36,6 +36,10 @@ import org.owasp.dependencycheck.data.update.exception.UpdateException;
|
||||
*/
|
||||
public class DatabaseProperties {
|
||||
|
||||
/**
|
||||
* The Logger.
|
||||
*/
|
||||
private static final Logger LOGGER = Logger.getLogger(DatabaseProperties.class.getName());
|
||||
/**
|
||||
* Modified key word, used as a key to store information about the modified file (i.e. the containing the last 8
|
||||
* days of updates)..
|
||||
@@ -87,7 +91,7 @@ public class DatabaseProperties {
|
||||
}
|
||||
|
||||
/**
|
||||
* Writes a properties file containing the last updated date to the VULNERABLE_CPE directory.
|
||||
* Saves the last updated information to the properties file.
|
||||
*
|
||||
* @param updatedValue the updated NVD CVE entry
|
||||
* @throws UpdateException is thrown if there is an update exception
|
||||
@@ -96,8 +100,19 @@ public class DatabaseProperties {
|
||||
if (updatedValue == null) {
|
||||
return;
|
||||
}
|
||||
properties.put(LAST_UPDATED_BASE + updatedValue.getId(), String.valueOf(updatedValue.getTimestamp()));
|
||||
cveDB.saveProperty(LAST_UPDATED_BASE + updatedValue.getId(), String.valueOf(updatedValue.getTimestamp()));
|
||||
save(LAST_UPDATED_BASE + updatedValue.getId(), String.valueOf(updatedValue.getTimestamp()));
|
||||
}
|
||||
|
||||
/**
|
||||
* Saves the key value pair to the properties store.
|
||||
*
|
||||
* @param key the property key
|
||||
* @param value the property value
|
||||
* @throws UpdateException is thrown if there is an update exception
|
||||
*/
|
||||
public void save(String key, String value) throws UpdateException {
|
||||
properties.put(key, value);
|
||||
cveDB.saveProperty(key, value);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -138,8 +153,8 @@ public class DatabaseProperties {
|
||||
*
|
||||
* @return a map of the database meta data
|
||||
*/
|
||||
public Map getMetaData() {
|
||||
final TreeMap map = new TreeMap();
|
||||
public Map<String, String> getMetaData() {
|
||||
final Map<String, String> map = new TreeMap<String, String>();
|
||||
for (Entry<Object, Object> entry : properties.entrySet()) {
|
||||
final String key = (String) entry.getKey();
|
||||
if (!"version".equals(key)) {
|
||||
@@ -150,12 +165,12 @@ public class DatabaseProperties {
|
||||
final DateFormat format = new SimpleDateFormat("dd/MM/yyyy HH:mm:ss");
|
||||
final String formatted = format.format(date);
|
||||
map.put(key, formatted);
|
||||
} catch (Throwable ex) { //deliberatly being broad in this catch clause
|
||||
Logger.getLogger(DatabaseProperties.class.getName()).log(Level.FINE, "Unable to parse timestamp from DB", ex);
|
||||
map.put(key, entry.getValue());
|
||||
} catch (Throwable ex) { //deliberately being broad in this catch clause
|
||||
LOGGER.log(Level.FINE, "Unable to parse timestamp from DB", ex);
|
||||
map.put(key, (String) entry.getValue());
|
||||
}
|
||||
} else {
|
||||
map.put(key, entry.getValue());
|
||||
map.put(key, (String) entry.getValue());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -27,6 +27,7 @@ import java.sql.Driver;
|
||||
import java.sql.DriverManager;
|
||||
import java.sql.SQLException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.logging.Level;
|
||||
import java.util.logging.Logger;
|
||||
|
||||
@@ -37,6 +38,11 @@ import java.util.logging.Logger;
|
||||
*/
|
||||
public final class DriverLoader {
|
||||
|
||||
/**
|
||||
* The logger.
|
||||
*/
|
||||
private static final Logger LOGGER = Logger.getLogger(DriverLoader.class.getName());
|
||||
|
||||
/**
|
||||
* Private constructor for a utility class.
|
||||
*/
|
||||
@@ -47,28 +53,30 @@ public final class DriverLoader {
|
||||
* Loads the specified class using the system class loader and registers the driver with the driver manager.
|
||||
*
|
||||
* @param className the fully qualified name of the desired class
|
||||
* @return the loaded Driver
|
||||
* @throws DriverLoadException thrown if the driver cannot be loaded
|
||||
*/
|
||||
public static void load(String className) throws DriverLoadException {
|
||||
public static Driver load(String className) throws DriverLoadException {
|
||||
final ClassLoader loader = DriverLoader.class.getClassLoader(); //ClassLoader.getSystemClassLoader();
|
||||
load(className, loader);
|
||||
return load(className, loader);
|
||||
}
|
||||
|
||||
/**
|
||||
* Loads the specified class by registering the supplied paths to the class loader and then registers the driver
|
||||
* with the driver manager. The pathToDriver argument is added to the class loader so that an external driver can be
|
||||
* loaded. Note, the pathTodriver can contain a semi-colon separated list of paths so any dependencies can be added
|
||||
* loaded. Note, the pathToDriver can contain a semi-colon separated list of paths so any dependencies can be added
|
||||
* as needed. If a path in the pathToDriver argument is a directory all files in the directory are added to the
|
||||
* class path.
|
||||
*
|
||||
* @param className the fully qualified name of the desired class
|
||||
* @param pathToDriver the path to the JAR file containing the driver; note, this can be a semi-colon separated list
|
||||
* of paths
|
||||
* @return the loaded Driver
|
||||
* @throws DriverLoadException thrown if the driver cannot be loaded
|
||||
*/
|
||||
public static void load(String className, String pathToDriver) throws DriverLoadException {
|
||||
public static Driver load(String className, String pathToDriver) throws DriverLoadException {
|
||||
final URLClassLoader parent = (URLClassLoader) ClassLoader.getSystemClassLoader();
|
||||
final ArrayList<URL> urls = new ArrayList<URL>();
|
||||
final List<URL> urls = new ArrayList<URL>();
|
||||
final String[] paths = pathToDriver.split(File.pathSeparator);
|
||||
for (String path : paths) {
|
||||
final File file = new File(path);
|
||||
@@ -81,7 +89,7 @@ public final class DriverLoader {
|
||||
} catch (MalformedURLException ex) {
|
||||
final String msg = String.format("Unable to load database driver '%s'; invalid path provided '%s'",
|
||||
className, f.getAbsoluteFile());
|
||||
Logger.getLogger(DriverLoader.class.getName()).log(Level.FINE, msg, ex);
|
||||
LOGGER.log(Level.FINE, msg, ex);
|
||||
throw new DriverLoadException(msg, ex);
|
||||
}
|
||||
}
|
||||
@@ -91,7 +99,7 @@ public final class DriverLoader {
|
||||
} catch (MalformedURLException ex) {
|
||||
final String msg = String.format("Unable to load database driver '%s'; invalid path provided '%s'",
|
||||
className, file.getAbsoluteFile());
|
||||
Logger.getLogger(DriverLoader.class.getName()).log(Level.FINE, msg, ex);
|
||||
LOGGER.log(Level.FINE, msg, ex);
|
||||
throw new DriverLoadException(msg, ex);
|
||||
}
|
||||
}
|
||||
@@ -103,7 +111,7 @@ public final class DriverLoader {
|
||||
}
|
||||
});
|
||||
|
||||
load(className, loader);
|
||||
return load(className, loader);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -111,30 +119,33 @@ public final class DriverLoader {
|
||||
*
|
||||
* @param className the fully qualified name of the desired class
|
||||
* @param loader the class loader to use when loading the driver
|
||||
* @return the loaded Driver
|
||||
* @throws DriverLoadException thrown if the driver cannot be loaded
|
||||
*/
|
||||
private static void load(String className, ClassLoader loader) throws DriverLoadException {
|
||||
private static Driver load(String className, ClassLoader loader) throws DriverLoadException {
|
||||
try {
|
||||
final Class c = Class.forName(className, true, loader);
|
||||
//final Class c = loader.loadClass(className);
|
||||
final Driver driver = (Driver) c.newInstance();
|
||||
final Driver shim = new DriverShim(driver);
|
||||
//using the DriverShim to get around the fact that the DriverManager won't register a driver not in the base class path
|
||||
DriverManager.registerDriver(new DriverShim(driver));
|
||||
DriverManager.registerDriver(shim);
|
||||
return shim;
|
||||
} catch (ClassNotFoundException ex) {
|
||||
final String msg = String.format("Unable to load database driver '%s'", className);
|
||||
Logger.getLogger(DriverLoader.class.getName()).log(Level.FINE, msg, ex);
|
||||
LOGGER.log(Level.FINE, msg, ex);
|
||||
throw new DriverLoadException(msg, ex);
|
||||
} catch (InstantiationException ex) {
|
||||
final String msg = String.format("Unable to load database driver '%s'", className);
|
||||
Logger.getLogger(DriverLoader.class.getName()).log(Level.FINE, msg, ex);
|
||||
LOGGER.log(Level.FINE, msg, ex);
|
||||
throw new DriverLoadException(msg, ex);
|
||||
} catch (IllegalAccessException ex) {
|
||||
final String msg = String.format("Unable to load database driver '%s'", className);
|
||||
Logger.getLogger(DriverLoader.class.getName()).log(Level.FINE, msg, ex);
|
||||
LOGGER.log(Level.FINE, msg, ex);
|
||||
throw new DriverLoadException(msg, ex);
|
||||
} catch (SQLException ex) {
|
||||
final String msg = String.format("Unable to load database driver '%s'", className);
|
||||
Logger.getLogger(DriverLoader.class.getName()).log(Level.FINE, msg, ex);
|
||||
LOGGER.log(Level.FINE, msg, ex);
|
||||
throw new DriverLoadException(msg, ex);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -17,12 +17,15 @@
|
||||
*/
|
||||
package org.owasp.dependencycheck.data.nvdcve;
|
||||
|
||||
import java.lang.reflect.InvocationTargetException;
|
||||
import java.lang.reflect.Method;
|
||||
import java.sql.Connection;
|
||||
import java.sql.Driver;
|
||||
import java.sql.DriverPropertyInfo;
|
||||
import java.sql.SQLException;
|
||||
import java.sql.SQLFeatureNotSupportedException;
|
||||
import java.util.Properties;
|
||||
import java.util.logging.Level;
|
||||
import java.util.logging.Logger;
|
||||
|
||||
/**
|
||||
@@ -36,6 +39,10 @@ import java.util.logging.Logger;
|
||||
*/
|
||||
class DriverShim implements Driver {
|
||||
|
||||
/**
|
||||
* The logger.
|
||||
*/
|
||||
private static final Logger LOGGER = Logger.getLogger(DriverShim.class.getName());
|
||||
/**
|
||||
* The database driver being wrapped.
|
||||
*/
|
||||
@@ -64,6 +71,20 @@ class DriverShim implements Driver {
|
||||
return this.driver.acceptsURL(url);
|
||||
}
|
||||
|
||||
/**
|
||||
* Wraps the call to the underlying driver's connect method.
|
||||
*
|
||||
* @param url the URL of the database
|
||||
* @param info a collection of string/value pairs
|
||||
* @return a Connection object
|
||||
* @throws SQLException thrown if there is an error connecting to the database
|
||||
* @see java.sql.Driver#connect(java.lang.String, java.util.Properties)
|
||||
*/
|
||||
@Override
|
||||
public Connection connect(String url, Properties info) throws SQLException {
|
||||
return this.driver.connect(url, info);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the wrapped driver's major version number.
|
||||
*
|
||||
@@ -87,28 +108,33 @@ class DriverShim implements Driver {
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns whether or not the wrapped driver is jdbcCompliant.
|
||||
* Wraps the call to the underlying driver's getParentLogger method.
|
||||
*
|
||||
* @return true if the wrapped driver is JDBC compliant; otherwise false
|
||||
* @see java.sql.Driver#jdbcCompliant()
|
||||
* @return the parent's Logger
|
||||
* @throws SQLFeatureNotSupportedException thrown if the feature is not supported
|
||||
* @see java.sql.Driver#getParentLogger()
|
||||
*/
|
||||
@Override
|
||||
public boolean jdbcCompliant() {
|
||||
return this.driver.jdbcCompliant();
|
||||
}
|
||||
|
||||
/**
|
||||
* Wraps the call to the underlying driver's connect method.
|
||||
*
|
||||
* @param url the URL of the database
|
||||
* @param info a collection of string/value pairs
|
||||
* @return a Connection object
|
||||
* @throws SQLException thrown if there is an error connecting to the database
|
||||
* @see java.sql.Driver#connect(java.lang.String, java.util.Properties)
|
||||
*/
|
||||
@Override
|
||||
public Connection connect(String url, Properties info) throws SQLException {
|
||||
return this.driver.connect(url, info);
|
||||
//@Override
|
||||
public Logger getParentLogger() throws SQLFeatureNotSupportedException {
|
||||
//return driver.getParentLogger();
|
||||
Method m = null;
|
||||
try {
|
||||
m = driver.getClass().getMethod("getParentLogger");
|
||||
} catch (Throwable e) {
|
||||
throw new SQLFeatureNotSupportedException();
|
||||
}
|
||||
if (m != null) {
|
||||
try {
|
||||
return (Logger) m.invoke(m);
|
||||
} catch (IllegalAccessException ex) {
|
||||
LOGGER.log(Level.FINER, null, ex);
|
||||
} catch (IllegalArgumentException ex) {
|
||||
LOGGER.log(Level.FINER, null, ex);
|
||||
} catch (InvocationTargetException ex) {
|
||||
LOGGER.log(Level.FINER, null, ex);
|
||||
}
|
||||
}
|
||||
throw new SQLFeatureNotSupportedException();
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -126,15 +152,14 @@ class DriverShim implements Driver {
|
||||
}
|
||||
|
||||
/**
|
||||
* Wraps the call to the underlying driver's getParentLogger method.
|
||||
* Returns whether or not the wrapped driver is jdbcCompliant.
|
||||
*
|
||||
* @return the parent's Logger
|
||||
* @throws SQLFeatureNotSupportedException thrown if the feature is not supported
|
||||
* @see java.sql.Driver#getParentLogger()
|
||||
* @return true if the wrapped driver is JDBC compliant; otherwise false
|
||||
* @see java.sql.Driver#jdbcCompliant()
|
||||
*/
|
||||
@Override
|
||||
public Logger getParentLogger() throws SQLFeatureNotSupportedException {
|
||||
return this.driver.getParentLogger();
|
||||
public boolean jdbcCompliant() {
|
||||
return this.driver.jdbcCompliant();
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -0,0 +1,214 @@
|
||||
/*
|
||||
* This file is part of dependency-check-core.
|
||||
*
|
||||
* Licensed under the Apache 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.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*
|
||||
* Copyright (c) 2014 Jeremy Long. All Rights Reserved.
|
||||
*/
|
||||
package org.owasp.dependencycheck.data.update;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.net.HttpURLConnection;
|
||||
import java.net.MalformedURLException;
|
||||
import java.net.URL;
|
||||
import java.util.Date;
|
||||
import java.util.logging.Level;
|
||||
import java.util.logging.Logger;
|
||||
import org.apache.commons.io.IOUtils;
|
||||
import org.owasp.dependencycheck.data.nvdcve.CveDB;
|
||||
import org.owasp.dependencycheck.data.nvdcve.DatabaseException;
|
||||
import org.owasp.dependencycheck.data.nvdcve.DatabaseProperties;
|
||||
import org.owasp.dependencycheck.data.update.exception.UpdateException;
|
||||
import org.owasp.dependencycheck.utils.DateUtil;
|
||||
import org.owasp.dependencycheck.utils.DependencyVersion;
|
||||
import org.owasp.dependencycheck.utils.Settings;
|
||||
import org.owasp.dependencycheck.utils.URLConnectionFactory;
|
||||
import org.owasp.dependencycheck.utils.URLConnectionFailureException;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author Jeremy Long <jeremy.long@owasp.org>
|
||||
*/
|
||||
public class EngineVersionCheck implements CachedWebDataSource {
|
||||
|
||||
/**
|
||||
* Static logger.
|
||||
*/
|
||||
private static final Logger LOGGER = Logger.getLogger(EngineVersionCheck.class.getName());
|
||||
/**
|
||||
* The property key indicating when the last version check occurred.
|
||||
*/
|
||||
public static final String ENGINE_VERSION_CHECKED_ON = "VersionCheckOn";
|
||||
/**
|
||||
* The property key indicating when the last version check occurred.
|
||||
*/
|
||||
public static final String CURRENT_ENGINE_RELEASE = "CurrentEngineRelease";
|
||||
/**
|
||||
* Reference to the Cve Database.
|
||||
*/
|
||||
private CveDB cveDB = null;
|
||||
|
||||
/**
|
||||
* The version retrieved from the database properties or web to check against.
|
||||
*/
|
||||
private String updateToVersion;
|
||||
|
||||
/**
|
||||
* Getter for updateToVersion - only used for testing. Represents the version retrieved from the database.
|
||||
*
|
||||
* @return the version to test
|
||||
*/
|
||||
protected String getUpdateToVersion() {
|
||||
return updateToVersion;
|
||||
}
|
||||
|
||||
/**
|
||||
* Setter for updateToVersion - only used for testing. Represents the version retrieved from the database.
|
||||
*
|
||||
* @param version the version to test
|
||||
*/
|
||||
protected void setUpdateToVersion(String version) {
|
||||
updateToVersion = version;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void update() throws UpdateException {
|
||||
try {
|
||||
openDatabase();
|
||||
LOGGER.fine("Begin Engine Version Check");
|
||||
final DatabaseProperties properties = cveDB.getDatabaseProperties();
|
||||
final long lastChecked = Long.parseLong(properties.getProperty(ENGINE_VERSION_CHECKED_ON, "0"));
|
||||
final long now = (new Date()).getTime();
|
||||
updateToVersion = properties.getProperty(CURRENT_ENGINE_RELEASE, "");
|
||||
final String currentVersion = Settings.getString(Settings.KEYS.APPLICATION_VERSION, "0.0.0");
|
||||
LOGGER.fine("Last checked: " + lastChecked);
|
||||
LOGGER.fine("Now: " + now);
|
||||
LOGGER.fine("Current version: " + currentVersion);
|
||||
final boolean updateNeeded = shouldUpdate(lastChecked, now, properties, currentVersion);
|
||||
if (updateNeeded) {
|
||||
final String msg = String.format("A new version of dependency-check is available. Consider updating to version %s.",
|
||||
updateToVersion);
|
||||
LOGGER.warning(msg);
|
||||
}
|
||||
} catch (DatabaseException ex) {
|
||||
LOGGER.log(Level.FINE, "Database Exception opening databases to retrieve properties", ex);
|
||||
throw new UpdateException("Error occured updating database properties.");
|
||||
} finally {
|
||||
closeDatabase();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Determines if a new version of the dependency-check engine has been released.
|
||||
*
|
||||
* @param lastChecked the epoch time of the last version check
|
||||
* @param now the current epoch time
|
||||
* @param properties the database properties object
|
||||
* @param currentVersion the current version of dependency-check
|
||||
* @return <code>true</code> if a newer version of the database has been released; otherwise <code>false</code>
|
||||
* @throws UpdateException thrown if there is an error connecting to the github documentation site or accessing the
|
||||
* local database.
|
||||
*/
|
||||
protected boolean shouldUpdate(final long lastChecked, final long now, final DatabaseProperties properties,
|
||||
String currentVersion) throws UpdateException {
|
||||
//check every 30 days if we know there is an update, otherwise check every 7 days
|
||||
int checkRange = 30;
|
||||
if (updateToVersion.isEmpty()) {
|
||||
checkRange = 7;
|
||||
}
|
||||
if (!DateUtil.withinDateRange(lastChecked, now, checkRange)) {
|
||||
LOGGER.fine("Checking web for new version.");
|
||||
final String currentRelease = getCurrentReleaseVersion();
|
||||
if (currentRelease != null) {
|
||||
final DependencyVersion v = new DependencyVersion(currentRelease);
|
||||
if (v.getVersionParts() != null && v.getVersionParts().size() >= 3) {
|
||||
updateToVersion = v.toString();
|
||||
if (!currentRelease.equals(updateToVersion)) {
|
||||
properties.save(CURRENT_ENGINE_RELEASE, updateToVersion);
|
||||
} else {
|
||||
properties.save(CURRENT_ENGINE_RELEASE, "");
|
||||
}
|
||||
properties.save(ENGINE_VERSION_CHECKED_ON, Long.toString(now));
|
||||
}
|
||||
}
|
||||
LOGGER.log(Level.FINE, "Current Release: {0}", updateToVersion);
|
||||
}
|
||||
final DependencyVersion running = new DependencyVersion(currentVersion);
|
||||
final DependencyVersion released = new DependencyVersion(updateToVersion);
|
||||
if (running.compareTo(released) < 0) {
|
||||
LOGGER.fine("Upgrade recommended");
|
||||
return true;
|
||||
}
|
||||
LOGGER.fine("Upgrade not needed");
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Opens the CVE and CPE data stores.
|
||||
*
|
||||
* @throws DatabaseException thrown if a data store cannot be opened
|
||||
*/
|
||||
protected final void openDatabase() throws DatabaseException {
|
||||
if (cveDB != null) {
|
||||
return;
|
||||
}
|
||||
cveDB = new CveDB();
|
||||
cveDB.open();
|
||||
}
|
||||
|
||||
/**
|
||||
* Closes the CVE and CPE data stores.
|
||||
*/
|
||||
protected void closeDatabase() {
|
||||
if (cveDB != null) {
|
||||
try {
|
||||
cveDB.close();
|
||||
} catch (Throwable ignore) {
|
||||
LOGGER.log(Level.FINEST, "Error closing the cveDB", ignore);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieves the current released version number from the github documentation site.
|
||||
*
|
||||
* @return the current released version number
|
||||
*/
|
||||
protected String getCurrentReleaseVersion() {
|
||||
HttpURLConnection conn = null;
|
||||
try {
|
||||
final String str = Settings.getString(Settings.KEYS.ENGINE_VERSION_CHECK_URL, "http://jeremylong.github.io/DependencyCheck/current.txt");
|
||||
final URL url = new URL(str);
|
||||
conn = URLConnectionFactory.createHttpURLConnection(url);
|
||||
conn.connect();
|
||||
if (conn.getResponseCode() != 200) {
|
||||
return null;
|
||||
}
|
||||
final String releaseVersion = IOUtils.toString(conn.getInputStream(), "UTF-8");
|
||||
if (releaseVersion != null) {
|
||||
return releaseVersion.trim();
|
||||
}
|
||||
} catch (MalformedURLException ex) {
|
||||
LOGGER.log(Level.FINE, "unable to retrieve current release version of dependency-check", ex);
|
||||
} catch (URLConnectionFailureException ex) {
|
||||
LOGGER.log(Level.FINE, "unable to retrieve current release version of dependency-check", ex);
|
||||
} catch (IOException ex) {
|
||||
LOGGER.log(Level.FINE, "unable to retrieve current release version of dependency-check", ex);
|
||||
} finally {
|
||||
if (conn != null) {
|
||||
conn.disconnect();
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
}
|
||||
@@ -22,6 +22,7 @@ import java.util.logging.Level;
|
||||
import java.util.logging.Logger;
|
||||
import org.owasp.dependencycheck.data.update.exception.UpdateException;
|
||||
import org.owasp.dependencycheck.utils.DownloadFailedException;
|
||||
import org.owasp.dependencycheck.utils.Settings;
|
||||
|
||||
/**
|
||||
* Class responsible for updating the NVD CVE and CPE data stores.
|
||||
@@ -30,6 +31,11 @@ import org.owasp.dependencycheck.utils.DownloadFailedException;
|
||||
*/
|
||||
public class NvdCveUpdater implements CachedWebDataSource {
|
||||
|
||||
/**
|
||||
* The logger
|
||||
*/
|
||||
private static final Logger LOGGER = Logger.getLogger(NvdCveUpdater.class.getName());
|
||||
|
||||
/**
|
||||
* <p>
|
||||
* Downloads the latest NVD CVE XML file from the web and imports it into the current CVE Database.</p>
|
||||
@@ -44,13 +50,17 @@ public class NvdCveUpdater implements CachedWebDataSource {
|
||||
task.update();
|
||||
}
|
||||
} catch (MalformedURLException ex) {
|
||||
Logger.getLogger(NvdCveUpdater.class.getName()).log(Level.WARNING,
|
||||
LOGGER.log(Level.WARNING,
|
||||
"NVD CVE properties files contain an invalid URL, unable to update the data to use the most current data.");
|
||||
Logger.getLogger(NvdCveUpdater.class.getName()).log(Level.FINE, null, ex);
|
||||
LOGGER.log(Level.FINE, null, ex);
|
||||
} catch (DownloadFailedException ex) {
|
||||
Logger.getLogger(NvdCveUpdater.class.getName()).log(Level.WARNING,
|
||||
"Unable to download the NVD CVE data, unable to update the data to use the most current data.");
|
||||
Logger.getLogger(NvdCveUpdater.class.getName()).log(Level.FINE, null, ex);
|
||||
LOGGER.log(Level.WARNING,
|
||||
"Unable to download the NVD CVE data; the results may not include the most recent CPE/CVEs from the NVD.");
|
||||
if (Settings.getString(Settings.KEYS.PROXY_SERVER) == null) {
|
||||
LOGGER.log(Level.INFO,
|
||||
"If you are behind a proxy you may need to configure dependency-check to use the proxy.");
|
||||
}
|
||||
LOGGER.log(Level.FINE, null, ex);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -34,8 +34,9 @@ import org.owasp.dependencycheck.data.nvdcve.DatabaseProperties;
|
||||
import static org.owasp.dependencycheck.data.nvdcve.DatabaseProperties.MODIFIED;
|
||||
import org.owasp.dependencycheck.data.update.exception.InvalidDataException;
|
||||
import org.owasp.dependencycheck.data.update.exception.UpdateException;
|
||||
import org.owasp.dependencycheck.data.update.task.CallableDownloadTask;
|
||||
import org.owasp.dependencycheck.data.update.task.DownloadTask;
|
||||
import org.owasp.dependencycheck.data.update.task.ProcessTask;
|
||||
import org.owasp.dependencycheck.utils.DateUtil;
|
||||
import org.owasp.dependencycheck.utils.DownloadFailedException;
|
||||
import org.owasp.dependencycheck.utils.InvalidSettingException;
|
||||
import org.owasp.dependencycheck.utils.Settings;
|
||||
@@ -47,6 +48,10 @@ import org.owasp.dependencycheck.utils.Settings;
|
||||
*/
|
||||
public class StandardUpdate {
|
||||
|
||||
/**
|
||||
* Static logger.
|
||||
*/
|
||||
private static final Logger LOGGER = Logger.getLogger(StandardUpdate.class.getName());
|
||||
/**
|
||||
* The max thread pool size to use when downloading files.
|
||||
*/
|
||||
@@ -104,7 +109,7 @@ public class StandardUpdate {
|
||||
return;
|
||||
}
|
||||
if (maxUpdates > 3) {
|
||||
Logger.getLogger(StandardUpdate.class.getName()).log(Level.INFO,
|
||||
LOGGER.log(Level.INFO,
|
||||
"NVD CVE requires several updates; this could take a couple of minutes.");
|
||||
}
|
||||
if (maxUpdates > 0) {
|
||||
@@ -118,7 +123,7 @@ public class StandardUpdate {
|
||||
final Set<Future<Future<ProcessTask>>> downloadFutures = new HashSet<Future<Future<ProcessTask>>>(maxUpdates);
|
||||
for (NvdCveInfo cve : updateable) {
|
||||
if (cve.getNeedsUpdate()) {
|
||||
final CallableDownloadTask call = new CallableDownloadTask(cve, processExecutor, cveDB);
|
||||
final DownloadTask call = new DownloadTask(cve, processExecutor, cveDB, Settings.getInstance());
|
||||
downloadFutures.add(downloadExecutors.submit(call));
|
||||
}
|
||||
}
|
||||
@@ -134,20 +139,20 @@ public class StandardUpdate {
|
||||
downloadExecutors.shutdownNow();
|
||||
processExecutor.shutdownNow();
|
||||
|
||||
Logger.getLogger(StandardUpdate.class.getName()).log(Level.FINE, "Thread was interupted during download", ex);
|
||||
throw new UpdateException("The download was interupted", ex);
|
||||
LOGGER.log(Level.FINE, "Thread was interrupted during download", ex);
|
||||
throw new UpdateException("The download was interrupted", ex);
|
||||
} catch (ExecutionException ex) {
|
||||
downloadExecutors.shutdownNow();
|
||||
processExecutor.shutdownNow();
|
||||
|
||||
Logger.getLogger(StandardUpdate.class.getName()).log(Level.FINE, "Thread was interupted during download execution", ex);
|
||||
throw new UpdateException("The execution of the download was interupted", ex);
|
||||
LOGGER.log(Level.FINE, "Thread was interrupted during download execution", ex);
|
||||
throw new UpdateException("The execution of the download was interrupted", ex);
|
||||
}
|
||||
if (task == null) {
|
||||
downloadExecutors.shutdownNow();
|
||||
processExecutor.shutdownNow();
|
||||
Logger.getLogger(StandardUpdate.class.getName()).log(Level.FINE, "Thread was interupted during download");
|
||||
throw new UpdateException("The download was interupted; unable to complete the update");
|
||||
LOGGER.log(Level.FINE, "Thread was interrupted during download");
|
||||
throw new UpdateException("The download was interrupted; unable to complete the update");
|
||||
} else {
|
||||
processFutures.add(task);
|
||||
}
|
||||
@@ -161,11 +166,11 @@ public class StandardUpdate {
|
||||
}
|
||||
} catch (InterruptedException ex) {
|
||||
processExecutor.shutdownNow();
|
||||
Logger.getLogger(StandardUpdate.class.getName()).log(Level.FINE, "Thread was interupted during processing", ex);
|
||||
LOGGER.log(Level.FINE, "Thread was interrupted during processing", ex);
|
||||
throw new UpdateException(ex);
|
||||
} catch (ExecutionException ex) {
|
||||
processExecutor.shutdownNow();
|
||||
Logger.getLogger(StandardUpdate.class.getName()).log(Level.FINE, "Execution Exception during process", ex);
|
||||
LOGGER.log(Level.FINE, "Execution Exception during process", ex);
|
||||
throw new UpdateException(ex);
|
||||
} finally {
|
||||
processExecutor.shutdown();
|
||||
@@ -174,7 +179,9 @@ public class StandardUpdate {
|
||||
|
||||
if (maxUpdates >= 1) { //ensure the modified file date gets written (we may not have actually updated it)
|
||||
properties.save(updateable.get(MODIFIED));
|
||||
LOGGER.log(Level.INFO, "Begin database maintenance.");
|
||||
cveDB.cleanupDatabase();
|
||||
LOGGER.log(Level.INFO, "End database maintenance.");
|
||||
}
|
||||
} finally {
|
||||
closeDataStores();
|
||||
@@ -197,10 +204,10 @@ public class StandardUpdate {
|
||||
updates = retrieveCurrentTimestampsFromWeb();
|
||||
} catch (InvalidDataException ex) {
|
||||
final String msg = "Unable to retrieve valid timestamp from nvd cve downloads page";
|
||||
Logger.getLogger(StandardUpdate.class.getName()).log(Level.FINE, msg, ex);
|
||||
LOGGER.log(Level.FINE, msg, ex);
|
||||
throw new DownloadFailedException(msg, ex);
|
||||
} catch (InvalidSettingException ex) {
|
||||
Logger.getLogger(StandardUpdate.class.getName()).log(Level.FINE, "Invalid setting found when retrieving timestamps", ex);
|
||||
LOGGER.log(Level.FINE, "Invalid setting found when retrieving timestamps", ex);
|
||||
throw new DownloadFailedException("Invalid settings", ex);
|
||||
}
|
||||
|
||||
@@ -214,7 +221,7 @@ public class StandardUpdate {
|
||||
final int days = Settings.getInt(Settings.KEYS.CVE_MODIFIED_VALID_FOR_DAYS, 7);
|
||||
if (lastUpdated == updates.getTimeStamp(MODIFIED)) {
|
||||
updates.clear(); //we don't need to update anything.
|
||||
} else if (withinRange(lastUpdated, now.getTime(), days)) {
|
||||
} else if (DateUtil.withinDateRange(lastUpdated, now.getTime(), days)) {
|
||||
for (NvdCveInfo entry : updates) {
|
||||
if (MODIFIED.equals(entry.getId())) {
|
||||
entry.setNeedsUpdate(true);
|
||||
@@ -233,9 +240,7 @@ public class StandardUpdate {
|
||||
} catch (NumberFormatException ex) {
|
||||
final String msg = String.format("Error parsing '%s' '%s' from nvdcve.lastupdated",
|
||||
DatabaseProperties.LAST_UPDATED_BASE, entry.getId());
|
||||
Logger
|
||||
.getLogger(StandardUpdate.class
|
||||
.getName()).log(Level.FINE, msg, ex);
|
||||
LOGGER.log(Level.FINE, msg, ex);
|
||||
}
|
||||
if (currentTimestamp == entry.getTimestamp()) {
|
||||
entry.setNeedsUpdate(false);
|
||||
@@ -245,11 +250,8 @@ public class StandardUpdate {
|
||||
}
|
||||
} catch (NumberFormatException ex) {
|
||||
final String msg = "An invalid schema version or timestamp exists in the data.properties file.";
|
||||
Logger
|
||||
.getLogger(StandardUpdate.class
|
||||
.getName()).log(Level.WARNING, msg);
|
||||
Logger.getLogger(StandardUpdate.class
|
||||
.getName()).log(Level.FINE, null, ex);
|
||||
LOGGER.log(Level.WARNING, msg);
|
||||
LOGGER.log(Level.FINE, "", ex);
|
||||
}
|
||||
}
|
||||
return updates;
|
||||
@@ -292,8 +294,8 @@ public class StandardUpdate {
|
||||
if (cveDB != null) {
|
||||
try {
|
||||
cveDB.close();
|
||||
} catch (Exception ignore) {
|
||||
Logger.getLogger(StandardUpdate.class.getName()).log(Level.FINEST, "Error closing the cveDB", ignore);
|
||||
} catch (Throwable ignore) {
|
||||
LOGGER.log(Level.FINEST, "Error closing the cveDB", ignore);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -312,23 +314,8 @@ public class StandardUpdate {
|
||||
cveDB.open();
|
||||
} catch (DatabaseException ex) {
|
||||
closeDataStores();
|
||||
Logger.getLogger(StandardUpdate.class.getName()).log(Level.FINE, "Database Exception opening databases", ex);
|
||||
LOGGER.log(Level.FINE, "Database Exception opening databases", ex);
|
||||
throw new UpdateException("Error updating the CPE/CVE data, please see the log file for more details.");
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Determines if the epoch date is within the range specified of the compareTo epoch time. This takes the
|
||||
* (compareTo-date)/1000/60/60/24 to get the number of days. If the calculated days is less then the range the date
|
||||
* is considered valid.
|
||||
*
|
||||
* @param date the date to be checked.
|
||||
* @param compareTo the date to compare to.
|
||||
* @param range the range in days to be considered valid.
|
||||
* @return whether or not the date is within the range.
|
||||
*/
|
||||
protected boolean withinRange(long date, long compareTo, int range) {
|
||||
final double differenceInDays = (compareTo - date) / 1000.0 / 60.0 / 60.0 / 24.0;
|
||||
return differenceInDays < range;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -21,37 +21,25 @@ import java.util.Iterator;
|
||||
import java.util.ServiceLoader;
|
||||
|
||||
/**
|
||||
* The CachedWebDataSource Service Loader. This class loads all services that implement
|
||||
* org.owasp.dependencycheck.data.update.CachedWebDataSource.
|
||||
*
|
||||
* @author Jeremy Long <jeremy.long@owasp.org>
|
||||
*/
|
||||
public final class UpdateService {
|
||||
public class UpdateService {
|
||||
|
||||
/**
|
||||
* the singleton reference to the service.
|
||||
*/
|
||||
private static UpdateService service;
|
||||
/**
|
||||
* the service loader for CachedWebDataSource.
|
||||
*/
|
||||
private final ServiceLoader<CachedWebDataSource> loader;
|
||||
|
||||
/**
|
||||
* Creates a new instance of UpdateService
|
||||
*/
|
||||
private UpdateService() {
|
||||
loader = ServiceLoader.load(CachedWebDataSource.class);
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieve the singleton instance of UpdateService.
|
||||
* Creates a new instance of UpdateService.
|
||||
*
|
||||
* @return a singleton UpdateService.
|
||||
* @param classLoader the ClassLoader to use when dynamically loading Analyzer and Update services
|
||||
*/
|
||||
public static synchronized UpdateService getInstance() {
|
||||
if (service == null) {
|
||||
service = new UpdateService();
|
||||
}
|
||||
return service;
|
||||
public UpdateService(ClassLoader classLoader) {
|
||||
loader = ServiceLoader.load(CachedWebDataSource.class, classLoader);
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -18,6 +18,9 @@
|
||||
package org.owasp.dependencycheck.data.update.task;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.FileInputStream;
|
||||
import java.io.FileNotFoundException;
|
||||
import java.io.FileOutputStream;
|
||||
import java.io.IOException;
|
||||
import java.net.URL;
|
||||
import java.util.concurrent.Callable;
|
||||
@@ -25,17 +28,26 @@ import java.util.concurrent.ExecutorService;
|
||||
import java.util.concurrent.Future;
|
||||
import java.util.logging.Level;
|
||||
import java.util.logging.Logger;
|
||||
import java.util.zip.GZIPInputStream;
|
||||
import org.apache.commons.io.FileUtils;
|
||||
import org.owasp.dependencycheck.data.nvdcve.CveDB;
|
||||
import org.owasp.dependencycheck.data.update.NvdCveInfo;
|
||||
import org.owasp.dependencycheck.data.update.exception.UpdateException;
|
||||
import org.owasp.dependencycheck.utils.DownloadFailedException;
|
||||
import org.owasp.dependencycheck.utils.Downloader;
|
||||
import org.owasp.dependencycheck.utils.Settings;
|
||||
|
||||
/**
|
||||
* A callable object to download two files.
|
||||
*
|
||||
* @author Jeremy Long <jeremy.long@owasp.org>
|
||||
*/
|
||||
public class CallableDownloadTask implements Callable<Future<ProcessTask>> {
|
||||
public class DownloadTask implements Callable<Future<ProcessTask>> {
|
||||
|
||||
/**
|
||||
* The Logger.
|
||||
*/
|
||||
private static final Logger LOGGER = Logger.getLogger(DownloadTask.class.getName());
|
||||
|
||||
/**
|
||||
* Simple constructor for the callable download task.
|
||||
@@ -43,20 +55,24 @@ public class CallableDownloadTask implements Callable<Future<ProcessTask>> {
|
||||
* @param nvdCveInfo the NVD CVE info
|
||||
* @param processor the processor service to submit the downloaded files to
|
||||
* @param cveDB the CVE DB to use to store the vulnerability data
|
||||
* @param settings a reference to the global settings object; this is necessary so that when the thread is started
|
||||
* the dependencies have a correct reference to the global settings.
|
||||
* @throws UpdateException thrown if temporary files could not be created
|
||||
*/
|
||||
public CallableDownloadTask(NvdCveInfo nvdCveInfo, ExecutorService processor, CveDB cveDB) {
|
||||
public DownloadTask(NvdCveInfo nvdCveInfo, ExecutorService processor, CveDB cveDB, Settings settings) throws UpdateException {
|
||||
this.nvdCveInfo = nvdCveInfo;
|
||||
this.processorService = processor;
|
||||
this.cveDB = cveDB;
|
||||
this.settings = settings;
|
||||
|
||||
final File file1;
|
||||
final File file2;
|
||||
|
||||
try {
|
||||
file1 = File.createTempFile("cve" + nvdCveInfo.getId() + "_", ".xml");
|
||||
file2 = File.createTempFile("cve_1_2_" + nvdCveInfo.getId() + "_", ".xml");
|
||||
file1 = File.createTempFile("cve" + nvdCveInfo.getId() + "_", ".xml", Settings.getTempDirectory());
|
||||
file2 = File.createTempFile("cve_1_2_" + nvdCveInfo.getId() + "_", ".xml", Settings.getTempDirectory());
|
||||
} catch (IOException ex) {
|
||||
return;
|
||||
throw new UpdateException("Unable to create temporary files", ex);
|
||||
}
|
||||
this.first = file1;
|
||||
this.second = file2;
|
||||
@@ -74,6 +90,10 @@ public class CallableDownloadTask implements Callable<Future<ProcessTask>> {
|
||||
* The NVD CVE Meta Data.
|
||||
*/
|
||||
private NvdCveInfo nvdCveInfo;
|
||||
/**
|
||||
* A reference to the global settings object.
|
||||
*/
|
||||
private Settings settings;
|
||||
|
||||
/**
|
||||
* Get the value of nvdCveInfo.
|
||||
@@ -162,30 +182,45 @@ public class CallableDownloadTask implements Callable<Future<ProcessTask>> {
|
||||
@Override
|
||||
public Future<ProcessTask> call() throws Exception {
|
||||
try {
|
||||
Settings.setInstance(settings);
|
||||
final URL url1 = new URL(nvdCveInfo.getUrl());
|
||||
final URL url2 = new URL(nvdCveInfo.getOldSchemaVersionUrl());
|
||||
String msg = String.format("Download Started for NVD CVE - %s", nvdCveInfo.getId());
|
||||
Logger.getLogger(CallableDownloadTask.class.getName()).log(Level.INFO, msg);
|
||||
LOGGER.log(Level.INFO, msg);
|
||||
try {
|
||||
Downloader.fetchFile(url1, first);
|
||||
Downloader.fetchFile(url2, second);
|
||||
} catch (DownloadFailedException ex) {
|
||||
msg = String.format("Download Failed for NVD CVE - %s%nSome CVEs may not be reported.", nvdCveInfo.getId());
|
||||
Logger.getLogger(CallableDownloadTask.class.getName()).log(Level.WARNING, msg);
|
||||
Logger.getLogger(CallableDownloadTask.class.getName()).log(Level.FINE, null, ex);
|
||||
LOGGER.log(Level.WARNING, msg);
|
||||
if (Settings.getString(Settings.KEYS.PROXY_SERVER) == null) {
|
||||
LOGGER.log(Level.INFO,
|
||||
"If you are behind a proxy you may need to configure dependency-check to use the proxy.");
|
||||
}
|
||||
LOGGER.log(Level.FINE, null, ex);
|
||||
return null;
|
||||
}
|
||||
if (url1.toExternalForm().endsWith(".xml.gz")) {
|
||||
extractGzip(first);
|
||||
}
|
||||
if (url2.toExternalForm().endsWith(".xml.gz")) {
|
||||
extractGzip(second);
|
||||
}
|
||||
|
||||
msg = String.format("Download Complete for NVD CVE - %s", nvdCveInfo.getId());
|
||||
Logger.getLogger(CallableDownloadTask.class.getName()).log(Level.INFO, msg);
|
||||
|
||||
final ProcessTask task = new ProcessTask(cveDB, this);
|
||||
LOGGER.log(Level.INFO, msg);
|
||||
if (this.processorService == null) {
|
||||
return null;
|
||||
}
|
||||
final ProcessTask task = new ProcessTask(cveDB, this, settings);
|
||||
return this.processorService.submit(task);
|
||||
|
||||
} catch (Throwable ex) {
|
||||
final String msg = String.format("An exception occurred downloading NVD CVE - %s%nSome CVEs may not be reported.", nvdCveInfo.getId());
|
||||
Logger.getLogger(CallableDownloadTask.class.getName()).log(Level.WARNING, msg);
|
||||
Logger.getLogger(CallableDownloadTask.class.getName()).log(Level.FINE, "Download Task Failed", ex);
|
||||
LOGGER.log(Level.WARNING, msg);
|
||||
LOGGER.log(Level.FINE, "Download Task Failed", ex);
|
||||
} finally {
|
||||
Settings.cleanup(false);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
@@ -215,4 +250,56 @@ public class CallableDownloadTask implements Callable<Future<ProcessTask>> {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Extracts the file contained in a gzip archive. The extracted file is placed in the exact same path as the file
|
||||
* specified.
|
||||
*
|
||||
* @param file the archive file
|
||||
* @throws FileNotFoundException thrown if the file does not exist
|
||||
* @throws IOException thrown if there is an error extracting the file.
|
||||
*/
|
||||
private void extractGzip(File file) throws FileNotFoundException, IOException {
|
||||
final String originalPath = file.getPath();
|
||||
final File gzip = new File(originalPath + ".gz");
|
||||
if (gzip.isFile() && !gzip.delete()) {
|
||||
gzip.deleteOnExit();
|
||||
}
|
||||
if (!file.renameTo(gzip)) {
|
||||
throw new IOException("Unable to rename '" + file.getPath() + "'");
|
||||
}
|
||||
final File newfile = new File(originalPath);
|
||||
|
||||
final byte[] buffer = new byte[4096];
|
||||
|
||||
GZIPInputStream cin = null;
|
||||
FileOutputStream out = null;
|
||||
try {
|
||||
cin = new GZIPInputStream(new FileInputStream(gzip));
|
||||
out = new FileOutputStream(newfile);
|
||||
|
||||
int len;
|
||||
while ((len = cin.read(buffer)) > 0) {
|
||||
out.write(buffer, 0, len);
|
||||
}
|
||||
} finally {
|
||||
if (cin != null) {
|
||||
try {
|
||||
cin.close();
|
||||
} catch (IOException ex) {
|
||||
LOGGER.log(Level.FINEST, "ignore", ex);
|
||||
}
|
||||
}
|
||||
if (out != null) {
|
||||
try {
|
||||
out.close();
|
||||
} catch (IOException ex) {
|
||||
LOGGER.log(Level.FINEST, "ignore", ex);
|
||||
}
|
||||
}
|
||||
if (gzip.isFile()) {
|
||||
FileUtils.deleteQuietly(gzip);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -32,11 +32,11 @@ import javax.xml.parsers.SAXParserFactory;
|
||||
import org.owasp.dependencycheck.data.nvdcve.CveDB;
|
||||
import org.owasp.dependencycheck.data.nvdcve.DatabaseException;
|
||||
import org.owasp.dependencycheck.data.nvdcve.DatabaseProperties;
|
||||
import org.owasp.dependencycheck.data.update.StandardUpdate;
|
||||
import org.owasp.dependencycheck.data.update.exception.UpdateException;
|
||||
import org.owasp.dependencycheck.data.update.xml.NvdCve12Handler;
|
||||
import org.owasp.dependencycheck.data.update.xml.NvdCve20Handler;
|
||||
import org.owasp.dependencycheck.dependency.VulnerableSoftware;
|
||||
import org.owasp.dependencycheck.utils.Settings;
|
||||
import org.xml.sax.SAXException;
|
||||
|
||||
/**
|
||||
@@ -46,6 +46,10 @@ import org.xml.sax.SAXException;
|
||||
*/
|
||||
public class ProcessTask implements Callable<ProcessTask> {
|
||||
|
||||
/**
|
||||
* The logger.
|
||||
*/
|
||||
private static final Logger LOGGER = Logger.getLogger(ProcessTask.class.getName());
|
||||
/**
|
||||
* A field to store any update exceptions that occur during the "call".
|
||||
*/
|
||||
@@ -75,22 +79,29 @@ public class ProcessTask implements Callable<ProcessTask> {
|
||||
/**
|
||||
* A reference to the callable download task.
|
||||
*/
|
||||
private final CallableDownloadTask filePair;
|
||||
private final DownloadTask filePair;
|
||||
/**
|
||||
* A reference to the properties.
|
||||
*/
|
||||
private final DatabaseProperties properties;
|
||||
/**
|
||||
* A reference to the global settings object.
|
||||
*/
|
||||
private Settings settings;
|
||||
|
||||
/**
|
||||
* Constructs a new ProcessTask used to process an NVD CVE update.
|
||||
*
|
||||
* @param cveDB the data store object
|
||||
* @param filePair the download task that contains the URL references to download
|
||||
* @param settings a reference to the global settings object; this is necessary so that when the thread is started
|
||||
* the dependencies have a correct reference to the global settings.
|
||||
*/
|
||||
public ProcessTask(final CveDB cveDB, final CallableDownloadTask filePair) {
|
||||
public ProcessTask(final CveDB cveDB, final DownloadTask filePair, Settings settings) {
|
||||
this.cveDB = cveDB;
|
||||
this.filePair = filePair;
|
||||
this.properties = cveDB.getDatabaseProperties();
|
||||
this.settings = settings;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -103,9 +114,12 @@ public class ProcessTask implements Callable<ProcessTask> {
|
||||
@Override
|
||||
public ProcessTask call() throws Exception {
|
||||
try {
|
||||
Settings.setInstance(settings);
|
||||
processFiles();
|
||||
} catch (UpdateException ex) {
|
||||
this.exception = ex;
|
||||
} finally {
|
||||
Settings.cleanup(false);
|
||||
}
|
||||
return this;
|
||||
}
|
||||
@@ -145,7 +159,7 @@ public class ProcessTask implements Callable<ProcessTask> {
|
||||
*/
|
||||
private void processFiles() throws UpdateException {
|
||||
String msg = String.format("Processing Started for NVD CVE - %s", filePair.getNvdCveInfo().getId());
|
||||
Logger.getLogger(StandardUpdate.class.getName()).log(Level.INFO, msg);
|
||||
LOGGER.log(Level.INFO, msg);
|
||||
try {
|
||||
importXML(filePair.getFirst(), filePair.getSecond());
|
||||
cveDB.commit();
|
||||
@@ -168,6 +182,6 @@ public class ProcessTask implements Callable<ProcessTask> {
|
||||
filePair.cleanup();
|
||||
}
|
||||
msg = String.format("Processing Complete for NVD CVE - %s", filePair.getNvdCveInfo().getId());
|
||||
Logger.getLogger(StandardUpdate.class.getName()).log(Level.INFO, msg);
|
||||
LOGGER.log(Level.INFO, msg);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -40,6 +40,10 @@ import org.xml.sax.helpers.DefaultHandler;
|
||||
*/
|
||||
public class NvdCve20Handler extends DefaultHandler {
|
||||
|
||||
/**
|
||||
* The logger.
|
||||
*/
|
||||
private static final Logger LOGGER = Logger.getLogger(NvdCve20Handler.class.getName());
|
||||
/**
|
||||
* the current supported schema version.
|
||||
*/
|
||||
@@ -168,8 +172,8 @@ public class NvdCve20Handler extends DefaultHandler {
|
||||
final float score = Float.parseFloat(nodeText.toString());
|
||||
vulnerability.setCvssScore(score);
|
||||
} catch (NumberFormatException ex) {
|
||||
Logger.getLogger(NvdCve20Handler.class.getName()).log(Level.SEVERE, "Error parsing CVSS Score.");
|
||||
Logger.getLogger(NvdCve20Handler.class.getName()).log(Level.FINE, null, ex);
|
||||
LOGGER.log(Level.SEVERE, "Error parsing CVSS Score.");
|
||||
LOGGER.log(Level.FINE, null, ex);
|
||||
}
|
||||
nodeText = null;
|
||||
} else if (current.isCVSSAccessVectorNode()) {
|
||||
|
||||
@@ -19,26 +19,33 @@ package org.owasp.dependencycheck.dependency;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.io.Serializable;
|
||||
import java.security.NoSuchAlgorithmException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
import java.util.SortedSet;
|
||||
import java.util.TreeSet;
|
||||
import java.util.logging.Level;
|
||||
import java.util.logging.Logger;
|
||||
import org.owasp.dependencycheck.data.nexus.MavenArtifact;
|
||||
import org.owasp.dependencycheck.utils.Checksum;
|
||||
import org.owasp.dependencycheck.utils.FileUtils;
|
||||
|
||||
/**
|
||||
* A program dependency. This object is one of the core components within DependencyCheck. It is used to collect
|
||||
* information about the dependency in the form of evidence. The Evidence is then used to determine if there are any
|
||||
* known, published, vulnerabilities associated with the program dependency.
|
||||
* A program dependency. This object is one of the core components within DependencyCheck. It is used to collect information about
|
||||
* the dependency in the form of evidence. The Evidence is then used to determine if there are any known, published,
|
||||
* vulnerabilities associated with the program dependency.
|
||||
*
|
||||
* @author Jeremy Long <jeremy.long@owasp.org>
|
||||
*/
|
||||
public class Dependency implements Comparable<Dependency> {
|
||||
public class Dependency implements Serializable, Comparable<Dependency> {
|
||||
|
||||
/**
|
||||
* The logger.
|
||||
*/
|
||||
private static final Logger LOGGER = Logger.getLogger(Dependency.class.getName());
|
||||
/**
|
||||
* The actual file path of the dependency on disk.
|
||||
*/
|
||||
@@ -89,6 +96,8 @@ public class Dependency implements Comparable<Dependency> {
|
||||
versionEvidence = new EvidenceCollection();
|
||||
identifiers = new TreeSet<Identifier>();
|
||||
vulnerabilities = new TreeSet<Vulnerability>(new VulnerabilityComparator());
|
||||
suppressedIdentifiers = new TreeSet<Identifier>();
|
||||
suppressedVulnerabilities = new TreeSet<Vulnerability>(new VulnerabilityComparator());
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -108,16 +117,26 @@ public class Dependency implements Comparable<Dependency> {
|
||||
/**
|
||||
* Returns the file name of the dependency.
|
||||
*
|
||||
* @return the file name of the dependency.
|
||||
* @return the file name of the dependency
|
||||
*/
|
||||
public String getFileName() {
|
||||
return this.fileName;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the file name of the dependency with the backslash escaped for use in JavaScript. This is a complete hack as I
|
||||
* could not get the replace to work in the template itself.
|
||||
*
|
||||
* @return the file name of the dependency with the backslash escaped for use in JavaScript
|
||||
*/
|
||||
public String getFileNameForJavaScript() {
|
||||
return this.fileName.replace("\\", "\\\\");
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the file name of the dependency.
|
||||
*
|
||||
* @param fileName the file name of the dependency.
|
||||
* @param fileName the file name of the dependency
|
||||
*/
|
||||
public void setFileName(String fileName) {
|
||||
this.fileName = fileName;
|
||||
@@ -126,7 +145,7 @@ public class Dependency implements Comparable<Dependency> {
|
||||
/**
|
||||
* Sets the actual file path of the dependency on disk.
|
||||
*
|
||||
* @param actualFilePath the file path of the dependency.
|
||||
* @param actualFilePath the file path of the dependency
|
||||
*/
|
||||
public void setActualFilePath(String actualFilePath) {
|
||||
this.actualFilePath = actualFilePath;
|
||||
@@ -139,7 +158,7 @@ public class Dependency implements Comparable<Dependency> {
|
||||
/**
|
||||
* Gets the file path of the dependency.
|
||||
*
|
||||
* @return the file path of the dependency.
|
||||
* @return the file path of the dependency
|
||||
*/
|
||||
public String getActualFilePath() {
|
||||
return this.actualFilePath;
|
||||
@@ -148,7 +167,7 @@ public class Dependency implements Comparable<Dependency> {
|
||||
/**
|
||||
* Gets a reference to the File object.
|
||||
*
|
||||
* @return the File object.
|
||||
* @return the File object
|
||||
*/
|
||||
public File getActualFile() {
|
||||
return new File(this.actualFilePath);
|
||||
@@ -157,20 +176,46 @@ public class Dependency implements Comparable<Dependency> {
|
||||
/**
|
||||
* Sets the file path of the dependency.
|
||||
*
|
||||
* @param filePath the file path of the dependency.
|
||||
* @param filePath the file path of the dependency
|
||||
*/
|
||||
public void setFilePath(String filePath) {
|
||||
this.filePath = filePath;
|
||||
}
|
||||
|
||||
/**
|
||||
* The file name to display in reports.
|
||||
*/
|
||||
private String displayName = null;
|
||||
|
||||
/**
|
||||
* Sets the file name to display in reports.
|
||||
*
|
||||
* @param displayName the name to display
|
||||
*/
|
||||
public void setDisplayFileName(String displayName) {
|
||||
this.displayName = displayName;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the file name to display in reports; if no display file name has been set it will default to the actual file name.
|
||||
*
|
||||
* @return the file name to display
|
||||
*/
|
||||
public String getDisplayFileName() {
|
||||
if (displayName == null) {
|
||||
return this.fileName;
|
||||
}
|
||||
return this.displayName;
|
||||
}
|
||||
|
||||
/**
|
||||
* <p>
|
||||
* Gets the file path of the dependency.</p>
|
||||
* <p>
|
||||
* <b>NOTE:</b> This may not be the actual path of the file on disk. The actual path of the file on disk can be
|
||||
* obtained via the getActualFilePath().</p>
|
||||
* <b>NOTE:</b> This may not be the actual path of the file on disk. The actual path of the file on disk can be obtained via
|
||||
* the getActualFilePath().</p>
|
||||
*
|
||||
* @return the file path of the dependency.
|
||||
* @return the file path of the dependency
|
||||
*/
|
||||
public String getFilePath() {
|
||||
return this.filePath;
|
||||
@@ -179,7 +224,7 @@ public class Dependency implements Comparable<Dependency> {
|
||||
/**
|
||||
* Sets the file name of the dependency.
|
||||
*
|
||||
* @param fileExtension the file name of the dependency.
|
||||
* @param fileExtension the file name of the dependency
|
||||
*/
|
||||
public void setFileExtension(String fileExtension) {
|
||||
this.fileExtension = fileExtension;
|
||||
@@ -188,7 +233,7 @@ public class Dependency implements Comparable<Dependency> {
|
||||
/**
|
||||
* Gets the file extension of the dependency.
|
||||
*
|
||||
* @return the file extension of the dependency.
|
||||
* @return the file extension of the dependency
|
||||
*/
|
||||
public String getFileExtension() {
|
||||
return this.fileExtension;
|
||||
@@ -233,7 +278,7 @@ public class Dependency implements Comparable<Dependency> {
|
||||
/**
|
||||
* Returns a List of Identifiers.
|
||||
*
|
||||
* @return an ArrayList of Identifiers.
|
||||
* @return an ArrayList of Identifiers
|
||||
*/
|
||||
public Set<Identifier> getIdentifiers() {
|
||||
return this.identifiers;
|
||||
@@ -242,7 +287,7 @@ public class Dependency implements Comparable<Dependency> {
|
||||
/**
|
||||
* Sets a List of Identifiers.
|
||||
*
|
||||
* @param identifiers A list of Identifiers.
|
||||
* @param identifiers A list of Identifiers
|
||||
*/
|
||||
public void setIdentifiers(Set<Identifier> identifiers) {
|
||||
this.identifiers = identifiers;
|
||||
@@ -274,6 +319,43 @@ public class Dependency implements Comparable<Dependency> {
|
||||
this.identifiers.add(i);
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds the maven artifact as evidence.
|
||||
*
|
||||
* @param source The source of the evidence
|
||||
* @param mavenArtifact The maven artifact
|
||||
* @param confidence The confidence level of this evidence
|
||||
*/
|
||||
public void addAsEvidence(String source, MavenArtifact mavenArtifact, Confidence confidence) {
|
||||
if (mavenArtifact.getGroupId() != null && !mavenArtifact.getGroupId().isEmpty()) {
|
||||
this.getVendorEvidence().addEvidence(source, "groupid", mavenArtifact.getGroupId(), confidence);
|
||||
}
|
||||
if (mavenArtifact.getArtifactId() != null && !mavenArtifact.getArtifactId().isEmpty()) {
|
||||
this.getProductEvidence().addEvidence(source, "artifactid", mavenArtifact.getArtifactId(), confidence);
|
||||
}
|
||||
if (mavenArtifact.getVersion() != null && !mavenArtifact.getVersion().isEmpty()) {
|
||||
this.getVersionEvidence().addEvidence(source, "version", mavenArtifact.getVersion(), confidence);
|
||||
}
|
||||
if (mavenArtifact.getArtifactUrl() != null && !mavenArtifact.getArtifactUrl().isEmpty()) {
|
||||
boolean found = false;
|
||||
for (Identifier i : this.getIdentifiers()) {
|
||||
if ("maven".equals(i.getType()) && i.getValue().equals(mavenArtifact.toString())) {
|
||||
found = true;
|
||||
i.setConfidence(Confidence.HIGHEST);
|
||||
final String url = "http://search.maven.org/#search|ga|1|1%3A%22" + this.getSha1sum() + "%22";
|
||||
i.setUrl(url);
|
||||
//i.setUrl(mavenArtifact.getArtifactUrl());
|
||||
LOGGER.fine(String.format("Already found identifier %s. Confidence set to highest", i.getValue()));
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (!found) {
|
||||
LOGGER.fine(String.format("Adding new maven identifier %s", mavenArtifact.toString()));
|
||||
this.addIdentifier("maven", mavenArtifact.toString(), mavenArtifact.getArtifactUrl(), Confidence.HIGHEST);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds an entry to the list of detected Identifiers for the dependency file.
|
||||
*
|
||||
@@ -283,6 +365,70 @@ public class Dependency implements Comparable<Dependency> {
|
||||
this.identifiers.add(identifier);
|
||||
}
|
||||
|
||||
/**
|
||||
* A set of identifiers that have been suppressed.
|
||||
*/
|
||||
private Set<Identifier> suppressedIdentifiers;
|
||||
|
||||
/**
|
||||
* Get the value of suppressedIdentifiers.
|
||||
*
|
||||
* @return the value of suppressedIdentifiers
|
||||
*/
|
||||
public Set<Identifier> getSuppressedIdentifiers() {
|
||||
return suppressedIdentifiers;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the value of suppressedIdentifiers.
|
||||
*
|
||||
* @param suppressedIdentifiers new value of suppressedIdentifiers
|
||||
*/
|
||||
public void setSuppressedIdentifiers(Set<Identifier> suppressedIdentifiers) {
|
||||
this.suppressedIdentifiers = suppressedIdentifiers;
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds an identifier to the list of suppressed identifiers.
|
||||
*
|
||||
* @param identifier an identifier that was suppressed.
|
||||
*/
|
||||
public void addSuppressedIdentifier(Identifier identifier) {
|
||||
this.suppressedIdentifiers.add(identifier);
|
||||
}
|
||||
|
||||
/**
|
||||
* A set of vulnerabilities that have been suppressed.
|
||||
*/
|
||||
private SortedSet<Vulnerability> suppressedVulnerabilities;
|
||||
|
||||
/**
|
||||
* Get the value of suppressedVulnerabilities.
|
||||
*
|
||||
* @return the value of suppressedVulnerabilities
|
||||
*/
|
||||
public SortedSet<Vulnerability> getSuppressedVulnerabilities() {
|
||||
return suppressedVulnerabilities;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the value of suppressedVulnerabilities.
|
||||
*
|
||||
* @param suppressedVulnerabilities new value of suppressedVulnerabilities
|
||||
*/
|
||||
public void setSuppressedVulnerabilities(SortedSet<Vulnerability> suppressedVulnerabilities) {
|
||||
this.suppressedVulnerabilities = suppressedVulnerabilities;
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds a vulnerability to the set of suppressed vulnerabilities.
|
||||
*
|
||||
* @param vulnerability the vulnerability that was suppressed
|
||||
*/
|
||||
public void addSuppressedVulnerability(Vulnerability vulnerability) {
|
||||
this.suppressedVulnerabilities.add(vulnerability);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the evidence used to identify this dependency.
|
||||
*
|
||||
@@ -292,6 +438,15 @@ public class Dependency implements Comparable<Dependency> {
|
||||
return EvidenceCollection.merge(this.productEvidence, this.vendorEvidence, this.versionEvidence);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the evidence used to identify this dependency.
|
||||
*
|
||||
* @return an EvidenceCollection.
|
||||
*/
|
||||
public Set<Evidence> getEvidenceForDisplay() {
|
||||
return EvidenceCollection.mergeForDisplay(this.productEvidence, this.vendorEvidence, this.versionEvidence);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the evidence used to identify this dependency.
|
||||
*
|
||||
@@ -327,37 +482,7 @@ public class Dependency implements Comparable<Dependency> {
|
||||
public EvidenceCollection getVersionEvidence() {
|
||||
return this.versionEvidence;
|
||||
}
|
||||
/**
|
||||
* A list of exceptions that occurred during analysis of this dependency.
|
||||
*/
|
||||
private List<Exception> analysisExceptions = new ArrayList<Exception>();
|
||||
|
||||
/**
|
||||
* Get the value of analysisExceptions.
|
||||
*
|
||||
* @return the value of analysisExceptions
|
||||
*/
|
||||
public List<Exception> getAnalysisExceptions() {
|
||||
return analysisExceptions;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the value of analysisExceptions.
|
||||
*
|
||||
* @param analysisExceptions new value of analysisExceptions
|
||||
*/
|
||||
public void setAnalysisExceptions(List<Exception> analysisExceptions) {
|
||||
this.analysisExceptions = analysisExceptions;
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds an exception to the analysis exceptions collection.
|
||||
*
|
||||
* @param ex an exception.
|
||||
*/
|
||||
public void addAnalysisException(Exception ex) {
|
||||
this.analysisExceptions.add(ex);
|
||||
}
|
||||
/**
|
||||
* The description of the JAR file.
|
||||
*/
|
||||
@@ -380,6 +505,7 @@ public class Dependency implements Comparable<Dependency> {
|
||||
public void setDescription(String description) {
|
||||
this.description = description;
|
||||
}
|
||||
|
||||
/**
|
||||
* The license that this dependency uses.
|
||||
*/
|
||||
@@ -402,6 +528,7 @@ public class Dependency implements Comparable<Dependency> {
|
||||
public void setLicense(String license) {
|
||||
this.license = license;
|
||||
}
|
||||
|
||||
/**
|
||||
* A list of vulnerabilities for this dependency.
|
||||
*/
|
||||
@@ -438,12 +565,12 @@ public class Dependency implements Comparable<Dependency> {
|
||||
sha1 = Checksum.getSHA1Checksum(file);
|
||||
} catch (IOException ex) {
|
||||
final String msg = String.format("Unable to read '%s' to determine hashes.", file.getName());
|
||||
Logger.getLogger(Dependency.class.getName()).log(Level.WARNING, msg);
|
||||
Logger.getLogger(Dependency.class.getName()).log(Level.FINE, null, ex);
|
||||
LOGGER.log(Level.WARNING, msg);
|
||||
LOGGER.log(Level.FINE, null, ex);
|
||||
} catch (NoSuchAlgorithmException ex) {
|
||||
final String msg = "Unable to use MD5 of SHA1 checksums.";
|
||||
Logger.getLogger(Dependency.class.getName()).log(Level.WARNING, msg);
|
||||
Logger.getLogger(Dependency.class.getName()).log(Level.FINE, null, ex);
|
||||
LOGGER.log(Level.WARNING, msg);
|
||||
LOGGER.log(Level.FINE, null, ex);
|
||||
}
|
||||
this.setMd5sum(md5);
|
||||
this.setSha1sum(sha1);
|
||||
@@ -457,6 +584,7 @@ public class Dependency implements Comparable<Dependency> {
|
||||
public void addVulnerability(Vulnerability vulnerability) {
|
||||
this.vulnerabilities.add(vulnerability);
|
||||
}
|
||||
|
||||
/**
|
||||
* A collection of related dependencies.
|
||||
*/
|
||||
@@ -471,6 +599,47 @@ public class Dependency implements Comparable<Dependency> {
|
||||
return relatedDependencies;
|
||||
}
|
||||
|
||||
/**
|
||||
* A list of projects that reference this dependency.
|
||||
*/
|
||||
private Set<String> projectReferences = new HashSet<String>();
|
||||
|
||||
/**
|
||||
* Get the value of projectReferences.
|
||||
*
|
||||
* @return the value of projectReferences
|
||||
*/
|
||||
public Set<String> getProjectReferences() {
|
||||
return projectReferences;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the value of projectReferences.
|
||||
*
|
||||
* @param projectReferences new value of projectReferences
|
||||
*/
|
||||
public void setProjectReferences(Set<String> projectReferences) {
|
||||
this.projectReferences = projectReferences;
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds a project reference.
|
||||
*
|
||||
* @param projectReference a project reference
|
||||
*/
|
||||
public void addProjectReference(String projectReference) {
|
||||
this.projectReferences.add(projectReference);
|
||||
}
|
||||
|
||||
/**
|
||||
* Add a collection of project reference.
|
||||
*
|
||||
* @param projectReferences a set of project references
|
||||
*/
|
||||
public void addAllProjectReferences(Set<String> projectReferences) {
|
||||
this.projectReferences.addAll(projectReferences);
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the value of relatedDependencies.
|
||||
*
|
||||
@@ -486,7 +655,46 @@ public class Dependency implements Comparable<Dependency> {
|
||||
* @param dependency a reference to the related dependency
|
||||
*/
|
||||
public void addRelatedDependency(Dependency dependency) {
|
||||
relatedDependencies.add(dependency);
|
||||
if (this == dependency) {
|
||||
LOGGER.warning("Attempted to add a circular reference - please post the log file to issue #172 here "
|
||||
+ "https://github.com/jeremylong/DependencyCheck/issues/172 ");
|
||||
LOGGER.log(Level.FINE, "this: {0}", this.toString());
|
||||
LOGGER.log(Level.FINE, "dependency: {0}", dependency.toString());
|
||||
} else {
|
||||
relatedDependencies.add(dependency);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* A list of available versions.
|
||||
*/
|
||||
private List<String> availableVersions = new ArrayList<String>();
|
||||
|
||||
/**
|
||||
* Get the value of availableVersions.
|
||||
*
|
||||
* @return the value of availableVersions
|
||||
*/
|
||||
public List<String> getAvailableVersions() {
|
||||
return availableVersions;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the value of availableVersions.
|
||||
*
|
||||
* @param availableVersions new value of availableVersions
|
||||
*/
|
||||
public void setAvailableVersions(List<String> availableVersions) {
|
||||
this.availableVersions = availableVersions;
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds a version to the available version list.
|
||||
*
|
||||
* @param version the version to add to the list
|
||||
*/
|
||||
public void addAvailableVersion(String version) {
|
||||
this.availableVersions.add(version);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -496,7 +704,7 @@ public class Dependency implements Comparable<Dependency> {
|
||||
* @return an integer representing the natural ordering
|
||||
*/
|
||||
public int compareTo(Dependency o) {
|
||||
return this.getFileName().compareToIgnoreCase(o.getFileName());
|
||||
return this.getFilePath().compareToIgnoreCase(o.getFilePath());
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -544,10 +752,6 @@ public class Dependency implements Comparable<Dependency> {
|
||||
if (this.versionEvidence != other.versionEvidence && (this.versionEvidence == null || !this.versionEvidence.equals(other.versionEvidence))) {
|
||||
return false;
|
||||
}
|
||||
if (this.analysisExceptions != other.analysisExceptions
|
||||
&& (this.analysisExceptions == null || !this.analysisExceptions.equals(other.analysisExceptions))) {
|
||||
return false;
|
||||
}
|
||||
if ((this.description == null) ? (other.description != null) : !this.description.equals(other.description)) {
|
||||
return false;
|
||||
}
|
||||
@@ -561,6 +765,15 @@ public class Dependency implements Comparable<Dependency> {
|
||||
&& (this.relatedDependencies == null || !this.relatedDependencies.equals(other.relatedDependencies))) {
|
||||
return false;
|
||||
}
|
||||
if (this.projectReferences != other.projectReferences
|
||||
&& (this.projectReferences == null || !this.projectReferences.equals(other.projectReferences))) {
|
||||
return false;
|
||||
}
|
||||
if (this.availableVersions != other.availableVersions
|
||||
&& (this.availableVersions == null || !this.availableVersions.equals(other.availableVersions))) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -582,11 +795,12 @@ public class Dependency implements Comparable<Dependency> {
|
||||
hash = 47 * hash + (this.vendorEvidence != null ? this.vendorEvidence.hashCode() : 0);
|
||||
hash = 47 * hash + (this.productEvidence != null ? this.productEvidence.hashCode() : 0);
|
||||
hash = 47 * hash + (this.versionEvidence != null ? this.versionEvidence.hashCode() : 0);
|
||||
hash = 47 * hash + (this.analysisExceptions != null ? this.analysisExceptions.hashCode() : 0);
|
||||
hash = 47 * hash + (this.description != null ? this.description.hashCode() : 0);
|
||||
hash = 47 * hash + (this.license != null ? this.license.hashCode() : 0);
|
||||
hash = 47 * hash + (this.vulnerabilities != null ? this.vulnerabilities.hashCode() : 0);
|
||||
hash = 47 * hash + (this.relatedDependencies != null ? this.relatedDependencies.hashCode() : 0);
|
||||
hash = 47 * hash + (this.projectReferences != null ? this.projectReferences.hashCode() : 0);
|
||||
hash = 47 * hash + (this.availableVersions != null ? this.availableVersions.hashCode() : 0);
|
||||
return hash;
|
||||
}
|
||||
|
||||
|
||||
@@ -17,12 +17,14 @@
|
||||
*/
|
||||
package org.owasp.dependencycheck.dependency;
|
||||
|
||||
import java.io.Serializable;
|
||||
|
||||
/**
|
||||
* Evidence is a piece of information about a Dependency.
|
||||
*
|
||||
* @author Jeremy Long <jeremy.long@owasp.org>
|
||||
*/
|
||||
public class Evidence implements Comparable<Evidence> {
|
||||
public class Evidence implements Serializable, Comparable<Evidence> {
|
||||
|
||||
/**
|
||||
* Creates a new Evidence object.
|
||||
@@ -220,22 +222,95 @@ public class Evidence implements Comparable<Evidence> {
|
||||
* @return an integer indicating the ordering of the two objects
|
||||
*/
|
||||
public int compareTo(Evidence o) {
|
||||
if (source.equals(o.source)) {
|
||||
if (name.equals(o.name)) {
|
||||
if (value.equals(o.value)) {
|
||||
if (confidence.equals(o.confidence)) {
|
||||
if (o == null) {
|
||||
return 1;
|
||||
}
|
||||
if (equalsWithNullCheck(source, o.source)) {
|
||||
if (equalsWithNullCheck(name, o.name)) {
|
||||
if (equalsWithNullCheck(value, o.value)) {
|
||||
if (equalsWithNullCheck(confidence, o.confidence)) {
|
||||
return 0; //they are equal
|
||||
} else {
|
||||
return confidence.compareTo(o.confidence);
|
||||
return compareToWithNullCheck(confidence, o.confidence);
|
||||
}
|
||||
} else {
|
||||
return value.compareToIgnoreCase(o.value);
|
||||
return compareToIgnoreCaseWithNullCheck(value, o.value);
|
||||
}
|
||||
} else {
|
||||
return name.compareToIgnoreCase(o.name);
|
||||
return compareToIgnoreCaseWithNullCheck(name, o.name);
|
||||
}
|
||||
} else {
|
||||
return source.compareToIgnoreCase(o.source);
|
||||
return compareToIgnoreCaseWithNullCheck(source, o.source);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Equality check with an exhaustive, possibly duplicative, check against nulls.
|
||||
*
|
||||
* @param me the value to be compared
|
||||
* @param other the other value to be compared
|
||||
* @return true if the values are equal; otherwise false
|
||||
*/
|
||||
private boolean equalsWithNullCheck(String me, String other) {
|
||||
if (me == null && other == null) {
|
||||
return true;
|
||||
} else if (me == null || other == null) {
|
||||
return false;
|
||||
}
|
||||
return me.equals(other);
|
||||
}
|
||||
|
||||
/**
|
||||
* Equality check with an exhaustive, possibly duplicative, check against nulls.
|
||||
*
|
||||
* @param me the value to be compared
|
||||
* @param other the other value to be compared
|
||||
* @return true if the values are equal; otherwise false
|
||||
*/
|
||||
private boolean equalsWithNullCheck(Confidence me, Confidence other) {
|
||||
if (me == null && other == null) {
|
||||
return true;
|
||||
} else if (me == null || other == null) {
|
||||
return false;
|
||||
}
|
||||
return me.equals(other);
|
||||
}
|
||||
|
||||
/**
|
||||
* Wrapper around {@link java.lang.String#compareToIgnoreCase(java.lang.String) String.compareToIgnoreCase} with an
|
||||
* exhaustive, possibly duplicative, check against nulls.
|
||||
*
|
||||
* @param me the value to be compared
|
||||
* @param other the other value to be compared
|
||||
* @return true if the values are equal; otherwise false
|
||||
*/
|
||||
private int compareToIgnoreCaseWithNullCheck(String me, String other) {
|
||||
if (me == null && other == null) {
|
||||
return 0;
|
||||
} else if (me == null) {
|
||||
return -1; //the other string is greater then me
|
||||
} else if (other == null) {
|
||||
return 1; //me is greater then the other string
|
||||
}
|
||||
return me.compareToIgnoreCase(other);
|
||||
}
|
||||
|
||||
/**
|
||||
* Wrapper around {@link java.lang.Enum#compareTo(java.lang.Enum) Enum.compareTo} with an exhaustive, possibly
|
||||
* duplicative, check against nulls.
|
||||
*
|
||||
* @param me the value to be compared
|
||||
* @param other the other value to be compared
|
||||
* @return true if the values are equal; otherwise false
|
||||
*/
|
||||
private int compareToWithNullCheck(Confidence me, Confidence other) {
|
||||
if (me == null && other == null) {
|
||||
return 0;
|
||||
} else if (me == null) {
|
||||
return -1; //the other string is greater then me
|
||||
} else if (other == null) {
|
||||
return 1; //me is greater then the other string
|
||||
}
|
||||
return me.compareTo(other);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -17,6 +17,7 @@
|
||||
*/
|
||||
package org.owasp.dependencycheck.dependency;
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.net.MalformedURLException;
|
||||
import java.util.HashSet;
|
||||
import java.util.Iterator;
|
||||
@@ -36,8 +37,12 @@ import org.owasp.dependencycheck.utils.UrlStringUtils;
|
||||
*
|
||||
* @author Jeremy Long <jeremy.long@owasp.org>
|
||||
*/
|
||||
public class EvidenceCollection implements Iterable<Evidence> {
|
||||
public class EvidenceCollection implements Serializable, Iterable<Evidence> {
|
||||
|
||||
/**
|
||||
* The logger.
|
||||
*/
|
||||
private static final Logger LOGGER = Logger.getLogger(EvidenceCollection.class.getName());
|
||||
/**
|
||||
* Used to iterate over highest confidence evidence contained in the collection.
|
||||
*/
|
||||
@@ -307,6 +312,26 @@ public class EvidenceCollection implements Iterable<Evidence> {
|
||||
return ret;
|
||||
}
|
||||
|
||||
/**
|
||||
* Merges multiple EvidenceCollections together; flattening all of the evidence items by removing the confidence.
|
||||
*
|
||||
* @param ec One or more EvidenceCollections
|
||||
* @return new set of evidence resulting from merging the evidence in the collections
|
||||
*/
|
||||
public static Set<Evidence> mergeForDisplay(EvidenceCollection... ec) {
|
||||
final Set<Evidence> ret = new TreeSet<Evidence>();
|
||||
for (EvidenceCollection col : ec) {
|
||||
for (Evidence e : col) {
|
||||
if (e.isUsed()) {
|
||||
final Evidence newEvidence = new Evidence(e.getSource(), e.getName(), e.getValue(), null);
|
||||
newEvidence.setUsed(true);
|
||||
ret.add(newEvidence);
|
||||
}
|
||||
}
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a string of evidence 'values'.
|
||||
*
|
||||
@@ -360,7 +385,7 @@ public class EvidenceCollection implements Iterable<Evidence> {
|
||||
final List<String> data = UrlStringUtils.extractImportantUrlData(part);
|
||||
sb.append(' ').append(StringUtils.join(data, ' '));
|
||||
} catch (MalformedURLException ex) {
|
||||
Logger.getLogger(EvidenceCollection.class.getName()).log(Level.INFO, "error parsing " + part, ex);
|
||||
LOGGER.log(Level.FINE, "error parsing " + part, ex);
|
||||
sb.append(' ').append(part);
|
||||
}
|
||||
} else {
|
||||
|
||||
@@ -17,11 +17,22 @@
|
||||
*/
|
||||
package org.owasp.dependencycheck.dependency;
|
||||
|
||||
import java.io.Serializable;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author Jeremy Long <jeremy.long@owasp.org>
|
||||
*/
|
||||
public class Identifier implements Comparable<Identifier> {
|
||||
public class Identifier implements Serializable, Comparable<Identifier> {
|
||||
|
||||
/**
|
||||
* Default constructor. Should only be used for automatic class
|
||||
* creation as is the case with many XML parsers (for the parsing
|
||||
* of the Dependency-Check XML report). For all other use-cases,
|
||||
* please use the non-default constructors.
|
||||
*/
|
||||
public Identifier() {
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructs a new Identifier with the specified data.
|
||||
|
||||
@@ -31,6 +31,10 @@ import org.owasp.dependencycheck.data.cpe.IndexEntry;
|
||||
*/
|
||||
public class VulnerableSoftware extends IndexEntry implements Serializable, Comparable<VulnerableSoftware> {
|
||||
|
||||
/**
|
||||
* The logger.
|
||||
*/
|
||||
private static final Logger LOGGER = Logger.getLogger(VulnerableSoftware.class.getName());
|
||||
/**
|
||||
* The serial version UID.
|
||||
*/
|
||||
@@ -46,8 +50,8 @@ public class VulnerableSoftware extends IndexEntry implements Serializable, Comp
|
||||
parseName(cpe);
|
||||
} catch (UnsupportedEncodingException ex) {
|
||||
final String msg = String.format("Character encoding is unsupported for CPE '%s'.", cpe);
|
||||
Logger.getLogger(VulnerableSoftware.class.getName()).log(Level.WARNING, msg);
|
||||
Logger.getLogger(VulnerableSoftware.class.getName()).log(Level.FINE, null, ex);
|
||||
LOGGER.log(Level.WARNING, msg);
|
||||
LOGGER.log(Level.FINE, null, ex);
|
||||
setName(cpe);
|
||||
}
|
||||
}
|
||||
@@ -73,19 +77,19 @@ public class VulnerableSoftware extends IndexEntry implements Serializable, Comp
|
||||
if (cpeName != null && cpeName.length() > 7) {
|
||||
final String[] data = cpeName.substring(7).split(":");
|
||||
if (data.length >= 1) {
|
||||
this.setVendor(URLDecoder.decode(data[0].replace("+", "%2B"), "UTF-8"));
|
||||
this.setVendor(urlDecode(data[0]));
|
||||
}
|
||||
if (data.length >= 2) {
|
||||
this.setProduct(URLDecoder.decode(data[1].replace("+", "%2B"), "UTF-8"));
|
||||
this.setProduct(urlDecode(data[1]));
|
||||
}
|
||||
if (data.length >= 3) {
|
||||
version = URLDecoder.decode(data[2].replace("+", "%2B"), "UTF-8");
|
||||
version = urlDecode(data[2]);
|
||||
}
|
||||
if (data.length >= 4) {
|
||||
revision = URLDecoder.decode(data[3].replace("+", "%2B"), "UTF-8");
|
||||
revision = urlDecode(data[3]);
|
||||
}
|
||||
if (data.length >= 5) {
|
||||
edition = URLDecoder.decode(data[4].replace("+", "%2B"), "UTF-8");
|
||||
edition = urlDecode(data[4]);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -337,4 +341,25 @@ public class VulnerableSoftware extends IndexEntry implements Serializable, Comp
|
||||
public void setEdition(String edition) {
|
||||
this.edition = edition;
|
||||
}
|
||||
|
||||
/**
|
||||
* Replaces '+' with '%2B' and then URL Decodes the string attempting first UTF-8, then ASCII, then default.
|
||||
*
|
||||
* @param string the string to URL Decode
|
||||
* @return the URL Decoded string
|
||||
*/
|
||||
private String urlDecode(String string) {
|
||||
final String text = string.replace("+", "%2B");
|
||||
String result;
|
||||
try {
|
||||
result = URLDecoder.decode(text, "UTF-8");
|
||||
} catch (UnsupportedEncodingException ex) {
|
||||
try {
|
||||
result = URLDecoder.decode(text, "ASCII");
|
||||
} catch (UnsupportedEncodingException ex1) {
|
||||
result = URLDecoder.decode(text);
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,68 @@
|
||||
/*
|
||||
* This file is part of dependency-check-core.
|
||||
*
|
||||
* Licensed under the Apache 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.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*
|
||||
* Copyright (c) 2014 Jeremy Long. All Rights Reserved.
|
||||
*/
|
||||
package org.owasp.dependencycheck.exception;
|
||||
|
||||
import java.io.IOException;
|
||||
|
||||
/**
|
||||
* An exception used when using @{link DependencyCheckScanAgent} to conduct a scan and the scan fails.
|
||||
*
|
||||
* @author Steve Springett <steve.springett@owasp.org>
|
||||
*/
|
||||
public class ScanAgentException extends IOException {
|
||||
|
||||
/**
|
||||
* The serial version uid.
|
||||
*/
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
/**
|
||||
* Creates a new ScanAgentException.
|
||||
*/
|
||||
public ScanAgentException() {
|
||||
super();
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new ScanAgentException.
|
||||
*
|
||||
* @param msg a message for the exception.
|
||||
*/
|
||||
public ScanAgentException(String msg) {
|
||||
super(msg);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new ScanAgentException.
|
||||
*
|
||||
* @param ex the cause of the exception.
|
||||
*/
|
||||
public ScanAgentException(Throwable ex) {
|
||||
super(ex);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new ScanAgentException.
|
||||
*
|
||||
* @param msg a message for the exception.
|
||||
* @param ex the cause of the exception.
|
||||
*/
|
||||
public ScanAgentException(String msg, Throwable ex) {
|
||||
super(msg, ex);
|
||||
}
|
||||
}
|
||||
@@ -56,16 +56,16 @@ public class MavenNamespaceFilter extends XMLFilterImpl {
|
||||
* @param uri the uri
|
||||
* @param localName the localName
|
||||
* @param qName the qualified name
|
||||
* @param atts the attributes
|
||||
* @param attributes the attributes
|
||||
* @throws SAXException thrown if there is a SAXException
|
||||
*/
|
||||
@Override
|
||||
public void startElement(String uri, String localName, String qName, Attributes atts) throws SAXException {
|
||||
super.startElement(NAMESPACE, localName, qName, atts);
|
||||
public void startElement(String uri, String localName, String qName, Attributes attributes) throws SAXException {
|
||||
super.startElement(NAMESPACE, localName, qName, attributes);
|
||||
}
|
||||
|
||||
/**
|
||||
* Indicatees the start of the document.
|
||||
* Indicates the start of the document.
|
||||
*
|
||||
* @param uri the uri
|
||||
* @param localName the localName
|
||||
|
||||
@@ -0,0 +1,226 @@
|
||||
/*
|
||||
* This file is part of dependency-check-core.
|
||||
*
|
||||
* Licensed under the Apache 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.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*
|
||||
* Copyright (c) 2015 Jeremy Long. All Rights Reserved.
|
||||
*/
|
||||
package org.owasp.dependencycheck.jaxb.pom;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.FileInputStream;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStreamReader;
|
||||
import java.util.logging.Level;
|
||||
import java.util.logging.Logger;
|
||||
import javax.xml.bind.JAXBContext;
|
||||
import javax.xml.bind.JAXBElement;
|
||||
import javax.xml.bind.JAXBException;
|
||||
import javax.xml.bind.Unmarshaller;
|
||||
import javax.xml.parsers.ParserConfigurationException;
|
||||
import javax.xml.parsers.SAXParser;
|
||||
import javax.xml.parsers.SAXParserFactory;
|
||||
import javax.xml.transform.sax.SAXSource;
|
||||
|
||||
import org.owasp.dependencycheck.analyzer.JarAnalyzer;
|
||||
import org.owasp.dependencycheck.analyzer.exception.AnalysisException;
|
||||
import org.owasp.dependencycheck.dependency.Confidence;
|
||||
import org.owasp.dependencycheck.dependency.Dependency;
|
||||
import org.owasp.dependencycheck.jaxb.pom.generated.Model;
|
||||
import org.owasp.dependencycheck.jaxb.pom.generated.Organization;
|
||||
import org.xml.sax.InputSource;
|
||||
import org.xml.sax.SAXException;
|
||||
import org.xml.sax.XMLFilter;
|
||||
import org.xml.sax.XMLReader;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author jeremy
|
||||
*/
|
||||
public class PomUtils {
|
||||
|
||||
/**
|
||||
* The logger.
|
||||
*/
|
||||
private static final Logger LOGGER = Logger.getLogger(PomUtils.class.getName());
|
||||
|
||||
/**
|
||||
* The unmarshaller used to parse the pom.xml from a JAR file.
|
||||
*/
|
||||
private Unmarshaller pomUnmarshaller;
|
||||
|
||||
/**
|
||||
* Constructs a new POM Utility.
|
||||
*/
|
||||
public PomUtils() {
|
||||
try {
|
||||
//final JAXBContext jaxbContext = JAXBContext.newInstance("org.owasp.dependencycheck.jaxb.pom.generated");
|
||||
final JAXBContext jaxbContext = JAXBContext.newInstance(Model.class);
|
||||
pomUnmarshaller = jaxbContext.createUnmarshaller();
|
||||
} catch (JAXBException ex) { //guess we will just have a null pointer exception later...
|
||||
LOGGER.log(Level.SEVERE, "Unable to load parser. See the log for more details.");
|
||||
LOGGER.log(Level.FINE, null, ex);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Reads in the specified POM and converts it to a Model.
|
||||
*
|
||||
* @param file the pom.xml file
|
||||
* @return returns a
|
||||
* @throws AnalysisException is thrown if there is an exception extracting or parsing the POM
|
||||
* {@link org.owasp.dependencycheck.jaxb.pom.generated.Model} object
|
||||
*/
|
||||
public Model readPom(File file) throws AnalysisException {
|
||||
Model model = null;
|
||||
try {
|
||||
final FileInputStream stream = new FileInputStream(file);
|
||||
final InputStreamReader reader = new InputStreamReader(stream, "UTF-8");
|
||||
final InputSource xml = new InputSource(reader);
|
||||
final SAXSource source = new SAXSource(xml);
|
||||
model = readPom(source);
|
||||
} catch (SecurityException ex) {
|
||||
final String msg = String.format("Unable to parse pom '%s'; invalid signature", file.getPath());
|
||||
LOGGER.log(Level.WARNING, msg);
|
||||
LOGGER.log(Level.FINE, "", ex);
|
||||
throw new AnalysisException(ex);
|
||||
} catch (IOException ex) {
|
||||
final String msg = String.format("Unable to parse pom '%s'(IO Exception)", file.getPath());
|
||||
LOGGER.log(Level.WARNING, msg);
|
||||
LOGGER.log(Level.FINE, "", ex);
|
||||
throw new AnalysisException(ex);
|
||||
} catch (Throwable ex) {
|
||||
final String msg = String.format("Unexpected error during parsing of the pom '%s'", file.getPath());
|
||||
LOGGER.log(Level.WARNING, msg);
|
||||
LOGGER.log(Level.FINE, "", ex);
|
||||
throw new AnalysisException(ex);
|
||||
}
|
||||
return model;
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieves the specified POM from a jar file and converts it to a Model.
|
||||
*
|
||||
* @param source the SAXSource input stream to read the POM from
|
||||
* @return returns the POM object
|
||||
* @throws AnalysisException is thrown if there is an exception extracting or parsing the POM
|
||||
* {@link org.owasp.dependencycheck.jaxb.pom.generated.Model} object
|
||||
*/
|
||||
public Model readPom(SAXSource source) throws AnalysisException {
|
||||
Model model = null;
|
||||
try {
|
||||
final XMLFilter filter = new MavenNamespaceFilter();
|
||||
final SAXParserFactory spf = SAXParserFactory.newInstance();
|
||||
final SAXParser sp = spf.newSAXParser();
|
||||
final XMLReader xr = sp.getXMLReader();
|
||||
filter.setParent(xr);
|
||||
final JAXBElement<Model> el = pomUnmarshaller.unmarshal(source, Model.class);
|
||||
model = el.getValue();
|
||||
} catch (SecurityException ex) {
|
||||
throw new AnalysisException(ex);
|
||||
} catch (ParserConfigurationException ex) {
|
||||
throw new AnalysisException(ex);
|
||||
} catch (SAXException ex) {
|
||||
throw new AnalysisException(ex);
|
||||
} catch (JAXBException ex) {
|
||||
throw new AnalysisException(ex);
|
||||
} catch (Throwable ex) {
|
||||
throw new AnalysisException(ex);
|
||||
}
|
||||
return model;
|
||||
}
|
||||
|
||||
/**
|
||||
* Reads in the pom file and adds elements as evidence to the given dependency.
|
||||
*
|
||||
* @param dependency the dependency being analyzed
|
||||
* @param pomFile the pom file to read
|
||||
* @throws AnalysisException is thrown if there is an exception parsing the pom
|
||||
*/
|
||||
public void analyzePOM(Dependency dependency, File pomFile) throws AnalysisException {
|
||||
final Model pom = this.readPom(pomFile);
|
||||
|
||||
String groupid = pom.getGroupId();
|
||||
String parentGroupId = null;
|
||||
|
||||
if (pom.getParent() != null) {
|
||||
parentGroupId = pom.getParent().getGroupId();
|
||||
if ((groupid == null || groupid.isEmpty()) && parentGroupId != null && !parentGroupId.isEmpty()) {
|
||||
groupid = parentGroupId;
|
||||
}
|
||||
}
|
||||
if (groupid != null && !groupid.isEmpty()) {
|
||||
dependency.getVendorEvidence().addEvidence("pom", "groupid", groupid, Confidence.HIGHEST);
|
||||
dependency.getProductEvidence().addEvidence("pom", "groupid", groupid, Confidence.LOW);
|
||||
if (parentGroupId != null && !parentGroupId.isEmpty() && !parentGroupId.equals(groupid)) {
|
||||
dependency.getVendorEvidence().addEvidence("pom", "parent-groupid", parentGroupId, Confidence.MEDIUM);
|
||||
dependency.getProductEvidence().addEvidence("pom", "parent-groupid", parentGroupId, Confidence.LOW);
|
||||
}
|
||||
}
|
||||
String artifactid = pom.getArtifactId();
|
||||
String parentArtifactId = null;
|
||||
if (pom.getParent() != null) {
|
||||
parentArtifactId = pom.getParent().getArtifactId();
|
||||
if ((artifactid == null || artifactid.isEmpty()) && parentArtifactId != null && !parentArtifactId.isEmpty()) {
|
||||
artifactid = parentArtifactId;
|
||||
}
|
||||
}
|
||||
if (artifactid != null && !artifactid.isEmpty()) {
|
||||
if (artifactid.startsWith("org.") || artifactid.startsWith("com.")) {
|
||||
artifactid = artifactid.substring(4);
|
||||
}
|
||||
dependency.getProductEvidence().addEvidence("pom", "artifactid", artifactid, Confidence.HIGHEST);
|
||||
dependency.getVendorEvidence().addEvidence("pom", "artifactid", artifactid, Confidence.LOW);
|
||||
if (parentArtifactId != null && !parentArtifactId.isEmpty() && !parentArtifactId.equals(artifactid)) {
|
||||
dependency.getProductEvidence().addEvidence("pom", "parent-artifactid", parentArtifactId, Confidence.MEDIUM);
|
||||
dependency.getVendorEvidence().addEvidence("pom", "parent-artifactid", parentArtifactId, Confidence.LOW);
|
||||
}
|
||||
}
|
||||
//version
|
||||
String version = pom.getVersion();
|
||||
String parentVersion = null;
|
||||
if (pom.getParent() != null) {
|
||||
parentVersion = pom.getParent().getVersion();
|
||||
if ((version == null || version.isEmpty()) && parentVersion != null && !parentVersion.isEmpty()) {
|
||||
version = parentVersion;
|
||||
}
|
||||
}
|
||||
if (version != null && !version.isEmpty()) {
|
||||
dependency.getVersionEvidence().addEvidence("pom", "version", version, Confidence.HIGHEST);
|
||||
if (parentVersion != null && !parentVersion.isEmpty() && !parentVersion.equals(version)) {
|
||||
dependency.getVersionEvidence().addEvidence("pom", "parent-version", version, Confidence.LOW);
|
||||
}
|
||||
}
|
||||
|
||||
final Organization org = pom.getOrganization();
|
||||
if (org != null) {
|
||||
final String orgName = org.getName();
|
||||
if (orgName != null && !orgName.isEmpty()) {
|
||||
dependency.getVendorEvidence().addEvidence("pom", "organization name", orgName, Confidence.HIGH);
|
||||
}
|
||||
}
|
||||
final String pomName = pom.getName();
|
||||
if (pomName != null && !pomName.isEmpty()) {
|
||||
dependency.getProductEvidence().addEvidence("pom", "name", pomName, Confidence.HIGH);
|
||||
dependency.getVendorEvidence().addEvidence("pom", "name", pomName, Confidence.HIGH);
|
||||
}
|
||||
|
||||
if (pom.getDescription() != null) {
|
||||
final String description = pom.getDescription();
|
||||
if (description != null && !description.isEmpty()) {
|
||||
JarAnalyzer.addDescription(dependency, description, "pom", "description");
|
||||
}
|
||||
}
|
||||
JarAnalyzer.extractLicense(pom, null, dependency);
|
||||
}
|
||||
}
|
||||
File diff suppressed because it is too large
Load Diff
@@ -31,7 +31,7 @@ import javax.xml.namespace.QName;
|
||||
@XmlRegistry
|
||||
public class ObjectFactory {
|
||||
|
||||
private final static QName _Project_QNAME = new QName("http://maven.apache.org/POM/4.0.0", "project");
|
||||
private static final QName _Project_QNAME = new QName("http://maven.apache.org/POM/4.0.0", "project");
|
||||
|
||||
/**
|
||||
* Create a new ObjectFactory that can be used to create new instances of schema derived classes for package: org.owasp.dependencycheck.analyzer.pom.generated
|
||||
|
||||
@@ -0,0 +1,74 @@
|
||||
/*
|
||||
* This file is part of dependency-check-core.
|
||||
*
|
||||
* Licensed under the Apache 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.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*
|
||||
* Copyright (c) 2014 Jeremy Long. All Rights Reserved.
|
||||
*/
|
||||
package org.owasp.dependencycheck.reporting;
|
||||
|
||||
import java.io.UnsupportedEncodingException;
|
||||
import java.net.URLEncoder;
|
||||
import java.util.logging.Level;
|
||||
import java.util.logging.Logger;
|
||||
import org.apache.commons.lang.StringEscapeUtils;
|
||||
|
||||
/**
|
||||
* An extremely simple wrapper around various escape utils to perform URL and HTML encoding within the reports. This
|
||||
* class was created to simplify the velocity configuration and avoid using the "built-in" escape tool.
|
||||
*
|
||||
* @author Jeremy Long <jeremy.long@owasp.org>
|
||||
*/
|
||||
public class EscapeTool {
|
||||
|
||||
/**
|
||||
* The logger.
|
||||
*/
|
||||
private static final Logger LOGGER = Logger.getLogger(EscapeTool.class.getName());
|
||||
|
||||
/**
|
||||
* URL Encodes the provided text.
|
||||
*
|
||||
* @param text the text to encode
|
||||
* @return the URL encoded text
|
||||
*/
|
||||
public String url(String text) {
|
||||
try {
|
||||
return URLEncoder.encode(text, "UTF-8");
|
||||
} catch (UnsupportedEncodingException ex) {
|
||||
LOGGER.log(Level.WARNING, "UTF-8 is not supported?");
|
||||
LOGGER.log(Level.INFO, null, ex);
|
||||
}
|
||||
return "";
|
||||
}
|
||||
|
||||
/**
|
||||
* HTML Encodes the provided text.
|
||||
*
|
||||
* @param text the text to encode
|
||||
* @return the HTML encoded text
|
||||
*/
|
||||
public String html(String text) {
|
||||
return StringEscapeUtils.escapeHtml(text);
|
||||
}
|
||||
|
||||
/**
|
||||
* XML Encodes the provided text.
|
||||
*
|
||||
* @param text the text to encode
|
||||
* @return the XML encoded text
|
||||
*/
|
||||
public String xml(String text) {
|
||||
return StringEscapeUtils.escapeXml(text);
|
||||
}
|
||||
}
|
||||
@@ -26,15 +26,16 @@ import java.io.InputStream;
|
||||
import java.io.InputStreamReader;
|
||||
import java.io.OutputStream;
|
||||
import java.io.OutputStreamWriter;
|
||||
import java.text.DateFormat;
|
||||
import java.text.SimpleDateFormat;
|
||||
import java.util.Date;
|
||||
import java.util.List;
|
||||
import java.util.logging.Level;
|
||||
import java.util.logging.Logger;
|
||||
import org.apache.velocity.VelocityContext;
|
||||
import org.apache.velocity.app.VelocityEngine;
|
||||
import org.apache.velocity.context.Context;
|
||||
import org.apache.velocity.runtime.RuntimeConstants;
|
||||
import org.apache.velocity.runtime.resource.loader.ClasspathResourceLoader;
|
||||
import org.apache.velocity.tools.ToolManager;
|
||||
import org.apache.velocity.tools.config.EasyFactoryConfiguration;
|
||||
import org.owasp.dependencycheck.analyzer.Analyzer;
|
||||
import org.owasp.dependencycheck.data.nvdcve.DatabaseProperties;
|
||||
import org.owasp.dependencycheck.dependency.Dependency;
|
||||
@@ -48,6 +49,11 @@ import org.owasp.dependencycheck.utils.Settings;
|
||||
*/
|
||||
public class ReportGenerator {
|
||||
|
||||
/**
|
||||
* The logger.
|
||||
*/
|
||||
private static final Logger LOGGER = Logger.getLogger(ReportGenerator.class.getName());
|
||||
|
||||
/**
|
||||
* An enumeration of the report formats.
|
||||
*/
|
||||
@@ -93,11 +99,21 @@ public class ReportGenerator {
|
||||
|
||||
engine.init();
|
||||
|
||||
final DateFormat dateFormat = new SimpleDateFormat("MMM d, yyyy 'at' HH:mm:ss z");
|
||||
final DateFormat dateFormatXML = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss.SSSZ");
|
||||
final Date d = new Date();
|
||||
final String scanDate = dateFormat.format(d);
|
||||
final String scanDateXML = dateFormatXML.format(d);
|
||||
final EscapeTool enc = new EscapeTool();
|
||||
|
||||
context.put("applicationName", applicationName);
|
||||
context.put("dependencies", dependencies);
|
||||
context.put("analyzers", analyzers);
|
||||
context.put("properties", properties);
|
||||
context.put("version", Settings.getString("application.version", "Unknown"));
|
||||
context.put("scanDate", scanDate);
|
||||
context.put("scanDateXML", scanDateXML);
|
||||
context.put("enc", enc);
|
||||
context.put("version", Settings.getString(Settings.KEYS.APPLICATION_VERSION, "Unknown"));
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -106,28 +122,39 @@ public class ReportGenerator {
|
||||
* @return a velocity engine.
|
||||
*/
|
||||
private VelocityEngine createVelocityEngine() {
|
||||
final VelocityEngine ve = new VelocityEngine();
|
||||
ve.setProperty(RuntimeConstants.RUNTIME_LOG_LOGSYSTEM_CLASS, VelocityLoggerRedirect.class.getName());
|
||||
ve.setProperty(RuntimeConstants.RESOURCE_LOADER, "classpath");
|
||||
ve.setProperty("classpath.resource.loader.class", ClasspathResourceLoader.class.getName());
|
||||
return ve;
|
||||
final VelocityEngine engine = new VelocityEngine();
|
||||
// Logging redirection for Velocity - Required by Jenkins and other server applications
|
||||
engine.setProperty(RuntimeConstants.RUNTIME_LOG_LOGSYSTEM_CLASS, VelocityLoggerRedirect.class.getName());
|
||||
return engine;
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new Velocity Context initialized with escape and date tools.
|
||||
* Creates a new Velocity Context.
|
||||
*
|
||||
* @return a Velocity Context.
|
||||
*/
|
||||
@edu.umd.cs.findbugs.annotations.SuppressWarnings(value = "RV_RETURN_VALUE_IGNORED_INFERRED",
|
||||
justification = "No plan to fix this style issue")
|
||||
private Context createContext() {
|
||||
final ToolManager manager = new ToolManager();
|
||||
final Context c = manager.createContext();
|
||||
final EasyFactoryConfiguration config = new EasyFactoryConfiguration();
|
||||
config.addDefaultTools();
|
||||
config.toolbox("application").tool("esc", "org.apache.velocity.tools.generic.EscapeTool").tool("org.apache.velocity.tools.generic.DateTool");
|
||||
manager.configure(config);
|
||||
return c;
|
||||
return new VelocityContext();
|
||||
}
|
||||
|
||||
/**
|
||||
* Generates the Dependency Reports for the identified dependencies.
|
||||
*
|
||||
* @param outputStream the OutputStream to send the generated report to
|
||||
* @param format the format the report should be written in
|
||||
* @throws IOException is thrown when the template file does not exist
|
||||
* @throws Exception is thrown if there is an error writing out the reports.
|
||||
*/
|
||||
public void generateReports(OutputStream outputStream, Format format) throws IOException, Exception {
|
||||
if (format == Format.XML || format == Format.ALL) {
|
||||
generateReport("XmlReport", outputStream);
|
||||
}
|
||||
if (format == Format.HTML || format == Format.ALL) {
|
||||
generateReport("HtmlReport", outputStream);
|
||||
}
|
||||
if (format == Format.VULN || format == Format.ALL) {
|
||||
generateReport("VulnerabilityReport", outputStream);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -140,13 +167,13 @@ public class ReportGenerator {
|
||||
*/
|
||||
public void generateReports(String outputDir, Format format) throws IOException, Exception {
|
||||
if (format == Format.XML || format == Format.ALL) {
|
||||
generateReport("XmlReport", outputDir + File.separator + "DependencyCheck-Report.xml");
|
||||
generateReport("XmlReport", outputDir + File.separator + "dependency-check-report.xml");
|
||||
}
|
||||
if (format == Format.HTML || format == Format.ALL) {
|
||||
generateReport("HtmlReport", outputDir + File.separator + "DependencyCheck-Report.html");
|
||||
generateReport("HtmlReport", outputDir + File.separator + "dependency-check-report.html");
|
||||
}
|
||||
if (format == Format.VULN || format == Format.ALL) {
|
||||
generateReport("VulnerabilityReport", outputDir + File.separator + "DependencyCheck-Vulnerability.html");
|
||||
generateReport("VulnerabilityReport", outputDir + File.separator + "dependency-check-vulnerability.html");
|
||||
}
|
||||
}
|
||||
|
||||
@@ -160,15 +187,28 @@ public class ReportGenerator {
|
||||
*/
|
||||
public void generateReports(String outputDir, String outputFormat) throws IOException, Exception {
|
||||
final String format = outputFormat.toUpperCase();
|
||||
final String pathToCheck = outputDir.toLowerCase();
|
||||
if (format.matches("^(XML|HTML|VULN|ALL)$")) {
|
||||
if ("XML".equalsIgnoreCase(format)) {
|
||||
generateReports(outputDir, Format.XML);
|
||||
if (pathToCheck.endsWith(".xml")) {
|
||||
generateReport("XmlReport", outputDir);
|
||||
} else {
|
||||
generateReports(outputDir, Format.XML);
|
||||
}
|
||||
}
|
||||
if ("HTML".equalsIgnoreCase(format)) {
|
||||
generateReports(outputDir, Format.HTML);
|
||||
if (pathToCheck.endsWith(".html") || pathToCheck.endsWith(".htm")) {
|
||||
generateReport("HtmlReport", outputDir);
|
||||
} else {
|
||||
generateReports(outputDir, Format.HTML);
|
||||
}
|
||||
}
|
||||
if ("VULN".equalsIgnoreCase(format)) {
|
||||
generateReports(outputDir, Format.VULN);
|
||||
if (pathToCheck.endsWith(".html") || pathToCheck.endsWith(".htm")) {
|
||||
generateReport("VulnReport", outputDir);
|
||||
} else {
|
||||
generateReports(outputDir, Format.VULN);
|
||||
}
|
||||
}
|
||||
if ("ALL".equalsIgnoreCase(format)) {
|
||||
generateReports(outputDir, Format.ALL);
|
||||
@@ -176,6 +216,70 @@ public class ReportGenerator {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Generates a report from a given Velocity Template. The template name provided can be the name of a template
|
||||
* contained in the jar file, such as 'XmlReport' or 'HtmlReport', or the template name can be the path to a
|
||||
* template file.
|
||||
*
|
||||
* @param templateName the name of the template to load.
|
||||
* @param outputStream the OutputStream to write the report to.
|
||||
* @throws IOException is thrown when the template file does not exist.
|
||||
* @throws Exception is thrown when an exception occurs.
|
||||
*/
|
||||
protected void generateReport(String templateName, OutputStream outputStream) throws IOException, Exception {
|
||||
InputStream input = null;
|
||||
String templatePath = null;
|
||||
final File f = new File(templateName);
|
||||
if (f.exists() && f.isFile()) {
|
||||
try {
|
||||
templatePath = templateName;
|
||||
input = new FileInputStream(f);
|
||||
} catch (FileNotFoundException ex) {
|
||||
final String msg = "Unable to generate the report, the report template file could not be found.";
|
||||
LOGGER.log(Level.SEVERE, msg);
|
||||
LOGGER.log(Level.FINE, null, ex);
|
||||
}
|
||||
} else {
|
||||
templatePath = "templates/" + templateName + ".vsl";
|
||||
input = this.getClass().getClassLoader().getResourceAsStream(templatePath);
|
||||
}
|
||||
if (input == null) {
|
||||
throw new IOException("Template file doesn't exist");
|
||||
}
|
||||
|
||||
final InputStreamReader reader = new InputStreamReader(input, "UTF-8");
|
||||
OutputStreamWriter writer = null;
|
||||
|
||||
try {
|
||||
writer = new OutputStreamWriter(outputStream, "UTF-8");
|
||||
|
||||
if (!engine.evaluate(context, writer, templatePath, reader)) {
|
||||
throw new Exception("Failed to convert the template into html.");
|
||||
}
|
||||
writer.flush();
|
||||
} finally {
|
||||
if (writer != null) {
|
||||
try {
|
||||
writer.close();
|
||||
} catch (IOException ex) {
|
||||
LOGGER.log(Level.FINEST, null, ex);
|
||||
}
|
||||
}
|
||||
if (outputStream != null) {
|
||||
try {
|
||||
outputStream.close();
|
||||
} catch (IOException ex) {
|
||||
LOGGER.log(Level.FINEST, null, ex);
|
||||
}
|
||||
}
|
||||
try {
|
||||
reader.close();
|
||||
} catch (IOException ex) {
|
||||
LOGGER.log(Level.FINEST, null, ex);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Generates a report from a given Velocity Template. The template name provided can be the name of a template
|
||||
* contained in the jar file, such as 'XmlReport' or 'HtmlReport', or the template name can be the path to a
|
||||
@@ -186,67 +290,30 @@ public class ReportGenerator {
|
||||
* @throws IOException is thrown when the template file does not exist.
|
||||
* @throws Exception is thrown when an exception occurs.
|
||||
*/
|
||||
protected void generateReport(String templateName, String outFileName) throws IOException, Exception {
|
||||
InputStream input = null;
|
||||
String templatePath = null;
|
||||
final File f = new File(templateName);
|
||||
if (f.exists() && f.isFile()) {
|
||||
try {
|
||||
templatePath = templateName;
|
||||
input = new FileInputStream(f);
|
||||
} catch (FileNotFoundException ex) {
|
||||
final String msg = "Unable to generate the report, the report template file could not be found.";
|
||||
Logger.getLogger(ReportGenerator.class.getName()).log(Level.SEVERE, msg);
|
||||
Logger.getLogger(ReportGenerator.class.getName()).log(Level.FINE, null, ex);
|
||||
protected void generateReport(String templateName, String outFileName) throws Exception {
|
||||
File outFile = new File(outFileName);
|
||||
if (outFile.getParentFile() == null) {
|
||||
outFile = new File(".", outFileName);
|
||||
}
|
||||
if (!outFile.getParentFile().exists()) {
|
||||
final boolean created = outFile.getParentFile().mkdirs();
|
||||
if (!created) {
|
||||
throw new Exception("Unable to create directory '" + outFile.getParentFile().getAbsolutePath() + "'.");
|
||||
}
|
||||
} else {
|
||||
templatePath = "templates/" + templateName + ".vsl";
|
||||
input = this.getClass().getClassLoader().getResourceAsStream(templatePath);
|
||||
}
|
||||
if (input == null) {
|
||||
throw new IOException("Template file doesn't exist");
|
||||
}
|
||||
|
||||
final InputStreamReader reader = new InputStreamReader(input, "UTF-8");
|
||||
OutputStreamWriter writer = null;
|
||||
OutputStream outputStream = null;
|
||||
|
||||
OutputStream outputSteam = null;
|
||||
try {
|
||||
final File outDir = new File(outFileName).getParentFile();
|
||||
if (!outDir.exists()) {
|
||||
final boolean created = outDir.mkdirs();
|
||||
if (!created) {
|
||||
throw new Exception("Unable to create directory '" + outDir.getAbsolutePath() + "'.");
|
||||
}
|
||||
}
|
||||
|
||||
outputStream = new FileOutputStream(outFileName);
|
||||
writer = new OutputStreamWriter(outputStream, "UTF-8");
|
||||
|
||||
if (!engine.evaluate(context, writer, templatePath, reader)) {
|
||||
throw new Exception("Failed to convert the template into html.");
|
||||
}
|
||||
writer.flush();
|
||||
outputSteam = new FileOutputStream(outFile);
|
||||
generateReport(templateName, outputSteam);
|
||||
} finally {
|
||||
if (writer != null) {
|
||||
if (outputSteam != null) {
|
||||
try {
|
||||
writer.close();
|
||||
outputSteam.close();
|
||||
} catch (IOException ex) {
|
||||
Logger.getLogger(ReportGenerator.class.getName()).log(Level.FINEST, null, ex);
|
||||
LOGGER.log(Level.FINEST, "ignore", ex);
|
||||
}
|
||||
}
|
||||
if (outputStream != null) {
|
||||
try {
|
||||
outputStream.close();
|
||||
} catch (IOException ex) {
|
||||
Logger.getLogger(ReportGenerator.class.getName()).log(Level.FINEST, null, ex);
|
||||
}
|
||||
}
|
||||
try {
|
||||
reader.close();
|
||||
} catch (IOException ex) {
|
||||
Logger.getLogger(ReportGenerator.class.getName()).log(Level.FINEST, null, ex);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -19,7 +19,6 @@ package org.owasp.dependencycheck.reporting;
|
||||
|
||||
import java.util.logging.Level;
|
||||
import java.util.logging.Logger;
|
||||
import org.apache.velocity.app.Velocity;
|
||||
import org.apache.velocity.runtime.RuntimeServices;
|
||||
import org.apache.velocity.runtime.log.LogChute;
|
||||
|
||||
@@ -37,6 +36,11 @@ import org.apache.velocity.runtime.log.LogChute;
|
||||
*/
|
||||
public class VelocityLoggerRedirect implements LogChute {
|
||||
|
||||
/**
|
||||
* The Logger.
|
||||
*/
|
||||
private static final Logger LOGGER = Logger.getLogger(VelocityLoggerRedirect.class.getName());
|
||||
|
||||
/**
|
||||
* This will be invoked once by the LogManager.
|
||||
*
|
||||
@@ -54,7 +58,7 @@ public class VelocityLoggerRedirect implements LogChute {
|
||||
* @param message the message to be logged
|
||||
*/
|
||||
public void log(int level, String message) {
|
||||
Logger.getLogger(Velocity.class.getName()).log(getLevel(level), message);
|
||||
LOGGER.log(getLevel(level), message);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -66,7 +70,7 @@ public class VelocityLoggerRedirect implements LogChute {
|
||||
* @param t a throwable to log
|
||||
*/
|
||||
public void log(int level, String message, Throwable t) {
|
||||
Logger.getLogger(Velocity.class.getName()).log(getLevel(level), message, t);
|
||||
LOGGER.log(getLevel(level), message, t);
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -30,6 +30,11 @@ import org.xml.sax.SAXParseException;
|
||||
*/
|
||||
public class SuppressionErrorHandler implements ErrorHandler {
|
||||
|
||||
/**
|
||||
* The logger.
|
||||
*/
|
||||
private static final Logger LOGGER = Logger.getLogger(SuppressionErrorHandler.class.getName());
|
||||
|
||||
/**
|
||||
* Builds a prettier exception message.
|
||||
*
|
||||
@@ -65,7 +70,7 @@ public class SuppressionErrorHandler implements ErrorHandler {
|
||||
*/
|
||||
@Override
|
||||
public void warning(SAXParseException ex) throws SAXException {
|
||||
Logger.getLogger(SuppressionErrorHandler.class.getName()).log(Level.FINE, null, ex);
|
||||
LOGGER.log(Level.FINE, null, ex);
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -54,6 +54,10 @@ public class SuppressionHandler extends DefaultHandler {
|
||||
* The CWE element name.
|
||||
*/
|
||||
public static final String CWE = "cwe";
|
||||
/**
|
||||
* The GAV element name.
|
||||
*/
|
||||
public static final String GAV = "gav";
|
||||
/**
|
||||
* The cvssBelow element name.
|
||||
*/
|
||||
@@ -95,13 +99,16 @@ public class SuppressionHandler extends DefaultHandler {
|
||||
*/
|
||||
@Override
|
||||
public void startElement(String uri, String localName, String qName, Attributes attributes) throws SAXException {
|
||||
currentAttributes = null;
|
||||
currentAttributes = attributes;
|
||||
currentText = new StringBuffer();
|
||||
|
||||
if (SUPPRESS.equals(qName)) {
|
||||
rule = new SuppressionRule();
|
||||
} else if (FILE_PATH.equals(qName)) {
|
||||
currentAttributes = attributes;
|
||||
final String base = currentAttributes.getValue("base");
|
||||
if (base != null) {
|
||||
rule.setBase(Boolean.parseBoolean(base));
|
||||
} else {
|
||||
rule.setBase(false);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -123,6 +130,9 @@ public class SuppressionHandler extends DefaultHandler {
|
||||
rule.setFilePath(pt);
|
||||
} else if (SHA1.equals(qName)) {
|
||||
rule.setSha1(currentText.toString());
|
||||
} else if (GAV.equals(qName)) {
|
||||
final PropertyType pt = processPropertyType();
|
||||
rule.setGav(pt);
|
||||
} else if (CPE.equals(qName)) {
|
||||
final PropertyType pt = processPropertyType();
|
||||
rule.addCpe(pt);
|
||||
@@ -164,7 +174,7 @@ public class SuppressionHandler extends DefaultHandler {
|
||||
pt.setRegex(Boolean.parseBoolean(regex));
|
||||
}
|
||||
final String caseSensitive = currentAttributes.getValue("caseSensitive");
|
||||
if (regex != null) {
|
||||
if (caseSensitive != null) {
|
||||
pt.setCaseSensitive(Boolean.parseBoolean(caseSensitive));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -26,11 +26,6 @@ import java.io.IOException;
|
||||
*/
|
||||
public class SuppressionParseException extends IOException {
|
||||
|
||||
/**
|
||||
* The serial version UID.
|
||||
*/
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
/**
|
||||
* Creates a new SuppressionParseException.
|
||||
*/
|
||||
@@ -50,7 +45,7 @@ public class SuppressionParseException extends IOException {
|
||||
/**
|
||||
* Creates a new SuppressionParseException.
|
||||
*
|
||||
* @param ex the cause of the download failure.
|
||||
* @param ex the cause of the parse exception
|
||||
*/
|
||||
public SuppressionParseException(Throwable ex) {
|
||||
super(ex);
|
||||
@@ -60,7 +55,7 @@ public class SuppressionParseException extends IOException {
|
||||
* Creates a new SuppressionParseException.
|
||||
*
|
||||
* @param msg a message for the exception.
|
||||
* @param ex the cause of the download failure.
|
||||
* @param ex the cause of the parse exception
|
||||
*/
|
||||
public SuppressionParseException(String msg, Throwable ex) {
|
||||
super(msg, ex);
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user