mirror of
https://github.com/ysoftdevs/DependencyCheck.git
synced 2026-01-14 15:53:36 +01:00
Compare commits
1379 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
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 | ||
|
|
846173844e | ||
|
|
59c28d8e51 | ||
|
|
abdfa3ccf6 | ||
|
|
99ad6634c4 | ||
|
|
84556fb055 | ||
|
|
26e14e0151 | ||
|
|
3df2daa5cb | ||
|
|
c55efddc81 | ||
|
|
a59c8908f0 | ||
|
|
a421c5f952 | ||
|
|
37b0612d45 | ||
|
|
07bc94f9f6 | ||
|
|
82511880ac | ||
|
|
2f5cc6a8a4 | ||
|
|
f9a0f5e7a1 | ||
|
|
47b083eaca | ||
|
|
8fcf5ee760 | ||
|
|
f2006206d3 | ||
|
|
c32361a428 | ||
|
|
ac83c2bc3c | ||
|
|
32808c16e7 | ||
|
|
e4e2433396 | ||
|
|
8196b6e69e | ||
|
|
8dd49b6156 | ||
|
|
c4ab83a801 | ||
|
|
2c51b7b835 | ||
|
|
bab49d04b7 | ||
|
|
6963d66240 | ||
|
|
8cbf3ffc6b | ||
|
|
2a4693f6ed | ||
|
|
217256746c | ||
|
|
6c90225024 | ||
|
|
92d8a894e3 | ||
|
|
c89d619808 | ||
|
|
31dd4f6305 | ||
|
|
ff9715ede7 | ||
|
|
ffd1e383c2 | ||
|
|
2cc4f8c2fe | ||
|
|
6f513eb359 | ||
|
|
b235a5bb49 | ||
|
|
25f1912573 | ||
|
|
d24d6f6b52 | ||
|
|
afdb156c84 | ||
|
|
643d3600b8 | ||
|
|
9c51bff55b | ||
|
|
81c91b3877 | ||
|
|
3d365eb258 | ||
|
|
6857f6d8f8 | ||
|
|
81bd9991bb | ||
|
|
056fa9ded2 | ||
|
|
a3792c474b | ||
|
|
ec233dbb46 | ||
|
|
d89cd789ac | ||
|
|
69088e162d | ||
|
|
ec53bd4125 | ||
|
|
35a264d21c | ||
|
|
0372c2eccc | ||
|
|
08c7ffc6d9 | ||
|
|
e386f6ac20 | ||
|
|
60ab893888 | ||
|
|
f2d960c3eb | ||
|
|
fb88aeaeb9 | ||
|
|
94561de719 | ||
|
|
89ed18cea3 | ||
|
|
b996fa234b | ||
|
|
f6cd5cb4b2 | ||
|
|
6ac8caaf5f | ||
|
|
e5a4145e37 | ||
|
|
2c8b408bfb | ||
|
|
58c5c04feb | ||
|
|
b0d6070d28 | ||
|
|
3728594f73 | ||
|
|
dc2f1eabb2 | ||
|
|
eda08e7454 | ||
|
|
1bf4b6daa9 | ||
|
|
f757266282 | ||
|
|
0321823125 | ||
|
|
33d190afaa | ||
|
|
ff16c4f127 | ||
|
|
134728438e | ||
|
|
754bd68a87 | ||
|
|
bd32eeeaa2 | ||
|
|
1b9a3bd4bd | ||
|
|
584d369b0b | ||
|
|
0ebe052752 | ||
|
|
535863bc52 | ||
|
|
dd925cd92b | ||
|
|
5529de3d95 | ||
|
|
ce6b65adb8 | ||
|
|
9897109332 | ||
|
|
cfc851a99b | ||
|
|
380178ccc8 | ||
|
|
3227ddd9f9 | ||
|
|
336be63237 | ||
|
|
37c9b9e1f5 | ||
|
|
ebb3e02dcc | ||
|
|
352505c54f | ||
|
|
0c7998712e | ||
|
|
b9a20e7ac5 | ||
|
|
7ab89b900c | ||
|
|
9620956727 | ||
|
|
9b85768b7e | ||
|
|
5276e1863d | ||
|
|
0fc1a30a2c | ||
|
|
8609b98b1c | ||
|
|
c85514a17a | ||
|
|
d00bef5546 | ||
|
|
b905f46f98 | ||
|
|
cdd4765d38 | ||
|
|
d62793f4ad | ||
|
|
d83d325a49 | ||
|
|
e5baf99814 | ||
|
|
b4aeab3501 | ||
|
|
039bfd372d | ||
|
|
1a92de71d1 | ||
|
|
d8279e11aa | ||
|
|
b1b8584641 | ||
|
|
11e75df1a9 | ||
|
|
25fc2bfbea | ||
|
|
a93c84ff64 | ||
|
|
986a4182d9 | ||
|
|
d38a8b109b | ||
|
|
711d8c8c6b | ||
|
|
0d1d22aeff | ||
|
|
ac2231f0f3 | ||
|
|
21344dacfc | ||
|
|
ca22ba5bbc | ||
|
|
fc64c34214 | ||
|
|
c35bc2476d | ||
|
|
222826af95 | ||
|
|
db28db0bc7 | ||
|
|
931f7d47ea | ||
|
|
987ed1cefc | ||
|
|
3e9a77abfa | ||
|
|
3879eb6b3a | ||
|
|
5e5a2040fc | ||
|
|
eea44d7de2 | ||
|
|
3fcbf075fb | ||
|
|
b2641494cc | ||
|
|
c48a794aee | ||
|
|
e53906aea8 | ||
|
|
05a4a1670f | ||
|
|
4bd35852a5 | ||
|
|
be4d56f8d2 | ||
|
|
dfbcd616f2 | ||
|
|
dc0106348d | ||
|
|
f2666d4a30 | ||
|
|
4220e58d26 | ||
|
|
07de43981a | ||
|
|
fa352c1a8f | ||
|
|
e5d582b30b | ||
|
|
8fb14ffdf3 | ||
|
|
c16e85e7db | ||
|
|
25a72e3508 | ||
|
|
20411da67b | ||
|
|
81bfdc69dd | ||
|
|
5e2829fe49 | ||
|
|
2aba09f090 | ||
|
|
38e27309fb | ||
|
|
6b586684e6 | ||
|
|
773e280339 | ||
|
|
297a67cd00 | ||
|
|
ceb61ebe74 | ||
|
|
6c85e3502e | ||
|
|
690192300f | ||
|
|
3ba963f474 | ||
|
|
9b2cacc3a0 | ||
|
|
315a616293 | ||
|
|
3c56cd6738 | ||
|
|
a48ac013e8 | ||
|
|
258602ce1a | ||
|
|
c85b547502 | ||
|
|
d6266c36bf | ||
|
|
fdd7f30e9a | ||
|
|
3994ef3619 | ||
|
|
633028a63f | ||
|
|
013374e9db | ||
|
|
4358b47e91 | ||
|
|
6decc1ce30 | ||
|
|
8a3dba3064 | ||
|
|
27bcead1bc | ||
|
|
acb9c01776 | ||
|
|
79fd23d51b | ||
|
|
776614d211 | ||
|
|
b03a498cd7 | ||
|
|
b612926fb6 | ||
|
|
b67377f505 | ||
|
|
2033acbe2a | ||
|
|
e435cfc489 | ||
|
|
a3199a52af | ||
|
|
99be870ab9 | ||
|
|
9b2ecb4701 | ||
|
|
be7443a0a0 | ||
|
|
0de6557872 | ||
|
|
258e890056 | ||
|
|
d84bbad79a | ||
|
|
07e6477686 | ||
|
|
acde161412 | ||
|
|
8d8f9c6d26 | ||
|
|
c7507d9743 | ||
|
|
ff970fde56 | ||
|
|
2c4a997c64 | ||
|
|
5c787e0b69 | ||
|
|
41da8435cc | ||
|
|
84ecc4c664 | ||
|
|
d18a36af22 | ||
|
|
b3e766aa50 | ||
|
|
0cee54c51b | ||
|
|
41e436a183 | ||
|
|
743fc19fa3 | ||
|
|
76e8c66b1b | ||
|
|
4379ea63f0 | ||
|
|
00ae54b4b2 | ||
|
|
3a7fd7d271 | ||
|
|
94a0c98bfe | ||
|
|
c2b2b2698d | ||
|
|
9bb630bae6 | ||
|
|
c47b2f5b18 | ||
|
|
ecdc9a968d | ||
|
|
c041ff66e2 | ||
|
|
fe0e2d5c2d | ||
|
|
2cf3bca8de | ||
|
|
b2a817e17b | ||
|
|
d1ca951ffa | ||
|
|
b3932ae8c5 | ||
|
|
35223d5737 | ||
|
|
9d263f11e5 | ||
|
|
3f28b30e95 | ||
|
|
d797abdb1f | ||
|
|
3b3a940ee4 | ||
|
|
1b5b61b25e | ||
|
|
00d29b88df | ||
|
|
ab9bc9da74 | ||
|
|
b79f7b7ab8 | ||
|
|
9b34b5ca89 | ||
|
|
b486788993 | ||
|
|
563e9c51e1 | ||
|
|
6ab5e3ed4f | ||
|
|
43a6c81151 | ||
|
|
887a5d50a4 | ||
|
|
be68f8c3f7 | ||
|
|
86a4923157 | ||
|
|
f80ff31412 | ||
|
|
94acc82bf5 | ||
|
|
3c1a1fcca1 | ||
|
|
b3d08e4cb8 | ||
|
|
ab766ce85b | ||
|
|
bcb8245c61 | ||
|
|
c9e60d5c3a | ||
|
|
eb7c74eea7 | ||
|
|
40f5911ceb | ||
|
|
2a8809adbb | ||
|
|
39524c4064 | ||
|
|
c1cc2d6350 | ||
|
|
acb857f433 | ||
|
|
d343d92b17 | ||
|
|
43cb4716a9 | ||
|
|
6222561431 | ||
|
|
07b10e9e23 | ||
|
|
dffe8cef7a | ||
|
|
bb26626fd5 | ||
|
|
2f207de1a0 | ||
|
|
a69419ed04 | ||
|
|
be7c1ba914 | ||
|
|
461f6ad2c1 | ||
|
|
aff85cbfb8 | ||
|
|
c0ce4523fa | ||
|
|
65f8b3978d | ||
|
|
80ca3e114e | ||
|
|
330e803675 | ||
|
|
337e9ac3ef | ||
|
|
dfb78788f9 | ||
|
|
2dc560f583 | ||
|
|
7355400548 | ||
|
|
50b4630436 | ||
|
|
132d43f999 | ||
|
|
0627f20f5e | ||
|
|
40f329512b | ||
|
|
c196c08ada | ||
|
|
8f1e0d57bf | ||
|
|
c30c455a9f | ||
|
|
cd0e8e1c6b | ||
|
|
cbeb91f9a9 | ||
|
|
a3830989ba | ||
|
|
86427e2042 | ||
|
|
8f079de0aa | ||
|
|
651727c697 | ||
|
|
5c55f4d4bb | ||
|
|
c8502d3b7b | ||
|
|
22e3b9b544 | ||
|
|
f16db8298b | ||
|
|
cf4a32b260 | ||
|
|
b8d83c37d9 | ||
|
|
617f6bb8ef | ||
|
|
0c9f2bf5d2 | ||
|
|
eb9afecd66 | ||
|
|
2c1f2ae589 | ||
|
|
9387b09a19 | ||
|
|
f17f04f00a | ||
|
|
07f0192088 | ||
|
|
0fd19f0de8 | ||
|
|
e954fa6478 | ||
|
|
a0fdfc0f39 | ||
|
|
57a4372b65 | ||
|
|
c11cb38269 | ||
|
|
e4fd446946 | ||
|
|
714d8ac3ba | ||
|
|
f09293e077 | ||
|
|
389e8bc325 | ||
|
|
367f763ce5 | ||
|
|
3febed82f1 | ||
|
|
8a6371fe68 | ||
|
|
93937feb13 | ||
|
|
21e62d8597 | ||
|
|
88e8019858 | ||
|
|
cbe562a204 | ||
|
|
4dc40389a3 | ||
|
|
0552f10c38 | ||
|
|
c9ac7401e8 | ||
|
|
60625b9978 | ||
|
|
b4b53cfa4c | ||
|
|
f1e1d67f4e | ||
|
|
982641752f | ||
|
|
ba66cbbc95 | ||
|
|
750d13a300 | ||
|
|
3c69a87fc2 | ||
|
|
dbaddab07b | ||
|
|
1d58811680 | ||
|
|
4d78fe9ca4 | ||
|
|
56d3082696 | ||
|
|
8f573aba2f | ||
|
|
96633360d0 | ||
|
|
8ae7935cee | ||
|
|
68e860baad | ||
|
|
38ead3133f | ||
|
|
553d1f85c4 | ||
|
|
d9a985ff38 | ||
|
|
d3a2d2b248 | ||
|
|
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 |
3
.gitignore
vendored
3
.gitignore
vendored
@@ -7,6 +7,9 @@
|
||||
# Eclipse project files
|
||||
.classpath
|
||||
.project
|
||||
.settings
|
||||
maven-eclipse.xml
|
||||
.externalToolBuilders
|
||||
# Netbeans configuration
|
||||
nb-configuration.xml
|
||||
/target/
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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.2.1</version>
|
||||
<version>1.2.7</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>
|
||||
@@ -324,6 +323,9 @@ Copyright (c) 2013 - Jeremy Long. All Rights Reserved.
|
||||
<groupId>org.apache.maven.plugins</groupId>
|
||||
<artifactId>maven-javadoc-plugin</artifactId>
|
||||
<version>2.9.1</version>
|
||||
<configuration>
|
||||
<bottom>Copyright© 2012-14 Jeremy Long. All Rights Reserved.</bottom>
|
||||
</configuration>
|
||||
<reportSets>
|
||||
<reportSet>
|
||||
<id>default</id>
|
||||
@@ -439,6 +441,11 @@ Copyright (c) 2013 - 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>
|
||||
<dependency>
|
||||
<groupId>org.owasp</groupId>
|
||||
<artifactId>dependency-check-core</artifactId>
|
||||
|
||||
@@ -285,26 +285,50 @@ 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.
|
||||
@@ -935,7 +959,7 @@ 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.
|
||||
* properties required to change the proxy server, port, and connection timeout.
|
||||
*/
|
||||
private void populateSettings() {
|
||||
Settings.initialize();
|
||||
@@ -967,8 +991,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);
|
||||
|
||||
@@ -32,7 +32,7 @@ failBuildOnCVSS | Specifies if the build should be failed if a CVSS score a
|
||||
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) |
|
||||
proxyUrl | The Proxy URL. |
|
||||
proxyServer | The Proxy Server. |
|
||||
proxyPort | The Proxy Port. |
|
||||
proxyUsername | Defines the proxy user name. |
|
||||
proxyPassword | Defines the proxy password. |
|
||||
@@ -46,17 +46,17 @@ 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
|
||||
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 Jar Analyzer will be used. | true
|
||||
nexusAnalyzerEnabled | Sets whether Nexus Analyzer will be used. | true
|
||||
nexusUrl | Defines the Nexus URL. | https://repository.sonatype.org/service/local/
|
||||
jarAnalyzer | Sets whether Jar Analyzer will be used. | true
|
||||
nexusAnalyzerEnabled | Sets whether Nexus Analyzer will be used. | 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 |
|
||||
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
|
||||
====================
|
||||
|
||||
@@ -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
|
||||
@@ -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.2.1</version>
|
||||
<version>1.2.7</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>
|
||||
@@ -174,6 +173,9 @@ Copyright (c) 2012 - Jeremy Long. All Rights Reserved.
|
||||
<groupId>org.apache.maven.plugins</groupId>
|
||||
<artifactId>maven-javadoc-plugin</artifactId>
|
||||
<version>2.9.1</version>
|
||||
<configuration>
|
||||
<bottom>Copyright© 2012-14 Jeremy Long. All Rights Reserved.</bottom>
|
||||
</configuration>
|
||||
<reportSets>
|
||||
<reportSet>
|
||||
<id>default</id>
|
||||
@@ -284,12 +286,12 @@ Copyright (c) 2012 - Jeremy Long. All Rights Reserved.
|
||||
<plugin>
|
||||
<groupId>org.codehaus.mojo</groupId>
|
||||
<artifactId>appassembler-maven-plugin</artifactId>
|
||||
<version>1.7</version>
|
||||
<version>1.8.1</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>
|
||||
@@ -341,5 +343,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;
|
||||
@@ -93,7 +97,11 @@ public class App {
|
||||
cli.printVersionInfo();
|
||||
} else if (cli.isRunScan()) {
|
||||
populateSettings(cli);
|
||||
runScan(cli.getReportDirectory(), cli.getReportFormat(), cli.getApplicationName(), cli.getScanFiles());
|
||||
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();
|
||||
}
|
||||
@@ -106,18 +114,71 @@ 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) {
|
||||
Engine scanner = null;
|
||||
private void runScan(String reportDirectory, String outputFormat, String applicationName, String[] files,
|
||||
String[] excludes) throws InvalidScanPathException {
|
||||
Engine engine = null;
|
||||
try {
|
||||
scanner = new Engine();
|
||||
|
||||
for (String file : files) {
|
||||
scanner.scan(file);
|
||||
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);
|
||||
}
|
||||
|
||||
scanner.analyzeDependencies();
|
||||
final List<Dependency> dependencies = scanner.getDependencies();
|
||||
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 {
|
||||
@@ -131,7 +192,7 @@ public class App {
|
||||
cve.close();
|
||||
}
|
||||
}
|
||||
final ReportGenerator report = new ReportGenerator(applicationName, dependencies, scanner.getAnalyzers(), prop);
|
||||
final ReportGenerator report = new ReportGenerator(applicationName, dependencies, engine.getAnalyzers(), prop);
|
||||
try {
|
||||
report.generateReports(reportDirectory, outputFormat);
|
||||
} catch (IOException ex) {
|
||||
@@ -145,8 +206,8 @@ public class App {
|
||||
LOGGER.log(Level.SEVERE, "Unable to connect to the dependency-check database; analysis has stopped");
|
||||
LOGGER.log(Level.FINE, "", ex);
|
||||
} finally {
|
||||
if (scanner != null) {
|
||||
scanner.cleanup();
|
||||
if (engine != null) {
|
||||
engine.cleanup();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -161,7 +222,7 @@ public class App {
|
||||
|
||||
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();
|
||||
@@ -212,8 +273,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);
|
||||
|
||||
@@ -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;
|
||||
@@ -39,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.
|
||||
*/
|
||||
@@ -85,16 +90,16 @@ public final class CliParser {
|
||||
*/
|
||||
private void validateArgs() throws FileNotFoundException, ParseException {
|
||||
if (isRunScan()) {
|
||||
validatePathExists(getScanFiles(), ArgumentName.SCAN);
|
||||
validatePathExists(getReportDirectory(), ArgumentName.OUT);
|
||||
validatePathExists(getScanFiles(), ARGUMENT.SCAN);
|
||||
validatePathExists(getReportDirectory(), ARGUMENT.OUT);
|
||||
if (getPathToMono() != null) {
|
||||
validatePathExists(getPathToMono(), ArgumentName.PATH_TO_MONO);
|
||||
validatePathExists(getPathToMono(), ARGUMENT.PATH_TO_MONO);
|
||||
}
|
||||
if (!line.hasOption(ArgumentName.APP_NAME)) {
|
||||
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) {
|
||||
@@ -129,14 +134,36 @@ public final class CliParser {
|
||||
* @throws FileNotFoundException is thrown if the path being validated does not exist.
|
||||
*/
|
||||
private void validatePathExists(String path, String argumentName) throws FileNotFoundException {
|
||||
if (!path.contains("*.")) {
|
||||
final File f = new File(path);
|
||||
if (!f.exists()) {
|
||||
isValid = false;
|
||||
final String msg = String.format("Invalid '%s' argument: '%s'", argumentName, path);
|
||||
throw new FileNotFoundException(msg);
|
||||
if (path == null) {
|
||||
isValid = false;
|
||||
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".equals(argumentName.substring(0, 1).toLowerCase()) && !"ALL".equals(this.getReportFormat().toUpperCase())) {
|
||||
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 { // TODO add a validation for *.zip extensions rather then relying on the engine to validate it.
|
||||
} 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);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -146,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;
|
||||
}
|
||||
|
||||
@@ -162,44 +188,50 @@ 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. To limit the scan"
|
||||
+ " to specific file types *.[ext] can be added to the end of the path.")
|
||||
.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.SUPPRESSION_FILE)
|
||||
final Option suppressionFile = OptionBuilder.withArgName("file").hasArg().withLongOpt(ARGUMENT.SUPPRESSION_FILE)
|
||||
.withDescription("The file path to the suppression XML file.")
|
||||
.create();
|
||||
|
||||
@@ -207,7 +239,11 @@ public final class CliParser {
|
||||
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)
|
||||
@@ -230,87 +266,87 @@ 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(ArgumentName.DISABLE_JAR)
|
||||
final Option disableJarAnalyzer = OptionBuilder.withLongOpt(ARGUMENT.DISABLE_JAR)
|
||||
.withDescription("Disable the Jar Analyzer.")
|
||||
.create();
|
||||
final Option disableArchiveAnalyzer = OptionBuilder.withLongOpt(ArgumentName.DISABLE_ARCHIVE)
|
||||
final Option disableArchiveAnalyzer = OptionBuilder.withLongOpt(ARGUMENT.DISABLE_ARCHIVE)
|
||||
.withDescription("Disable the Archive Analyzer.")
|
||||
.create();
|
||||
final Option disableNuspecAnalyzer = OptionBuilder.withLongOpt(ArgumentName.DISABLE_NUSPEC)
|
||||
final Option disableNuspecAnalyzer = OptionBuilder.withLongOpt(ARGUMENT.DISABLE_NUSPEC)
|
||||
.withDescription("Disable the Nuspec Analyzer.")
|
||||
.create();
|
||||
final Option disableAssemblyAnalyzer = OptionBuilder.withLongOpt(ArgumentName.DISABLE_ASSEMBLY)
|
||||
final Option disableAssemblyAnalyzer = OptionBuilder.withLongOpt(ARGUMENT.DISABLE_ASSEMBLY)
|
||||
.withDescription("Disable the .NET Assembly Analyzer.")
|
||||
.create();
|
||||
|
||||
final Option disableNexusAnalyzer = OptionBuilder.withLongOpt(ArgumentName.DISABLE_NEXUS)
|
||||
final Option disableNexusAnalyzer = OptionBuilder.withLongOpt(ARGUMENT.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.")
|
||||
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(ArgumentName.NEXUS_USES_PROXY)
|
||||
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(ArgumentName.ADDITIONAL_ZIP_EXTENSIONS)
|
||||
.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(ArgumentName.PATH_TO_MONO)
|
||||
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)
|
||||
@@ -331,13 +367,30 @@ public final class CliParser {
|
||||
.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);
|
||||
}
|
||||
|
||||
/**
|
||||
* Determines if the 'version' command line argument was passed in.
|
||||
*
|
||||
* @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);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -346,7 +399,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);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -355,7 +408,7 @@ 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);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -364,7 +417,7 @@ public final class CliParser {
|
||||
* @return true if the disableJar command line argument was specified; otherwise false
|
||||
*/
|
||||
public boolean isJarDisabled() {
|
||||
return (line != null) && line.hasOption(ArgumentName.DISABLE_JAR);
|
||||
return (line != null) && line.hasOption(ARGUMENT.DISABLE_JAR);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -373,7 +426,7 @@ public final class CliParser {
|
||||
* @return true if the disableArchive command line argument was specified; otherwise false
|
||||
*/
|
||||
public boolean isArchiveDisabled() {
|
||||
return (line != null) && line.hasOption(ArgumentName.DISABLE_ARCHIVE);
|
||||
return (line != null) && line.hasOption(ARGUMENT.DISABLE_ARCHIVE);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -382,7 +435,7 @@ public final class CliParser {
|
||||
* @return true if the disableNuspec command line argument was specified; otherwise false
|
||||
*/
|
||||
public boolean isNuspecDisabled() {
|
||||
return (line != null) && line.hasOption(ArgumentName.DISABLE_NUSPEC);
|
||||
return (line != null) && line.hasOption(ARGUMENT.DISABLE_NUSPEC);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -391,7 +444,7 @@ public final class CliParser {
|
||||
* @return true if the disableAssembly command line argument was specified; otherwise false
|
||||
*/
|
||||
public boolean isAssemblyDisabled() {
|
||||
return (line != null) && line.hasOption(ArgumentName.DISABLE_ASSEMBLY);
|
||||
return (line != null) && line.hasOption(ARGUMENT.DISABLE_ASSEMBLY);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -400,7 +453,7 @@ 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);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -409,10 +462,10 @@ 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);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -425,14 +478,14 @@ public final class CliParser {
|
||||
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(ArgumentName.NEXUS_USES_PROXY)) {
|
||||
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(ArgumentName.NEXUS_USES_PROXY));
|
||||
return Boolean.parseBoolean(line.getOptionValue(ARGUMENT.NEXUS_USES_PROXY));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -443,7 +496,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"
|
||||
@@ -457,7 +510,6 @@ public final class CliParser {
|
||||
options,
|
||||
"",
|
||||
true);
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -466,7 +518,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);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -475,7 +536,7 @@ public final class CliParser {
|
||||
* @return the path to the reports directory.
|
||||
*/
|
||||
public String getReportDirectory() {
|
||||
return line.getOptionValue(ArgumentName.OUT, ".");
|
||||
return line.getOptionValue(ARGUMENT.OUT, ".");
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -484,7 +545,7 @@ public final class CliParser {
|
||||
* @return the path to Mono
|
||||
*/
|
||||
public String getPathToMono() {
|
||||
return line.getOptionValue(ArgumentName.PATH_TO_MONO);
|
||||
return line.getOptionValue(ARGUMENT.PATH_TO_MONO);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -493,7 +554,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");
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -502,7 +563,7 @@ public final class CliParser {
|
||||
* @return the application name.
|
||||
*/
|
||||
public String getApplicationName() {
|
||||
return line.getOptionValue(ArgumentName.APP_NAME);
|
||||
return line.getOptionValue(ARGUMENT.APP_NAME);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -511,16 +572,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;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -529,7 +598,7 @@ public final class CliParser {
|
||||
* @return the proxy port
|
||||
*/
|
||||
public String getProxyPort() {
|
||||
return line.getOptionValue(ArgumentName.PROXY_PORT);
|
||||
return line.getOptionValue(ARGUMENT.PROXY_PORT);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -538,7 +607,7 @@ public final class CliParser {
|
||||
* @return the proxy username
|
||||
*/
|
||||
public String getProxyUsername() {
|
||||
return line.getOptionValue(ArgumentName.PROXY_USERNAME);
|
||||
return line.getOptionValue(ARGUMENT.PROXY_USERNAME);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -547,7 +616,7 @@ public final class CliParser {
|
||||
* @return the proxy password
|
||||
*/
|
||||
public String getProxyPassword() {
|
||||
return line.getOptionValue(ArgumentName.PROXY_PASSWORD);
|
||||
return line.getOptionValue(ARGUMENT.PROXY_PASSWORD);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -556,7 +625,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);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -565,7 +634,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);
|
||||
}
|
||||
@@ -578,7 +647,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);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -587,7 +656,7 @@ public final class CliParser {
|
||||
* @return the path to the suppression file
|
||||
*/
|
||||
public String getSuppressionFile() {
|
||||
return line.getOptionValue(ArgumentName.SUPPRESSION_FILE);
|
||||
return line.getOptionValue(ARGUMENT.SUPPRESSION_FILE);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -598,8 +667,8 @@ 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);
|
||||
}
|
||||
|
||||
@@ -610,7 +679,7 @@ public final class CliParser {
|
||||
* @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);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -619,7 +688,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);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -628,7 +697,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);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -637,7 +706,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);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -646,7 +715,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);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -655,7 +724,7 @@ 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);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -664,13 +733,13 @@ public final class CliParser {
|
||||
* @return the additional Extensions; otherwise null is returned
|
||||
*/
|
||||
public String getAdditionalZipExtensions() {
|
||||
return line.getOptionValue(ArgumentName.ADDITIONAL_ZIP_EXTENSIONS);
|
||||
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.
|
||||
@@ -732,21 +801,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.
|
||||
@@ -848,5 +916,9 @@ public final class CliParser {
|
||||
* 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;
|
||||
@@ -3,11 +3,12 @@ Command Line Arguments
|
||||
|
||||
The following table lists the command line arguments:
|
||||
|
||||
Short | Argument Name | Parameter | Description | Requirement
|
||||
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 specific file types that should be scanned by supplying a scan path of '[path]/[to]/[scan]/*.zip'. The wild card can only be used to denote any file-name with a specific extension. | Required
|
||||
\-o | \-\-out | \<folder\> | The folder to write reports to. This defaults to the current directory. | Optional
|
||||
\-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
|
||||
@@ -18,26 +19,25 @@ Short | Argument Name | Parameter | Description | Requirement
|
||||
|
||||
Advanced Options
|
||||
================
|
||||
Short | Argument Name | Parameter | Description | Default Value
|
||||
-------|-----------------------|-----------------|-------------|---------------
|
||||
| \-\-disableArchive | | Sets whether the Archive Analyzer will be used. | false
|
||||
Short | Argument Name | Parameter | Description | Default Value
|
||||
-------|-----------------------|-----------------|-----------------------------------------------------------------------------|---------------
|
||||
| \-\-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 Jar Analyzer will be used. | false
|
||||
| \-\-disableNexus | | Sets whether Nexus Analyzer will be used. | false
|
||||
| \-\-disableNexus | | Disable the Nexus Analyzer. |
|
||||
| \-\-nexus | \<url\> | The url to the Nexus Server. | https://repository.sonatype.org/service/local/
|
||||
| \-\-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. |
|
||||
| \-\-proxyurl | \<url\> | The proxy url to use when downloading resources. |
|
||||
| \-\-proxyport | \<port\> | The proxy port to use when downloading resources. |
|
||||
| \-\-disableJar | | Sets whether Jar Analyzer will be used. | false
|
||||
| \-\-disableNexus | | Sets whether Nexus Analyzer will be used. | 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. |
|
||||
| \-\-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. |
|
||||
| \-\-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. |
|
||||
|
||||
@@ -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;
|
||||
@@ -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.2.1</version>
|
||||
<version>1.2.7</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>
|
||||
@@ -220,6 +220,11 @@ Copyright (c) 2012 Jeremy Long. All Rights Reserved.
|
||||
<name>data.directory</name>
|
||||
<value>${project.build.directory}/data</value>
|
||||
</property>
|
||||
<property>
|
||||
<name>temp.directory</name>
|
||||
<value>${project.build.directory}/temp</value>
|
||||
</property>
|
||||
|
||||
</systemProperties>
|
||||
<includes>
|
||||
<include>**/*IntegrationTest.java</include>
|
||||
@@ -267,6 +272,9 @@ Copyright (c) 2012 Jeremy Long. All Rights Reserved.
|
||||
<groupId>org.apache.maven.plugins</groupId>
|
||||
<artifactId>maven-javadoc-plugin</artifactId>
|
||||
<version>2.9.1</version>
|
||||
<configuration>
|
||||
<bottom>Copyright© 2012-14 Jeremy Long. All Rights Reserved.</bottom>
|
||||
</configuration>
|
||||
<reportSets>
|
||||
<reportSet>
|
||||
<id>default</id>
|
||||
@@ -392,6 +400,7 @@ Copyright (c) 2012 Jeremy Long. All Rights Reserved.
|
||||
<version>3.1</version>
|
||||
<configuration>
|
||||
<showDeprecation>false</showDeprecation>
|
||||
<compilerArgument>-Xlint:unchecked</compilerArgument>
|
||||
<source>1.6</source>
|
||||
<target>1.6</target>
|
||||
</configuration>
|
||||
@@ -399,12 +408,23 @@ Copyright (c) 2012 Jeremy Long. All Rights Reserved.
|
||||
</plugins>
|
||||
</build>
|
||||
<dependencies>
|
||||
<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>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.jmockit</groupId>
|
||||
<artifactId>jmockit</artifactId>
|
||||
<version>1.12</version>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>com.google.code.findbugs</groupId>
|
||||
<artifactId>annotations</artifactId>
|
||||
@@ -419,7 +439,7 @@ Copyright (c) 2012 Jeremy Long. All Rights Reserved.
|
||||
<dependency>
|
||||
<groupId>org.apache.commons</groupId>
|
||||
<artifactId>commons-compress</artifactId>
|
||||
<version>1.8</version>
|
||||
<version>1.8.1</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>commons-io</groupId>
|
||||
@@ -451,50 +471,6 @@ Copyright (c) 2012 Jeremy Long. All Rights Reserved.
|
||||
<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>
|
||||
@@ -521,6 +497,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>
|
||||
@@ -601,6 +584,13 @@ Copyright (c) 2012 Jeremy Long. All Rights Reserved.
|
||||
<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>
|
||||
@@ -717,6 +707,28 @@ Copyright (c) 2012 Jeremy Long. All Rights Reserved.
|
||||
<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>
|
||||
|
||||
</dependencies>
|
||||
</profile>
|
||||
</profiles>
|
||||
|
||||
@@ -31,8 +31,6 @@ import org.owasp.dependencycheck.analyzer.Analyzer;
|
||||
import org.owasp.dependencycheck.analyzer.AnalyzerService;
|
||||
import org.owasp.dependencycheck.analyzer.FileTypeAnalyzer;
|
||||
import org.owasp.dependencycheck.analyzer.exception.AnalysisException;
|
||||
import org.owasp.dependencycheck.data.cpe.CpeMemoryIndex;
|
||||
import org.owasp.dependencycheck.data.cpe.IndexException;
|
||||
import org.owasp.dependencycheck.data.nvdcve.ConnectionFactory;
|
||||
import org.owasp.dependencycheck.data.nvdcve.CveDB;
|
||||
import org.owasp.dependencycheck.data.nvdcve.DatabaseException;
|
||||
@@ -57,19 +55,21 @@ public class Engine {
|
||||
/**
|
||||
* The list of dependencies.
|
||||
*/
|
||||
private 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 Map of analyzers grouped by Analysis phase.
|
||||
*/
|
||||
private final Set<FileTypeAnalyzer> fileTypeAnalyzers;
|
||||
private Set<FileTypeAnalyzer> fileTypeAnalyzers = new HashSet<FileTypeAnalyzer>();
|
||||
|
||||
/**
|
||||
* The ClassLoader to use when dynamically loading Analyzer and Update services.
|
||||
*/
|
||||
private ClassLoader serviceClassLoader;
|
||||
private ClassLoader serviceClassLoader = Thread.currentThread().getContextClassLoader();
|
||||
/**
|
||||
* The Logger for use throughout the class.
|
||||
*/
|
||||
@@ -81,32 +81,27 @@ public class Engine {
|
||||
* @throws DatabaseException thrown if there is an error connecting to the database
|
||||
*/
|
||||
public Engine() throws DatabaseException {
|
||||
this(Thread.currentThread().getContextClassLoader());
|
||||
initializeEngine();
|
||||
}
|
||||
|
||||
/**
|
||||
* 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.
|
||||
*
|
||||
* @param serviceClassLoader the ClassLoader to use when dynamically loading Analyzer and Update services
|
||||
* @throws DatabaseException thrown if there is an error connecting to the database
|
||||
*/
|
||||
public Engine(ClassLoader serviceClassLoader) throws DatabaseException {
|
||||
this.dependencies = new ArrayList<Dependency>();
|
||||
this.analyzers = new EnumMap<AnalysisPhase, List<Analyzer>>(AnalysisPhase.class);
|
||||
this.fileTypeAnalyzers = new HashSet<FileTypeAnalyzer>();
|
||||
this.serviceClassLoader = serviceClassLoader;
|
||||
|
||||
protected final void initializeEngine() throws DatabaseException {
|
||||
ConnectionFactory.initialize();
|
||||
|
||||
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();
|
||||
}
|
||||
loadAnalyzers();
|
||||
}
|
||||
|
||||
@@ -121,7 +116,9 @@ public class Engine {
|
||||
* Loads the analyzers specified in the configuration file (or system properties).
|
||||
*/
|
||||
private void loadAnalyzers() {
|
||||
|
||||
if (analyzers.size() > 0) {
|
||||
return;
|
||||
}
|
||||
for (AnalysisPhase phase : AnalysisPhase.values()) {
|
||||
analyzers.put(phase, new ArrayList<Analyzer>());
|
||||
}
|
||||
@@ -158,157 +155,193 @@ public class Engine {
|
||||
|
||||
public void setDependencies(List<Dependency> dependencies) {
|
||||
this.dependencies = dependencies;
|
||||
//for (Dependency dependency: dependencies) {
|
||||
// dependencies.add(dependency);
|
||||
//}
|
||||
}
|
||||
|
||||
/**
|
||||
* 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) {
|
||||
if (path.matches("^.*[\\/]\\*\\.[^\\/:*|?<>\"]+$")) {
|
||||
final String[] parts = path.split("\\*\\.");
|
||||
final String[] ext = new String[]{parts[parts.length - 1]};
|
||||
final File dir = new File(path.substring(0, path.length() - ext[0].length() - 2));
|
||||
if (dir.isDirectory()) {
|
||||
final List<File> files = (List<File>) org.apache.commons.io.FileUtils.listFiles(dir, ext, true);
|
||||
scan(files);
|
||||
} else {
|
||||
final String msg = String.format("Invalid file path provided to scan '%s'", path);
|
||||
LOGGER.log(Level.SEVERE, msg);
|
||||
}
|
||||
} else {
|
||||
final File file = new File(path);
|
||||
scan(file);
|
||||
}
|
||||
public List<Dependency> scan(String path) {
|
||||
final File file = new File(path);
|
||||
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.log(Level.FINE, msg);
|
||||
return;
|
||||
return null;
|
||||
}
|
||||
final String fileName = file.getName();
|
||||
final String extension = FileUtils.getFileExtension(fileName);
|
||||
Dependency dependency = null;
|
||||
if (extension != null) {
|
||||
if (supportsExtension(extension)) {
|
||||
final Dependency dependency = new Dependency(file);
|
||||
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());
|
||||
final String msg = String.format("No file extension found on file '%s'. The file was not analyzed.", file.toString());
|
||||
LOGGER.log(Level.FINEST, 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();
|
||||
@@ -337,7 +370,7 @@ public class Engine {
|
||||
final List<Analyzer> analyzerList = analyzers.get(phase);
|
||||
|
||||
for (Analyzer a : analyzerList) {
|
||||
initializeAnalyzer(a);
|
||||
a = initializeAnalyzer(a);
|
||||
|
||||
/* need to create a copy of the collection because some of the
|
||||
* analyzers may modify it. This prevents ConcurrentModificationExceptions.
|
||||
@@ -392,8 +425,9 @@ public class Engine {
|
||||
* Initializes the given analyzer.
|
||||
*
|
||||
* @param analyzer the analyzer to initialize
|
||||
* @return the initialized analyzer
|
||||
*/
|
||||
private void initializeAnalyzer(Analyzer analyzer) {
|
||||
protected Analyzer initializeAnalyzer(Analyzer analyzer) {
|
||||
try {
|
||||
final String msg = String.format("Initializing %s", analyzer.getName());
|
||||
LOGGER.log(Level.FINE, msg);
|
||||
@@ -408,6 +442,7 @@ public class Engine {
|
||||
LOGGER.log(Level.FINEST, null, ex1);
|
||||
}
|
||||
}
|
||||
return analyzer;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -415,7 +450,7 @@ public class Engine {
|
||||
*
|
||||
* @param analyzer the analyzer to close
|
||||
*/
|
||||
private void closeAnalyzer(Analyzer analyzer) {
|
||||
protected void closeAnalyzer(Analyzer analyzer) {
|
||||
final String msg = String.format("Closing Analyzer '%s'", analyzer.getName());
|
||||
LOGGER.log(Level.FINE, msg);
|
||||
try {
|
||||
@@ -429,6 +464,7 @@ public class Engine {
|
||||
* Cycles through the cached web data sources and calls update on all of them.
|
||||
*/
|
||||
private void doUpdates() {
|
||||
LOGGER.info("Checking for updates");
|
||||
final UpdateService service = new UpdateService(serviceClassLoader);
|
||||
final Iterator<CachedWebDataSource> iterator = service.getDataSources();
|
||||
while (iterator.hasNext()) {
|
||||
@@ -438,10 +474,10 @@ public class Engine {
|
||||
} catch (UpdateException ex) {
|
||||
LOGGER.log(Level.WARNING,
|
||||
"Unable to update Cached Web DataSource, using local data instead. Results may not include recent vulnerabilities.");
|
||||
LOGGER.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");
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -484,22 +520,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");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -13,7 +13,7 @@
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*
|
||||
* Copyright (c) 2014 Jeremy Long. All Rights Reserved.
|
||||
* Copyright (c) 2014 Steve Springett. All Rights Reserved.
|
||||
*/
|
||||
package org.owasp.dependencycheck.agent;
|
||||
|
||||
@@ -234,26 +234,49 @@ public class DependencyCheckScanAgent {
|
||||
}
|
||||
|
||||
/**
|
||||
* 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 proxyServer new value of proxyServer
|
||||
*/
|
||||
public void setProxyServer(String proxyServer) {
|
||||
this.proxyServer = proxyServer;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the value of proxyServer.
|
||||
*
|
||||
* @return the value of proxyServer
|
||||
* @deprecated use {@link org.owasp.dependencycheck.agent.DependencyCheckScanAgent#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.agent.DependencyCheckScanAgent#setProxyServer(java.lang.String)
|
||||
* } instead
|
||||
*/
|
||||
@Deprecated
|
||||
public void setProxyUrl(String proxyUrl) {
|
||||
this.proxyUrl = proxyUrl;
|
||||
this.proxyServer = proxyUrl;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -417,6 +440,52 @@ public class DependencyCheckScanAgent {
|
||||
this.showSummary = showSummary;
|
||||
}
|
||||
|
||||
/**
|
||||
* Whether or not the Maven Central analyzer is enabled.
|
||||
*/
|
||||
private boolean centralAnalyzerEnabled = true;
|
||||
|
||||
/**
|
||||
* 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;
|
||||
}
|
||||
|
||||
/**
|
||||
* The URL of Maven Central.
|
||||
*/
|
||||
private String centralUrl;
|
||||
|
||||
/**
|
||||
* Get the value of centralUrl.
|
||||
*
|
||||
* @return the value of centralUrl
|
||||
*/
|
||||
public String getCentralUrl() {
|
||||
return centralUrl;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the value of centralUrl.
|
||||
*
|
||||
* @param centralUrl new value of centralUrl
|
||||
*/
|
||||
public void setCentralUrl(String centralUrl) {
|
||||
this.centralUrl = centralUrl;
|
||||
}
|
||||
|
||||
/**
|
||||
* Whether or not the nexus analyzer is enabled.
|
||||
*/
|
||||
@@ -792,7 +861,7 @@ public class DependencyCheckScanAgent {
|
||||
|
||||
/**
|
||||
* 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.
|
||||
* properties required to change the proxy server, port, and connection timeout.
|
||||
*/
|
||||
private void populateSettings() {
|
||||
Settings.initialize();
|
||||
@@ -808,8 +877,8 @@ public class DependencyCheckScanAgent {
|
||||
|
||||
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);
|
||||
@@ -826,6 +895,10 @@ public class DependencyCheckScanAgent {
|
||||
if (suppressionFile != null && !suppressionFile.isEmpty()) {
|
||||
Settings.setString(Settings.KEYS.SUPPRESSION_FILE, suppressionFile);
|
||||
}
|
||||
Settings.setBoolean(Settings.KEYS.ANALYZER_CENTRAL_ENABLED, centralAnalyzerEnabled);
|
||||
if (centralUrl != null && !centralUrl.isEmpty()) {
|
||||
Settings.setString(Settings.KEYS.ANALYZER_CENTRAL_URL, centralUrl);
|
||||
}
|
||||
Settings.setBoolean(Settings.KEYS.ANALYZER_NEXUS_ENABLED, nexusAnalyzerEnabled);
|
||||
if (nexusUrl != null && !nexusUrl.isEmpty()) {
|
||||
Settings.setString(Settings.KEYS.ANALYZER_NEXUS_URL, nexusUrl);
|
||||
|
||||
@@ -98,11 +98,17 @@ public abstract class AbstractSuppressionAnalyzer extends AbstractAnalyzer {
|
||||
* @throws SuppressionParseException thrown if the XML cannot be parsed.
|
||||
*/
|
||||
private void loadSuppressionData() throws SuppressionParseException {
|
||||
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;
|
||||
}
|
||||
File file = null;
|
||||
boolean deleteTempFile = false;
|
||||
try {
|
||||
final Pattern uriRx = Pattern.compile("^(https?|file)\\:.*", Pattern.CASE_INSENSITIVE);
|
||||
@@ -132,9 +138,9 @@ public abstract class AbstractSuppressionAnalyzer extends AbstractAnalyzer {
|
||||
}
|
||||
|
||||
if (file != null) {
|
||||
final SuppressionParser parser = new SuppressionParser();
|
||||
try {
|
||||
rules = parser.parseSuppressionRules(file);
|
||||
//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());
|
||||
|
||||
@@ -110,7 +110,7 @@ public class ArchiveAnalyzer extends AbstractFileTypeAnalyzer {
|
||||
static {
|
||||
final String additionalZipExt = Settings.getString(Settings.KEYS.ADDITIONAL_ZIP_EXTENSIONS);
|
||||
if (additionalZipExt != null) {
|
||||
final HashSet ext = new HashSet<String>(Arrays.asList(additionalZipExt));
|
||||
final HashSet<String> ext = new HashSet<String>(Arrays.asList(additionalZipExt));
|
||||
ZIPPABLES.addAll(ext);
|
||||
}
|
||||
EXTENSIONS.addAll(ZIPPABLES);
|
||||
@@ -186,7 +186,7 @@ public class ArchiveAnalyzer extends AbstractFileTypeAnalyzer {
|
||||
if (tempFileLocation != null && tempFileLocation.exists()) {
|
||||
LOGGER.log(Level.FINE, "Attempting to delete temporary files");
|
||||
final boolean success = FileUtils.delete(tempFileLocation);
|
||||
if (!success && tempFileLocation != null & tempFileLocation.exists()) {
|
||||
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");
|
||||
}
|
||||
}
|
||||
@@ -221,9 +221,8 @@ public class ArchiveAnalyzer extends AbstractFileTypeAnalyzer {
|
||||
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);
|
||||
@@ -242,7 +241,7 @@ public class ArchiveAnalyzer extends AbstractFileTypeAnalyzer {
|
||||
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 deep copy and analyzing it as a JAR.", fileName));
|
||||
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 {
|
||||
@@ -339,7 +338,7 @@ public class ArchiveAnalyzer extends AbstractFileTypeAnalyzer {
|
||||
try {
|
||||
fis.close();
|
||||
} catch (IOException ex) {
|
||||
LOGGER.log(Level.FINEST, null, ex);
|
||||
LOGGER.log(Level.FINE, null, ex);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -368,8 +367,10 @@ public class ArchiveAnalyzer extends AbstractFileTypeAnalyzer {
|
||||
final File file = new File(destination, entry.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()) {
|
||||
@@ -402,6 +403,13 @@ public class ArchiveAnalyzer extends AbstractFileTypeAnalyzer {
|
||||
LOGGER.log(Level.FINEST, null, ex);
|
||||
}
|
||||
}
|
||||
if (fos != null) {
|
||||
try {
|
||||
fos.close();
|
||||
} catch (IOException ex) {
|
||||
LOGGER.log(Level.FINEST, null, ex);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -429,6 +437,8 @@ public class ArchiveAnalyzer extends AbstractFileTypeAnalyzer {
|
||||
* @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);
|
||||
|
||||
@@ -120,9 +120,11 @@ public class AssemblyAnalyzer extends AbstractFileTypeAnalyzer {
|
||||
// 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());
|
||||
|
||||
@@ -205,6 +207,7 @@ public class AssemblyAnalyzer extends AbstractFileTypeAnalyzer {
|
||||
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 {
|
||||
@@ -232,9 +235,11 @@ public class AssemblyAnalyzer extends AbstractFileTypeAnalyzer {
|
||||
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);
|
||||
@@ -242,6 +247,7 @@ public class AssemblyAnalyzer extends AbstractFileTypeAnalyzer {
|
||||
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) {
|
||||
@@ -250,6 +256,7 @@ public class AssemblyAnalyzer extends AbstractFileTypeAnalyzer {
|
||||
} 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 {
|
||||
@@ -261,7 +268,6 @@ public class AssemblyAnalyzer extends AbstractFileTypeAnalyzer {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
builder = DocumentBuilderFactory.newInstance().newDocumentBuilder();
|
||||
}
|
||||
|
||||
|
||||
@@ -170,29 +170,10 @@ 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);
|
||||
}
|
||||
@@ -201,10 +182,28 @@ public class CPEAnalyzer implements Analyzer {
|
||||
}
|
||||
/* 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 (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) {
|
||||
if (verifyEntry(e, dependency)) {
|
||||
final String vendor = e.getVendor();
|
||||
final String product = e.getProduct();
|
||||
identifierAdded |= determineIdentifiers(dependency, vendor, product, confidence);
|
||||
}
|
||||
}
|
||||
if (identifierAdded) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
} while ((++ctr) < 4);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -239,22 +238,6 @@ 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
|
||||
@@ -269,27 +252,24 @@ public class CPEAnalyzer implements Analyzer {
|
||||
* @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 {
|
||||
Set<String> vendorWeightings, Set<String> productWeightings) {
|
||||
|
||||
final ArrayList<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));
|
||||
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));
|
||||
// if (d.score < 0.08) {
|
||||
// System.out.print(entry.getVendor());
|
||||
// System.out.print(":");
|
||||
@@ -297,13 +277,23 @@ public class CPEAnalyzer implements Analyzer {
|
||||
// System.out.print(":");
|
||||
// System.out.println(d.score);
|
||||
// }
|
||||
entry.setSearchScore(d.score);
|
||||
if (!ret.contains(entry)) {
|
||||
ret.add(entry);
|
||||
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;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -508,14 +498,21 @@ public class CPEAnalyzer implements Analyzer {
|
||||
* @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) {
|
||||
@@ -528,10 +525,12 @@ 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);
|
||||
@@ -557,7 +556,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 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;
|
||||
}
|
||||
@@ -567,6 +570,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())) {
|
||||
@@ -577,8 +581,10 @@ public class CPEAnalyzer implements Analyzer {
|
||||
i.setConfidence(bestEvidenceQuality);
|
||||
}
|
||||
dependency.addIdentifier(i);
|
||||
identifierAdded = true;
|
||||
}
|
||||
}
|
||||
return identifierAdded;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -593,7 +599,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
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -0,0 +1,201 @@
|
||||
/*
|
||||
* 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.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.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.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;
|
||||
|
||||
/**
|
||||
* 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);
|
||||
}
|
||||
} 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;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -55,7 +55,7 @@ public class DependencyBundlingAnalyzer extends AbstractAnalyzer implements Anal
|
||||
/**
|
||||
* 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.
|
||||
*/
|
||||
@@ -107,21 +107,25 @@ 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 (hashesMatch(dependency, nextDependency)) {
|
||||
if (isCore(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")) {
|
||||
dependenciesToRemove.add(dependency);
|
||||
mergeDependencies(nextDependency, dependency, dependenciesToRemove);
|
||||
nextDependency.getRelatedDependencies().remove(dependency);
|
||||
break;
|
||||
} else {
|
||||
dependenciesToRemove.add(nextDependency);
|
||||
mergeDependencies(dependency, nextDependency, dependenciesToRemove);
|
||||
nextDependency.getRelatedDependencies().remove(nextDependency);
|
||||
}
|
||||
} else if (cpeIdentifiersMatch(dependency, nextDependency)
|
||||
&& hasSameBasePath(dependency, nextDependency)
|
||||
@@ -131,6 +135,7 @@ public class DependencyBundlingAnalyzer extends AbstractAnalyzer implements Anal
|
||||
mergeDependencies(dependency, nextDependency, dependenciesToRemove);
|
||||
} else {
|
||||
mergeDependencies(nextDependency, dependency, dependenciesToRemove);
|
||||
break; //since we merged into the next dependency - skip forward to the next in mainIterator
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -138,9 +143,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);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -201,26 +204,24 @@ 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();
|
||||
|
||||
// //REMOVED because this is attempting to duplicate what is in the hasSameBasePath function.
|
||||
// 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;
|
||||
// }
|
||||
//version check
|
||||
final DependencyVersion version1 = DependencyVersionUtil.parseVersion(fileName1);
|
||||
final DependencyVersion version2 = DependencyVersionUtil.parseVersion(fileName2);
|
||||
@@ -267,9 +268,11 @@ 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;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -338,6 +341,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,
|
||||
@@ -390,4 +397,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;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -86,12 +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>
|
||||
@@ -161,11 +195,20 @@ public class FalsePositiveAnalyzer extends AbstractAnalyzer {
|
||||
*/
|
||||
public static final Pattern CORE_JAVA = Pattern.compile("^cpe:/a:(sun|oracle|ibm):(j2[ems]e|"
|
||||
+ "java(_platform_micro_edition|_runtime_environment|_se|virtual_machine|se_development_kit|fx)?|"
|
||||
+ "jdk|jre|jsf|jsse)($|:.*)");
|
||||
+ "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
|
||||
@@ -182,6 +225,11 @@ public class FalsePositiveAnalyzer extends AbstractAnalyzer {
|
||||
if (coreCPE.matches() && !coreFiles.matches()) {
|
||||
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();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -250,6 +298,14 @@ public class FalsePositiveAnalyzer extends AbstractAnalyzer {
|
||||
|| 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();
|
||||
|
||||
@@ -73,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
|
||||
|
||||
@@ -64,7 +64,6 @@ import org.owasp.dependencycheck.jaxb.pom.MavenNamespaceFilter;
|
||||
import org.owasp.dependencycheck.jaxb.pom.generated.License;
|
||||
import org.owasp.dependencycheck.jaxb.pom.generated.Model;
|
||||
import org.owasp.dependencycheck.jaxb.pom.generated.Organization;
|
||||
import org.owasp.dependencycheck.jaxb.pom.generated.Parent;
|
||||
import org.owasp.dependencycheck.utils.FileUtils;
|
||||
import org.owasp.dependencycheck.utils.NonClosingStream;
|
||||
import org.owasp.dependencycheck.utils.Settings;
|
||||
@@ -74,7 +73,6 @@ import org.xml.sax.XMLFilter;
|
||||
import org.xml.sax.XMLReader;
|
||||
|
||||
/**
|
||||
*
|
||||
* Used to load a JAR file and collect information that can be used to determine the associated CPE.
|
||||
*
|
||||
* @author Jeremy Long <jeremy.long@owasp.org>
|
||||
@@ -171,7 +169,8 @@ public class JarAnalyzer extends AbstractFileTypeAnalyzer {
|
||||
*/
|
||||
public JarAnalyzer() {
|
||||
try {
|
||||
final JAXBContext jaxbContext = JAXBContext.newInstance("org.owasp.dependencycheck.jaxb.pom.generated");
|
||||
//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.");
|
||||
@@ -294,13 +293,27 @@ public class JarAnalyzer extends AbstractFileTypeAnalyzer {
|
||||
LOGGER.log(Level.FINE, msg, ex);
|
||||
return false;
|
||||
}
|
||||
File externalPom = null;
|
||||
if (pomEntries.isEmpty()) {
|
||||
return false;
|
||||
if (dependency.getActualFilePath().matches(".*\\.m2.repository\\b.*")) {
|
||||
String pomPath = dependency.getActualFilePath();
|
||||
pomPath = pomPath.substring(0, pomPath.lastIndexOf('.')) + ".pom";
|
||||
externalPom = new File(pomPath);
|
||||
if (externalPom.isFile()) {
|
||||
pomEntries.add(pomPath);
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
for (String path : pomEntries) {
|
||||
Properties pomProperties = null;
|
||||
try {
|
||||
pomProperties = retrievePomProperties(path, jar);
|
||||
if (externalPom == null) {
|
||||
pomProperties = retrievePomProperties(path, jar);
|
||||
}
|
||||
} catch (IOException ex) {
|
||||
LOGGER.log(Level.FINEST, "ignore this, failed reading a non-existent pom.properties", ex);
|
||||
}
|
||||
@@ -314,19 +327,23 @@ public class JarAnalyzer extends AbstractFileTypeAnalyzer {
|
||||
final String displayPath = String.format("%s%s%s",
|
||||
dependency.getFilePath(),
|
||||
File.separator,
|
||||
path); //.replaceAll("[\\/]", File.separator));
|
||||
path);
|
||||
final String displayName = String.format("%s%s%s",
|
||||
dependency.getFileName(),
|
||||
File.separator,
|
||||
path); //.replaceAll("[\\/]", File.separator));
|
||||
path);
|
||||
|
||||
newDependency.setFileName(displayName);
|
||||
newDependency.setFilePath(displayPath);
|
||||
addPomEvidence(newDependency, pom, pomProperties);
|
||||
setPomEvidence(newDependency, pom, pomProperties, null);
|
||||
engine.getDependencies().add(newDependency);
|
||||
Collections.sort(engine.getDependencies());
|
||||
} else {
|
||||
pom = retrievePom(path, jar);
|
||||
if (externalPom == null) {
|
||||
pom = retrievePom(path, jar);
|
||||
} else {
|
||||
pom = retrievePom(externalPom);
|
||||
}
|
||||
foundSomething |= setPomEvidence(dependency, pom, pomProperties, classes);
|
||||
}
|
||||
} catch (AnalysisException ex) {
|
||||
@@ -346,16 +363,25 @@ public class JarAnalyzer extends AbstractFileTypeAnalyzer {
|
||||
* @return a Properties object or null if no pom.properties was found
|
||||
* @throws IOException thrown if there is an exception reading the pom.properties
|
||||
*/
|
||||
@edu.umd.cs.findbugs.annotations.SuppressWarnings(value = "OS_OPEN_STREAM",
|
||||
justification = "The reader is closed by closing the zipEntry")
|
||||
private Properties retrievePomProperties(String path, final JarFile jar) throws IOException {
|
||||
Properties pomProperties = null;
|
||||
final String propPath = path.substring(0, path.length() - 7) + "pom.properies";
|
||||
final ZipEntry propEntry = jar.getEntry(propPath);
|
||||
if (propEntry != null) {
|
||||
final Reader reader = new InputStreamReader(jar.getInputStream(propEntry), "UTF-8");
|
||||
pomProperties = new Properties();
|
||||
pomProperties.load(reader);
|
||||
Reader reader = null;
|
||||
try {
|
||||
reader = new InputStreamReader(jar.getInputStream(propEntry), "UTF-8");
|
||||
pomProperties = new Properties();
|
||||
pomProperties.load(reader);
|
||||
} finally {
|
||||
if (reader != null) {
|
||||
try {
|
||||
reader.close();
|
||||
} catch (IOException ex) {
|
||||
LOGGER.log(Level.FINEST, "close error", ex);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return pomProperties;
|
||||
}
|
||||
@@ -515,6 +541,41 @@ public class JarAnalyzer extends AbstractFileTypeAnalyzer {
|
||||
return model;
|
||||
}
|
||||
|
||||
/**
|
||||
* 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
|
||||
*/
|
||||
private Model retrievePom(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, null, 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.
|
||||
*
|
||||
@@ -559,37 +620,90 @@ public class JarAnalyzer extends AbstractFileTypeAnalyzer {
|
||||
*/
|
||||
private boolean setPomEvidence(Dependency dependency, Model pom, Properties pomProperties, ArrayList<ClassNameInformation> classes) {
|
||||
boolean foundSomething = false;
|
||||
boolean addAsIdentifier = true;
|
||||
if (pom == null) {
|
||||
return foundSomething;
|
||||
}
|
||||
String groupid = interpolateString(pom.getGroupId(), pomProperties);
|
||||
if (groupid != null && !groupid.isEmpty()) {
|
||||
if (groupid.startsWith("org.") || groupid.startsWith("com.")) {
|
||||
groupid = groupid.substring(4);
|
||||
String parentGroupId = null;
|
||||
|
||||
if (pom.getParent() != null) {
|
||||
parentGroupId = interpolateString(pom.getParent().getGroupId(), pomProperties);
|
||||
if ((groupid == null || groupid.isEmpty()) && parentGroupId != null && !parentGroupId.isEmpty()) {
|
||||
groupid = parentGroupId;
|
||||
}
|
||||
}
|
||||
final String originalGroupID = groupid;
|
||||
|
||||
if (groupid != null && !groupid.isEmpty()) {
|
||||
foundSomething = true;
|
||||
dependency.getVendorEvidence().addEvidence("pom", "groupid", groupid, Confidence.HIGH);
|
||||
dependency.getVendorEvidence().addEvidence("pom", "groupid", groupid, Confidence.HIGHEST);
|
||||
dependency.getProductEvidence().addEvidence("pom", "groupid", groupid, Confidence.LOW);
|
||||
addMatchingValues(classes, groupid, dependency.getVendorEvidence());
|
||||
addMatchingValues(classes, groupid, dependency.getProductEvidence());
|
||||
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);
|
||||
addMatchingValues(classes, parentGroupId, dependency.getVendorEvidence());
|
||||
addMatchingValues(classes, parentGroupId, dependency.getProductEvidence());
|
||||
}
|
||||
} else {
|
||||
addAsIdentifier = false;
|
||||
}
|
||||
|
||||
String artifactid = interpolateString(pom.getArtifactId(), pomProperties);
|
||||
String parentArtifactId = null;
|
||||
|
||||
if (pom.getParent() != null) {
|
||||
parentArtifactId = interpolateString(pom.getParent().getArtifactId(), pomProperties);
|
||||
if ((artifactid == null || artifactid.isEmpty()) && parentArtifactId != null && !parentArtifactId.isEmpty()) {
|
||||
artifactid = parentArtifactId;
|
||||
}
|
||||
}
|
||||
final String originalArtifactID = artifactid;
|
||||
if (artifactid != null && !artifactid.isEmpty()) {
|
||||
if (artifactid.startsWith("org.") || artifactid.startsWith("com.")) {
|
||||
artifactid = artifactid.substring(4);
|
||||
}
|
||||
foundSomething = true;
|
||||
dependency.getProductEvidence().addEvidence("pom", "artifactid", artifactid, Confidence.HIGH);
|
||||
dependency.getProductEvidence().addEvidence("pom", "artifactid", artifactid, Confidence.HIGHEST);
|
||||
dependency.getVendorEvidence().addEvidence("pom", "artifactid", artifactid, Confidence.LOW);
|
||||
addMatchingValues(classes, artifactid, dependency.getVendorEvidence());
|
||||
addMatchingValues(classes, artifactid, dependency.getProductEvidence());
|
||||
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);
|
||||
addMatchingValues(classes, parentArtifactId, dependency.getVendorEvidence());
|
||||
addMatchingValues(classes, parentArtifactId, dependency.getProductEvidence());
|
||||
}
|
||||
} else {
|
||||
addAsIdentifier = false;
|
||||
}
|
||||
//version
|
||||
final String version = interpolateString(pom.getVersion(), pomProperties);
|
||||
String version = interpolateString(pom.getVersion(), pomProperties);
|
||||
String parentVersion = null;
|
||||
|
||||
if (pom.getParent() != null) {
|
||||
parentVersion = interpolateString(pom.getParent().getVersion(), pomProperties);
|
||||
if ((version == null || version.isEmpty()) && parentVersion != null && !parentVersion.isEmpty()) {
|
||||
version = parentVersion;
|
||||
}
|
||||
}
|
||||
|
||||
if (version != null && !version.isEmpty()) {
|
||||
foundSomething = true;
|
||||
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);
|
||||
}
|
||||
} else {
|
||||
addAsIdentifier = false;
|
||||
}
|
||||
|
||||
if (addAsIdentifier) {
|
||||
dependency.addIdentifier("maven", String.format("%s:%s:%s", originalGroupID, originalArtifactID, version), null, Confidence.LOW);
|
||||
}
|
||||
|
||||
// org name
|
||||
final Organization org = pom.getOrganization();
|
||||
if (org != null && org.getName() != null) {
|
||||
@@ -648,7 +762,7 @@ public class JarAnalyzer extends AbstractFileTypeAnalyzer {
|
||||
//TODO remove weighting
|
||||
vendor.addWeighting(entry.getKey());
|
||||
if (addPackagesAsEvidence && entry.getKey().length() > 1) {
|
||||
vendor.addEvidence("jar", "package", entry.getKey(), Confidence.LOW);
|
||||
vendor.addEvidence("jar", "package name", entry.getKey(), Confidence.LOW);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -657,7 +771,7 @@ public class JarAnalyzer extends AbstractFileTypeAnalyzer {
|
||||
if (ratio > 0.5) {
|
||||
product.addWeighting(entry.getKey());
|
||||
if (addPackagesAsEvidence && entry.getKey().length() > 1) {
|
||||
product.addEvidence("jar", "package", entry.getKey(), Confidence.LOW);
|
||||
product.addEvidence("jar", "package name", entry.getKey(), Confidence.LOW);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1113,7 +1227,7 @@ public class JarAnalyzer extends AbstractFileTypeAnalyzer {
|
||||
* @param evidence the evidence collection to add new entries too
|
||||
*/
|
||||
private void addMatchingValues(ArrayList<ClassNameInformation> classes, String value, EvidenceCollection evidence) {
|
||||
if (value == null || value.isEmpty()) {
|
||||
if (value == null || value.isEmpty() || classes == null || classes.isEmpty()) {
|
||||
return;
|
||||
}
|
||||
final String text = value.toLowerCase();
|
||||
@@ -1140,93 +1254,6 @@ public class JarAnalyzer extends AbstractFileTypeAnalyzer {
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds evidence from the POM to the dependency. This includes the GAV and in some situations the parent GAV if
|
||||
* specified.
|
||||
*
|
||||
* @param dependency the dependency being analyzed
|
||||
* @param pom the POM data
|
||||
* @param pomProperties the properties file associated with the pom
|
||||
*/
|
||||
private void addPomEvidence(Dependency dependency, Model pom, Properties pomProperties) {
|
||||
if (pom == null) {
|
||||
return;
|
||||
}
|
||||
String groupid = interpolateString(pom.getGroupId(), pomProperties);
|
||||
if (groupid != null && !groupid.isEmpty()) {
|
||||
if (groupid.startsWith("org.") || groupid.startsWith("com.")) {
|
||||
groupid = groupid.substring(4);
|
||||
}
|
||||
dependency.getVendorEvidence().addEvidence("pom", "groupid", groupid, Confidence.HIGH);
|
||||
dependency.getProductEvidence().addEvidence("pom", "groupid", groupid, Confidence.LOW);
|
||||
}
|
||||
String artifactid = interpolateString(pom.getArtifactId(), pomProperties);
|
||||
if (artifactid != null && !artifactid.isEmpty()) {
|
||||
if (artifactid.startsWith("org.") || artifactid.startsWith("com.")) {
|
||||
artifactid = artifactid.substring(4);
|
||||
}
|
||||
dependency.getProductEvidence().addEvidence("pom", "artifactid", artifactid, Confidence.HIGH);
|
||||
dependency.getVendorEvidence().addEvidence("pom", "artifactid", artifactid, Confidence.LOW);
|
||||
}
|
||||
final String version = interpolateString(pom.getVersion(), pomProperties);
|
||||
if (version != null && !version.isEmpty()) {
|
||||
dependency.getVersionEvidence().addEvidence("pom", "version", version, Confidence.HIGHEST);
|
||||
}
|
||||
|
||||
final Parent parent = pom.getParent(); //grab parent GAV
|
||||
if (parent != null) {
|
||||
final String parentGroupId = interpolateString(parent.getGroupId(), pomProperties);
|
||||
if (parentGroupId != null && !parentGroupId.isEmpty()) {
|
||||
if (groupid == null || groupid.isEmpty()) {
|
||||
dependency.getVendorEvidence().addEvidence("pom", "parent.groupid", parentGroupId, Confidence.HIGH);
|
||||
} else {
|
||||
dependency.getVendorEvidence().addEvidence("pom", "parent.groupid", parentGroupId, Confidence.MEDIUM);
|
||||
}
|
||||
dependency.getProductEvidence().addEvidence("pom", "parent.groupid", parentGroupId, Confidence.LOW);
|
||||
}
|
||||
final String parentArtifactId = interpolateString(parent.getArtifactId(), pomProperties);
|
||||
if (parentArtifactId != null && !parentArtifactId.isEmpty()) {
|
||||
if (artifactid == null || artifactid.isEmpty()) {
|
||||
dependency.getProductEvidence().addEvidence("pom", "parent.artifactid", parentArtifactId, Confidence.HIGH);
|
||||
} else {
|
||||
dependency.getProductEvidence().addEvidence("pom", "parent.artifactid", parentArtifactId, Confidence.MEDIUM);
|
||||
}
|
||||
dependency.getVendorEvidence().addEvidence("pom", "parent.artifactid", parentArtifactId, Confidence.LOW);
|
||||
}
|
||||
final String parentVersion = interpolateString(parent.getVersion(), pomProperties);
|
||||
if (parentVersion != null && !parentVersion.isEmpty()) {
|
||||
if (version == null || version.isEmpty()) {
|
||||
dependency.getVersionEvidence().addEvidence("pom", "parent.version", parentVersion, Confidence.HIGH);
|
||||
} else {
|
||||
dependency.getVersionEvidence().addEvidence("pom", "parent.version", parentVersion, Confidence.LOW);
|
||||
}
|
||||
}
|
||||
}
|
||||
// org name
|
||||
final Organization org = pom.getOrganization();
|
||||
if (org != null && org.getName() != null) {
|
||||
final String orgName = interpolateString(org.getName(), pomProperties);
|
||||
if (orgName != null && !orgName.isEmpty()) {
|
||||
dependency.getVendorEvidence().addEvidence("pom", "organization name", orgName, Confidence.HIGH);
|
||||
}
|
||||
}
|
||||
//pom name
|
||||
final String pomName = interpolateString(pom.getName(), pomProperties);
|
||||
if (pomName != null && !pomName.isEmpty()) {
|
||||
dependency.getProductEvidence().addEvidence("pom", "name", pomName, Confidence.HIGH);
|
||||
dependency.getVendorEvidence().addEvidence("pom", "name", pomName, Confidence.HIGH);
|
||||
}
|
||||
|
||||
//Description
|
||||
if (pom.getDescription() != null) {
|
||||
final String description = interpolateString(pom.getDescription(), pomProperties);
|
||||
if (description != null && !description.isEmpty()) {
|
||||
addDescription(dependency, description, "pom", "description");
|
||||
}
|
||||
}
|
||||
extractLicense(pom, pomProperties, dependency);
|
||||
}
|
||||
|
||||
/**
|
||||
* Extracts the license information from the pom and adds it to the dependency.
|
||||
*
|
||||
|
||||
@@ -30,6 +30,7 @@ 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.utils.InvalidSettingException;
|
||||
import org.owasp.dependencycheck.utils.Settings;
|
||||
|
||||
/**
|
||||
@@ -48,6 +49,11 @@ import org.owasp.dependencycheck.utils.Settings;
|
||||
*/
|
||||
public class NexusAnalyzer extends AbstractFileTypeAnalyzer {
|
||||
|
||||
/**
|
||||
* 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.
|
||||
*/
|
||||
@@ -73,6 +79,47 @@ public class NexusAnalyzer extends AbstractFileTypeAnalyzer {
|
||||
*/
|
||||
private NexusSearch searcher;
|
||||
|
||||
/**
|
||||
* Field indicating if the analyzer is enabled.
|
||||
*/
|
||||
private final boolean enabled = checkEnabled();
|
||||
|
||||
/**
|
||||
* 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.
|
||||
*
|
||||
@@ -149,20 +196,12 @@ public class NexusAnalyzer extends AbstractFileTypeAnalyzer {
|
||||
*/
|
||||
@Override
|
||||
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);
|
||||
}
|
||||
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);
|
||||
}
|
||||
dependency.addAsEvidence("nexus", ma, Confidence.HIGH);
|
||||
} catch (IllegalArgumentException iae) {
|
||||
//dependency.addAnalysisException(new AnalysisException("Invalid SHA-1"));
|
||||
LOGGER.info(String.format("invalid sha-1 hash on %s", dependency.getFileName()));
|
||||
|
||||
@@ -0,0 +1,151 @@
|
||||
/*
|
||||
* 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));
|
||||
LOGGER.finest(String.format("Version: %s", v));
|
||||
result.add(new MavenArtifact(g, a, v, url.toString()));
|
||||
}
|
||||
|
||||
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;
|
||||
@@ -54,6 +54,7 @@ import org.owasp.dependencycheck.utils.Pair;
|
||||
* @author Jeremy Long <jeremy.long@owasp.org>
|
||||
*/
|
||||
public final class CpeMemoryIndex {
|
||||
|
||||
/**
|
||||
* The logger.
|
||||
*/
|
||||
@@ -160,7 +161,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);
|
||||
|
||||
@@ -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() {
|
||||
}
|
||||
}
|
||||
|
||||
@@ -29,10 +29,12 @@ import java.util.logging.Logger;
|
||||
* @author Jeremy Long <jeremy.long@owasp.org>
|
||||
*/
|
||||
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.
|
||||
*/
|
||||
@@ -55,7 +57,9 @@ 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.log(Level.WARNING, "Unable to load CWE data. This should not be an issue.");
|
||||
LOGGER.log(Level.FINE, null, ex);
|
||||
|
||||
@@ -64,7 +64,7 @@ public class NexusSearch {
|
||||
public NexusSearch(URL rootURL) {
|
||||
this.rootURL = rootURL;
|
||||
try {
|
||||
if (null != Settings.getString(Settings.KEYS.PROXY_URL)
|
||||
if (null != Settings.getString(Settings.KEYS.PROXY_SERVER)
|
||||
&& Settings.getBoolean(Settings.KEYS.ANALYZER_NEXUS_PROXY)) {
|
||||
useProxy = true;
|
||||
LOGGER.fine("Using proxy");
|
||||
|
||||
@@ -42,6 +42,7 @@ import org.owasp.dependencycheck.utils.Settings;
|
||||
* @author Jeremy Long <jeremy.long@owasp.org>
|
||||
*/
|
||||
public final class ConnectionFactory {
|
||||
|
||||
/**
|
||||
* The Logger.
|
||||
*/
|
||||
@@ -49,7 +50,7 @@ public final class ConnectionFactory {
|
||||
/**
|
||||
* 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.
|
||||
*/
|
||||
@@ -111,7 +112,10 @@ public final class ConnectionFactory {
|
||||
//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 = getConnectionString();
|
||||
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);
|
||||
@@ -120,7 +124,7 @@ public final class ConnectionFactory {
|
||||
boolean shouldCreateSchema = false;
|
||||
try {
|
||||
if (connectionString.startsWith("jdbc:h2:file:")) { //H2
|
||||
shouldCreateSchema = !dbSchemaExists();
|
||||
shouldCreateSchema = !h2DataFileExists();
|
||||
LOGGER.log(Level.FINE, "Need to create DB Structure: {0}", shouldCreateSchema);
|
||||
}
|
||||
} catch (IOException ioex) {
|
||||
@@ -217,51 +221,17 @@ public final class ConnectionFactory {
|
||||
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.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 dbSchemaExists() 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);
|
||||
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();
|
||||
}
|
||||
|
||||
|
||||
@@ -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;
|
||||
@@ -39,6 +40,7 @@ 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.
|
||||
@@ -87,7 +89,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();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -248,6 +252,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.
|
||||
@@ -260,6 +265,7 @@ public class CveDB {
|
||||
/**
|
||||
* SQL Statement to delete a property.
|
||||
*/
|
||||
@SuppressWarnings("unused")
|
||||
private static final String DELETE_PROPERTY = "DELETE FROM properties WHERE id = ?";
|
||||
|
||||
//</editor-fold>
|
||||
@@ -304,14 +310,14 @@ public class CveDB {
|
||||
* @throws DatabaseException thrown when there is an error retrieving the data from the DB
|
||||
*/
|
||||
public Set<Pair<String, String>> getVendorProductList() throws DatabaseException {
|
||||
final HashSet data = new HashSet<Pair<String, String>>();
|
||||
final Set<Pair<String, String>> data = new HashSet<Pair<String, String>>();
|
||||
ResultSet rs = null;
|
||||
PreparedStatement ps = null;
|
||||
try {
|
||||
ps = getConnection().prepareStatement(SELECT_VENDOR_PRODUCT_LIST);
|
||||
rs = ps.executeQuery();
|
||||
while (rs.next()) {
|
||||
data.add(new Pair(rs.getString(1), rs.getString(2)));
|
||||
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.";
|
||||
@@ -698,6 +704,43 @@ public class CveDB {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 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.
|
||||
@@ -729,7 +772,7 @@ public class CveDB {
|
||||
* @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) {
|
||||
protected 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);
|
||||
|
||||
@@ -91,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
|
||||
@@ -100,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);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -142,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 TreeMap<String, String> map = new TreeMap<String, String>();
|
||||
for (Entry<Object, Object> entry : properties.entrySet()) {
|
||||
final String key = (String) entry.getKey();
|
||||
if (!"version".equals(key)) {
|
||||
@@ -156,10 +167,10 @@ public class DatabaseProperties {
|
||||
map.put(key, formatted);
|
||||
} catch (Throwable ex) { //deliberately being broad in this catch clause
|
||||
LOGGER.log(Level.FINE, "Unable to parse timestamp from DB", ex);
|
||||
map.put(key, entry.getValue());
|
||||
map.put(key, (String) entry.getValue());
|
||||
}
|
||||
} else {
|
||||
map.put(key, entry.getValue());
|
||||
map.put(key, (String) entry.getValue());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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.
|
||||
@@ -54,7 +55,11 @@ public class NvdCveUpdater implements CachedWebDataSource {
|
||||
LOGGER.log(Level.FINE, null, ex);
|
||||
} catch (DownloadFailedException ex) {
|
||||
LOGGER.log(Level.WARNING,
|
||||
"Unable to download the NVD CVE data, unable to update the data to use the most current data.");
|
||||
"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;
|
||||
@@ -122,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, Settings.getInstance());
|
||||
final DownloadTask call = new DownloadTask(cve, processExecutor, cveDB, Settings.getInstance());
|
||||
downloadFutures.add(downloadExecutors.submit(call));
|
||||
}
|
||||
}
|
||||
@@ -220,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);
|
||||
@@ -317,19 +318,4 @@ public class StandardUpdate {
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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,6 +28,8 @@ 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;
|
||||
@@ -37,12 +42,12 @@ import org.owasp.dependencycheck.utils.Settings;
|
||||
*
|
||||
* @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(CallableDownloadTask.class.getName());
|
||||
private static final Logger LOGGER = Logger.getLogger(DownloadTask.class.getName());
|
||||
|
||||
/**
|
||||
* Simple constructor for the callable download task.
|
||||
@@ -54,7 +59,7 @@ public class CallableDownloadTask implements Callable<Future<ProcessTask>> {
|
||||
* 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, Settings settings) throws UpdateException {
|
||||
public DownloadTask(NvdCveInfo nvdCveInfo, ExecutorService processor, CveDB cveDB, Settings settings) throws UpdateException {
|
||||
this.nvdCveInfo = nvdCveInfo;
|
||||
this.processorService = processor;
|
||||
this.cveDB = cveDB;
|
||||
@@ -188,13 +193,25 @@ public class CallableDownloadTask implements Callable<Future<ProcessTask>> {
|
||||
} catch (DownloadFailedException ex) {
|
||||
msg = String.format("Download Failed for NVD CVE - %s%nSome CVEs may not be reported.", nvdCveInfo.getId());
|
||||
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.log(Level.INFO, msg);
|
||||
|
||||
if (this.processorService == null) {
|
||||
return null;
|
||||
}
|
||||
final ProcessTask task = new ProcessTask(cveDB, this, settings);
|
||||
return this.processorService.submit(task);
|
||||
|
||||
@@ -233,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();
|
||||
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);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -79,7 +79,7 @@ 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.
|
||||
*/
|
||||
@@ -97,7 +97,7 @@ public class ProcessTask implements Callable<ProcessTask> {
|
||||
* @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, Settings settings) {
|
||||
public ProcessTask(final CveDB cveDB, final DownloadTask filePair, Settings settings) {
|
||||
this.cveDB = cveDB;
|
||||
this.filePair = filePair;
|
||||
this.properties = cveDB.getDatabaseProperties();
|
||||
|
||||
@@ -19,12 +19,14 @@ package org.owasp.dependencycheck.dependency;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.io.Serializable;
|
||||
import java.security.NoSuchAlgorithmException;
|
||||
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;
|
||||
|
||||
@@ -35,7 +37,7 @@ import org.owasp.dependencycheck.utils.FileUtils;
|
||||
*
|
||||
* @author Jeremy Long <jeremy.long@owasp.org>
|
||||
*/
|
||||
public class Dependency implements Comparable<Dependency> {
|
||||
public class Dependency implements Serializable, Comparable<Dependency> {
|
||||
|
||||
/**
|
||||
* The logger.
|
||||
@@ -315,6 +317,41 @@ 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);
|
||||
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.
|
||||
*
|
||||
@@ -323,6 +360,7 @@ public class Dependency implements Comparable<Dependency> {
|
||||
public void addIdentifier(Identifier identifier) {
|
||||
this.identifiers.add(identifier);
|
||||
}
|
||||
|
||||
/**
|
||||
* A set of identifiers that have been suppressed.
|
||||
*/
|
||||
@@ -440,6 +478,7 @@ public class Dependency implements Comparable<Dependency> {
|
||||
public EvidenceCollection getVersionEvidence() {
|
||||
return this.versionEvidence;
|
||||
}
|
||||
|
||||
/**
|
||||
* The description of the JAR file.
|
||||
*/
|
||||
@@ -462,6 +501,7 @@ public class Dependency implements Comparable<Dependency> {
|
||||
public void setDescription(String description) {
|
||||
this.description = description;
|
||||
}
|
||||
|
||||
/**
|
||||
* The license that this dependency uses.
|
||||
*/
|
||||
@@ -484,6 +524,7 @@ public class Dependency implements Comparable<Dependency> {
|
||||
public void setLicense(String license) {
|
||||
this.license = license;
|
||||
}
|
||||
|
||||
/**
|
||||
* A list of vulnerabilities for this dependency.
|
||||
*/
|
||||
@@ -539,6 +580,7 @@ public class Dependency implements Comparable<Dependency> {
|
||||
public void addVulnerability(Vulnerability vulnerability) {
|
||||
this.vulnerabilities.add(vulnerability);
|
||||
}
|
||||
|
||||
/**
|
||||
* A collection of related dependencies.
|
||||
*/
|
||||
@@ -578,7 +620,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());
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -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.
|
||||
|
||||
@@ -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,7 +37,7 @@ 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.
|
||||
|
||||
@@ -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.
|
||||
|
||||
@@ -48,7 +48,7 @@ public class ScanAgentException extends IOException {
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new NoDataException.
|
||||
* Creates a new ScanAgentException.
|
||||
*
|
||||
* @param ex the cause of the exception.
|
||||
*/
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -113,7 +113,7 @@ public class ReportGenerator {
|
||||
context.put("scanDate", scanDate);
|
||||
context.put("scanDateXML", scanDateXML);
|
||||
context.put("enc", enc);
|
||||
context.put("version", Settings.getString("application.version", "Unknown"));
|
||||
context.put("version", Settings.getString(Settings.KEYS.APPLICATION_VERSION, "Unknown"));
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -137,6 +137,26 @@ public class ReportGenerator {
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Generates the Dependency Reports for the identified dependencies.
|
||||
*
|
||||
@@ -167,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);
|
||||
@@ -189,11 +222,11 @@ public class ReportGenerator {
|
||||
* template file.
|
||||
*
|
||||
* @param templateName the name of the template to load.
|
||||
* @param outFileName the filename and path to write the report to.
|
||||
* @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, String outFileName) throws IOException, Exception {
|
||||
protected void generateReport(String templateName, OutputStream outputStream) throws IOException, Exception {
|
||||
InputStream input = null;
|
||||
String templatePath = null;
|
||||
final File f = new File(templateName);
|
||||
@@ -216,18 +249,8 @@ public class ReportGenerator {
|
||||
|
||||
final InputStreamReader reader = new InputStreamReader(input, "UTF-8");
|
||||
OutputStreamWriter writer = null;
|
||||
OutputStream outputStream = 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)) {
|
||||
@@ -256,4 +279,41 @@ 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 outFileName the filename and path 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, 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() + "'.");
|
||||
}
|
||||
}
|
||||
|
||||
OutputStream outputSteam = null;
|
||||
try {
|
||||
outputSteam = new FileOutputStream(outFile);
|
||||
generateReport(templateName, outputSteam);
|
||||
} finally {
|
||||
if (outputSteam != null) {
|
||||
try {
|
||||
outputSteam.close();
|
||||
} catch (IOException ex) {
|
||||
LOGGER.log(Level.FINEST, "ignore", 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);
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -66,10 +66,35 @@ public class SuppressionParser {
|
||||
* @throws SuppressionParseException thrown if the xml file cannot be parsed
|
||||
*/
|
||||
public List<SuppressionRule> parseSuppressionRules(File file) throws SuppressionParseException {
|
||||
FileInputStream fis = null;
|
||||
try {
|
||||
fis = new FileInputStream(file);
|
||||
return parseSuppressionRules(fis);
|
||||
} catch (IOException ex) {
|
||||
LOGGER.log(Level.FINE, null, ex);
|
||||
throw new SuppressionParseException(ex);
|
||||
} finally {
|
||||
if (fis != null) {
|
||||
try {
|
||||
fis.close();
|
||||
} catch (IOException ex) {
|
||||
LOGGER.log(Level.FINE, "Unable to close stream", ex);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Parses the given xml stream and returns a list of the suppression rules contained.
|
||||
*
|
||||
* @param inputStream an InputStream containing suppression rues
|
||||
* @return a list of suppression rules
|
||||
* @throws SuppressionParseException if the xml cannot be parsed
|
||||
*/
|
||||
public List<SuppressionRule> parseSuppressionRules(InputStream inputStream) throws SuppressionParseException {
|
||||
try {
|
||||
final InputStream schemaStream = this.getClass().getClassLoader().getResourceAsStream("schema/suppression.xsd");
|
||||
final SuppressionHandler handler = new SuppressionHandler();
|
||||
|
||||
final SAXParserFactory factory = SAXParserFactory.newInstance();
|
||||
factory.setNamespaceAware(true);
|
||||
factory.setValidating(true);
|
||||
@@ -80,7 +105,6 @@ public class SuppressionParser {
|
||||
xmlReader.setErrorHandler(new SuppressionErrorHandler());
|
||||
xmlReader.setContentHandler(handler);
|
||||
|
||||
final InputStream inputStream = new FileInputStream(file);
|
||||
final Reader reader = new InputStreamReader(inputStream, "UTF-8");
|
||||
final InputSource in = new InputSource(reader);
|
||||
//in.setEncoding("UTF-8");
|
||||
|
||||
@@ -234,6 +234,61 @@ public class SuppressionRule {
|
||||
public boolean hasCve() {
|
||||
return cve.size() > 0;
|
||||
}
|
||||
/**
|
||||
* A Maven GAV to suppression.
|
||||
*/
|
||||
private PropertyType gav = null;
|
||||
|
||||
/**
|
||||
* Get the value of Maven GAV.
|
||||
*
|
||||
* @return the value of gav
|
||||
*/
|
||||
public PropertyType getGav() {
|
||||
return gav;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the value of Maven GAV.
|
||||
*
|
||||
* @param gav new value of Maven gav
|
||||
*/
|
||||
public void setGav(PropertyType gav) {
|
||||
this.gav = gav;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns whether or not this suppression rule as GAV entries.
|
||||
*
|
||||
* @return whether or not this suppression rule as GAV entries
|
||||
*/
|
||||
public boolean hasGav() {
|
||||
return gav != null;
|
||||
}
|
||||
|
||||
/**
|
||||
* A flag indicating whether or not the suppression rule is a core/base rule that should not be included in the
|
||||
* resulting report in the "suppressed" section.
|
||||
*/
|
||||
private boolean base;
|
||||
|
||||
/**
|
||||
* Get the value of base.
|
||||
*
|
||||
* @return the value of base
|
||||
*/
|
||||
public boolean isBase() {
|
||||
return base;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the value of base.
|
||||
*
|
||||
* @param base new value of base
|
||||
*/
|
||||
public void setBase(boolean base) {
|
||||
this.base = base;
|
||||
}
|
||||
|
||||
/**
|
||||
* Processes a given dependency to determine if any CPE, CVE, CWE, or CVSS scores should be suppressed. If any
|
||||
@@ -248,13 +303,30 @@ public class SuppressionRule {
|
||||
if (sha1 != null && !sha1.equalsIgnoreCase(dependency.getSha1sum())) {
|
||||
return;
|
||||
}
|
||||
if (gav != null) {
|
||||
final Iterator<Identifier> itr = dependency.getIdentifiers().iterator();
|
||||
boolean gavFound = false;
|
||||
while (itr.hasNext()) {
|
||||
final Identifier i = itr.next();
|
||||
if (identifierMatches("maven", this.gav, i)) {
|
||||
gavFound = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (!gavFound) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
if (this.hasCpe()) {
|
||||
final Iterator<Identifier> itr = dependency.getIdentifiers().iterator();
|
||||
while (itr.hasNext()) {
|
||||
final Identifier i = itr.next();
|
||||
for (PropertyType c : this.cpe) {
|
||||
if (cpeMatches(c, i)) {
|
||||
dependency.addSuppressedIdentifier(i);
|
||||
if (identifierMatches("cpe", c, i)) {
|
||||
if (!isBase()) {
|
||||
dependency.addSuppressedIdentifier(i);
|
||||
}
|
||||
itr.remove();
|
||||
break;
|
||||
}
|
||||
@@ -293,7 +365,9 @@ public class SuppressionRule {
|
||||
}
|
||||
}
|
||||
if (remove) {
|
||||
dependency.addSuppressedVulnerability(v);
|
||||
if (!isBase()) {
|
||||
dependency.addSuppressedVulnerability(v);
|
||||
}
|
||||
itr.remove();
|
||||
}
|
||||
}
|
||||
@@ -309,7 +383,7 @@ public class SuppressionRule {
|
||||
boolean cpeHasNoVersion(PropertyType c) {
|
||||
if (c.isRegex()) {
|
||||
return false;
|
||||
} // cpe:/a:jboss:jboss:1.0.0:
|
||||
}
|
||||
if (countCharacter(c.getValue(), ':') == 3) {
|
||||
return true;
|
||||
}
|
||||
@@ -336,26 +410,75 @@ public class SuppressionRule {
|
||||
/**
|
||||
* Determines if the cpeEntry specified as a PropertyType matches the given Identifier.
|
||||
*
|
||||
* @param cpeEntry a suppression rule entry
|
||||
* @param identifierType the type of identifier ("cpe", "maven", etc.)
|
||||
* @param suppressionEntry a suppression rule entry
|
||||
* @param identifier a CPE identifier to check
|
||||
* @return true if the entry matches; otherwise false
|
||||
*/
|
||||
boolean cpeMatches(PropertyType cpeEntry, Identifier identifier) {
|
||||
if (cpeEntry.matches(identifier.getValue())) {
|
||||
return true;
|
||||
} else if (cpeHasNoVersion(cpeEntry)) {
|
||||
if (cpeEntry.isCaseSensitive()) {
|
||||
if (identifier.getValue().startsWith(cpeEntry.getValue())) {
|
||||
return true;
|
||||
}
|
||||
} else {
|
||||
final String id = identifier.getValue().toLowerCase();
|
||||
final String check = cpeEntry.getValue().toLowerCase();
|
||||
if (id.startsWith(check)) {
|
||||
return true;
|
||||
boolean identifierMatches(String identifierType, PropertyType suppressionEntry, Identifier identifier) {
|
||||
if (identifierType.equals(identifier.getType())) {
|
||||
if (suppressionEntry.matches(identifier.getValue())) {
|
||||
return true;
|
||||
} else if ("cpe".equals(identifierType) && cpeHasNoVersion(suppressionEntry)) {
|
||||
if (suppressionEntry.isCaseSensitive()) {
|
||||
return identifier.getValue().startsWith(suppressionEntry.getValue());
|
||||
} else {
|
||||
final String id = identifier.getValue().toLowerCase();
|
||||
final String check = suppressionEntry.getValue().toLowerCase();
|
||||
return id.startsWith(check);
|
||||
}
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Standard toString implementation.
|
||||
*
|
||||
* @return a string representation of this object
|
||||
*/
|
||||
@Override
|
||||
public String toString() {
|
||||
final StringBuilder sb = new StringBuilder();
|
||||
sb.append("SuppressionRule{");
|
||||
if (filePath != null) {
|
||||
sb.append("filePath=").append(filePath).append(",");
|
||||
}
|
||||
if (sha1 != null) {
|
||||
sb.append("sha1=").append(sha1).append(",");
|
||||
}
|
||||
if (gav != null) {
|
||||
sb.append("gav=").append(gav).append(",");
|
||||
}
|
||||
if (cpe != null && cpe.size() > 0) {
|
||||
sb.append("cpe={");
|
||||
for (PropertyType pt : cpe) {
|
||||
sb.append(pt).append(",");
|
||||
}
|
||||
sb.append("}");
|
||||
}
|
||||
if (cwe != null && cwe.size() > 0) {
|
||||
sb.append("cwe={");
|
||||
for (String s : cwe) {
|
||||
sb.append(s).append(",");
|
||||
}
|
||||
sb.append("}");
|
||||
}
|
||||
if (cve != null && cve.size() > 0) {
|
||||
sb.append("cve={");
|
||||
for (String s : cve) {
|
||||
sb.append(s).append(",");
|
||||
}
|
||||
sb.append("}");
|
||||
}
|
||||
if (cvssBelow != null && cvssBelow.size() > 0) {
|
||||
sb.append("cvssBelow={");
|
||||
for (Float s : cvssBelow) {
|
||||
sb.append(s).append(",");
|
||||
}
|
||||
sb.append("}");
|
||||
}
|
||||
sb.append("}");
|
||||
return sb.toString();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -54,7 +54,9 @@ public final class DBUtils {
|
||||
int id = 0;
|
||||
try {
|
||||
rs = statement.getGeneratedKeys();
|
||||
rs.next();
|
||||
if (!rs.next()) {
|
||||
throw new DatabaseException("Unable to get primary key for inserted row");
|
||||
}
|
||||
id = rs.getInt(1);
|
||||
} catch (SQLException ex) {
|
||||
throw new DatabaseException("Unable to get primary key for inserted row");
|
||||
|
||||
@@ -0,0 +1,46 @@
|
||||
/*
|
||||
* 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.utils;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author Jeremy Long <jeremy.long@owasp.org>
|
||||
*/
|
||||
public final class DateUtil {
|
||||
|
||||
/**
|
||||
* Private constructor for utility class.
|
||||
*/
|
||||
private DateUtil() {
|
||||
}
|
||||
|
||||
/**
|
||||
* 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.
|
||||
*/
|
||||
public static boolean withinDateRange(long date, long compareTo, int range) {
|
||||
final double differenceInDays = (compareTo - date) / 1000.0 / 60.0 / 60.0 / 24.0;
|
||||
return differenceInDays < range;
|
||||
}
|
||||
}
|
||||
@@ -65,7 +65,7 @@ public class DependencyVersion implements Iterable, Comparable<DependencyVersion
|
||||
public final void parseVersion(String version) {
|
||||
versionParts = new ArrayList<String>();
|
||||
if (version != null) {
|
||||
final Pattern rx = Pattern.compile("(\\d+|[a-z]+\\d+|(release|beta|alpha)$)");
|
||||
final Pattern rx = Pattern.compile("(\\d+[a-z]{1,3}$|[a-z]+\\d+|\\d+|(release|beta|alpha)$)");
|
||||
final Matcher matcher = rx.matcher(version.toLowerCase());
|
||||
while (matcher.find()) {
|
||||
versionParts.add(matcher.group());
|
||||
@@ -189,17 +189,23 @@ public class DependencyVersion implements Iterable, Comparable<DependencyVersion
|
||||
if (version == null) {
|
||||
return false;
|
||||
}
|
||||
|
||||
boolean ret = true;
|
||||
int max = (this.versionParts.size() < version.versionParts.size())
|
||||
? this.versionParts.size() : version.versionParts.size();
|
||||
|
||||
if (max > 3) {
|
||||
max = 3;
|
||||
if (Math.abs(this.versionParts.size() - version.versionParts.size()) >= 3) {
|
||||
return false;
|
||||
}
|
||||
|
||||
final int max = (this.versionParts.size() < version.versionParts.size())
|
||||
? this.versionParts.size() : version.versionParts.size();
|
||||
|
||||
boolean ret = true;
|
||||
for (int i = 0; i < max; i++) {
|
||||
if (this.versionParts.get(i) == null || !this.versionParts.get(i).equals(version.versionParts.get(i))) {
|
||||
final String thisVersion = this.versionParts.get(i);
|
||||
final String otherVersion = version.getVersionParts().get(i);
|
||||
if (i >= 3) {
|
||||
if (thisVersion.compareToIgnoreCase(otherVersion) >= 0) {
|
||||
ret = false;
|
||||
break;
|
||||
}
|
||||
} else if (!thisVersion.equals(otherVersion)) {
|
||||
ret = false;
|
||||
break;
|
||||
}
|
||||
|
||||
@@ -32,7 +32,7 @@ public final class DependencyVersionUtil {
|
||||
/**
|
||||
* Regular expression to extract version numbers from file names.
|
||||
*/
|
||||
private static final Pattern RX_VERSION = Pattern.compile("\\d+(\\.\\d{1,6})+(\\.?([_-](release|beta|alpha)|[a-zA-Z_-]{1,3}\\d{1,8}))?");
|
||||
private static final Pattern RX_VERSION = Pattern.compile("\\d+(\\.\\d{1,6})+(\\.?([_-](release|beta|alpha|\\d+)|[a-zA-Z_-]{1,3}\\d{0,8}))?");
|
||||
/**
|
||||
* Regular expression to extract a single version number without periods. This is a last ditch effort just to check
|
||||
* in case we are missing a version number using the previous regex.
|
||||
|
||||
@@ -0,0 +1,147 @@
|
||||
/*
|
||||
* 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) 2013 Jeremy Long. All Rights Reserved.
|
||||
*/
|
||||
package org.owasp.dependencycheck.utils;
|
||||
|
||||
import java.io.BufferedInputStream;
|
||||
import java.io.BufferedOutputStream;
|
||||
import java.io.File;
|
||||
import java.io.FileInputStream;
|
||||
import java.io.FileNotFoundException;
|
||||
import java.io.FileOutputStream;
|
||||
import java.io.IOException;
|
||||
import java.util.logging.Level;
|
||||
import java.util.logging.Logger;
|
||||
import java.util.zip.ZipEntry;
|
||||
import java.util.zip.ZipInputStream;
|
||||
import org.owasp.dependencycheck.Engine;
|
||||
import static org.owasp.dependencycheck.utils.FileUtils.getFileExtension;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author Jeremy Long <jeremy.long@owasp.org>
|
||||
*/
|
||||
public final class ExtractionUtil {
|
||||
|
||||
/**
|
||||
* The logger.
|
||||
*/
|
||||
private static final Logger LOGGER = Logger.getLogger(ExtractionUtil.class.getName());
|
||||
/**
|
||||
* The buffer size to use when extracting files from the archive.
|
||||
*/
|
||||
private static final int BUFFER_SIZE = 4096;
|
||||
|
||||
/**
|
||||
* Private constructor for a utility class.
|
||||
*/
|
||||
private ExtractionUtil() {
|
||||
}
|
||||
|
||||
/**
|
||||
* Extracts the contents of an archive into the specified directory.
|
||||
*
|
||||
* @param archive an archive file such as a WAR or EAR
|
||||
* @param extractTo a directory to extract the contents to
|
||||
* @throws ExtractionException thrown if an exception occurs while extracting the files
|
||||
*/
|
||||
public static void extractFiles(File archive, File extractTo) throws ExtractionException {
|
||||
extractFiles(archive, extractTo, null);
|
||||
}
|
||||
|
||||
/**
|
||||
* Extracts the contents of an archive into the specified directory. The files are only extracted if they are
|
||||
* supported by the analyzers loaded into the specified engine. If the engine is specified as null then all files
|
||||
* are extracted.
|
||||
*
|
||||
* @param archive an archive file such as a WAR or EAR
|
||||
* @param extractTo a directory to extract the contents to
|
||||
* @param engine the scanning engine
|
||||
* @throws ExtractionException thrown if there is an error extracting the files
|
||||
*/
|
||||
public static void extractFiles(File archive, File extractTo, Engine engine) throws ExtractionException {
|
||||
if (archive == null || extractTo == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
FileInputStream fis = null;
|
||||
ZipInputStream zis = null;
|
||||
|
||||
try {
|
||||
fis = new FileInputStream(archive);
|
||||
} catch (FileNotFoundException ex) {
|
||||
LOGGER.log(Level.FINE, null, ex);
|
||||
throw new ExtractionException("Archive file was not found.", ex);
|
||||
}
|
||||
zis = new ZipInputStream(new BufferedInputStream(fis));
|
||||
ZipEntry entry;
|
||||
try {
|
||||
while ((entry = zis.getNextEntry()) != null) {
|
||||
if (entry.isDirectory()) {
|
||||
final File d = new File(extractTo, entry.getName());
|
||||
if (!d.exists() && !d.mkdirs()) {
|
||||
final String msg = String.format("Unable to create '%s'.", d.getAbsolutePath());
|
||||
throw new ExtractionException(msg);
|
||||
}
|
||||
} else {
|
||||
final File file = new File(extractTo, entry.getName());
|
||||
final String ext = getFileExtension(file.getName());
|
||||
if (engine == null || engine.supportsExtension(ext)) {
|
||||
BufferedOutputStream bos = null;
|
||||
FileOutputStream fos;
|
||||
try {
|
||||
fos = new FileOutputStream(file);
|
||||
bos = new BufferedOutputStream(fos, BUFFER_SIZE);
|
||||
int count;
|
||||
final byte data[] = new byte[BUFFER_SIZE];
|
||||
while ((count = zis.read(data, 0, BUFFER_SIZE)) != -1) {
|
||||
bos.write(data, 0, count);
|
||||
}
|
||||
bos.flush();
|
||||
} catch (FileNotFoundException ex) {
|
||||
LOGGER.log(Level.FINE, null, ex);
|
||||
final String msg = String.format("Unable to find file '%s'.", file.getName());
|
||||
throw new ExtractionException(msg, ex);
|
||||
} catch (IOException ex) {
|
||||
LOGGER.log(Level.FINE, null, ex);
|
||||
final String msg = String.format("IO Exception while parsing file '%s'.", file.getName());
|
||||
throw new ExtractionException(msg, ex);
|
||||
} finally {
|
||||
if (bos != null) {
|
||||
try {
|
||||
bos.close();
|
||||
} catch (IOException ex) {
|
||||
LOGGER.log(Level.FINEST, null, ex);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
} catch (IOException ex) {
|
||||
final String msg = String.format("Exception reading archive '%s'.", archive.getName());
|
||||
LOGGER.log(Level.FINE, msg, ex);
|
||||
throw new ExtractionException(msg, ex);
|
||||
} finally {
|
||||
try {
|
||||
zis.close();
|
||||
} catch (IOException ex) {
|
||||
LOGGER.log(Level.FINEST, null, ex);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
BIN
dependency-check-core/src/main/resources/GrokAssembly.exe
Executable file → Normal file
BIN
dependency-check-core/src/main/resources/GrokAssembly.exe
Executable file → Normal file
Binary file not shown.
@@ -8,6 +8,7 @@ org.owasp.dependencycheck.analyzer.CpeSuppressionAnalyzer
|
||||
org.owasp.dependencycheck.analyzer.DependencyBundlingAnalyzer
|
||||
org.owasp.dependencycheck.analyzer.NvdCveAnalyzer
|
||||
org.owasp.dependencycheck.analyzer.VulnerabilitySuppressionAnalyzer
|
||||
org.owasp.dependencycheck.analyzer.CentralAnalyzer
|
||||
org.owasp.dependencycheck.analyzer.NexusAnalyzer
|
||||
org.owasp.dependencycheck.analyzer.NuspecAnalyzer
|
||||
org.owasp.dependencycheck.analyzer.AssemblyAnalyzer
|
||||
@@ -1 +1,2 @@
|
||||
org.owasp.dependencycheck.data.update.NvdCveUpdater
|
||||
org.owasp.dependencycheck.data.update.NvdCveUpdater
|
||||
org.owasp.dependencycheck.data.update.EngineVersionCheck
|
||||
@@ -0,0 +1,65 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<suppressions xmlns="https://www.owasp.org/index.php/OWASP_Dependency_Check_Suppression">
|
||||
<suppress base="true">
|
||||
<notes><![CDATA[
|
||||
This suppresses false positives identified on spring security.
|
||||
]]></notes>
|
||||
<gav regex="true">org\.springframework\.security:spring.*</gav>
|
||||
<cpe>cpe:/a:mod_security:mod_security</cpe>
|
||||
<cpe>cpe:/a:springsource:spring_framework</cpe>
|
||||
<cpe>cpe:/a:vmware:springsource_spring_framework</cpe>
|
||||
</suppress>
|
||||
<suppress base="true">
|
||||
<notes><![CDATA[
|
||||
This suppresses false positives identified on spring security.
|
||||
]]></notes>
|
||||
<filePath regex="true">.*spring-security-[^\\/]*\.jar$</filePath>
|
||||
<cpe>cpe:/a:mod_security:mod_security</cpe>
|
||||
<cpe>cpe:/a:springsource:spring_framework</cpe>
|
||||
<cpe>cpe:/a:vmware:springsource_spring_framework</cpe>
|
||||
</suppress>
|
||||
<suppress base="true">
|
||||
<notes><![CDATA[
|
||||
This suppreses additional false positives for the xstream library that occur because spring has a copy of this library.
|
||||
com.springsource.com.thoughtworks.xstream-1.3.1.jar
|
||||
]]></notes>
|
||||
<gav regex="true">com\.thoughtworks\.xstream:xstream:.*</gav>
|
||||
<cpe>cpe:/a:springsource:spring_framework</cpe>
|
||||
</suppress>
|
||||
<suppress base="true">
|
||||
<notes><![CDATA[
|
||||
Suppresses false positives on velocity tools.
|
||||
]]></notes>
|
||||
<gav regex="true">org\.apache\.velocity:velocity-tools:.*</gav>
|
||||
<cpe>cpe:/a:apache:struts</cpe>
|
||||
</suppress>
|
||||
<suppress base="true">
|
||||
<notes><![CDATA[
|
||||
Sandbox is a php blog platform and should not be flagged as a CPE for java or .net dependencies.
|
||||
]]></notes>
|
||||
<filePath regex="true">.*\.(jar|dll|exe|ear|war|pom)</filePath>
|
||||
<cpe>cpe:/a:sandbox:sandbox</cpe>
|
||||
</suppress>
|
||||
<suppress base="true">
|
||||
<notes><![CDATA[
|
||||
Suppresses false positives on Jersey core client.
|
||||
]]></notes>
|
||||
<gav regex="true">(com\.sun\.jersey|org\.glassfish\.jersey\.core):jersey-(client|common):.*</gav>
|
||||
<cpe>cpe:/a:oracle:glassfish</cpe>
|
||||
<cpe>cpe:/a:oracle:oracle_client</cpe>
|
||||
</suppress>
|
||||
<suppress>
|
||||
<notes><![CDATA[
|
||||
Suppresses false positives on the grizzly-framework
|
||||
]]></notes>
|
||||
<gav regex="true">org\.glassfish\.grizzly:grizzly-framework:.*</gav>
|
||||
<cpe>cpe:/a:oracle:glassfish</cpe>
|
||||
</suppress>
|
||||
<suppress>
|
||||
<notes><![CDATA[
|
||||
Suppresses false positives on the grizzly-framework
|
||||
]]></notes>
|
||||
<gav regex="true">org\.forgerock\.opendj:opendj-ldap-sdk:.*</gav>
|
||||
<cpe>cpe:/a:ldap_project:ldap</cpe>
|
||||
</suppress>
|
||||
</suppressions>
|
||||
@@ -4,7 +4,7 @@ analyzer.AssemblyAnalyzer.notassembly={0} is not a .NET assembly or executable a
|
||||
analyzer.AssemblyAnalyzer.grokassembly.rc=Return code {0} from GrokAssembly
|
||||
analyzer.AssemblyAnalyzer.grokassembly.deployed=Extracted GrokAssembly.exe to {0}
|
||||
analyzer.AssemblyAnalyzer.grokassembly.notdeployed=Could not extract GrokAssembly.exe: {0}
|
||||
analyzer.AssemblyAnalyzer.grokassembly.initlization.failed=An error occurred with the .NET AssemblyAnalyzer; \
|
||||
analyzer.AssemblyAnalyzer.grokassembly.initialization.failed=An error occurred with the .NET AssemblyAnalyzer; \
|
||||
this can be ignored unless you are scanning .NET DLLs. Please see the log for more details.
|
||||
analyzer.AssemblyAnalyzer.grokassembly.initialization.message=Could not execute GrokAssembly {0}
|
||||
analyzer.AssemblyAnalyzer.grokassembly.notdeleted=Can't delete temporary GrokAssembly.exe
|
||||
@@ -3,6 +3,9 @@ application.version=${pom.version}
|
||||
autoupdate=true
|
||||
max.download.threads=3
|
||||
|
||||
# the url to obtain the current engine version from
|
||||
engine.version.url=http://jeremylong.github.io/DependencyCheck/current.txt
|
||||
|
||||
#temp.directory defaults to System.getProperty("java.io.tmpdir")
|
||||
#temp.directory=[path to temp directory]
|
||||
|
||||
@@ -13,8 +16,10 @@ max.download.threads=3
|
||||
# will not be used. The data.directory will be resolved and if the connection string
|
||||
# below contains a %s then the data.directory will replace the %s.
|
||||
data.directory=[JAR]/data
|
||||
#if the filename has a %s it will be replaced with the current expected version
|
||||
data.file_name=cve.%s.h2.db
|
||||
data.version=2.9
|
||||
data.connection_string=jdbc:h2:file:%s;FILE_LOCK=SERIALIZED;AUTOCOMMIT=ON;
|
||||
#data.connection_string=jdbc:h2:file:%s;AUTO_SERVER=TRUE;AUTOCOMMIT=ON;
|
||||
#data.connection_string=jdbc:mysql://localhost:3306/dependencycheck
|
||||
|
||||
# user name and password for the database connection. The inherent case is to use H2.
|
||||
@@ -38,11 +43,16 @@ data.driver_path=
|
||||
cve.url.modified.validfordays=7
|
||||
|
||||
# the path to the modified nvd cve xml file.
|
||||
cve.url-1.2.modified=http://nvd.nist.gov/download/nvdcve-modified.xml
|
||||
cve.url-2.0.modified=http://static.nvd.nist.gov/feeds/xml/cve/nvdcve-2.0-modified.xml
|
||||
cve.url-1.2.modified=https://nvd.nist.gov/download/nvdcve-Modified.xml.gz
|
||||
#cve.url-1.2.modified=http://nvd.nist.gov/download/nvdcve-modified.xml
|
||||
cve.url-2.0.modified=https://nvd.nist.gov/feeds/xml/cve/nvdcve-2.0-Modified.xml.gz
|
||||
#cve.url-2.0.modified=http://static.nvd.nist.gov/feeds/xml/cve/nvdcve-2.0-modified.xml
|
||||
cve.startyear=2002
|
||||
cve.url-2.0.base=http://static.nvd.nist.gov/feeds/xml/cve/nvdcve-2.0-%d.xml
|
||||
cve.url-1.2.base=http://nvd.nist.gov/download/nvdcve-%d.xml
|
||||
cve.url-1.2.base=https://nvd.nist.gov/download/nvdcve-%d.xml.gz
|
||||
#cve.url-1.2.base=http://nvd.nist.gov/download/nvdcve-%d.xml
|
||||
cve.url-2.0.base=https://nvd.nist.gov/feeds/xml/cve/nvdcve-2.0-%d.xml.gz
|
||||
#cve.url-2.0.base=http://static.nvd.nist.gov/feeds/xml/cve/nvdcve-2.0-%d.xml
|
||||
|
||||
|
||||
# file type analyzer settings:
|
||||
analyzer.archive.enabled=true
|
||||
@@ -56,3 +66,7 @@ analyzer.nexus.url=https://repository.sonatype.org/service/local/
|
||||
# If set to true, the proxy will still ONLY be used if the proxy properties (proxy.url, proxy.port)
|
||||
# are configured
|
||||
analyzer.nexus.proxy=true
|
||||
|
||||
# the URL for searching search.maven.org for SHA-1 and whether it's enabled
|
||||
analyzer.central.enabled=true
|
||||
analyzer.central.url=http://search.maven.org/solrsearch/select
|
||||
|
||||
@@ -41,6 +41,7 @@
|
||||
<xs:choice minOccurs="0" maxOccurs="1">
|
||||
<xs:element name="filePath" type="dc:regexStringType"/>
|
||||
<xs:element name="sha1" type="dc:sha1Type"/>
|
||||
<xs:element name="gav" type="dc:regexStringType"/>
|
||||
</xs:choice>
|
||||
<xs:choice minOccurs="0" maxOccurs="unbounded">
|
||||
<xs:element name="cpe" type="dc:regexStringType"/>
|
||||
@@ -49,6 +50,7 @@
|
||||
<xs:element name="cvssBelow" type="dc:cvssScoreType"/>
|
||||
</xs:choice>
|
||||
</xs:sequence>
|
||||
<xs:attribute name="base" use="optional" type="xs:boolean" default="false"/>
|
||||
</xs:complexType>
|
||||
</xs:element>
|
||||
</xs:sequence>
|
||||
|
||||
@@ -33,8 +33,8 @@ Copyright (c) 2012 Jeremy Long. All Rights Reserved.
|
||||
</script>
|
||||
<script type="text/javascript">
|
||||
$(document).ready(function() {
|
||||
$(".expandable").click(function (e) {
|
||||
e = e || window.event;
|
||||
$(".expandable").click(function (event) {
|
||||
e = event || window.event;
|
||||
var h = e.target || e.srcElement;
|
||||
var content = "#content" + h.id.substr(6);
|
||||
var header = "#" + h.id;
|
||||
@@ -56,6 +56,7 @@ Copyright (c) 2012 Jeremy Long. All Rights Reserved.
|
||||
$(header).addClass("expandablesubsection");
|
||||
$(header).removeClass("collaspablesubsection");
|
||||
}
|
||||
return false;
|
||||
});
|
||||
});
|
||||
|
||||
@@ -84,13 +85,14 @@ Copyright (c) 2012 Jeremy Long. All Rights Reserved.
|
||||
$('#modal-text').focus();
|
||||
$('#modal-text').select();
|
||||
}
|
||||
function toggleDisplay(el, clzName) {
|
||||
function toggleDisplay(el, clzName, all, some) {
|
||||
$(clzName).toggle();
|
||||
if (el.innerHTML == 'show all') {
|
||||
el.innerHTML = 'less';
|
||||
if (el.innerHTML == all) {
|
||||
el.innerHTML = some;
|
||||
} else {
|
||||
el.innerHTML = 'show all';
|
||||
el.innerHTML = all;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
</script>
|
||||
<style type="text/css">
|
||||
@@ -427,15 +429,24 @@ Copyright (c) 2012 Jeremy Long. All Rights Reserved.
|
||||
.indent {
|
||||
margin-left:20px;
|
||||
}
|
||||
td, th {
|
||||
td{
|
||||
vertical-align:text-top;
|
||||
padding:6px;
|
||||
margin:0px;
|
||||
}
|
||||
th {
|
||||
text-align:left
|
||||
vertical-align:text-top;
|
||||
padding:6px;
|
||||
margin:0px;
|
||||
border-bottom:1px;
|
||||
border-color: black;
|
||||
}
|
||||
table {
|
||||
border: 0px;
|
||||
}
|
||||
table.lined tr:nth-child(even) {
|
||||
background-color: #fbfbfb;
|
||||
background-color: #f3f3f3;
|
||||
}
|
||||
.fullwidth {
|
||||
width:100%;
|
||||
@@ -448,10 +459,7 @@ Copyright (c) 2012 Jeremy Long. All Rights Reserved.
|
||||
margin-bottom:3px;
|
||||
}
|
||||
.vulnerable {
|
||||
color: #f00;
|
||||
}
|
||||
.vulnerable li {
|
||||
color: #000;
|
||||
color: #000;
|
||||
}
|
||||
.notvulnerable {
|
||||
display:none;
|
||||
@@ -481,7 +489,7 @@ Copyright (c) 2012 Jeremy Long. All Rights Reserved.
|
||||
<div id="modal-content">
|
||||
<div>Press CTR-C to copy XML <a href="http://jeremylong.github.io/DependencyCheck/suppression.html" class="infolink" target="_blank" title="Help with suppressing false positives">[help]</a></div>
|
||||
<textarea id="modal-text" cols="50" rows="10"></textarea><br/>
|
||||
<button id="modal-add-header" class="modal-button">Complete XML Doc</button><button id="modal-close" class="modal-button-right">Close</button>
|
||||
<button id="modal-add-header" title="Add the parent XML nodes to create the complete XML file that can be used to suppress this finding" class="modal-button">Complete XML Doc</button><button id="modal-close" class="modal-button-right">Close</button>
|
||||
</div>
|
||||
<div class="wrapper">
|
||||
<h1>Dependency-Check Report</h1>
|
||||
@@ -513,7 +521,7 @@ arising out of or in connection with the use of this tool, the analysis performe
|
||||
#set($vulnSuppressedCount=$vulnSuppressedCount+$dependency.getSuppressedVulnerabilities().size())
|
||||
#end
|
||||
#end
|
||||
Scan Information (<a href="#" onclick="toggleDisplay(this, '.scaninfo'); return false;">show all</a>):<br/>
|
||||
Scan Information (<a href="#" title="Click to toggle display" onclick="return toggleDisplay(this, '.scaninfo', 'show all', 'show less'); return false;">show all</a>):<br/>
|
||||
<ul class="indent">
|
||||
<li><i>dependency-check version</i>: $version</li>
|
||||
<li><i>Report Generated On</i>: $scanDate</li>
|
||||
@@ -526,23 +534,94 @@ arising out of or in connection with the use of this tool, the analysis performe
|
||||
<li class="scaninfo hidden"><i>$enc.html($prop.key)</i>: $enc.html($prop.value)</li>
|
||||
#end
|
||||
</ul><br/>
|
||||
Dependency Display: <a href="#" onclick="toggleDisplay(this,'.notvulnerable'); return false;">show all</a><br/><br/>
|
||||
<ul class="indent">
|
||||
Display: <a href="#" title="Click to toggle display" onclick="return toggleDisplay(this, '.notvulnerable', 'Showing Vulnerable Dependencies', 'Showing All Dependencies'); return false;">Showing Vulnerable Dependencies</a><br/><br/>
|
||||
#set($lnkcnt=0)
|
||||
#foreach($dependency in $dependencies)
|
||||
<table class="lined">
|
||||
<tr style="text-align:left">
|
||||
<th title="The name of the dependency">Dependency</th>
|
||||
<th title="The Common Platform Enumeration">CPE</th>
|
||||
<th title="The Maven GAV Coordinates">GAV</th>
|
||||
<th title="The highest CVE Severity">Highest Severity</th>
|
||||
<th title="The number of Common Vulnerability and Exposure (CVE) entries">CVE Count</th>
|
||||
<th title="The confidence rating dependency-check has for the identified CPE">CPE Confidence</th>
|
||||
<th title="The count of evidence used to identify the CPE">Evidence Count</th>
|
||||
</tr>
|
||||
#foreach($dependency in $dependencies)
|
||||
#set($lnkcnt=$lnkcnt+1)
|
||||
<li class="#if($dependency.getVulnerabilities().size()==0)notvulnerable#else vulnerable#end">
|
||||
<a href="#l${lnkcnt}_$enc.html($enc.url($dependency.Sha1sum))">$enc.html($dependency.DisplayFileName)</a>
|
||||
#if($dependency.getRelatedDependencies().size()>0)
|
||||
<ul>
|
||||
#foreach($related in $dependency.getRelatedDependencies())
|
||||
<li>$enc.html($related.DisplayFileName)</li>
|
||||
<tr class="#if($dependency.getVulnerabilities().size()==0)notvulnerable#else vulnerable#end">
|
||||
<td><a href="#l${lnkcnt}_$enc.html($enc.url($dependency.Sha1sum))">$enc.html($dependency.DisplayFileName)</a></td>
|
||||
#set($mavenlink="")
|
||||
#set($cpeIdCount=0)
|
||||
#set($cpeIdConf="")
|
||||
<td>
|
||||
#foreach($id in $dependency.getIdentifiers())
|
||||
#if ($id.type=="maven")
|
||||
#if ($mavenlink=="" || !$mavenlink.url)
|
||||
#set($mavenlink=$id)
|
||||
#end
|
||||
#else
|
||||
#if ($cpeIdCount>=1)
|
||||
<br/>
|
||||
#end
|
||||
#if( $id.url )
|
||||
<a href="$enc.html($id.url)" target="_blank">$enc.html($id.value)</a>
|
||||
#else
|
||||
$enc.html($id.value)
|
||||
#end
|
||||
#if ($cpeIdConf == "")
|
||||
#set($cpeIdConf=$id.confidence)
|
||||
#elseif ($cpeIdConf.compareTo($id.confidence)>0)
|
||||
#set($cpeIdConf=$id.confidence)
|
||||
#end
|
||||
#set($cpeIdCount=$cpeIdCount+1)
|
||||
#end
|
||||
#end
|
||||
</ul>
|
||||
</td>
|
||||
<td>#if( $mavenlink.url )
|
||||
##yes, we are HTML Encoding the href. this is okay. We can't URL encode as we have to trust the analyzer here...
|
||||
<a href="$enc.html($mavenlink.url)" target="_blank">$enc.html($mavenlink.value)</a>
|
||||
#elseif ($mavenlink.value)
|
||||
$enc.html($mavenlink.value)
|
||||
#end</td>
|
||||
#set($cveImpact=-1)
|
||||
#foreach($vuln in $dependency.getVulnerabilities())
|
||||
#if ($cveImpact<$vuln.cvssScore)
|
||||
#set($cveImpact=$vuln.cvssScore)
|
||||
#end
|
||||
#end
|
||||
<td>
|
||||
#if ($cveImpact<0)
|
||||
|
||||
#elseif ($cveImpact<4.0)
|
||||
Low
|
||||
#elseif ($cveImpact>=7.0)
|
||||
High
|
||||
#else
|
||||
Medium
|
||||
#end
|
||||
</td>
|
||||
<td>$dependency.getVulnerabilities().size()</td>
|
||||
<td>$cpeIdConf</td>
|
||||
<td>$dependency.getEvidenceForDisplay().size()</td>
|
||||
</tr>
|
||||
#end
|
||||
</li>
|
||||
#end
|
||||
</ul>
|
||||
</table>
|
||||
## <ul class="indent">
|
||||
## #set($lnkcnt=0)
|
||||
## #foreach($dependency in $dependencies)
|
||||
## #set($lnkcnt=$lnkcnt+1)
|
||||
## <li class="#if($dependency.getVulnerabilities().size()==0)notvulnerable#else vulnerable#end">
|
||||
## <a href="#l${lnkcnt}_$enc.html($enc.url($dependency.Sha1sum))">$enc.html($dependency.DisplayFileName)</a>
|
||||
## #if($dependency.getRelatedDependencies().size()>0)
|
||||
## <ul>
|
||||
## #foreach($related in $dependency.getRelatedDependencies())
|
||||
## <li>$enc.html($related.DisplayFileName)</li>
|
||||
## #end
|
||||
## </ul>
|
||||
## #end
|
||||
## </li>
|
||||
## #end
|
||||
## </ul>
|
||||
<h2>Dependencies</h2>
|
||||
#set($lnkcnt=0)
|
||||
#set($cnt=0)
|
||||
@@ -630,7 +709,7 @@ arising out of or in connection with the use of this tool, the analysis performe
|
||||
#end
|
||||
#if ($id.type=="cpe")
|
||||
##yes, we are HTML Encoding into JavaScript... the escape utils don't have a JS Encode and I haven't written one yet
|
||||
<button class="copybutton" onclick="copyText('$enc.html($dependency.FileNameForJavaScript)', '$enc.html($dependency.Sha1sum)', 'cpe', '$enc.html($id.value)')">suppress</button>
|
||||
<button class="copybutton" title="Generate Suppression XML for this CPE for this file" onclick="copyText('$enc.html($dependency.FileNameForJavaScript)', '$enc.html($dependency.Sha1sum)', 'cpe', '$enc.html($id.value)')">suppress</button>
|
||||
#end
|
||||
#if ($id.description)
|
||||
<br/>$enc.html($id.description)
|
||||
@@ -646,7 +725,7 @@ arising out of or in connection with the use of this tool, the analysis performe
|
||||
<div id="content$cnt" class="subsectioncontent standardsubsection">
|
||||
#foreach($vuln in $dependency.getVulnerabilities())
|
||||
#set($vsctr=$vsctr+1)
|
||||
<p><b><a target="_blank" href="http://web.nvd.nist.gov/view/vuln/detail?vulnId=$enc.url($vuln.name)">$enc.html($vuln.name)</a></b> <button class="copybutton" onclick="copyText('$enc.html($dependency.FileNameForJavaScript)', '$enc.html($dependency.Sha1sum)', 'cve', '$enc.html($vuln.name)')">suppress</button></p>
|
||||
<p><b><a target="_blank" href="http://web.nvd.nist.gov/view/vuln/detail?vulnId=$enc.url($vuln.name)">$enc.html($vuln.name)</a></b> <button class="copybutton" title="Generate Suppression XML for this CCE for this file" onclick="copyText('$enc.html($dependency.FileNameForJavaScript)', '$enc.html($dependency.Sha1sum)', 'cve', '$enc.html($vuln.name)')">suppress</button></p>
|
||||
<p>Severity:
|
||||
#if ($vuln.cvssScore<4.0)
|
||||
Low
|
||||
@@ -674,7 +753,7 @@ arising out of or in connection with the use of this tool, the analysis performe
|
||||
<li class="vs$vsctr"><a target="_blank" href="https://web.nvd.nist.gov/view/vuln/search-results?adv_search=true&cves=on&cpe_version=$enc.url($vuln.matchedCPE)">$enc.html($vuln.matchedCPE)</a> #if($vuln.hasMatchedAllPreviousCPE()) and all previous versions#end</li>
|
||||
</ul></p>
|
||||
#else
|
||||
<p>Vulnerable Software & Versions: (<a href="#" onclick="toggleDisplay(this,'.vs$vsctr'); return false;">show all</a>)<ul>
|
||||
<p>Vulnerable Software & Versions: (<a href="#" onclick="return toggleDisplay(this,'.vs$vsctr', 'show all', 'show less');">show all</a>)<ul>
|
||||
<li class="vs$vsctr"><a target="_blank" href="https://web.nvd.nist.gov/view/vuln/search-results?adv_search=true&cves=on&cpe_version=$enc.url($vuln.matchedCPE)">$enc.html($vuln.matchedCPE)</a> #if($vuln.hasMatchedAllPreviousCPE()) and all previous versions#end</li>
|
||||
<li class="vs$vsctr">...</li>
|
||||
#foreach($vs in $vuln.getVulnerableSoftware())
|
||||
@@ -808,7 +887,7 @@ arising out of or in connection with the use of this tool, the analysis performe
|
||||
git st<li class="vs$vsctr"><a target="_blank" href="https://web.nvd.nist.gov/view/vuln/search-results?adv_search=true&cves=on&cpe_version=$enc.url($vuln.matchedCPE)">$enc.html($vuln.matchedCPE)</a> #if($vuln.hasMatchedAllPreviousCPE()) and all previous versions#end</li>
|
||||
</ul></p>
|
||||
#else
|
||||
<p>Vulnerable Software & Versions: (<a href="#" onclick="toggleDisplay(this,'.vs$vsctr'); return false;">show all</a>)<ul>
|
||||
<p>Vulnerable Software & Versions: (<a href="#" onclick="return toggleDisplay(this,'.vs$vsctr', 'show all', 'show less');">show all</a>)<ul>
|
||||
<li class="vs$vsctr"><a target="_blank" href="https://web.nvd.nist.gov/view/vuln/search-results?adv_search=true&cves=on&cpe_version=$enc.url($vuln.matchedCPE)">$enc.html($vuln.matchedCPE)</a> #if($vuln.hasMatchedAllPreviousCPE()) and all previous versions#end</li>
|
||||
<li class="vs$vsctr">...</li>
|
||||
#foreach($vs in $vuln.getVulnerableSoftware())
|
||||
@@ -827,6 +906,6 @@ arising out of or in connection with the use of this tool, the analysis performe
|
||||
## END SUPPRESSED VULNERABILITIES
|
||||
</div>
|
||||
</div>
|
||||
<div><br/><br/>This report contains data retrieved from the <a href="nvd.nist.gov">National Vulnerability Database</a>.</div>
|
||||
<div><br/><br/>This report contains data retrieved from the <a href="http://nvd.nist.gov">National Vulnerability Database</a>.</div>
|
||||
</body>
|
||||
</html>
|
||||
|
||||
@@ -236,6 +236,6 @@ arising out of or in connection with the use of this tool, the analysis performe
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
<p><br/><br/>This report contains data retrieved from the <a href="nvd.nist.gov">National Vulnerability Database</a>.</p>
|
||||
<p><br/><br/>This report contains data retrieved from the <a href="http://nvd.nist.gov">National Vulnerability Database</a>.</p>
|
||||
</body>
|
||||
</html>
|
||||
|
||||
@@ -23,7 +23,6 @@ import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
import org.owasp.dependencycheck.data.nvdcve.CveDB;
|
||||
import org.owasp.dependencycheck.data.nvdcve.DatabaseProperties;
|
||||
import org.owasp.dependencycheck.dependency.Dependency;
|
||||
import org.owasp.dependencycheck.reporting.ReportGenerator;
|
||||
import org.owasp.dependencycheck.utils.Settings;
|
||||
|
||||
@@ -42,26 +41,6 @@ public class EngineIntegrationTest extends BaseTest {
|
||||
public void tearDown() {
|
||||
}
|
||||
|
||||
/**
|
||||
* Test of scan method, of class Engine.
|
||||
*
|
||||
* @throws Exception is thrown when an exception occurs.
|
||||
*/
|
||||
@Test
|
||||
public void testScan() throws Exception {
|
||||
String testClasses = "target/test-classes/*.zip";
|
||||
boolean autoUpdate = Settings.getBoolean(Settings.KEYS.AUTO_UPDATE);
|
||||
Settings.setBoolean(Settings.KEYS.AUTO_UPDATE, false);
|
||||
Engine instance = new Engine();
|
||||
Settings.setBoolean(Settings.KEYS.AUTO_UPDATE, autoUpdate);
|
||||
instance.scan(testClasses);
|
||||
assertTrue(instance.getDependencies().size() > 0);
|
||||
for (Dependency d : instance.getDependencies()) {
|
||||
assertTrue("non-zip file collected " + d.getFileName(), d.getFileName().toLowerCase().endsWith(".zip"));
|
||||
}
|
||||
instance.cleanup();
|
||||
}
|
||||
|
||||
/**
|
||||
* Test running the entire engine.
|
||||
*
|
||||
@@ -70,10 +49,10 @@ public class EngineIntegrationTest extends BaseTest {
|
||||
@Test
|
||||
public void testEngine() throws Exception {
|
||||
String testClasses = "target/test-classes";
|
||||
// boolean autoUpdate = Settings.getBoolean(Settings.KEYS.AUTO_UPDATE);
|
||||
// Settings.setBoolean(Settings.KEYS.AUTO_UPDATE, false);
|
||||
boolean autoUpdate = Settings.getBoolean(Settings.KEYS.AUTO_UPDATE);
|
||||
Settings.setBoolean(Settings.KEYS.AUTO_UPDATE, false);
|
||||
Engine instance = new Engine();
|
||||
// Settings.setBoolean(Settings.KEYS.AUTO_UPDATE, autoUpdate);
|
||||
Settings.setBoolean(Settings.KEYS.AUTO_UPDATE, autoUpdate);
|
||||
instance.scan(testClasses);
|
||||
assertTrue(instance.getDependencies().size() > 0);
|
||||
instance.analyzeDependencies();
|
||||
@@ -81,8 +60,7 @@ public class EngineIntegrationTest extends BaseTest {
|
||||
cveDB.open();
|
||||
DatabaseProperties dbProp = cveDB.getDatabaseProperties();
|
||||
cveDB.close();
|
||||
ReportGenerator rg = new ReportGenerator("DependencyCheck",
|
||||
instance.getDependencies(), instance.getAnalyzers(), dbProp);
|
||||
ReportGenerator rg = new ReportGenerator("DependencyCheck", instance.getDependencies(), instance.getAnalyzers(), dbProp);
|
||||
rg.generateReports("./target/", "ALL");
|
||||
instance.cleanup();
|
||||
}
|
||||
|
||||
@@ -34,8 +34,8 @@ import java.util.Set;
|
||||
import java.util.logging.Level;
|
||||
import java.util.logging.Logger;
|
||||
|
||||
import static org.junit.Assert.assertEquals;
|
||||
import static org.junit.Assert.assertNull;
|
||||
import static org.junit.Assert.assertTrue;
|
||||
|
||||
/**
|
||||
* @author Jeremy Long <jeremy.long@owasp.org>
|
||||
@@ -67,7 +67,7 @@ public class AbstractSuppressionAnalyzerTest extends BaseTest {
|
||||
instance.initialize();
|
||||
int expCount = 5;
|
||||
List<SuppressionRule> result = instance.getRules();
|
||||
assertEquals(expCount, result.size());
|
||||
assertTrue(expCount <= result.size());
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -79,7 +79,7 @@ public class AbstractSuppressionAnalyzerTest extends BaseTest {
|
||||
instance.initialize();
|
||||
int expCount = 5;
|
||||
List<SuppressionRule> result = instance.getRules();
|
||||
assertEquals(expCount, result.size());
|
||||
assertTrue(expCount <= result.size());
|
||||
}
|
||||
|
||||
@Test(expected = SuppressionParseException.class)
|
||||
|
||||
@@ -40,7 +40,7 @@ public class ArchiveAnalyzerIntegrationTest extends AbstractDatabaseTestCase {
|
||||
@Test
|
||||
public void testGetSupportedExtensions() {
|
||||
ArchiveAnalyzer instance = new ArchiveAnalyzer();
|
||||
Set expResult = new HashSet<String>();
|
||||
Set<String> expResult = new HashSet<String>();
|
||||
expResult.add("zip");
|
||||
expResult.add("war");
|
||||
expResult.add("ear");
|
||||
|
||||
@@ -25,9 +25,11 @@ import java.util.Set;
|
||||
import org.apache.lucene.index.CorruptIndexException;
|
||||
import org.apache.lucene.queryparser.classic.ParseException;
|
||||
import org.junit.Assert;
|
||||
import static org.junit.Assert.assertTrue;
|
||||
import org.junit.Test;
|
||||
import org.owasp.dependencycheck.data.cpe.AbstractDatabaseTestCase;
|
||||
import org.owasp.dependencycheck.data.cpe.IndexEntry;
|
||||
import org.owasp.dependencycheck.dependency.Confidence;
|
||||
import org.owasp.dependencycheck.dependency.Dependency;
|
||||
import org.owasp.dependencycheck.dependency.Identifier;
|
||||
|
||||
@@ -81,12 +83,24 @@ public class CPEAnalyzerIntegrationTest extends AbstractDatabaseTestCase {
|
||||
*/
|
||||
@Test
|
||||
public void testDetermineCPE_full() throws Exception {
|
||||
callDetermineCPE_full("hazelcast-2.5.jar", null);
|
||||
callDetermineCPE_full("spring-context-support-2.5.5.jar", "cpe:/a:vmware:springsource_spring_framework:2.5.5");
|
||||
callDetermineCPE_full("spring-core-3.0.0.RELEASE.jar", "cpe:/a:vmware:springsource_spring_framework:3.0.0");
|
||||
callDetermineCPE_full("org.mortbay.jetty.jar", "cpe:/a:mortbay_jetty:jetty:4.2");
|
||||
callDetermineCPE_full("jaxb-xercesImpl-1.5.jar", null);
|
||||
callDetermineCPE_full("ehcache-core-2.2.0.jar", null);
|
||||
CPEAnalyzer instance = new CPEAnalyzer();
|
||||
instance.open();
|
||||
FileNameAnalyzer fnAnalyzer = new FileNameAnalyzer();
|
||||
JarAnalyzer jarAnalyzer = new JarAnalyzer();
|
||||
HintAnalyzer hAnalyzer = new HintAnalyzer();
|
||||
FalsePositiveAnalyzer fp = new FalsePositiveAnalyzer();
|
||||
|
||||
try {
|
||||
//callDetermineCPE_full("struts2-core-2.3.16.3.jar", "cpe:/a:apache:struts:2.3.16.3", instance, fnAnalyzer, jarAnalyzer, hAnalyzer, fp);
|
||||
callDetermineCPE_full("hazelcast-2.5.jar", null, instance, fnAnalyzer, jarAnalyzer, hAnalyzer, fp);
|
||||
callDetermineCPE_full("spring-context-support-2.5.5.jar", "cpe:/a:vmware:springsource_spring_framework:2.5.5", instance, fnAnalyzer, jarAnalyzer, hAnalyzer, fp);
|
||||
callDetermineCPE_full("spring-core-3.0.0.RELEASE.jar", "cpe:/a:vmware:springsource_spring_framework:3.0.0", instance, fnAnalyzer, jarAnalyzer, hAnalyzer, fp);
|
||||
callDetermineCPE_full("org.mortbay.jetty.jar", "cpe:/a:mortbay_jetty:jetty:4.2", instance, fnAnalyzer, jarAnalyzer, hAnalyzer, fp);
|
||||
callDetermineCPE_full("jaxb-xercesImpl-1.5.jar", null, instance, fnAnalyzer, jarAnalyzer, hAnalyzer, fp);
|
||||
callDetermineCPE_full("ehcache-core-2.2.0.jar", null, instance, fnAnalyzer, jarAnalyzer, hAnalyzer, fp);
|
||||
} finally {
|
||||
instance.close();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -94,37 +108,25 @@ public class CPEAnalyzerIntegrationTest extends AbstractDatabaseTestCase {
|
||||
*
|
||||
* @throws Exception is thrown when an exception occurs
|
||||
*/
|
||||
public void callDetermineCPE_full(String depName, String expResult) throws Exception {
|
||||
public void callDetermineCPE_full(String depName, String expResult, CPEAnalyzer instance, FileNameAnalyzer fnAnalyzer, JarAnalyzer jarAnalyzer, HintAnalyzer hAnalyzer, FalsePositiveAnalyzer fp) throws Exception {
|
||||
|
||||
File file = new File(this.getClass().getClassLoader().getResource(depName).getPath());
|
||||
|
||||
Dependency dep = new Dependency(file);
|
||||
|
||||
FileNameAnalyzer fnAnalyzer = new FileNameAnalyzer();
|
||||
fnAnalyzer.analyze(dep, null);
|
||||
|
||||
JarAnalyzer jarAnalyzer = new JarAnalyzer();
|
||||
jarAnalyzer.analyze(dep, null);
|
||||
HintAnalyzer hAnalyzer = new HintAnalyzer();
|
||||
hAnalyzer.analyze(dep, null);
|
||||
|
||||
CPEAnalyzer instance = new CPEAnalyzer();
|
||||
instance.open();
|
||||
instance.analyze(dep, null);
|
||||
instance.close();
|
||||
FalsePositiveAnalyzer fp = new FalsePositiveAnalyzer();
|
||||
fp.analyze(dep, null);
|
||||
|
||||
// for (Identifier i : dep.getIdentifiers()) {
|
||||
// System.out.println(i.getValue());
|
||||
// }
|
||||
if (expResult != null) {
|
||||
Identifier expIdentifier = new Identifier("cpe", expResult, expResult);
|
||||
Assert.assertTrue("Incorrect match: { dep:'" + dep.getFileName() + "' }", dep.getIdentifiers().contains(expIdentifier));
|
||||
} else if (dep.getIdentifiers().isEmpty()) {
|
||||
Assert.assertTrue("Match found when an Identifier should not have been found: { dep:'" + dep.getFileName() + "' }", dep.getIdentifiers().isEmpty());
|
||||
} else {
|
||||
Assert.assertTrue("Match found when an Identifier should not have been found: { dep:'" + dep.getFileName() + "', identifier:'" + dep.getIdentifiers().iterator().next().getValue() + "' }", dep.getIdentifiers().isEmpty());
|
||||
for (Identifier i : dep.getIdentifiers()) {
|
||||
Assert.assertFalse(String.format("%s - found a CPE identifier when should have been none (found '%s')", dep.getFileName(), i.getValue()), "cpe".equals(i.getType()));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -170,7 +172,10 @@ public class CPEAnalyzerIntegrationTest extends AbstractDatabaseTestCase {
|
||||
String expResultSpring = "cpe:/a:springsource:spring_framework:2.5.5";
|
||||
String expResultSpring3 = "cpe:/a:vmware:springsource_spring_framework:3.0.0";
|
||||
|
||||
Assert.assertTrue("Apache Common Validator - found an identifier?", commonValidator.getIdentifiers().isEmpty());
|
||||
for (Identifier i : commonValidator.getIdentifiers()) {
|
||||
Assert.assertFalse("Apache Common Validator - found a CPE identifier?", "cpe".equals(i.getType()));
|
||||
}
|
||||
|
||||
Assert.assertTrue("Incorrect match size - struts", struts.getIdentifiers().size() >= 1);
|
||||
Assert.assertTrue("Incorrect match - struts", struts.getIdentifiers().contains(expIdentifier));
|
||||
Assert.assertTrue("Incorrect match size - spring3 - " + spring3.getIdentifiers().size(), spring3.getIdentifiers().size() >= 1);
|
||||
@@ -180,6 +185,30 @@ public class CPEAnalyzerIntegrationTest extends AbstractDatabaseTestCase {
|
||||
//Assert.assertTrue("Incorrect match - spring", spring.getIdentifiers().get(0).getValue().equals(expResultSpring));
|
||||
}
|
||||
|
||||
/**
|
||||
* Test of determineIdentifiers method, of class CPEAnalyzer.
|
||||
*
|
||||
* @throws Exception is thrown when an exception occurs
|
||||
*/
|
||||
@Test
|
||||
public void testDetermineIdentifiers() throws Exception {
|
||||
Dependency openssl = new Dependency();
|
||||
openssl.getVendorEvidence().addEvidence("test", "vendor", "openssl", Confidence.HIGHEST);
|
||||
openssl.getProductEvidence().addEvidence("test", "product", "openssl", Confidence.HIGHEST);
|
||||
openssl.getVersionEvidence().addEvidence("test", "version", "1.0.1c", Confidence.HIGHEST);
|
||||
|
||||
CPEAnalyzer instance = new CPEAnalyzer();
|
||||
instance.open();
|
||||
instance.determineIdentifiers(openssl, "openssl", "openssl", Confidence.HIGHEST);
|
||||
instance.close();
|
||||
|
||||
String expResult = "cpe:/a:openssl:openssl:1.0.1c";
|
||||
Identifier expIdentifier = new Identifier("cpe", expResult, expResult);
|
||||
|
||||
assertTrue(openssl.getIdentifiers().contains(expIdentifier));
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Test of searchCPE method, of class CPEAnalyzer.
|
||||
*
|
||||
@@ -190,12 +219,12 @@ public class CPEAnalyzerIntegrationTest extends AbstractDatabaseTestCase {
|
||||
String vendor = "apache software foundation";
|
||||
String product = "struts 2 core";
|
||||
String version = "2.1.2";
|
||||
String expResult = "cpe:/a:apache:struts:2.1.2";
|
||||
String expVendor = "apache";
|
||||
String expProduct = "struts";
|
||||
|
||||
CPEAnalyzer instance = new CPEAnalyzer();
|
||||
instance.open();
|
||||
|
||||
//TODO - yeah, not a very good test as the results are the same with or without weighting...
|
||||
Set<String> productWeightings = new HashSet<String>(1);
|
||||
productWeightings.add("struts2");
|
||||
|
||||
@@ -203,9 +232,16 @@ public class CPEAnalyzerIntegrationTest extends AbstractDatabaseTestCase {
|
||||
vendorWeightings.add("apache");
|
||||
|
||||
List<IndexEntry> result = instance.searchCPE(vendor, product, productWeightings, vendorWeightings);
|
||||
//TODO fix this assert
|
||||
//Assert.assertEquals(expResult, result.get(0).getName());
|
||||
|
||||
instance.close();
|
||||
|
||||
boolean found = false;
|
||||
for (IndexEntry entry : result) {
|
||||
if (expVendor.equals(entry.getVendor()) && expProduct.equals(entry.getProduct())) {
|
||||
found = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
assertTrue("apache:struts was not identified", found);
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@@ -86,4 +86,40 @@ public class DependencyBundlingAnalyzerTest extends BaseTest {
|
||||
assertEquals(expResult, result);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testFirstPathIsShortest() {
|
||||
DependencyBundlingAnalyzer instance = new DependencyBundlingAnalyzer();
|
||||
|
||||
String left = "./a/c.jar";
|
||||
String right = "./d/e/f.jar";
|
||||
boolean expResult = true;
|
||||
boolean result = instance.firstPathIsShortest(left, right);
|
||||
assertEquals(expResult, result);
|
||||
|
||||
left = "./a/b/c.jar";
|
||||
right = "./d/e/f.jar";
|
||||
expResult = true;
|
||||
result = instance.firstPathIsShortest(left, right);
|
||||
assertEquals(expResult, result);
|
||||
|
||||
left = "./d/b/c.jar";
|
||||
right = "./a/e/f.jar";
|
||||
expResult = false;
|
||||
result = instance.firstPathIsShortest(left, right);
|
||||
assertEquals(expResult, result);
|
||||
|
||||
left = "./a/b/c.jar";
|
||||
right = "./d/f.jar";
|
||||
expResult = false;
|
||||
result = instance.firstPathIsShortest(left, right);
|
||||
assertEquals(expResult, result);
|
||||
|
||||
left = "./a/b/c.jar";
|
||||
right = "./a/b/c.jar";
|
||||
expResult = true;
|
||||
result = instance.firstPathIsShortest(left, right);
|
||||
assertEquals(expResult, result);
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -85,7 +85,7 @@ public class HintAnalyzerTest extends BaseTest {
|
||||
for (Dependency d : engine.getDependencies()) {
|
||||
if (d.getActualFile().equals(guice)) {
|
||||
gdep = d;
|
||||
} else {
|
||||
} else if (d.getActualFile().equals(spring)) {
|
||||
sdep = d;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -93,7 +93,7 @@ public class JarAnalyzerTest extends BaseTest {
|
||||
@Test
|
||||
public void testGetSupportedExtensions() {
|
||||
JarAnalyzer instance = new JarAnalyzer();
|
||||
Set expResult = new HashSet();
|
||||
Set<String> expResult = new HashSet<String>();
|
||||
expResult.add("jar");
|
||||
expResult.add("war");
|
||||
Set result = instance.getSupportedExtensions();
|
||||
|
||||
@@ -38,7 +38,7 @@ public class JavaScriptAnalyzerTest extends BaseTest {
|
||||
@Test
|
||||
public void testGetSupportedExtensions() {
|
||||
JavaScriptAnalyzer instance = new JavaScriptAnalyzer();
|
||||
Set expResult = new HashSet<String>();
|
||||
Set<String> expResult = new HashSet<String>();
|
||||
expResult.add("js");
|
||||
Set result = instance.getSupportedExtensions();
|
||||
assertEquals(expResult, result);
|
||||
|
||||
@@ -0,0 +1,63 @@
|
||||
package org.owasp.dependencycheck.data.central;
|
||||
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
import org.owasp.dependencycheck.BaseTest;
|
||||
import org.owasp.dependencycheck.data.nexus.MavenArtifact;
|
||||
import org.owasp.dependencycheck.utils.Settings;
|
||||
|
||||
import java.io.FileNotFoundException;
|
||||
import java.net.URL;
|
||||
import java.util.List;
|
||||
import java.util.logging.Logger;
|
||||
|
||||
import static org.junit.Assert.*;
|
||||
|
||||
/**
|
||||
* Created by colezlaw on 10/13/14.
|
||||
*/
|
||||
public class CentralSearchTest extends BaseTest {
|
||||
private static final Logger LOGGER = Logger.getLogger(CentralSearchTest.class.getName());
|
||||
private CentralSearch searcher;
|
||||
|
||||
@Before
|
||||
public void setUp() throws Exception {
|
||||
String centralUrl = Settings.getString(Settings.KEYS.ANALYZER_CENTRAL_URL);
|
||||
LOGGER.fine(centralUrl);
|
||||
searcher = new CentralSearch(new URL(centralUrl));
|
||||
}
|
||||
|
||||
@Test(expected = IllegalArgumentException.class)
|
||||
public void testNullSha1() throws Exception { searcher.searchSha1(null); }
|
||||
|
||||
@Test(expected = IllegalArgumentException.class)
|
||||
public void testMalformedSha1() throws Exception {
|
||||
searcher.searchSha1("invalid");
|
||||
}
|
||||
|
||||
// This test does generate network traffic and communicates with a host
|
||||
// you may not be able to reach. Remove the @Ignore annotation if you want to
|
||||
// test it anyway
|
||||
@Test
|
||||
public void testValidSha1() throws Exception {
|
||||
List<MavenArtifact> ma = searcher.searchSha1("9977a8d04e75609cf01badc4eb6a9c7198c4c5ea");
|
||||
assertEquals("Incorrect group", "org.apache.maven.plugins", ma.get(0).getGroupId());
|
||||
assertEquals("Incorrect artifact", "maven-compiler-plugin", ma.get(0).getArtifactId());
|
||||
assertEquals("Incorrect version", "3.1", ma.get(0).getVersion());
|
||||
}
|
||||
|
||||
// This test does generate network traffic and communicates with a host
|
||||
// you may not be able to reach. Remove the @Ignore annotation if you want to
|
||||
// test it anyway
|
||||
@Test(expected = FileNotFoundException.class)
|
||||
public void testMissingSha1() throws Exception {
|
||||
searcher.searchSha1("AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA");
|
||||
}
|
||||
|
||||
// This test should give us multiple results back from Central
|
||||
@Test
|
||||
public void testMultipleReturns() throws Exception {
|
||||
List<MavenArtifact> ma = searcher.searchSha1("94A9CE681A42D0352B3AD22659F67835E560D107");
|
||||
assertTrue(ma.size() > 1);
|
||||
}
|
||||
}
|
||||
@@ -45,8 +45,10 @@ public abstract class BaseDBTestCase extends BaseTest {
|
||||
|
||||
public static void ensureDBExists() throws Exception {
|
||||
|
||||
java.io.File dataPath = Settings.getDataFile(Settings.KEYS.DATA_DIRECTORY);
|
||||
if (!dataPath.exists() || (dataPath.isDirectory() && dataPath.listFiles().length < 3)) {
|
||||
java.io.File dataPath = Settings.getDataDirectory();
|
||||
String fileName = String.format(Settings.getString(Settings.KEYS.DB_FILE_NAME), Settings.getString(Settings.KEYS.DB_VERSION));
|
||||
java.io.File dataFile = new File(dataPath, fileName);
|
||||
if (!dataPath.exists() || !dataFile.exists()) {
|
||||
dataPath.mkdirs();
|
||||
FileInputStream fis = null;
|
||||
ZipInputStream zin = null;
|
||||
|
||||
@@ -19,9 +19,11 @@ package org.owasp.dependencycheck.data.nvdcve;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
import static org.junit.Assert.assertFalse;
|
||||
import static org.junit.Assert.assertTrue;
|
||||
import org.junit.Test;
|
||||
import org.owasp.dependencycheck.dependency.VulnerableSoftware;
|
||||
import org.owasp.dependencycheck.utils.DependencyVersion;
|
||||
|
||||
/**
|
||||
*
|
||||
@@ -72,4 +74,21 @@ public class CveDBIntegrationTest extends BaseDBTestCase {
|
||||
instance.close();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Test of isAffected method, of class CveDB.
|
||||
*/
|
||||
@Test
|
||||
public void testIsAffected() throws Exception {
|
||||
String vendor = "openssl";
|
||||
String product = "openssl";
|
||||
DependencyVersion identifiedVersion = new DependencyVersion("1.0.1o");
|
||||
String cpeId = "cpe:/a:openssl:openssl:1.0.1e";
|
||||
String previous = "y";
|
||||
|
||||
CveDB instance = new CveDB();
|
||||
assertFalse(instance.isAffected(vendor, product, identifiedVersion, cpeId, previous));
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -0,0 +1,144 @@
|
||||
/*
|
||||
* Copyright 2014 OWASP.
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
package org.owasp.dependencycheck.data.update;
|
||||
|
||||
import java.text.DateFormat;
|
||||
import java.text.SimpleDateFormat;
|
||||
import java.util.Properties;
|
||||
import mockit.Mock;
|
||||
import mockit.MockUp;
|
||||
import static org.junit.Assert.assertEquals;
|
||||
import org.junit.Test;
|
||||
import org.owasp.dependencycheck.BaseTest;
|
||||
import org.owasp.dependencycheck.data.nvdcve.DatabaseProperties;
|
||||
import org.owasp.dependencycheck.data.update.exception.UpdateException;
|
||||
import org.owasp.dependencycheck.utils.DependencyVersion;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author Jeremy Long <jeremy.long@owasp.org>
|
||||
*/
|
||||
public class EngineVersionCheckTest extends BaseTest {
|
||||
|
||||
// /**
|
||||
// * Test of update method, of class EngineVersionCheck.
|
||||
// */
|
||||
// @Test
|
||||
// public void testUpdate() throws Exception {
|
||||
// EngineVersionCheck instance = new EngineVersionCheck();
|
||||
// instance.update();
|
||||
// }
|
||||
/**
|
||||
* Test of shouldUpdate method, of class EngineVersionCheck.
|
||||
*/
|
||||
@Test
|
||||
public void testShouldUpdate() throws Exception {
|
||||
DatabaseProperties properties = new MockUp<DatabaseProperties>() {
|
||||
final private Properties properties = new Properties();
|
||||
|
||||
@Mock
|
||||
public void save(String key, String value) throws UpdateException {
|
||||
properties.setProperty(key, value);
|
||||
}
|
||||
|
||||
@Mock
|
||||
public String getProperty(String key) {
|
||||
return properties.getProperty(key);
|
||||
}
|
||||
|
||||
}.getMockInstance();
|
||||
|
||||
DateFormat df = new SimpleDateFormat("yyyy-MM-dd");
|
||||
|
||||
String updateToVersion = "1.2.6";
|
||||
String currentVersion = "1.2.6";
|
||||
long lastChecked = df.parse("2014-12-01").getTime();
|
||||
long now = df.parse("2014-12-01").getTime();
|
||||
|
||||
EngineVersionCheck instance = new EngineVersionCheck();
|
||||
boolean expResult = false;
|
||||
instance.setUpdateToVersion(updateToVersion);
|
||||
boolean result = instance.shouldUpdate(lastChecked, now, properties, currentVersion);
|
||||
assertEquals(expResult, result);
|
||||
|
||||
updateToVersion = "1.2.5";
|
||||
currentVersion = "1.2.5";
|
||||
lastChecked = df.parse("2014-10-01").getTime();
|
||||
now = df.parse("2014-12-01").getTime();
|
||||
expResult = true;
|
||||
instance.setUpdateToVersion(updateToVersion);
|
||||
result = instance.shouldUpdate(lastChecked, now, properties, currentVersion);
|
||||
assertEquals(expResult, result);
|
||||
//System.out.println(properties.getProperty(CURRENT_ENGINE_RELEASE));
|
||||
|
||||
updateToVersion = "1.2.5";
|
||||
currentVersion = "1.2.5";
|
||||
lastChecked = df.parse("2014-12-01").getTime();
|
||||
now = df.parse("2014-12-03").getTime();
|
||||
expResult = false;
|
||||
instance.setUpdateToVersion(updateToVersion);
|
||||
result = instance.shouldUpdate(lastChecked, now, properties, currentVersion);
|
||||
assertEquals(expResult, result);
|
||||
|
||||
updateToVersion = "1.2.6";
|
||||
currentVersion = "1.2.5";
|
||||
lastChecked = df.parse("2014-12-01").getTime();
|
||||
now = df.parse("2014-12-03").getTime();
|
||||
expResult = true;
|
||||
instance.setUpdateToVersion(updateToVersion);
|
||||
result = instance.shouldUpdate(lastChecked, now, properties, currentVersion);
|
||||
assertEquals(expResult, result);
|
||||
|
||||
updateToVersion = "1.2.5";
|
||||
currentVersion = "1.2.6";
|
||||
lastChecked = df.parse("2014-12-01").getTime();
|
||||
now = df.parse("2014-12-08").getTime();
|
||||
expResult = false;
|
||||
instance.setUpdateToVersion(updateToVersion);
|
||||
result = instance.shouldUpdate(lastChecked, now, properties, currentVersion);
|
||||
assertEquals(expResult, result);
|
||||
|
||||
updateToVersion = "";
|
||||
currentVersion = "1.2.5";
|
||||
lastChecked = df.parse("2014-12-01").getTime();
|
||||
now = df.parse("2014-12-03").getTime();
|
||||
expResult = false;
|
||||
instance.setUpdateToVersion(updateToVersion);
|
||||
result = instance.shouldUpdate(lastChecked, now, properties, currentVersion);
|
||||
assertEquals(expResult, result);
|
||||
|
||||
updateToVersion = "";
|
||||
currentVersion = "1.2.5";
|
||||
lastChecked = df.parse("2014-12-01").getTime();
|
||||
now = df.parse("2014-12-08").getTime();
|
||||
expResult = true;
|
||||
instance.setUpdateToVersion(updateToVersion);
|
||||
result = instance.shouldUpdate(lastChecked, now, properties, currentVersion);
|
||||
assertEquals(expResult, result);
|
||||
}
|
||||
|
||||
/**
|
||||
* Test of getCurrentReleaseVersion method, of class EngineVersionCheck.
|
||||
*/
|
||||
@Test
|
||||
public void testGetCurrentReleaseVersion() {
|
||||
EngineVersionCheck instance = new EngineVersionCheck();
|
||||
DependencyVersion expResult = new DependencyVersion("1.2.6");
|
||||
String release = instance.getCurrentReleaseVersion();
|
||||
DependencyVersion result = new DependencyVersion(release);
|
||||
assertEquals(expResult, result);
|
||||
}
|
||||
}
|
||||
@@ -18,8 +18,6 @@
|
||||
package org.owasp.dependencycheck.data.update;
|
||||
|
||||
import java.net.MalformedURLException;
|
||||
import java.util.Calendar;
|
||||
import static org.junit.Assert.assertEquals;
|
||||
import static org.junit.Assert.assertNotNull;
|
||||
import org.junit.Test;
|
||||
import org.owasp.dependencycheck.BaseTest;
|
||||
@@ -47,26 +45,6 @@ public class StandardUpdateIntegrationTest extends BaseTest {
|
||||
instance.closeDataStores();
|
||||
}
|
||||
|
||||
/**
|
||||
* Test of withinRange method, of class StandardUpdate.
|
||||
*/
|
||||
@Test
|
||||
public void testWithinRange() throws Exception {
|
||||
Calendar c = Calendar.getInstance();
|
||||
|
||||
long current = c.getTimeInMillis();
|
||||
long lastRun = c.getTimeInMillis() - (3 * (1000 * 60 * 60 * 24));
|
||||
int range = 7; // 7 days
|
||||
StandardUpdate instance = getStandardUpdateTask();
|
||||
boolean expResult = true;
|
||||
boolean result = instance.withinRange(lastRun, current, range);
|
||||
assertEquals(expResult, result);
|
||||
|
||||
lastRun = c.getTimeInMillis() - (8 * (1000 * 60 * 60 * 24));
|
||||
expResult = false;
|
||||
result = instance.withinRange(lastRun, current, range);
|
||||
assertEquals(expResult, result);
|
||||
}
|
||||
// test removed as it is duplicative of the EngineIntegrationTest and the NvdCveUpdaterIntergraionTest
|
||||
// /**
|
||||
// * Test of update method, of class StandardUpdate.
|
||||
@@ -77,7 +55,6 @@ public class StandardUpdateIntegrationTest extends BaseTest {
|
||||
// instance.update();
|
||||
// //TODO make this an actual test
|
||||
// }
|
||||
|
||||
/**
|
||||
* Test of updatesNeeded method, of class StandardUpdate.
|
||||
*/
|
||||
|
||||
@@ -0,0 +1,75 @@
|
||||
/*
|
||||
* 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.task;
|
||||
|
||||
import java.util.concurrent.ExecutorService;
|
||||
import java.util.concurrent.Future;
|
||||
import org.junit.After;
|
||||
import org.junit.AfterClass;
|
||||
import static org.junit.Assert.assertNull;
|
||||
import org.junit.Before;
|
||||
import org.junit.BeforeClass;
|
||||
import org.junit.Test;
|
||||
import org.owasp.dependencycheck.data.nvdcve.CveDB;
|
||||
import org.owasp.dependencycheck.data.update.NvdCveInfo;
|
||||
import org.owasp.dependencycheck.utils.Settings;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author Jeremy Long <jeremy.long@owasp.org>
|
||||
*/
|
||||
public class DownloadTaskTest {
|
||||
|
||||
public DownloadTaskTest() {
|
||||
}
|
||||
|
||||
@BeforeClass
|
||||
public static void setUpClass() {
|
||||
}
|
||||
|
||||
@AfterClass
|
||||
public static void tearDownClass() {
|
||||
}
|
||||
|
||||
@Before
|
||||
public void setUp() {
|
||||
Settings.initialize();
|
||||
}
|
||||
|
||||
@After
|
||||
public void tearDown() {
|
||||
Settings.cleanup();
|
||||
}
|
||||
|
||||
/**
|
||||
* Test of call method, of class DownloadTask.
|
||||
*/
|
||||
@Test
|
||||
public void testCall() throws Exception {
|
||||
NvdCveInfo cve = new NvdCveInfo();
|
||||
cve.setId("modified");
|
||||
cve.setNeedsUpdate(true);
|
||||
cve.setUrl(Settings.getString(Settings.KEYS.CVE_MODIFIED_20_URL));
|
||||
cve.setOldSchemaVersionUrl(Settings.getString(Settings.KEYS.CVE_MODIFIED_12_URL));
|
||||
ExecutorService processExecutor = null;
|
||||
CveDB cveDB = null;
|
||||
DownloadTask instance = new DownloadTask(cve, processExecutor, cveDB, Settings.getInstance());;
|
||||
Future<ProcessTask> result = instance.call();
|
||||
assertNull(result);
|
||||
}
|
||||
}
|
||||
@@ -23,10 +23,12 @@ import java.util.Set;
|
||||
import org.junit.After;
|
||||
import org.junit.AfterClass;
|
||||
import static org.junit.Assert.assertEquals;
|
||||
import static org.junit.Assert.assertFalse;
|
||||
import static org.junit.Assert.assertTrue;
|
||||
import org.junit.Before;
|
||||
import org.junit.BeforeClass;
|
||||
import org.junit.Test;
|
||||
import org.owasp.dependencycheck.data.nexus.MavenArtifact;
|
||||
|
||||
/**
|
||||
*
|
||||
@@ -152,7 +154,7 @@ public class DependencyTest {
|
||||
public void testGetMd5sum() {
|
||||
File file = new File(this.getClass().getClassLoader().getResource("struts2-core-2.1.2.jar").getPath());
|
||||
Dependency instance = new Dependency(file);
|
||||
// assertEquals("89CE9E36AA9A9E03F1450936D2F4F8DD0F961F8B", result.getSha1sum());
|
||||
//assertEquals("89CE9E36AA9A9E03F1450936D2F4F8DD0F961F8B", result.getSha1sum());
|
||||
String expResult = "C30B57142E1CCBC1EFD5CD15F307358F";
|
||||
String result = instance.getMd5sum();
|
||||
assertEquals(expResult, result);
|
||||
@@ -294,4 +296,34 @@ public class DependencyTest {
|
||||
EvidenceCollection result = instance.getVersionEvidence();
|
||||
assertTrue(true); //this is just a getter setter pair.
|
||||
}
|
||||
|
||||
/**
|
||||
* Test of addAsEvidence method, of class Dependency.
|
||||
*/
|
||||
@Test
|
||||
public void testAddAsEvidence() {
|
||||
Dependency instance = new Dependency();
|
||||
MavenArtifact mavenArtifact = new MavenArtifact("group", "artifact", "version", "url");
|
||||
instance.addAsEvidence("pom", mavenArtifact, Confidence.HIGH);
|
||||
assertTrue(instance.getEvidence().contains(Confidence.HIGH));
|
||||
assertFalse(instance.getEvidence().getEvidence("pom", "groupid").isEmpty());
|
||||
assertFalse(instance.getEvidence().getEvidence("pom", "artifactid").isEmpty());
|
||||
assertFalse(instance.getEvidence().getEvidence("pom", "version").isEmpty());
|
||||
assertFalse(instance.getIdentifiers().isEmpty());
|
||||
}
|
||||
|
||||
/**
|
||||
* Test of addAsEvidence method, of class Dependency.
|
||||
*/
|
||||
@Test
|
||||
public void testAddAsEvidenceWithEmptyArtefact() {
|
||||
Dependency instance = new Dependency();
|
||||
MavenArtifact mavenArtifact = new MavenArtifact(null, null, null, null);
|
||||
instance.addAsEvidence("pom", mavenArtifact, Confidence.HIGH);
|
||||
assertFalse(instance.getEvidence().contains(Confidence.HIGH));
|
||||
assertTrue(instance.getEvidence().getEvidence("pom", "groupid").isEmpty());
|
||||
assertTrue(instance.getEvidence().getEvidence("pom", "artifactid").isEmpty());
|
||||
assertTrue(instance.getEvidence().getEvidence("pom", "version").isEmpty());
|
||||
assertTrue(instance.getIdentifiers().isEmpty());
|
||||
}
|
||||
}
|
||||
|
||||
@@ -88,7 +88,15 @@ public class SuppressionHandlerTest {
|
||||
|
||||
xmlReader.parse(in);
|
||||
|
||||
List result = handler.getSuppressionRules();
|
||||
List<SuppressionRule> result = handler.getSuppressionRules();
|
||||
assertTrue(result.size() > 3);
|
||||
int baseCount = 0;
|
||||
for (SuppressionRule r : result) {
|
||||
if (r.isBase()) {
|
||||
baseCount++;
|
||||
}
|
||||
}
|
||||
assertTrue(baseCount > 0);
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@@ -146,6 +146,17 @@ public class SuppressionRuleTest {
|
||||
List<String> result = instance.getCve();
|
||||
assertEquals(cve, result);
|
||||
}
|
||||
|
||||
/**
|
||||
* Test of base property, of class SuppressionRule.
|
||||
*/
|
||||
@Test
|
||||
public void testBase() {
|
||||
SuppressionRule instance = new SuppressionRule();
|
||||
assertFalse(instance.isBase());
|
||||
instance.setBase(true);
|
||||
assertTrue(instance.isBase());
|
||||
}
|
||||
//</editor-fold>
|
||||
|
||||
//<editor-fold defaultstate="collapsed" desc="Ignored duplicate tests, left in, as empty tests, so IDE doesn't re-generate them">
|
||||
@@ -339,55 +350,70 @@ public class SuppressionRuleTest {
|
||||
}
|
||||
|
||||
/**
|
||||
* Test of cpeMatches method, of class SuppressionRule.
|
||||
* Test of identifierMatches method, of class SuppressionRule.
|
||||
*/
|
||||
@Test
|
||||
public void testCpeMatches() {
|
||||
Identifier identifier = new Identifier("cwe", "cpe:/a:microsoft:.net_framework:4.5", "some url not needed for this test");
|
||||
Identifier identifier = new Identifier("cpe", "cpe:/a:microsoft:.net_framework:4.5", "some url not needed for this test");
|
||||
|
||||
PropertyType cpe = new PropertyType();
|
||||
cpe.setValue("cpe:/a:microsoft:.net_framework:4.5");
|
||||
|
||||
SuppressionRule instance = new SuppressionRule();
|
||||
boolean expResult = true;
|
||||
boolean result = instance.cpeMatches(cpe, identifier);
|
||||
boolean result = instance.identifierMatches("cpe", cpe, identifier);
|
||||
assertEquals(expResult, result);
|
||||
|
||||
cpe.setValue("cpe:/a:microsoft:.net_framework:4.0");
|
||||
expResult = false;
|
||||
result = instance.cpeMatches(cpe, identifier);
|
||||
result = instance.identifierMatches("cpe", cpe, identifier);
|
||||
assertEquals(expResult, result);
|
||||
|
||||
cpe.setValue("CPE:/a:microsoft:.net_framework:4.5");
|
||||
cpe.setCaseSensitive(true);
|
||||
expResult = false;
|
||||
result = instance.cpeMatches(cpe, identifier);
|
||||
result = instance.identifierMatches("cpe", cpe, identifier);
|
||||
assertEquals(expResult, result);
|
||||
|
||||
cpe.setValue("cpe:/a:microsoft:.net_framework");
|
||||
cpe.setCaseSensitive(false);
|
||||
expResult = true;
|
||||
result = instance.cpeMatches(cpe, identifier);
|
||||
result = instance.identifierMatches("cpe", cpe, identifier);
|
||||
assertEquals(expResult, result);
|
||||
|
||||
cpe.setValue("cpe:/a:microsoft:.*");
|
||||
cpe.setRegex(true);
|
||||
expResult = true;
|
||||
result = instance.cpeMatches(cpe, identifier);
|
||||
result = instance.identifierMatches("cpe", cpe, identifier);
|
||||
assertEquals(expResult, result);
|
||||
|
||||
cpe.setValue("CPE:/a:microsoft:.*");
|
||||
cpe.setRegex(true);
|
||||
cpe.setCaseSensitive(true);
|
||||
expResult = false;
|
||||
result = instance.cpeMatches(cpe, identifier);
|
||||
result = instance.identifierMatches("cpe", cpe, identifier);
|
||||
assertEquals(expResult, result);
|
||||
|
||||
cpe.setValue("cpe:/a:apache:.*");
|
||||
cpe.setRegex(true);
|
||||
cpe.setCaseSensitive(false);
|
||||
expResult = false;
|
||||
result = instance.cpeMatches(cpe, identifier);
|
||||
result = instance.identifierMatches("cpe", cpe, identifier);
|
||||
assertEquals(expResult, result);
|
||||
|
||||
identifier = new Identifier("maven", "org.springframework:spring-core:2.5.5", "https://repository.sonatype.org/service/local/artifact/maven/redirect?r=central-proxy&g=org.springframework&a=spring-core&v=2.5.5&e=jar");
|
||||
cpe.setValue("org.springframework:spring-core:2.5.5");
|
||||
cpe.setRegex(false);
|
||||
cpe.setCaseSensitive(false);
|
||||
expResult = true;
|
||||
result = instance.identifierMatches("maven", cpe, identifier);
|
||||
assertEquals(expResult, result);
|
||||
|
||||
cpe.setValue("org\\.springframework\\.security:spring.*");
|
||||
cpe.setRegex(true);
|
||||
cpe.setCaseSensitive(false);
|
||||
expResult = false;
|
||||
result = instance.identifierMatches("maven", cpe, identifier);
|
||||
assertEquals(expResult, result);
|
||||
}
|
||||
|
||||
@@ -398,7 +424,7 @@ public class SuppressionRuleTest {
|
||||
public void testProcess() {
|
||||
File struts = new File(this.getClass().getClassLoader().getResource("struts2-core-2.1.2.jar").getPath());
|
||||
Dependency dependency = new Dependency(struts);
|
||||
dependency.addIdentifier("cwe", "cpe:/a:microsoft:.net_framework:4.5", "some url not needed for this test");
|
||||
dependency.addIdentifier("cpe", "cpe:/a:microsoft:.net_framework:4.5", "some url not needed for this test");
|
||||
String sha1 = dependency.getSha1sum();
|
||||
dependency.setSha1sum("384FAA82E193D4E4B0546059CA09572654BC3970");
|
||||
Vulnerability v = createVulnerability();
|
||||
@@ -409,33 +435,33 @@ public class SuppressionRuleTest {
|
||||
instance.setSha1(sha1);
|
||||
instance.addCwe("287");
|
||||
instance.process(dependency);
|
||||
assertTrue(dependency.getVulnerabilities().size() == 1);
|
||||
assertEquals(1, dependency.getVulnerabilities().size());
|
||||
dependency.setSha1sum(sha1);
|
||||
instance.process(dependency);
|
||||
assertTrue(dependency.getVulnerabilities().isEmpty());
|
||||
assertTrue(dependency.getSuppressedVulnerabilities().size() == 1);
|
||||
assertEquals(1, dependency.getSuppressedVulnerabilities().size());
|
||||
|
||||
//cvss
|
||||
dependency.addVulnerability(v);
|
||||
instance = new SuppressionRule();
|
||||
instance.addCvssBelow(5f);
|
||||
instance.process(dependency);
|
||||
assertTrue(dependency.getVulnerabilities().size() == 1);
|
||||
assertEquals(1, dependency.getVulnerabilities().size());
|
||||
instance.addCvssBelow(8f);
|
||||
instance.process(dependency);
|
||||
assertTrue(dependency.getVulnerabilities().isEmpty());
|
||||
assertTrue(dependency.getSuppressedVulnerabilities().size() == 1);
|
||||
assertEquals(1, dependency.getSuppressedVulnerabilities().size());
|
||||
|
||||
//cve
|
||||
dependency.addVulnerability(v);
|
||||
instance = new SuppressionRule();
|
||||
instance.addCve("CVE-2012-1337");
|
||||
instance.process(dependency);
|
||||
assertTrue(dependency.getVulnerabilities().size() == 1);
|
||||
assertEquals(1, dependency.getVulnerabilities().size());
|
||||
instance.addCve("CVE-2013-1337");
|
||||
instance.process(dependency);
|
||||
assertTrue(dependency.getVulnerabilities().isEmpty());
|
||||
assertTrue(dependency.getSuppressedVulnerabilities().size() == 1);
|
||||
assertEquals(1, dependency.getSuppressedVulnerabilities().size());
|
||||
|
||||
//cpe
|
||||
instance = new SuppressionRule();
|
||||
@@ -453,18 +479,58 @@ public class SuppressionRuleTest {
|
||||
instance.setFilePath(pt);
|
||||
instance.process(dependency);
|
||||
assertTrue(dependency.getIdentifiers().isEmpty());
|
||||
assertTrue(dependency.getSuppressedIdentifiers().size() == 1);
|
||||
assertEquals(1, dependency.getSuppressedIdentifiers().size());
|
||||
|
||||
dependency.addIdentifier("cwe", "cpe:/a:microsoft:.net_framework:4.0", "some url not needed for this test");
|
||||
dependency.addIdentifier("cwe", "cpe:/a:microsoft:.net_framework:4.5", "some url not needed for this test");
|
||||
dependency.addIdentifier("cwe", "cpe:/a:microsoft:.net_framework:5.0", "some url not needed for this test");
|
||||
instance = new SuppressionRule();
|
||||
dependency.addIdentifier("cpe", "cpe:/a:microsoft:.net_framework:4.0", "some url not needed for this test");
|
||||
dependency.addIdentifier("cpe", "cpe:/a:microsoft:.net_framework:4.5", "some url not needed for this test");
|
||||
dependency.addIdentifier("cpe", "cpe:/a:microsoft:.net_framework:5.0", "some url not needed for this test");
|
||||
pt = new PropertyType();
|
||||
pt.setValue("cpe:/a:microsoft:.net_framework");
|
||||
instance.addCpe(pt);
|
||||
assertTrue(dependency.getIdentifiers().size() == 3);
|
||||
instance.setBase(true);
|
||||
assertEquals(3, dependency.getIdentifiers().size());
|
||||
assertEquals(1, dependency.getSuppressedIdentifiers().size());
|
||||
instance.process(dependency);
|
||||
assertTrue(dependency.getIdentifiers().isEmpty());
|
||||
assertTrue(dependency.getSuppressedIdentifiers().size() == 3);
|
||||
assertEquals(1, dependency.getSuppressedIdentifiers().size());
|
||||
}
|
||||
|
||||
/**
|
||||
* Test of process method, of class SuppressionRule.
|
||||
*/
|
||||
@Test
|
||||
public void testProcessGAV() {
|
||||
File spring = new File(this.getClass().getClassLoader().getResource("spring-security-web-3.0.0.RELEASE.jar").getPath());
|
||||
Dependency dependency = new Dependency(spring);
|
||||
dependency.addIdentifier("cpe", "cpe:/a:vmware:springsource_spring_framework:3.0.0", "some url not needed for this test");
|
||||
dependency.addIdentifier("cpe", "cpe:/a:springsource:spring_framework:3.0.0", "some url not needed for this test");
|
||||
dependency.addIdentifier("cpe", "cpe:/a:mod_security:mod_security:3.0.0", "some url not needed for this test");
|
||||
dependency.addIdentifier("cpe", "cpe:/a:vmware:springsource_spring_security:3.0.0", "some url not needed for this test");
|
||||
dependency.addIdentifier("maven", "org.springframework.security:spring-security-web:3.0.0.RELEASE", "some url not needed for this test");
|
||||
|
||||
//cpe
|
||||
SuppressionRule instance = new SuppressionRule();
|
||||
PropertyType pt = new PropertyType();
|
||||
|
||||
pt.setValue("org\\.springframework\\.security:spring.*");
|
||||
pt.setRegex(true);
|
||||
pt.setCaseSensitive(false);
|
||||
instance.setGav(pt);
|
||||
|
||||
pt = new PropertyType();
|
||||
pt.setValue("cpe:/a:mod_security:mod_security");
|
||||
instance.addCpe(pt);
|
||||
pt = new PropertyType();
|
||||
pt.setValue("cpe:/a:springsource:spring_framework");
|
||||
instance.addCpe(pt);
|
||||
pt = new PropertyType();
|
||||
pt.setValue("cpe:/a:vmware:springsource_spring_framework");
|
||||
instance.addCpe(pt);
|
||||
|
||||
instance.process(dependency);
|
||||
assertEquals(2, dependency.getIdentifiers().size());
|
||||
|
||||
}
|
||||
|
||||
private Vulnerability createVulnerability() {
|
||||
|
||||
@@ -0,0 +1,71 @@
|
||||
/*
|
||||
* Copyright 2014 OWASP.
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
package org.owasp.dependencycheck.utils;
|
||||
|
||||
import java.util.Calendar;
|
||||
import org.junit.After;
|
||||
import org.junit.AfterClass;
|
||||
import static org.junit.Assert.assertEquals;
|
||||
import org.junit.Before;
|
||||
import org.junit.BeforeClass;
|
||||
import org.junit.Test;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author Jeremy Long <jeremy.long@owasp.org>
|
||||
*/
|
||||
public class DateUtilTest {
|
||||
|
||||
public DateUtilTest() {
|
||||
}
|
||||
|
||||
@BeforeClass
|
||||
public static void setUpClass() {
|
||||
}
|
||||
|
||||
@AfterClass
|
||||
public static void tearDownClass() {
|
||||
}
|
||||
|
||||
@Before
|
||||
public void setUp() {
|
||||
}
|
||||
|
||||
@After
|
||||
public void tearDown() {
|
||||
}
|
||||
|
||||
/**
|
||||
* Test of withinDateRange method, of class DateUtil.
|
||||
*/
|
||||
@Test
|
||||
public void testWithinDateRange() {
|
||||
Calendar c = Calendar.getInstance();
|
||||
|
||||
long current = c.getTimeInMillis();
|
||||
long lastRun = c.getTimeInMillis() - (3 * (1000 * 60 * 60 * 24));
|
||||
int range = 7; // 7 days
|
||||
boolean expResult = true;
|
||||
boolean result = DateUtil.withinDateRange(lastRun, current, range);
|
||||
assertEquals(expResult, result);
|
||||
|
||||
lastRun = c.getTimeInMillis() - (8 * (1000 * 60 * 60 * 24));
|
||||
expResult = false;
|
||||
result = DateUtil.withinDateRange(lastRun, current, range);
|
||||
assertEquals(expResult, result);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -134,14 +134,14 @@ public class DependencyVersionTest {
|
||||
@Test
|
||||
public void testMatchesAtLeastThreeLevels() {
|
||||
|
||||
DependencyVersion instance = new DependencyVersion("1.2.3.4");
|
||||
DependencyVersion version = new DependencyVersion("1.2.3.5");
|
||||
DependencyVersion instance = new DependencyVersion("2.3.16.3");
|
||||
DependencyVersion version = new DependencyVersion("2.3.16.4");
|
||||
//true tests
|
||||
assertEquals(true, instance.matchesAtLeastThreeLevels(version));
|
||||
version = new DependencyVersion("1.2");
|
||||
version = new DependencyVersion("2.3");
|
||||
assertEquals(true, instance.matchesAtLeastThreeLevels(version));
|
||||
//false tests
|
||||
version = new DependencyVersion("1.2.2.5");
|
||||
version = new DependencyVersion("2.3.16.1");
|
||||
assertEquals(false, instance.matchesAtLeastThreeLevels(version));
|
||||
version = new DependencyVersion("2");
|
||||
assertEquals(false, instance.matchesAtLeastThreeLevels(version));
|
||||
@@ -165,6 +165,14 @@ public class DependencyVersionTest {
|
||||
version = new DependencyVersion("1.2.3.1");
|
||||
assertEquals(-1, instance.compareTo(version));
|
||||
|
||||
instance = new DependencyVersion("1.0.1n");
|
||||
version = new DependencyVersion("1.0.1m");
|
||||
assertEquals(1, instance.compareTo(version));
|
||||
version = new DependencyVersion("1.0.1n");
|
||||
assertEquals(0, instance.compareTo(version));
|
||||
version = new DependencyVersion("1.0.1o");
|
||||
assertEquals(-1, instance.compareTo(version));
|
||||
|
||||
DependencyVersion[] dv = new DependencyVersion[7];
|
||||
dv[0] = new DependencyVersion("2.1.3");
|
||||
dv[1] = new DependencyVersion("2.1.3.r2");
|
||||
|
||||
@@ -54,13 +54,13 @@ public class DependencyVersionUtilTest {
|
||||
* Test of parseVersion method, of class DependencyVersionUtil.
|
||||
*/
|
||||
@Test
|
||||
public void testParseVersionFromFileName() {
|
||||
public void testParseVersion() {
|
||||
final String[] fileName = {"something-0.9.5.jar", "lib2-1.1.jar", "lib1.5r4-someflag-R26.jar",
|
||||
"lib-1.2.5-dev-20050313.jar", "testlib_V4.4.0.jar", "lib-core-2.0.0-RC1-SNAPSHOT.jar",
|
||||
"lib-jsp-2.0.1_R114940.jar", "dev-api-2.3.11_R121413.jar", "lib-api-3.7-SNAPSHOT.jar",
|
||||
"-", "", "1.3-beta", "6"};
|
||||
"-", "", "1.3-beta", "6", "openssl1.0.1c", "jsf-impl-2.2.8-02.jar"};
|
||||
final String[] expResult = {"0.9.5", "1.1", "1.5.r4", "1.2.5", "4.4.0", "2.0.0.rc1",
|
||||
"2.0.1.r114940", "2.3.11.r121413", "3.7", "-", null, "1.3.beta", "6"};
|
||||
"2.0.1.r114940", "2.3.11.r121413", "3.7", "-", null, "1.3.beta", "6", "1.0.1c", "2.2.8.02"};
|
||||
|
||||
for (int i = 0; i < fileName.length; i++) {
|
||||
final DependencyVersion version = DependencyVersionUtil.parseVersion(fileName[i]);
|
||||
|
||||
@@ -3,6 +3,9 @@ application.version=${pom.version}
|
||||
autoupdate=true
|
||||
max.download.threads=3
|
||||
|
||||
# the url to obtain the current engine version from
|
||||
engine.version.url=http://jeremylong.github.io/DependencyCheck/current.txt
|
||||
|
||||
#temp.directory defaults to System.getProperty("java.io.tmpdir")
|
||||
#temp.directory=[path to temp directory]
|
||||
|
||||
@@ -13,8 +16,12 @@ max.download.threads=3
|
||||
# will not be used. The data.directory will be resolved and if the connection string
|
||||
# below contains a %s then the data.directory will replace the %s.
|
||||
data.directory=[JAR]/data
|
||||
# if the filename has a %s it will be replaced with the current expected version. For file
|
||||
# based databases the below filename will be added to the data directory above and then
|
||||
# if the connection string has a %s it will be replaced by the directory/filename path.
|
||||
data.file_name=cve.%s.h2.db
|
||||
data.version=2.9
|
||||
data.connection_string=jdbc:h2:file:%s;FILE_LOCK=SERIALIZED;AUTOCOMMIT=ON;
|
||||
#data.connection_string=jdbc:h2:file:%s;AUTO_SERVER=TRUE;AUTOCOMMIT=ON;
|
||||
#data.connection_string=jdbc:mysql://localhost:3306/dependencycheck
|
||||
|
||||
# user name and password for the database connection. The inherent case is to use H2.
|
||||
@@ -43,11 +50,16 @@ cpe.meta.url=http://static.nvd.nist.gov/feeds/xml/cpe/dictionary/official-cpe-di
|
||||
cve.url.modified.validfordays=7
|
||||
|
||||
# the path to the modified nvd cve xml file.
|
||||
cve.url-1.2.modified=http://nvd.nist.gov/download/nvdcve-modified.xml
|
||||
cve.url-2.0.modified=http://static.nvd.nist.gov/feeds/xml/cve/nvdcve-2.0-modified.xml
|
||||
cve.startyear=2014
|
||||
cve.url-2.0.base=http://static.nvd.nist.gov/feeds/xml/cve/nvdcve-2.0-%d.xml
|
||||
cve.url-1.2.base=http://nvd.nist.gov/download/nvdcve-%d.xml
|
||||
cve.url-1.2.modified=https://nvd.nist.gov/download/nvdcve-Modified.xml.gz
|
||||
#cve.url-1.2.modified=http://nvd.nist.gov/download/nvdcve-modified.xml
|
||||
cve.url-2.0.modified=https://nvd.nist.gov/feeds/xml/cve/nvdcve-2.0-Modified.xml.gz
|
||||
#cve.url-2.0.modified=http://static.nvd.nist.gov/feeds/xml/cve/nvdcve-2.0-modified.xml
|
||||
cve.url-1.2.base=https://nvd.nist.gov/download/nvdcve-%d.xml.gz
|
||||
#cve.url-1.2.base=http://nvd.nist.gov/download/nvdcve-%d.xml
|
||||
cve.url-2.0.base=https://nvd.nist.gov/feeds/xml/cve/nvdcve-2.0-%d.xml.gz
|
||||
#cve.url-2.0.base=http://static.nvd.nist.gov/feeds/xml/cve/nvdcve-2.0-%d.xml
|
||||
|
||||
|
||||
# the URL for searching Nexus for SHA-1 hashes and whether it's enabled
|
||||
analyzer.nexus.enabled=true
|
||||
@@ -55,3 +67,7 @@ analyzer.nexus.url=https://repository.sonatype.org/service/local/
|
||||
# If set to true, the proxy will still ONLY be used if the proxy properties (proxy.url, proxy.port)
|
||||
# are configured
|
||||
analyzer.nexus.proxy=true
|
||||
|
||||
# the URL for searching search.maven.org for SHA-1 and whether it's enabled
|
||||
analyzer.central.enabled=true
|
||||
analyzer.central.url=http://search.maven.org/solrsearch/select
|
||||
|
||||
@@ -10,7 +10,7 @@
|
||||
<filePath>c:\path\to\some.jar</filePath>
|
||||
<cpe>cpe:/a:csv:csv:1.0</cpe>
|
||||
</suppress>
|
||||
<suppress>
|
||||
<suppress base="true">
|
||||
<notes><![CDATA[
|
||||
This suppresses any jboss:jboss cpe for any test.jar in any directory.
|
||||
]]></notes>
|
||||
|
||||
@@ -1,17 +1,25 @@
|
||||
<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/maven-v4_0_0.xsd">
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
|
||||
<description>This plug-in can independently execute a Dependency-Check analysis and visualize the results.</description>
|
||||
<url>http://wiki.jenkins-ci.org/display/JENKINS/OWASP+Dependency-Check+Plugin</url>
|
||||
<parent>
|
||||
<groupId>org.owasp</groupId>
|
||||
<artifactId>dependency-check-parent</artifactId>
|
||||
<version>1.2.1</version>
|
||||
<version>1.2.7</version>
|
||||
</parent>
|
||||
|
||||
<groupId>org.owasp</groupId>
|
||||
<artifactId>dependency-check-jenkins</artifactId>
|
||||
<name>Dependency-Check Jenkins Plugin</name>
|
||||
<url>http://wiki.jenkins-ci.org/display/JENKINS/OWASP+Dependency-Check+Plugin</url>
|
||||
<description>dependency-check-jenkins is a Jenkins plugin that runs dependency-check-core on a project to detect publicly disclosed vulnerabilities associated with the project's dependencies. The plugin will generate a report listing the dependency, any identified Common Platform Enumeration (CPE) identifiers, and the associated Common Vulnerability and Exposure (CVE) entries. This module is simply a placeholder and does not contain the actual plugin source code. The source code and distribution of the plugin is handled via https://github.com/jenkinsci/dependency-check-jenkins and Jenkin's plugin management.</description>
|
||||
<!-- begin copy from http://minds.coremedia.com/2012/09/11/problem-solved-deploy-multi-module-maven-project-site-as-github-pages/ -->
|
||||
<distributionManagement>
|
||||
<site>
|
||||
<id>github-pages-site</id>
|
||||
<name>Deployment through GitHub's site deployment plugin</name>
|
||||
<url>${basedir}/../target/site/${project.version}/dependency-check-jenkins</url>
|
||||
</site>
|
||||
</distributionManagement>
|
||||
<!-- end copy -->
|
||||
|
||||
<packaging>pom</packaging>
|
||||
<inceptionYear>2012</inceptionYear>
|
||||
<organization>
|
||||
@@ -31,15 +39,6 @@
|
||||
</roles>
|
||||
</developer>
|
||||
</developers>
|
||||
<!-- begin copy from http://minds.coremedia.com/2012/09/11/problem-solved-deploy-multi-module-maven-project-site-as-github-pages/ -->
|
||||
<distributionManagement>
|
||||
<site>
|
||||
<id>github-pages-site</id>
|
||||
<name>Deployment through GitHub's site deployment plugin</name>
|
||||
<url>${basedir}/../target/site/${project.version}/dependency-check-maven</url>
|
||||
</site>
|
||||
</distributionManagement>
|
||||
<!-- end copy -->
|
||||
<scm>
|
||||
<connection>scm:git:git@github.com:jenkinsci/dependency-check-jenkins.git</connection>
|
||||
<url>https://github.com/jenkinsci/dependency-check-jenkins</url>
|
||||
|
||||
@@ -15,7 +15,6 @@ 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/maven-v4_0_0.xsd">
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
<url>http://maven.apache.org</url>
|
||||
@@ -23,14 +22,14 @@ Copyright (c) 2013 Jeremy Long. All Rights Reserved.
|
||||
<parent>
|
||||
<groupId>org.owasp</groupId>
|
||||
<artifactId>dependency-check-parent</artifactId>
|
||||
<version>1.2.1</version>
|
||||
<version>1.2.7</version>
|
||||
</parent>
|
||||
|
||||
<artifactId>dependency-check-maven</artifactId>
|
||||
<packaging>maven-plugin</packaging>
|
||||
|
||||
<name>Dependency-Check Maven Plugin</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-maven is a Maven Plugin that uses dependency-check-core to detect publicly disclosed vulnerabilities associated with the project's dependencies. The plugin will generate a report listing the dependency, any identified Common Platform Enumeration (CPE) identifiers, and the associated Common Vulnerability and Exposure (CVE) entries.</description>
|
||||
<inceptionYear>2013</inceptionYear>
|
||||
<!-- begin copy from http://minds.coremedia.com/2012/09/11/problem-solved-deploy-multi-module-maven-project-site-as-github-pages/ -->
|
||||
<distributionManagement>
|
||||
@@ -150,6 +149,9 @@ Copyright (c) 2013 Jeremy Long. All Rights Reserved.
|
||||
<groupId>org.apache.maven.plugins</groupId>
|
||||
<artifactId>maven-javadoc-plugin</artifactId>
|
||||
<version>2.9.1</version>
|
||||
<configuration>
|
||||
<bottom>Copyright© 2012-14 Jeremy Long. All Rights Reserved.</bottom>
|
||||
</configuration>
|
||||
<reportSets>
|
||||
<reportSet>
|
||||
<id>default</id>
|
||||
@@ -239,7 +241,7 @@ Copyright (c) 2013 Jeremy Long. All Rights Reserved.
|
||||
<linkXref>true</linkXref>
|
||||
<sourceEncoding>utf-8</sourceEncoding>
|
||||
<excludes>
|
||||
<exclude>**/generated/*.java</exclude>
|
||||
<exclude>**/generated/**/*.java</exclude>
|
||||
<exclude>**/HelpMojo.java</exclude>
|
||||
</excludes>
|
||||
<rulesets>
|
||||
@@ -277,6 +279,11 @@ Copyright (c) 2013 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>
|
||||
<dependency>
|
||||
<groupId>org.apache.maven</groupId>
|
||||
<artifactId>maven-plugin-api</artifactId>
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,161 @@
|
||||
/*
|
||||
* This file is part of dependency-check-maven.
|
||||
*
|
||||
* 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.maven;
|
||||
|
||||
import java.util.logging.Logger;
|
||||
import org.apache.maven.project.MavenProject;
|
||||
import org.owasp.dependencycheck.analyzer.Analyzer;
|
||||
import org.owasp.dependencycheck.analyzer.CPEAnalyzer;
|
||||
import org.owasp.dependencycheck.data.nvdcve.DatabaseException;
|
||||
import org.owasp.dependencycheck.utils.Settings;
|
||||
|
||||
/**
|
||||
* A modified version of the core engine specifically designed to persist some data between multiple executions of a
|
||||
* multi-module Maven project.
|
||||
*
|
||||
* @author Jeremy Long <jeremy.long@owasp.org>
|
||||
*/
|
||||
public class Engine extends org.owasp.dependencycheck.Engine {
|
||||
|
||||
/**
|
||||
* The logger.
|
||||
*/
|
||||
private static final transient Logger LOGGER = Logger.getLogger(Engine.class.getName());
|
||||
/**
|
||||
* A key used to persist an object in the MavenProject.
|
||||
*/
|
||||
private static final String CPE_ANALYZER_KEY = "dependency-check-CPEAnalyzer";
|
||||
/**
|
||||
* The current MavenProject.
|
||||
*/
|
||||
private MavenProject currentProject;
|
||||
|
||||
/**
|
||||
* Creates a new Engine to perform anyalsis on dependencies.
|
||||
*
|
||||
* @param project the current Maven project
|
||||
* @throws DatabaseException thrown if there is an issue connecting to the database
|
||||
*/
|
||||
public Engine(MavenProject project) throws DatabaseException {
|
||||
this.currentProject = project;
|
||||
final MavenProject parent = getRootParent();
|
||||
if (parent != null && parent.getContextValue("dependency-check-data-was-updated") != null) {
|
||||
System.setProperty(Settings.KEYS.AUTO_UPDATE, Boolean.FALSE.toString());
|
||||
}
|
||||
initializeEngine();
|
||||
if (parent != null) {
|
||||
parent.setContextValue("dependency-check-data-was-updated", Boolean.valueOf(true));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* This constructor should not be called. Use Engine(MavenProject) instead.
|
||||
*
|
||||
* @throws DatabaseException thrown if there is an issue connecting to the database
|
||||
*/
|
||||
private Engine() throws DatabaseException {
|
||||
}
|
||||
|
||||
/**
|
||||
* Initializes the given analyzer. This skips the initialization of the CPEAnalyzer if it has been initialized by a
|
||||
* previous execution.
|
||||
*
|
||||
* @param analyzer the analyzer to initialize
|
||||
* @return the initialized analyzer
|
||||
*/
|
||||
@Override
|
||||
protected Analyzer initializeAnalyzer(Analyzer analyzer) {
|
||||
if ((analyzer instanceof CPEAnalyzer)) {
|
||||
CPEAnalyzer cpe = getPreviouslyLoadedAnalyzer();
|
||||
if (cpe != null) {
|
||||
return cpe;
|
||||
}
|
||||
cpe = (CPEAnalyzer) super.initializeAnalyzer(analyzer);
|
||||
storeCPEAnalyzer(cpe);
|
||||
}
|
||||
return super.initializeAnalyzer(analyzer);
|
||||
}
|
||||
|
||||
/**
|
||||
* Closes the given analyzer. This skips closing the CPEAnalyzer.
|
||||
*
|
||||
* @param analyzer the analyzer to close
|
||||
*/
|
||||
@Override
|
||||
protected void closeAnalyzer(Analyzer analyzer) {
|
||||
if ((analyzer instanceof CPEAnalyzer)) {
|
||||
if (getPreviouslyLoadedAnalyzer() == null) {
|
||||
super.closeAnalyzer(analyzer);
|
||||
}
|
||||
} else {
|
||||
super.closeAnalyzer(analyzer);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Closes the CPEAnalyzer if it has been created and persisted in the root parent MavenProject context.
|
||||
*/
|
||||
public void cleanupFinal() {
|
||||
final CPEAnalyzer cpe = getPreviouslyLoadedAnalyzer();
|
||||
if (cpe != null) {
|
||||
cpe.close();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the CPEAnalyzer from the root Maven Project.
|
||||
*
|
||||
* @return an initialized CPEAnalyzer
|
||||
*/
|
||||
private CPEAnalyzer getPreviouslyLoadedAnalyzer() {
|
||||
CPEAnalyzer cpe = null;
|
||||
final MavenProject project = getRootParent();
|
||||
if (project != null) {
|
||||
cpe = (CPEAnalyzer) project.getContextValue(CPE_ANALYZER_KEY);
|
||||
}
|
||||
return cpe;
|
||||
}
|
||||
|
||||
/**
|
||||
* Stores a CPEAnalyzer in the root Maven Project.
|
||||
*
|
||||
* @param cpe the CPEAnalyzer to store
|
||||
*/
|
||||
private void storeCPEAnalyzer(CPEAnalyzer cpe) {
|
||||
final MavenProject p = getRootParent();
|
||||
if (p != null) {
|
||||
p.setContextValue(CPE_ANALYZER_KEY, cpe);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the root Maven Project.
|
||||
*
|
||||
* @return the root Maven Project
|
||||
*/
|
||||
private MavenProject getRootParent() {
|
||||
if (this.currentProject == null) {
|
||||
return null;
|
||||
}
|
||||
MavenProject p = this.currentProject;
|
||||
while (p.getParent() != null) {
|
||||
p = p.getParent();
|
||||
}
|
||||
return p;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,468 @@
|
||||
/*
|
||||
* This file is part of dependency-check-maven.
|
||||
*
|
||||
* 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.maven;
|
||||
|
||||
import java.io.File;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.HashMap;
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
import java.util.Locale;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
import java.util.logging.Logger;
|
||||
import org.apache.maven.doxia.sink.Sink;
|
||||
import org.apache.maven.plugin.AbstractMojo;
|
||||
import org.apache.maven.plugin.MojoExecutionException;
|
||||
import org.apache.maven.plugin.MojoFailureException;
|
||||
import org.apache.maven.plugins.annotations.Component;
|
||||
import org.apache.maven.plugins.annotations.Parameter;
|
||||
import org.apache.maven.project.MavenProject;
|
||||
import org.apache.maven.reporting.MavenReport;
|
||||
import org.apache.maven.reporting.MavenReportException;
|
||||
|
||||
/**
|
||||
* <p>
|
||||
* This is an abstract reporting mojo that enables report aggregation. Some of the code in the this class was copied
|
||||
* from the CoberturaReportMojo (http://mojo.codehaus.org/cobertura-maven-plugin/, version 2.6). The authors of the
|
||||
* CoberturaReportMojo were <a href="will.gwaltney@sas.com">Will Gwaltney</a> and
|
||||
* <a href="mailto:joakim@erdfelt.com">Joakim Erdfelt</a>. There working example of how to do report aggregation was
|
||||
* invaluable.</p>
|
||||
* <p>
|
||||
* An important point about using this abstract class is that it is intended for one to write some form of serialized
|
||||
* data (via the {@link org.owasp.dependencycheck.maven.ReportAggregationMojo#writeDataFile() }; note that the
|
||||
* <code>writeDataFile()</code> function is called automatically after either {@link org.owasp.dependencycheck.maven.ReportAggregationMojo#executeNonAggregateReport(org.apache.maven.doxia.sink.Sink,
|
||||
* org.apache.maven.doxia.sink.SinkFactory, java.util.Locale)
|
||||
* } or {@link org.owasp.dependencycheck.maven.ReportAggregationMojo#executeAggregateReport(org.apache.maven.doxia.sink.Sink,
|
||||
* org.apache.maven.doxia.sink.SinkFactory, java.util.Locale)
|
||||
* } are called. When <code>executeAggregateReport()</code> is implemented, one can call {@link org.owasp.dependencycheck.maven.ReportAggregationMojo#getChildDataFiles()
|
||||
* } to obtain a list of the data files to aggregate.</p>
|
||||
*
|
||||
*
|
||||
* @author Jeremy Long <jeremy.long@owasp.org>
|
||||
*/
|
||||
public abstract class ReportAggregationMojo extends AbstractMojo implements MavenReport {
|
||||
|
||||
/**
|
||||
* The Maven Project Object.
|
||||
*/
|
||||
@Component
|
||||
private MavenProject project;
|
||||
|
||||
/**
|
||||
* Logger field reference.
|
||||
*/
|
||||
private static final Logger LOGGER = Logger.getLogger(ReportAggregationMojo.class.getName());
|
||||
|
||||
/**
|
||||
* List of Maven project of the current build
|
||||
*/
|
||||
@Parameter(readonly = true, required = true, property = "reactorProjects")
|
||||
private List<MavenProject> reactorProjects;
|
||||
|
||||
/**
|
||||
* Generate aggregate reports in multi-module projects.
|
||||
*/
|
||||
@Parameter(property = "aggregate", defaultValue = "false")
|
||||
private boolean aggregate;
|
||||
|
||||
/**
|
||||
* Sets whether or not the external report format should be used.
|
||||
*/
|
||||
@Parameter(property = "metaFileName", defaultValue = "dependency-check.ser", required = true)
|
||||
private String dataFileName;
|
||||
/**
|
||||
* Specifies the destination directory for the generated Dependency-Check report. This generally maps to
|
||||
* "target/site".
|
||||
*/
|
||||
@Parameter(property = "reportOutputDirectory", defaultValue = "${project.reporting.outputDirectory}", required = true)
|
||||
private File reportOutputDirectory;
|
||||
|
||||
/**
|
||||
* Sets the Reporting output directory.
|
||||
*
|
||||
* @param directory the output directory
|
||||
*/
|
||||
@Override
|
||||
public void setReportOutputDirectory(File directory) {
|
||||
reportOutputDirectory = directory;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the output directory.
|
||||
*
|
||||
* @return the output directory
|
||||
*/
|
||||
@Override
|
||||
public File getReportOutputDirectory() {
|
||||
return reportOutputDirectory;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the output directory for the given project.
|
||||
*
|
||||
* @param project the Maven project to get the output directory for
|
||||
* @return the output directory for the given project
|
||||
*/
|
||||
public File getReportOutputDirectory(MavenProject project) {
|
||||
final Object o = project.getContextValue(getOutputDirectoryContextKey());
|
||||
if (o != null && o instanceof File) {
|
||||
return (File) o;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns whether this is an external report. This method always returns true.
|
||||
*
|
||||
* @return <code>true</code>
|
||||
*/
|
||||
@Override
|
||||
public final boolean isExternalReport() {
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Initializes the mojo.
|
||||
*/
|
||||
protected abstract void initialize();
|
||||
|
||||
/**
|
||||
* The collection of child projects.
|
||||
*/
|
||||
private final Map<MavenProject, Set<MavenProject>> projectChildren = new HashMap<MavenProject, Set<MavenProject>>();
|
||||
|
||||
/**
|
||||
* Called before execute; allows for any setup that is needed. If this is overridden you must call
|
||||
* </code>super.preExecute()</code>.
|
||||
*
|
||||
* @throws MojoExecutionException thrown if there is an issue executing the mojo
|
||||
* @throws MojoFailureException thrown if there is an issue executing the mojo
|
||||
*/
|
||||
protected void preExecute() throws MojoExecutionException, MojoFailureException {
|
||||
buildAggregateInfo();
|
||||
}
|
||||
|
||||
/**
|
||||
* Called when the mojo is being executed.
|
||||
*
|
||||
* @throws MojoExecutionException thrown if there is an issue executing the mojo
|
||||
* @throws MojoFailureException thrown if there is an issue executing the mojo
|
||||
*/
|
||||
protected abstract void performExecute() throws MojoExecutionException, MojoFailureException;
|
||||
|
||||
/**
|
||||
* Runs after the mojo has executed. This implementation will call <code>writeDataFile()</code>. As such, it is
|
||||
* important that if this method is overriden that <code>super.postExecute()</code> is called.
|
||||
*
|
||||
* @throws MojoExecutionException thrown if there is an issue executing the mojo
|
||||
* @throws MojoFailureException thrown if there is an issue executing the mojo
|
||||
*/
|
||||
protected void postExecute() throws MojoExecutionException, MojoFailureException {
|
||||
final File written = writeDataFile();
|
||||
if (written != null) {
|
||||
project.setContextValue(getDataFileContextKey(), written.getAbsolutePath());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the key used to store the path to the data file that is saved by <code>writeDataFile()</code>. This key
|
||||
* is used in the <code>MavenProject.(set|get)ContextValue</code>.
|
||||
*
|
||||
* @return the key used to store the path to the data file
|
||||
*/
|
||||
protected String getDataFileContextKey() {
|
||||
return "dependency-check-path-" + this.getDataFileName();
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the key used to store the path to the output directory. When generating the report in the
|
||||
* <code>executeAggregateReport()</code> the output directory should be obtained by using this key.
|
||||
*
|
||||
* @return the key used to store the path to the output directory
|
||||
*/
|
||||
protected String getOutputDirectoryContextKey() {
|
||||
return "dependency-output-dir-" + this.getDataFileName();
|
||||
}
|
||||
|
||||
/**
|
||||
* Is called by Maven to execute the mojo.
|
||||
*
|
||||
* @throws MojoExecutionException thrown if there is an issue executing the mojo
|
||||
* @throws MojoFailureException thrown if there is an issue executing the mojo
|
||||
*/
|
||||
public final void execute() throws MojoExecutionException, MojoFailureException {
|
||||
try {
|
||||
initialize();
|
||||
preExecute();
|
||||
performExecute();
|
||||
} finally {
|
||||
postExecute();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Runs prior to the site report generation.
|
||||
*
|
||||
* @throws MavenReportException if a maven report exception occurs
|
||||
*/
|
||||
protected void preGenerate() throws MavenReportException {
|
||||
buildAggregateInfo();
|
||||
|
||||
project.setContextValue(getOutputDirectoryContextKey(), getReportOutputDirectory());
|
||||
}
|
||||
|
||||
/**
|
||||
* Executes after the site report has been generated.
|
||||
*
|
||||
* @throws MavenReportException if a maven report exception occurs
|
||||
*/
|
||||
protected void postGenerate() throws MavenReportException {
|
||||
final File written = writeDataFile();
|
||||
if (written != null) {
|
||||
project.setContextValue(getDataFileContextKey(), written.getAbsolutePath());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Generates the non aggregate report.
|
||||
*
|
||||
* @param locale the locale to use when generating the report
|
||||
* @throws MavenReportException if a maven report exception occurs
|
||||
*/
|
||||
protected abstract void executeNonAggregateReport(Locale locale) throws MavenReportException;
|
||||
|
||||
/**
|
||||
* Generates the aggregate Site Report.
|
||||
*
|
||||
* @param project the maven project used to generate the aggregate report
|
||||
* @param locale the locale to use when generating the report
|
||||
* @throws MavenReportException if a maven report exception occurs
|
||||
*/
|
||||
protected abstract void executeAggregateReport(MavenProject project, Locale locale) throws MavenReportException;
|
||||
|
||||
/**
|
||||
* Generates the Dependency-Check Site Report.
|
||||
*
|
||||
* @param sink the sink to write the report to
|
||||
* @param locale the locale to use when generating the report
|
||||
* @throws MavenReportException if a maven report exception occurs
|
||||
* @deprecated use {@link #generate(org.apache.maven.doxia.sink.Sink, java.util.Locale) instead.
|
||||
*/
|
||||
@Deprecated
|
||||
public final void generate(@SuppressWarnings("deprecation") org.codehaus.doxia.sink.Sink sink, Locale locale) throws MavenReportException {
|
||||
generate((Sink) sink, locale);
|
||||
}
|
||||
|
||||
/**
|
||||
* Generates the Dependency-Check Site Report.
|
||||
*
|
||||
* @param sink the sink to write the report to
|
||||
* @param locale the locale to use when generating the report
|
||||
* @throws MavenReportException if a maven report exception occurs
|
||||
*/
|
||||
public final void generate(Sink sink, Locale locale) throws MavenReportException {
|
||||
try {
|
||||
initialize();
|
||||
preGenerate();
|
||||
if (canGenerateNonAggregateReport()) {
|
||||
executeNonAggregateReport(locale);
|
||||
}
|
||||
} finally {
|
||||
postGenerate();
|
||||
}
|
||||
if (canGenerateAggregateReport()) {
|
||||
for (MavenProject proj : reactorProjects) {
|
||||
if (!isMultiModule(proj)) {
|
||||
continue;
|
||||
}
|
||||
executeAggregateReport(proj, locale);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns whether or not the mojo can generate a non-aggregate report for this project.
|
||||
*
|
||||
* @return <code>true</code> if a non-aggregate report can be generated, otherwise <code>false</code>
|
||||
*/
|
||||
protected abstract boolean canGenerateNonAggregateReport();
|
||||
|
||||
/**
|
||||
* Returns whether or not we can generate any aggregate reports at this time.
|
||||
*
|
||||
* @return <code>true</code> if an aggregate report can be generated, otherwise <code>false</code>
|
||||
*/
|
||||
protected abstract boolean canGenerateAggregateReport();
|
||||
|
||||
/**
|
||||
* Returns the name of the data file that contains the serialized data.
|
||||
*
|
||||
* @return the name of the data file that contains the serialized data
|
||||
*/
|
||||
protected String getDataFileName() {
|
||||
return dataFileName;
|
||||
}
|
||||
|
||||
/**
|
||||
* Writes the data file to disk in the target directory.
|
||||
*
|
||||
* @return the File object referencing the data file that was written
|
||||
*/
|
||||
protected abstract File writeDataFile();
|
||||
|
||||
/**
|
||||
* Collects the information needed for building aggregate reports.
|
||||
*/
|
||||
private void buildAggregateInfo() {
|
||||
// build parent-child map
|
||||
for (MavenProject proj : reactorProjects) {
|
||||
Set<MavenProject> depList = projectChildren.get(proj.getParent());
|
||||
if (depList == null) {
|
||||
depList = new HashSet<MavenProject>();
|
||||
projectChildren.put(proj.getParent(), depList);
|
||||
}
|
||||
depList.add(proj);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a list containing all the recursive, non-pom children of the given project, never <code>null</code>.
|
||||
*
|
||||
* @return a list of child projects
|
||||
*/
|
||||
protected List<MavenProject> getAllChildren() {
|
||||
return getAllChildren(project);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a list containing all the recursive, non-pom children of the given project, never <code>null</code>.
|
||||
*
|
||||
* @param parentProject the parent project to collect the child project references
|
||||
* @return a list of child projects
|
||||
*/
|
||||
protected List<MavenProject> getAllChildren(MavenProject parentProject) {
|
||||
final Set<MavenProject> children = projectChildren.get(parentProject);
|
||||
if (children == null) {
|
||||
return Collections.emptyList();
|
||||
}
|
||||
|
||||
final List<MavenProject> result = new ArrayList<MavenProject>();
|
||||
for (MavenProject child : children) {
|
||||
if (isMultiModule(child)) {
|
||||
result.addAll(getAllChildren(child));
|
||||
} else {
|
||||
result.add(child);
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a list of data files that were produced by the direct children of the given MavenProject.
|
||||
*
|
||||
* @param project the Maven project to obtain the child data files from
|
||||
* @return a list of the data files
|
||||
*/
|
||||
protected List<File> getAllChildDataFiles(MavenProject project) {
|
||||
final List<MavenProject> children = getAllChildren(project);
|
||||
return getDataFiles(children);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns any existing output files from the given list of projects.
|
||||
*
|
||||
* @param projects the list of projects to obtain the output files from
|
||||
* @return a list of output files
|
||||
*/
|
||||
protected List<File> getDataFiles(List<MavenProject> projects) {
|
||||
final List<File> files = new ArrayList<File>();
|
||||
for (MavenProject proj : projects) {
|
||||
final Object path = project.getContextValue(getDataFileContextKey());
|
||||
if (path == null) {
|
||||
final String msg = String.format("Unable to aggregate data for '%s' - aggregate data file was not generated",
|
||||
proj.getName());
|
||||
LOGGER.warning(msg);
|
||||
} else {
|
||||
final File outputFile = new File((String) path);
|
||||
if (outputFile.exists()) {
|
||||
files.add(outputFile);
|
||||
} else {
|
||||
if (!isMultiModule(project)) {
|
||||
final String msg = String.format("Unable to aggregate data for '%s' - missing data file '%s'",
|
||||
proj.getName(), outputFile.getPath());
|
||||
LOGGER.warning(msg);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return files;
|
||||
}
|
||||
|
||||
/**
|
||||
* Test if the project has pom packaging
|
||||
*
|
||||
* @param mavenProject Project to test
|
||||
* @return <code>true</code> if it has a pom packaging; otherwise <code>false</code>
|
||||
*/
|
||||
protected boolean isMultiModule(MavenProject mavenProject) {
|
||||
return "pom".equals(mavenProject.getPackaging());
|
||||
}
|
||||
|
||||
/**
|
||||
* Test if the current project has pom packaging
|
||||
*
|
||||
* @return <code>true</code> if it has a pom packaging; otherwise <code>false</code>
|
||||
*/
|
||||
protected boolean isMultiModule() {
|
||||
return isMultiModule(project);
|
||||
}
|
||||
|
||||
/**
|
||||
* Check whether the current project is the last project in a multi-module build. If the maven build is not a
|
||||
* multi-module project then this will always return true.
|
||||
*
|
||||
* @return <code>true</code> if the current project is the last project in a multi-module build; otherwise
|
||||
* <code>false</code>
|
||||
*/
|
||||
protected boolean isLastProject() {
|
||||
return project.equals(reactorProjects.get(reactorProjects.size() - 1));
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns whether or not the mojo is configured to perform report aggregation.
|
||||
*
|
||||
* @return <code>true</code> if report aggregation is enabled; otherwise <code>false</code>
|
||||
*/
|
||||
public boolean isAggregate() {
|
||||
return aggregate;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a reference to the current project. This method is used instead of auto-binding the project via component
|
||||
* annotation in concrete implementations of this. If the child has a <code>@Component MavenProject project;</code>
|
||||
* defined then the abstract class (i.e. this class) will not have access to the current project (just the way Maven
|
||||
* works with the binding).
|
||||
*
|
||||
* @return returns a reference to the current project
|
||||
*/
|
||||
protected MavenProject getProject() {
|
||||
return project;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,455 @@
|
||||
/*
|
||||
* This file is part of dependency-check-maven.
|
||||
*
|
||||
* 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.maven;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.io.UnsupportedEncodingException;
|
||||
import java.net.URLEncoder;
|
||||
import java.text.DateFormat;
|
||||
import java.util.Date;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
import java.util.logging.Level;
|
||||
import java.util.logging.Logger;
|
||||
import org.apache.maven.doxia.sink.Sink;
|
||||
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.dependency.Evidence;
|
||||
import org.owasp.dependencycheck.dependency.Identifier;
|
||||
import org.owasp.dependencycheck.dependency.Reference;
|
||||
import org.owasp.dependencycheck.dependency.Vulnerability;
|
||||
import org.owasp.dependencycheck.dependency.VulnerableSoftware;
|
||||
import org.owasp.dependencycheck.reporting.ReportGenerator;
|
||||
|
||||
/**
|
||||
* A utility class that encapsulates the report generation for dependency-check-maven.
|
||||
*
|
||||
* @author Jeremy Long <jeremy.long@owasp.org>
|
||||
*/
|
||||
final class ReportingUtil {
|
||||
|
||||
/**
|
||||
* Logger field reference.
|
||||
*/
|
||||
private static final Logger LOGGER = Logger.getLogger(ReportingUtil.class.getName());
|
||||
|
||||
/**
|
||||
* Empty private constructor for this utility class.
|
||||
*/
|
||||
private ReportingUtil() {
|
||||
}
|
||||
|
||||
/**
|
||||
* Generates the reports for a given dependency-check engine.
|
||||
*
|
||||
* @param engine a dependency-check engine
|
||||
* @param outDirectory the directory to write the reports to
|
||||
* @param projectName the name of the project that a report is being generated for
|
||||
* @param format the format of the report to generate
|
||||
*/
|
||||
static void generateExternalReports(Engine engine, File outDirectory, String projectName, String format) {
|
||||
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 r = new ReportGenerator(projectName, engine.getDependencies(), engine.getAnalyzers(), prop);
|
||||
try {
|
||||
r.generateReports(outDirectory.getCanonicalPath(), format);
|
||||
} catch (IOException ex) {
|
||||
LOGGER.log(Level.SEVERE,
|
||||
"Unexpected exception occurred during analysis; please see the verbose error log for more details.");
|
||||
LOGGER.log(Level.FINE, null, ex);
|
||||
} catch (Throwable ex) {
|
||||
LOGGER.log(Level.SEVERE,
|
||||
"Unexpected exception occurred during analysis; please see the verbose error log for more details.");
|
||||
LOGGER.log(Level.FINE, null, ex);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Generates a dependency-check report using the Maven Site format.
|
||||
*
|
||||
* @param engine the engine used to scan the dependencies
|
||||
* @param sink the sink to write the data to
|
||||
* @param projectName the name of the project
|
||||
*/
|
||||
static void generateMavenSiteReport(final Engine engine, Sink sink, String projectName) {
|
||||
final List<Dependency> dependencies = engine.getDependencies();
|
||||
|
||||
writeSiteReportHeader(sink, projectName);
|
||||
writeSiteReportTOC(sink, dependencies);
|
||||
|
||||
int cnt = 0;
|
||||
for (Dependency d : dependencies) {
|
||||
writeSiteReportDependencyHeader(sink, d);
|
||||
cnt = writeSiteReportDependencyEvidenceUsed(d, cnt, sink);
|
||||
cnt = writeSiteReportDependencyRelatedDependencies(d, cnt, sink);
|
||||
writeSiteReportDependencyIdentifiers(d, sink);
|
||||
writeSiteReportDependencyVulnerabilities(d, sink, cnt);
|
||||
}
|
||||
sink.body_();
|
||||
}
|
||||
|
||||
// <editor-fold defaultstate="collapsed" desc="various writeXXXXX methods to generate the Site Report">
|
||||
/**
|
||||
* Writes the vulnerabilities to the site report.
|
||||
*
|
||||
* @param d the dependency
|
||||
* @param sink the sink to write the data to
|
||||
* @param collapsibleHeaderCount the collapsible header count
|
||||
*/
|
||||
private static void writeSiteReportDependencyVulnerabilities(Dependency d, Sink sink, int collapsibleHeaderCount) {
|
||||
int cnt = collapsibleHeaderCount;
|
||||
if (d.getVulnerabilities() != null && !d.getVulnerabilities().isEmpty()) {
|
||||
for (Vulnerability v : d.getVulnerabilities()) {
|
||||
|
||||
sink.paragraph();
|
||||
sink.bold();
|
||||
try {
|
||||
sink.link("http://web.nvd.nist.gov/view/vuln/detail?vulnId=" + URLEncoder.encode(v.getName(), "US-ASCII"));
|
||||
sink.text(v.getName());
|
||||
sink.link_();
|
||||
sink.bold_();
|
||||
} catch (UnsupportedEncodingException ex) {
|
||||
sink.text(v.getName());
|
||||
sink.bold_();
|
||||
sink.lineBreak();
|
||||
sink.text("http://web.nvd.nist.gov/view/vuln/detail?vulnId=" + v.getName());
|
||||
}
|
||||
sink.paragraph_();
|
||||
sink.paragraph();
|
||||
sink.text("Severity: ");
|
||||
if (v.getCvssScore() < 4.0) {
|
||||
sink.text("Low");
|
||||
} else {
|
||||
if (v.getCvssScore() >= 7.0) {
|
||||
sink.text("High");
|
||||
} else {
|
||||
sink.text("Medium");
|
||||
}
|
||||
}
|
||||
sink.lineBreak();
|
||||
sink.text("CVSS Score: " + v.getCvssScore());
|
||||
if (v.getCwe() != null && !v.getCwe().isEmpty()) {
|
||||
sink.lineBreak();
|
||||
sink.text("CWE: ");
|
||||
sink.text(v.getCwe());
|
||||
}
|
||||
sink.paragraph_();
|
||||
sink.paragraph();
|
||||
sink.text(v.getDescription());
|
||||
if (v.getReferences() != null && !v.getReferences().isEmpty()) {
|
||||
sink.list();
|
||||
for (Reference ref : v.getReferences()) {
|
||||
sink.listItem();
|
||||
sink.text(ref.getSource());
|
||||
sink.text(" - ");
|
||||
sink.link(ref.getUrl());
|
||||
sink.text(ref.getName());
|
||||
sink.link_();
|
||||
sink.listItem_();
|
||||
}
|
||||
sink.list_();
|
||||
}
|
||||
sink.paragraph_();
|
||||
if (v.getVulnerableSoftware() != null && !v.getVulnerableSoftware().isEmpty()) {
|
||||
sink.paragraph();
|
||||
|
||||
cnt += 1;
|
||||
sink.rawText("Vulnerable Software <a href=\"javascript:toggleElement(this, 'vulnSoft" + cnt + "')\">[-]</a>");
|
||||
sink.rawText("<div id=\"vulnSoft" + cnt + "\" style=\"display:block\">");
|
||||
sink.list();
|
||||
for (VulnerableSoftware vs : v.getVulnerableSoftware()) {
|
||||
sink.listItem();
|
||||
try {
|
||||
sink.link("http://web.nvd.nist.gov/view/vuln/search-results?cpe=" + URLEncoder.encode(vs.getName(), "US-ASCII"));
|
||||
sink.text(vs.getName());
|
||||
sink.link_();
|
||||
if (vs.hasPreviousVersion()) {
|
||||
sink.text(" and all previous versions.");
|
||||
}
|
||||
} catch (UnsupportedEncodingException ex) {
|
||||
sink.text(vs.getName());
|
||||
if (vs.hasPreviousVersion()) {
|
||||
sink.text(" and all previous versions.");
|
||||
}
|
||||
sink.text(" (http://web.nvd.nist.gov/view/vuln/search-results?cpe=" + vs.getName() + ")");
|
||||
}
|
||||
|
||||
sink.listItem_();
|
||||
}
|
||||
sink.list_();
|
||||
sink.rawText("</div>");
|
||||
sink.paragraph_();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Writes the identifiers to the site report.
|
||||
*
|
||||
* @param d the dependency
|
||||
* @param sink the sink to write the data to
|
||||
*/
|
||||
private static void writeSiteReportDependencyIdentifiers(Dependency d, Sink sink) {
|
||||
if (d.getIdentifiers() != null && !d.getIdentifiers().isEmpty()) {
|
||||
sink.sectionTitle4();
|
||||
sink.text("Identifiers");
|
||||
sink.sectionTitle4_();
|
||||
sink.list();
|
||||
for (Identifier i : d.getIdentifiers()) {
|
||||
sink.listItem();
|
||||
sink.text(i.getType());
|
||||
sink.text(": ");
|
||||
if (i.getUrl() != null && i.getUrl().length() > 0) {
|
||||
sink.link(i.getUrl());
|
||||
sink.text(i.getValue());
|
||||
sink.link_();
|
||||
} else {
|
||||
sink.text(i.getValue());
|
||||
}
|
||||
if (i.getDescription() != null && i.getDescription().length() > 0) {
|
||||
sink.lineBreak();
|
||||
sink.text(i.getDescription());
|
||||
}
|
||||
sink.listItem_();
|
||||
}
|
||||
sink.list_();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Writes the related dependencies to the site report.
|
||||
*
|
||||
* @param d the dependency
|
||||
* @param sink the sink to write the data to
|
||||
* @param collapsibleHeaderCount the collapsible header count
|
||||
* @return the collapsible header count
|
||||
*/
|
||||
private static int writeSiteReportDependencyRelatedDependencies(Dependency d, int collapsibleHeaderCount, Sink sink) {
|
||||
int cnt = collapsibleHeaderCount;
|
||||
if (d.getRelatedDependencies() != null && !d.getRelatedDependencies().isEmpty()) {
|
||||
cnt += 1;
|
||||
sink.sectionTitle4();
|
||||
sink.rawText("Related Dependencies <a href=\"javascript:toggleElement(this, 'related" + cnt + "')\">[+]</a>");
|
||||
sink.sectionTitle4_();
|
||||
sink.rawText("<div id=\"related" + cnt + "\" style=\"display:none\">");
|
||||
sink.list();
|
||||
for (Dependency r : d.getRelatedDependencies()) {
|
||||
sink.listItem();
|
||||
sink.text(r.getFileName());
|
||||
sink.list();
|
||||
writeListItem(sink, "File Path: " + r.getFilePath());
|
||||
writeListItem(sink, "SHA1: " + r.getSha1sum());
|
||||
writeListItem(sink, "MD5: " + r.getMd5sum());
|
||||
sink.list_();
|
||||
sink.listItem_();
|
||||
}
|
||||
sink.list_();
|
||||
sink.rawText("</div>");
|
||||
}
|
||||
return cnt;
|
||||
}
|
||||
|
||||
/**
|
||||
* Writes the evidence used to the site report.
|
||||
*
|
||||
* @param d the dependency
|
||||
* @param sink the sink to write the data to
|
||||
* @param collapsibleHeaderCount the collapsible header count
|
||||
* @return the collapsible header count
|
||||
*/
|
||||
private static int writeSiteReportDependencyEvidenceUsed(Dependency d, int collapsibleHeaderCount, Sink sink) {
|
||||
int cnt = collapsibleHeaderCount;
|
||||
final Set<Evidence> evidence = d.getEvidenceForDisplay();
|
||||
if (evidence != null && evidence.size() > 0) {
|
||||
cnt += 1;
|
||||
sink.sectionTitle4();
|
||||
sink.rawText("Evidence Collected <a href=\"javascript:toggleElement(this, 'evidence" + cnt + "')\">[+]</a>");
|
||||
sink.sectionTitle4_();
|
||||
sink.rawText("<div id=\"evidence" + cnt + "\" style=\"display:none\">");
|
||||
sink.table();
|
||||
sink.tableRow();
|
||||
writeTableHeaderCell(sink, "Source");
|
||||
writeTableHeaderCell(sink, "Name");
|
||||
writeTableHeaderCell(sink, "Value");
|
||||
sink.tableRow_();
|
||||
for (Evidence e : evidence) {
|
||||
sink.tableRow();
|
||||
writeTableCell(sink, e.getSource());
|
||||
writeTableCell(sink, e.getName());
|
||||
writeTableCell(sink, e.getValue());
|
||||
sink.tableRow_();
|
||||
}
|
||||
sink.table_();
|
||||
sink.rawText("</div>");
|
||||
}
|
||||
return cnt;
|
||||
}
|
||||
|
||||
/**
|
||||
* Writes the dependency header to the site report.
|
||||
*
|
||||
* @param d the dependency
|
||||
* @param sink the sink to write the data to
|
||||
*/
|
||||
private static void writeSiteReportDependencyHeader(Sink sink, Dependency d) {
|
||||
sink.sectionTitle2();
|
||||
sink.anchor("sha1" + d.getSha1sum());
|
||||
sink.text(d.getFileName());
|
||||
sink.anchor_();
|
||||
sink.sectionTitle2_();
|
||||
if (d.getDescription() != null && d.getDescription().length() > 0) {
|
||||
sink.paragraph();
|
||||
sink.bold();
|
||||
sink.text("Description: ");
|
||||
sink.bold_();
|
||||
sink.text(d.getDescription());
|
||||
sink.paragraph_();
|
||||
}
|
||||
if (d.getLicense() != null && d.getLicense().length() > 0) {
|
||||
sink.paragraph();
|
||||
sink.bold();
|
||||
sink.text("License: ");
|
||||
sink.bold_();
|
||||
if (d.getLicense().startsWith("http://") && !d.getLicense().contains(" ")) {
|
||||
sink.link(d.getLicense());
|
||||
sink.text(d.getLicense());
|
||||
sink.link_();
|
||||
} else {
|
||||
sink.text(d.getLicense());
|
||||
}
|
||||
sink.paragraph_();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds a list item to the site report.
|
||||
*
|
||||
* @param sink the sink to write the data to
|
||||
* @param text the text to write
|
||||
*/
|
||||
private static void writeListItem(Sink sink, String text) {
|
||||
sink.listItem();
|
||||
sink.text(text);
|
||||
sink.listItem_();
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds a table cell to the site report.
|
||||
*
|
||||
* @param sink the sink to write the data to
|
||||
* @param text the text to write
|
||||
*/
|
||||
private static void writeTableCell(Sink sink, String text) {
|
||||
sink.tableCell();
|
||||
sink.text(text);
|
||||
sink.tableCell_();
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds a table header cell to the site report.
|
||||
*
|
||||
* @param sink the sink to write the data to
|
||||
* @param text the text to write
|
||||
*/
|
||||
private static void writeTableHeaderCell(Sink sink, String text) {
|
||||
sink.tableHeaderCell();
|
||||
sink.text(text);
|
||||
sink.tableHeaderCell_();
|
||||
}
|
||||
|
||||
/**
|
||||
* Writes the TOC for the site report.
|
||||
*
|
||||
* @param sink the sink to write the data to
|
||||
* @param dependencies the dependencies that are being reported on
|
||||
*/
|
||||
private static void writeSiteReportTOC(Sink sink, final List<Dependency> dependencies) {
|
||||
sink.list();
|
||||
for (Dependency d : dependencies) {
|
||||
sink.listItem();
|
||||
sink.link("#sha1" + d.getSha1sum());
|
||||
sink.text(d.getFileName());
|
||||
sink.link_();
|
||||
if (!d.getVulnerabilities().isEmpty()) {
|
||||
sink.rawText(" <font style=\"color:red\">•</font>");
|
||||
}
|
||||
if (!d.getRelatedDependencies().isEmpty()) {
|
||||
sink.list();
|
||||
for (Dependency r : d.getRelatedDependencies()) {
|
||||
writeListItem(sink, r.getFileName());
|
||||
}
|
||||
sink.list_();
|
||||
}
|
||||
sink.listItem_();
|
||||
}
|
||||
sink.list_();
|
||||
}
|
||||
|
||||
/**
|
||||
* Writes the site report header.
|
||||
*
|
||||
* @param sink the sink to write the data to
|
||||
* @param projectName the name of the project
|
||||
*/
|
||||
private static void writeSiteReportHeader(Sink sink, String projectName) {
|
||||
sink.head();
|
||||
sink.title();
|
||||
sink.text("Dependency-Check Report: " + projectName);
|
||||
sink.title_();
|
||||
sink.head_();
|
||||
sink.body();
|
||||
sink.rawText("<script type=\"text/javascript\">");
|
||||
sink.rawText("function toggleElement(el, targetId) {");
|
||||
sink.rawText("if (el.innerText == '[+]') {");
|
||||
sink.rawText(" el.innerText = '[-]';");
|
||||
sink.rawText(" document.getElementById(targetId).style.display='block';");
|
||||
sink.rawText("} else {");
|
||||
sink.rawText(" el.innerText = '[+]';");
|
||||
sink.rawText(" document.getElementById(targetId).style.display='none';");
|
||||
sink.rawText("}");
|
||||
|
||||
sink.rawText("}");
|
||||
sink.rawText("</script>");
|
||||
sink.section1();
|
||||
sink.sectionTitle1();
|
||||
sink.text("Project: " + projectName);
|
||||
sink.sectionTitle1_();
|
||||
sink.date();
|
||||
final Date now = new Date();
|
||||
sink.text(DateFormat.getDateTimeInstance().format(now));
|
||||
sink.date_();
|
||||
sink.section1_();
|
||||
}
|
||||
// </editor-fold>
|
||||
|
||||
}
|
||||
@@ -4,8 +4,8 @@ The following properties can be set on the dependency-check-maven plugin.
|
||||
|
||||
Property | Description | Default Value
|
||||
---------------------|------------------------------------|------------------
|
||||
aggregate | Sets whether report aggregation will be performed for multi-module site reports. This option only affects the report generation when configured within the reporting section. | false
|
||||
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
|
||||
@@ -23,49 +23,44 @@ 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
|
||||
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 Jar Analyzer will be used. | true
|
||||
nexusAnalyzerEnabled | Sets whether Nexus Analyzer will be used. | true
|
||||
nexusUrl | Defines the Nexus URL. | https://repository.sonatype.org/service/local/
|
||||
jarAnalyzer | Sets whether Jar Analyzer will be used. | true
|
||||
nexusAnalyzerEnabled | Sets whether Nexus Analyzer will be used. | true
|
||||
nexusUrl | Defines the Nexus Pro Server 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 |
|
||||
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
|
||||
connectionTimeout | The URL Connection Timeout. |
|
||||
dataDirectory | Data directory to hold SQL CVEs contents. This should generally not be changed. |
|
||||
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
|
||||
connectionTimeout | Sets the URL Connection Timeout used when downloading external data. |
|
||||
dataDirectory | Sets the 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. |
|
||||
metaFileName | Sets the name of the file to use for storing the metadata about the project. | dependency-check.ser
|
||||
|
||||
|
||||
Deprecated Configuration
|
||||
Proxy Configuration
|
||||
====================
|
||||
The following properties have been deprecated. These can still be set in
|
||||
the dependency-check-maven plugin's configuration. However, future versions
|
||||
will remove these properties. Instead using these properties you should
|
||||
use [Maven's settings](https://maven.apache.org/settings.html#Proxies) to
|
||||
configure a proxy.
|
||||
Use [Maven's settings](https://maven.apache.org/settings.html#Proxies) to configure a proxy server. If multiple proxies
|
||||
are configured in the Maven settings file you must tell dependency-check which proxy to use with the following property:
|
||||
|
||||
Property | Description | Default Value
|
||||
---------------------|--------------------------------------------------------------------------------------|------------------
|
||||
mavenSettingsProxyId | The id for the proxy, configured via settings.xml, that dependency-check should use. |
|
||||
|
||||
Property | Description | Default Value
|
||||
---------------------|------------------------------------|------------------
|
||||
proxyUrl | The Proxy URL. |
|
||||
proxyPort | The Proxy Port. |
|
||||
proxyUsername | Defines the proxy user name. |
|
||||
proxyPassword | Defines the proxy password. |
|
||||
|
||||
@@ -17,7 +17,9 @@ Create the DependencyCheck-report.html in the target directory
|
||||
|
||||
```xml
|
||||
<project>
|
||||
...
|
||||
<build>
|
||||
...
|
||||
<plugins>
|
||||
...
|
||||
<plugin>
|
||||
@@ -41,11 +43,48 @@ Create the DependencyCheck-report.html in the target directory
|
||||
```
|
||||
|
||||
$H$H$H Example 2:
|
||||
Create an aggregated dependency-check report within the site
|
||||
|
||||
```xml
|
||||
<project>
|
||||
...
|
||||
<reporting>
|
||||
...
|
||||
<plugins>
|
||||
...
|
||||
<plugin>
|
||||
<plugin>
|
||||
<groupId>org.owasp</groupId>
|
||||
<artifactId>dependency-check-maven</artifactId>
|
||||
<version>${project.version}</version>
|
||||
<configuration>
|
||||
<aggregate>true</aggregate>
|
||||
</configuration>
|
||||
<reportSets>
|
||||
<reportSet>
|
||||
<reports>
|
||||
<report>check</report>
|
||||
</reports>
|
||||
</reportSet>
|
||||
</reportSets>
|
||||
</plugin>
|
||||
</plugin>
|
||||
...
|
||||
</plugins>
|
||||
...
|
||||
</reporting>
|
||||
...
|
||||
</project>
|
||||
```
|
||||
|
||||
$H$H$H Example 3:
|
||||
Create the DependencyCheck-report.html and fail the build for CVSS greater then 8
|
||||
|
||||
```xml
|
||||
<project>
|
||||
...
|
||||
<build>
|
||||
...
|
||||
<plugins>
|
||||
...
|
||||
<plugin>
|
||||
@@ -71,44 +110,14 @@ Create the DependencyCheck-report.html and fail the build for CVSS greater then
|
||||
</project>
|
||||
```
|
||||
|
||||
$H$H$H Example 3:
|
||||
Create the dependency-check report within the site
|
||||
|
||||
```xml
|
||||
<project>
|
||||
<build>
|
||||
<plugins>
|
||||
...
|
||||
<plugin>
|
||||
<groupId>org.apache.maven.plugins</groupId>
|
||||
<artifactId>maven-site-plugin</artifactId>
|
||||
<configuration>
|
||||
<reportPlugins>
|
||||
<plugin>
|
||||
<groupId>org.owasp</groupId>
|
||||
<artifactId>dependency-check-maven</artifactId>
|
||||
<version>${project.version}</version>
|
||||
<configuration>
|
||||
<externalReport>false</externalReport>
|
||||
</configuration>
|
||||
</plugin>
|
||||
</reportPlugins>
|
||||
</configuration>
|
||||
</plugin>
|
||||
...
|
||||
</plugins>
|
||||
...
|
||||
</build>
|
||||
...
|
||||
</project>
|
||||
```
|
||||
|
||||
$H$H$H Example 4:
|
||||
Create the DependencyCheck-report.html and skip artifacts no bundled in distribution (Provided and Runtime scope)
|
||||
Create the DependencyCheck-report.html and skip artifacts not bundled in distribution (Provided and Runtime scope)
|
||||
|
||||
```xml
|
||||
<project>
|
||||
...
|
||||
<build>
|
||||
...
|
||||
<plugins>
|
||||
...
|
||||
<plugin>
|
||||
@@ -140,7 +149,9 @@ Create the DependencyCheck-report.html and use internal mirroring of CVE content
|
||||
|
||||
```xml
|
||||
<project>
|
||||
...
|
||||
<build>
|
||||
...
|
||||
<plugins>
|
||||
...
|
||||
<plugin>
|
||||
|
||||
289
dependency-check-utils/pom.xml
Normal file
289
dependency-check-utils/pom.xml
Normal file
@@ -0,0 +1,289 @@
|
||||
<!--
|
||||
This file is part of dependency-check-utils.
|
||||
|
||||
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.
|
||||
-->
|
||||
<project xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd" xmlns="http://maven.apache.org/POM/4.0.0"
|
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
<parent>
|
||||
<groupId>org.owasp</groupId>
|
||||
<artifactId>dependency-check-parent</artifactId>
|
||||
<version>1.2.7</version>
|
||||
</parent>
|
||||
|
||||
<artifactId>dependency-check-utils</artifactId>
|
||||
<name>Dependency-Check Utils</name>
|
||||
<description>dependency-check-utils is a collection of common utlity classes used within dependency-check that might be useful in other projects.</description>
|
||||
<!-- begin copy from http://minds.coremedia.com/2012/09/11/problem-solved-deploy-multi-module-maven-project-site-as-github-pages/ -->
|
||||
<distributionManagement>
|
||||
<site>
|
||||
<id>github-pages-site</id>
|
||||
<name>Deployment through GitHub's site deployment plugin</name>
|
||||
<url>${basedir}/../target/site/${project.version}/dependency-check-utils</url>
|
||||
</site>
|
||||
</distributionManagement>
|
||||
<!-- end copy -->
|
||||
|
||||
<properties>
|
||||
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
|
||||
</properties>
|
||||
<build>
|
||||
<plugins>
|
||||
<plugin>
|
||||
<groupId>org.codehaus.mojo</groupId>
|
||||
<artifactId>cobertura-maven-plugin</artifactId>
|
||||
<version>2.6</version>
|
||||
<configuration>
|
||||
<instrumentation>
|
||||
<ignoreTrivial>true</ignoreTrivial>
|
||||
</instrumentation>
|
||||
<check>
|
||||
<branchRate>85</branchRate>
|
||||
<lineRate>85</lineRate>
|
||||
<haltOnFailure>false</haltOnFailure>
|
||||
<totalBranchRate>85</totalBranchRate>
|
||||
<totalLineRate>85</totalLineRate>
|
||||
<packageLineRate>85</packageLineRate>
|
||||
<packageBranchRate>85</packageBranchRate>
|
||||
<regexes>
|
||||
<regex>
|
||||
<pattern>.*\$.*</pattern>
|
||||
<branchRate>0</branchRate>
|
||||
<lineRate>0</lineRate>
|
||||
</regex>
|
||||
</regexes>
|
||||
</check>
|
||||
</configuration>
|
||||
<executions>
|
||||
<execution>
|
||||
<goals>
|
||||
<goal>clean</goal>
|
||||
</goals>
|
||||
</execution>
|
||||
</executions>
|
||||
</plugin>
|
||||
<plugin>
|
||||
<groupId>org.apache.maven.plugins</groupId>
|
||||
<artifactId>maven-surefire-plugin</artifactId>
|
||||
<version>2.16</version>
|
||||
<configuration>
|
||||
<systemProperties>
|
||||
<property>
|
||||
<name>temp.directory</name>
|
||||
<value>${project.build.directory}/temp</value>
|
||||
</property>
|
||||
</systemProperties>
|
||||
<excludes>
|
||||
<exclude>**/*IntegrationTest.java</exclude>
|
||||
</excludes>
|
||||
</configuration>
|
||||
</plugin>
|
||||
<plugin>
|
||||
<groupId>org.apache.maven.plugins</groupId>
|
||||
<artifactId>maven-failsafe-plugin</artifactId>
|
||||
<version>2.16</version>
|
||||
<configuration>
|
||||
<systemProperties>
|
||||
<property>
|
||||
<name>temp.directory</name>
|
||||
<value>${project.build.directory}/temp</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-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>
|
||||
<configuration>
|
||||
<bottom>Copyright© 2012-14 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>
|
||||
<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>**/org/owasp/dependencycheck/org/apache/**/*.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>
|
||||
<configuration>
|
||||
<onlyAnalyze>org.owasp.dependencycheck.utils.*</onlyAnalyze>
|
||||
</configuration>
|
||||
</plugin>
|
||||
</reportPlugins>
|
||||
</configuration>
|
||||
</plugin>
|
||||
</plugins>
|
||||
</build>
|
||||
<dependencies>
|
||||
<dependency>
|
||||
<groupId>commons-io</groupId>
|
||||
<artifactId>commons-io</artifactId>
|
||||
<version>2.4</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>junit</groupId>
|
||||
<artifactId>junit</artifactId>
|
||||
<version>4.11</version>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
</project>
|
||||
@@ -0,0 +1,153 @@
|
||||
/*
|
||||
* Licensed to the Apache Software Foundation (ASF) under one or more
|
||||
* contributor license agreements. See the NOTICE file distributed with
|
||||
* this work for additional information regarding copyright ownership.
|
||||
* The ASF licenses this file to You 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.
|
||||
*
|
||||
*/
|
||||
package org.owasp.dependencycheck.org.apache.tools.ant;
|
||||
|
||||
/**
|
||||
* Signals an error condition during a build
|
||||
*/
|
||||
public class BuildException extends RuntimeException {
|
||||
|
||||
private static final long serialVersionUID = -5419014565354664240L;
|
||||
|
||||
/** Location in the build file where the exception occurred */
|
||||
private Location location = Location.UNKNOWN_LOCATION;
|
||||
|
||||
/**
|
||||
* Constructs a build exception with no descriptive information.
|
||||
*/
|
||||
public BuildException() {
|
||||
super();
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructs an exception with the given descriptive message.
|
||||
*
|
||||
* @param message A description of or information about the exception.
|
||||
* Should not be <code>null</code>.
|
||||
*/
|
||||
public BuildException(String message) {
|
||||
super(message);
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructs an exception with the given message and exception as
|
||||
* a root cause.
|
||||
*
|
||||
* @param message A description of or information about the exception.
|
||||
* Should not be <code>null</code> unless a cause is specified.
|
||||
* @param cause The exception that might have caused this one.
|
||||
* May be <code>null</code>.
|
||||
*/
|
||||
public BuildException(String message, Throwable cause) {
|
||||
super(message, cause);
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructs an exception with the given message and exception as
|
||||
* a root cause and a location in a file.
|
||||
*
|
||||
* @param msg A description of or information about the exception.
|
||||
* Should not be <code>null</code> unless a cause is specified.
|
||||
* @param cause The exception that might have caused this one.
|
||||
* May be <code>null</code>.
|
||||
* @param location The location in the project file where the error
|
||||
* occurred. Must not be <code>null</code>.
|
||||
*/
|
||||
public BuildException(String msg, Throwable cause, Location location) {
|
||||
this(msg, cause);
|
||||
this.location = location;
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructs an exception with the given exception as a root cause.
|
||||
*
|
||||
* @param cause The exception that might have caused this one.
|
||||
* Should not be <code>null</code>.
|
||||
*/
|
||||
public BuildException(Throwable cause) {
|
||||
super(cause);
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructs an exception with the given descriptive message and a
|
||||
* location in a file.
|
||||
*
|
||||
* @param message A description of or information about the exception.
|
||||
* Should not be <code>null</code>.
|
||||
* @param location The location in the project file where the error
|
||||
* occurred. Must not be <code>null</code>.
|
||||
*/
|
||||
public BuildException(String message, Location location) {
|
||||
super(message);
|
||||
this.location = location;
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructs an exception with the given exception as
|
||||
* a root cause and a location in a file.
|
||||
*
|
||||
* @param cause The exception that might have caused this one.
|
||||
* Should not be <code>null</code>.
|
||||
* @param location The location in the project file where the error
|
||||
* occurred. Must not be <code>null</code>.
|
||||
*/
|
||||
public BuildException(Throwable cause, Location location) {
|
||||
this(cause);
|
||||
this.location = location;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the nested exception, if any.
|
||||
*
|
||||
* @return the nested exception, or <code>null</code> if no
|
||||
* exception is associated with this one
|
||||
* @deprecated Use {@link #getCause} instead.
|
||||
*/
|
||||
public Throwable getException() {
|
||||
return getCause();
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the location of the error and the error message.
|
||||
*
|
||||
* @return the location of the error and the error message
|
||||
*/
|
||||
public String toString() {
|
||||
return location.toString() + getMessage();
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the file location where the error occurred.
|
||||
*
|
||||
* @param location The file location where the error occurred.
|
||||
* Must not be <code>null</code>.
|
||||
*/
|
||||
public void setLocation(Location location) {
|
||||
this.location = location;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the file location where the error occurred.
|
||||
*
|
||||
* @return the file location where the error occurred.
|
||||
*/
|
||||
public Location getLocation() {
|
||||
return location;
|
||||
}
|
||||
|
||||
}
|
||||
File diff suppressed because it is too large
Load Diff
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user