mirror of
https://github.com/ysoftdevs/DependencyCheck.git
synced 2026-01-15 00:03:43 +01:00
Compare commits
2148 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
d529e88242 | ||
|
|
5d6ad8bc6c | ||
|
|
01769a6f38 | ||
|
|
a43cc38739 | ||
|
|
085069c2c7 | ||
|
|
816a6d057a | ||
|
|
19ab099f98 | ||
|
|
99a1097953 | ||
|
|
673cf7018b | ||
|
|
624f52882e | ||
|
|
654ab4a289 | ||
|
|
ec86dc5734 | ||
|
|
44f37c12c3 | ||
|
|
d0b704d7f4 | ||
|
|
7452942091 | ||
|
|
ea4ea680a2 | ||
|
|
ac7ae3d8df | ||
|
|
4fa5f2ac72 | ||
|
|
8b1a44fe42 | ||
|
|
c4d26f9194 | ||
|
|
79b59f2aae | ||
|
|
1eecd13ea7 | ||
|
|
1ae3a63f5c | ||
|
|
561694a991 | ||
|
|
096af016ef | ||
|
|
498835015a | ||
|
|
cafa0d6578 | ||
|
|
5444253ed6 | ||
|
|
d0ae12a167 | ||
|
|
e323c7f810 | ||
|
|
dd3758af43 | ||
|
|
94ae6e76f1 | ||
|
|
ee969a5ed9 | ||
|
|
a547a219a4 | ||
|
|
d4eba634ea | ||
|
|
0927897451 | ||
|
|
63e5a2c5ba | ||
|
|
a7f3f1d806 | ||
|
|
97d3a2986c | ||
|
|
d3b20757ef | ||
|
|
d99804f14e | ||
|
|
1b8dc71980 | ||
|
|
dc466f1480 | ||
|
|
ba6a783834 | ||
|
|
b2edf5683c | ||
|
|
dacb91b9a8 | ||
|
|
7ac71a7b2a | ||
|
|
4b44bb5426 | ||
|
|
8cd68c7c16 | ||
|
|
0ae228d6f8 | ||
|
|
6a2ed23822 | ||
|
|
fe0035fe0e | ||
|
|
aeabaf8513 | ||
|
|
43907e07c2 | ||
|
|
2413dc9a41 | ||
|
|
2d92c9d240 | ||
|
|
a24813b678 | ||
|
|
dffb2887d6 | ||
|
|
68f1c1a54c | ||
|
|
726aa7b894 | ||
|
|
44c795cd4f | ||
|
|
4d5d46d08a | ||
|
|
52cdff14bd | ||
|
|
0372167f25 | ||
|
|
005e401c7f | ||
|
|
479212dd60 | ||
|
|
0af9239906 | ||
|
|
13d871ab21 | ||
|
|
136830ce22 | ||
|
|
afe8e343b1 | ||
|
|
f7c2cdff9b | ||
|
|
a7abe97ca0 | ||
|
|
5354137c76 | ||
|
|
433c2e5916 | ||
|
|
e5fdda60fc | ||
|
|
b227cf890b | ||
|
|
0a4c3102dd | ||
|
|
54094ebc21 | ||
|
|
bf3fe6404a | ||
|
|
58888ac389 | ||
|
|
07df8ecc02 | ||
|
|
c86becb169 | ||
|
|
98a43606ce | ||
|
|
5b2353e612 | ||
|
|
a3ad598004 | ||
|
|
c02d1d73b8 | ||
|
|
77c99e1d7c | ||
|
|
055d34818a | ||
|
|
3a06503b74 | ||
|
|
cae15a8d7a | ||
|
|
70554d1158 | ||
|
|
db42da14d1 | ||
|
|
9daa9b6cca | ||
|
|
30087b5e79 | ||
|
|
c214b70459 | ||
|
|
ad0b6c28ba | ||
|
|
8127dc2620 | ||
|
|
fed5d3efc0 | ||
|
|
ed3c806869 | ||
|
|
b8a32eb086 | ||
|
|
e537ce155e | ||
|
|
be506964b0 | ||
|
|
df39b490f5 | ||
|
|
e3256e4bb9 | ||
|
|
4d01d636cc | ||
|
|
1bf07036e8 | ||
|
|
da058fcaf5 | ||
|
|
7203c91c70 | ||
|
|
44893a2a2c | ||
|
|
bdf2ca6e1d | ||
|
|
621ac3b6ec | ||
|
|
9fbf8b58a1 | ||
|
|
70ac55f983 | ||
|
|
890bb4a2c3 | ||
|
|
888f2aed97 | ||
|
|
e6707c65a5 | ||
|
|
414912de67 | ||
|
|
723ba740e0 | ||
|
|
e2389b4992 | ||
|
|
39e587085f | ||
|
|
42e77c77a9 | ||
|
|
e8353089f3 | ||
|
|
d76799cfd0 | ||
|
|
4907c20ba6 | ||
|
|
fa16a960a5 | ||
|
|
aa66e5ab15 | ||
|
|
802e4fc238 | ||
|
|
2494fec2a7 | ||
|
|
13db27854b | ||
|
|
190e17e6b9 | ||
|
|
02acd3162e | ||
|
|
47fa6e67d9 | ||
|
|
aba7b47fa8 | ||
|
|
c1ae4f8cc2 | ||
|
|
4f43793e17 | ||
|
|
8fd32ebd5e | ||
|
|
0b2059462b | ||
|
|
b0df41213a | ||
|
|
f421f30122 | ||
|
|
358ac46393 | ||
|
|
ebd98b9094 | ||
|
|
c713bb0353 | ||
|
|
d61a7b090d | ||
|
|
9f1a894b86 | ||
|
|
cc86d73719 | ||
|
|
86b1802d16 | ||
|
|
3cdf66a0a4 | ||
|
|
faeee200d3 | ||
|
|
4b34734919 | ||
|
|
765c1b8875 | ||
|
|
f89cefd9ae | ||
|
|
23dfa8645c | ||
|
|
9556e7bf51 | ||
|
|
7fa306dd9a | ||
|
|
d9a322b533 | ||
|
|
fde1b21d1f | ||
|
|
124249a35d | ||
|
|
6d6e9a6df7 | ||
|
|
77ae9dfbef | ||
|
|
4ed642ed5d | ||
|
|
556be02696 | ||
|
|
572418a2f5 | ||
|
|
fce742910e | ||
|
|
370b0cb049 | ||
|
|
76333b8647 | ||
|
|
ce7d12e850 | ||
|
|
63d92c62a5 | ||
|
|
7e2720e673 | ||
|
|
a7c0ea3602 | ||
|
|
374829ecd5 | ||
|
|
6a67c04ca2 | ||
|
|
f4ce087649 | ||
|
|
4566ce7de8 | ||
|
|
a898e61a7a | ||
|
|
6d524bdc99 | ||
|
|
1ba21f7f71 | ||
|
|
7f710e0782 | ||
|
|
acb78c18bf | ||
|
|
5b1f632035 | ||
|
|
8aca739f54 | ||
|
|
efdfcee7fc | ||
|
|
1b4cb1379a | ||
|
|
820d7f18c4 | ||
|
|
7a5a5e0211 | ||
|
|
07dda233ec | ||
|
|
02209fc039 | ||
|
|
a372882c18 | ||
|
|
91c05598b2 | ||
|
|
0130ab6356 | ||
|
|
581a3f8388 | ||
|
|
2587ad21c0 | ||
|
|
8b56349daa | ||
|
|
25f2eb69b9 | ||
|
|
46b4761f1a | ||
|
|
4d3f96f979 | ||
|
|
084371a1e3 | ||
|
|
f5aaaf1c63 | ||
|
|
316bab6fff | ||
|
|
65a5d38fc6 | ||
|
|
aa927e9168 | ||
|
|
7b0a120e66 | ||
|
|
143ce58cb3 | ||
|
|
9244b44ce6 | ||
|
|
4720312b26 | ||
|
|
d43610701b | ||
|
|
243b0b2c21 | ||
|
|
930894ced5 | ||
|
|
63ce7850e1 | ||
|
|
984a38ce91 | ||
|
|
12ce2275e0 | ||
|
|
214b88ea1c | ||
|
|
980e00e824 | ||
|
|
80276d5e4d | ||
|
|
28c2db9edc | ||
|
|
5e66f70cf0 | ||
|
|
4e41187bf3 | ||
|
|
0a09760aec | ||
|
|
500ad62470 | ||
|
|
1204d98e8d | ||
|
|
ae3596ac99 | ||
|
|
d662c693f1 | ||
|
|
1820cd0ae8 | ||
|
|
c5e144d211 | ||
|
|
e1c041a250 | ||
|
|
82dff86802 | ||
|
|
b2019d7633 | ||
|
|
f6afea0004 | ||
|
|
309eb502cd | ||
|
|
712252eb6b | ||
|
|
c3baf36eb5 | ||
|
|
771fd77088 | ||
|
|
7d3ac21e42 | ||
|
|
cc3a72f4fd | ||
|
|
d87fa374ec | ||
|
|
154a576388 | ||
|
|
29fe71b82c | ||
|
|
e960fd31fa | ||
|
|
132fb87c2c | ||
|
|
6e281e0b66 | ||
|
|
a86ff9dfd1 | ||
|
|
3ea33f1dd6 | ||
|
|
b645fd495f | ||
|
|
5e635224e2 | ||
|
|
54d8becd74 | ||
|
|
87243537e7 | ||
|
|
0604361d4e | ||
|
|
399c052129 | ||
|
|
362c7e9c04 | ||
|
|
c4843253c0 | ||
|
|
928d8dbb15 | ||
|
|
7f528d8d4a | ||
|
|
8ddf4a0e72 | ||
|
|
5c589136e5 | ||
|
|
00f10771d9 | ||
|
|
583a5cda61 | ||
|
|
f9e5ebccfd | ||
|
|
77eebb6c1b | ||
|
|
53d01e5fe1 | ||
|
|
3d08e8db06 | ||
|
|
50a3ce2036 | ||
|
|
a127948c4c | ||
|
|
36b406f7ec | ||
|
|
3c50e9f784 | ||
|
|
51e2af148e | ||
|
|
d7351f97fe | ||
|
|
1a042fab4b | ||
|
|
c3f000c5ef | ||
|
|
e848dd5bee | ||
|
|
566e11f755 | ||
|
|
13aa00e465 | ||
|
|
e9df060e0c | ||
|
|
c4724e8020 | ||
|
|
9c36087dae | ||
|
|
51c3ebcdb8 | ||
|
|
f29e4a5d36 | ||
|
|
99dd04a1c1 | ||
|
|
29c47e3e96 | ||
|
|
659248ff22 | ||
|
|
71a7e8d2dc | ||
|
|
caabdc6584 | ||
|
|
0b92d2ec17 | ||
|
|
db8bcd8fd6 | ||
|
|
17cb96ef41 | ||
|
|
2248380c90 | ||
|
|
ffe64d2f8f | ||
|
|
a0c624fca6 | ||
|
|
31022ea8de | ||
|
|
0d0de4d5b3 | ||
|
|
1fdb4c4627 | ||
|
|
76665c54e2 | ||
|
|
04166766da | ||
|
|
aa7f903210 | ||
|
|
c4ca53cdf9 | ||
|
|
d5885acd6e | ||
|
|
550b3332a3 | ||
|
|
93b98576b8 | ||
|
|
e6f2c25167 | ||
|
|
0b207c6141 | ||
|
|
3ed5e85646 | ||
|
|
4068da33c8 | ||
|
|
d1d53ee65b | ||
|
|
38413c4f64 | ||
|
|
a6bb6cd170 | ||
|
|
145bf70420 | ||
|
|
e2c92c57e6 | ||
|
|
1fa59270c1 | ||
|
|
d5c1fda958 | ||
|
|
b0e34fd062 | ||
|
|
8fbf8df0bd | ||
|
|
bcc2173768 | ||
|
|
aa1df53ab0 | ||
|
|
fb6a2a2c37 | ||
|
|
f403fc732c | ||
|
|
03aa7c56a2 | ||
|
|
547d6d4bcc | ||
|
|
2cba8f906d | ||
|
|
bb5ee6a347 | ||
|
|
34604efde4 | ||
|
|
c232a4fbad | ||
|
|
0c5dfdbe24 | ||
|
|
c0f9a382b3 | ||
|
|
8ca32fcace | ||
|
|
0461a9fc89 | ||
|
|
2b600290ae | ||
|
|
56fd3f2566 | ||
|
|
142e06e752 | ||
|
|
cbf2a047be | ||
|
|
1880e22d22 | ||
|
|
963b1eae1c | ||
|
|
d173573e6c | ||
|
|
b6c0426c1c | ||
|
|
4f18e9ee7f | ||
|
|
e227b90370 | ||
|
|
360b112bd2 | ||
|
|
ff7027439d | ||
|
|
a5ed91611a | ||
|
|
168b1c3684 | ||
|
|
7e1141ff16 | ||
|
|
168d55c54c | ||
|
|
d5ed2bc765 | ||
|
|
940a4613ee | ||
|
|
4f6d96e16b | ||
|
|
707d9925a8 | ||
|
|
657340c912 | ||
|
|
3e220704a1 | ||
|
|
4a2309a3f8 | ||
|
|
09122be7be | ||
|
|
e26ec47ad7 | ||
|
|
05ae73eea2 | ||
|
|
511d2b9457 | ||
|
|
bf96c24ec3 | ||
|
|
e328ec990c | ||
|
|
a5dee0cb27 | ||
|
|
7fb5d5bde5 | ||
|
|
5a329b4a6d | ||
|
|
500f6c5b6f | ||
|
|
29f76ba62a | ||
|
|
70e0c84a20 | ||
|
|
3dd95180e0 | ||
|
|
dcd8fc0320 | ||
|
|
bcd9fb0be9 | ||
|
|
a088d20612 | ||
|
|
29fb347bbb | ||
|
|
b2a436b3bc | ||
|
|
d288912df1 | ||
|
|
7bde6baaac | ||
|
|
26ca6d9b77 | ||
|
|
961626a136 | ||
|
|
641a311537 | ||
|
|
995ba02357 | ||
|
|
fb3e6e4208 | ||
|
|
e5363f7c8f | ||
|
|
d1a128b897 | ||
|
|
2b5fb4d75a | ||
|
|
6439ddde23 | ||
|
|
f2994ed4ff | ||
|
|
019bf67f93 | ||
|
|
78c1dcd0d0 | ||
|
|
e07b30df85 | ||
|
|
96cd517c36 | ||
|
|
2cb8e00c99 | ||
|
|
92f093009e | ||
|
|
27256a1854 | ||
|
|
ba782ca56f | ||
|
|
3f3e33a366 | ||
|
|
343fd75477 | ||
|
|
7bcfb6ff49 | ||
|
|
78ec08792f | ||
|
|
461b41f300 | ||
|
|
5b246424fb | ||
|
|
6af4b4cd5e | ||
|
|
6d348eb5a7 | ||
|
|
b26f6b697a | ||
|
|
554510bb78 | ||
|
|
3f2e5b7c69 | ||
|
|
3c4989f5ca | ||
|
|
d33c649be6 | ||
|
|
c55954e5e8 | ||
|
|
678311e65b | ||
|
|
ab1d3075e8 | ||
|
|
0a6f8b7ac1 | ||
|
|
422a1f78fc | ||
|
|
f21af8bd1e | ||
|
|
924278e387 | ||
|
|
c6ea4466fb | ||
|
|
318cc7a8fb | ||
|
|
9554a30286 | ||
|
|
5336da52d9 | ||
|
|
bd0c2e4ee4 | ||
|
|
64aad66adc | ||
|
|
587bf131db | ||
|
|
fc96c727ec | ||
|
|
d17bd5bd9e | ||
|
|
b22a935a6c | ||
|
|
a7c1d594dc | ||
|
|
dd20a9c7cc | ||
|
|
e0994e0e54 | ||
|
|
0f8ce09646 | ||
|
|
871e27d19f | ||
|
|
c429df3280 | ||
|
|
13f355c385 | ||
|
|
d33ddefb2d | ||
|
|
75b3f4b3c8 | ||
|
|
03ce1d2ea8 | ||
|
|
08eae2b09c | ||
|
|
c94f9e2d2b | ||
|
|
520370688c | ||
|
|
725949db2f | ||
|
|
5d647155b6 | ||
|
|
c152bd0517 | ||
|
|
f35146d93d | ||
|
|
e8e58555d0 | ||
|
|
7190dcc04e | ||
|
|
b623e3b3c8 | ||
|
|
d78e82bd56 | ||
|
|
ff478253e3 | ||
|
|
85c3368cda | ||
|
|
a4095cec8d | ||
|
|
c840ce249f | ||
|
|
b70812fc3d | ||
|
|
3ccf06321d | ||
|
|
1d5dd5ea11 | ||
|
|
0cadd88769 | ||
|
|
75499a3321 | ||
|
|
5096027523 | ||
|
|
5c8c07794d | ||
|
|
18a72bbb59 | ||
|
|
7b3c4475da | ||
|
|
419c446f01 | ||
|
|
735c16cc11 | ||
|
|
ed41abcf9d | ||
|
|
b750a8c802 | ||
|
|
1ee75dd8cb | ||
|
|
396efad518 | ||
|
|
8f33be262a | ||
|
|
9daa111f9c | ||
|
|
889bf22840 | ||
|
|
f46e96c7de | ||
|
|
9be6dc2935 | ||
|
|
6188f6d74a | ||
|
|
8837fab9fa | ||
|
|
316339011b | ||
|
|
fe7121e057 | ||
|
|
bc09bfd3ba | ||
|
|
26f19cead1 | ||
|
|
777b35f412 | ||
|
|
9e94ffb422 | ||
|
|
b6a38bf4d1 | ||
|
|
92d12ec68e | ||
|
|
93dd5e4b31 | ||
|
|
79e325e2ab | ||
|
|
0e095018a4 | ||
|
|
7040071ab9 | ||
|
|
e157350d03 | ||
|
|
28f6ef5eec | ||
|
|
15bcee3d10 | ||
|
|
67dbf70f5b | ||
|
|
c75b99837f | ||
|
|
cbc951be62 | ||
|
|
f5b38852a7 | ||
|
|
45b5fd3762 | ||
|
|
04c14f3a27 | ||
|
|
a55d89cc93 | ||
|
|
888801ab0c | ||
|
|
731528ef6e | ||
|
|
d7fbd0df47 | ||
|
|
6f95e6d499 | ||
|
|
79e6a13b29 | ||
|
|
b9a53775b6 | ||
|
|
1b15603227 | ||
|
|
a7ffeb7016 | ||
|
|
13b1c0fe0c | ||
|
|
1d259c510f | ||
|
|
56783bbf4d | ||
|
|
e63c296b16 | ||
|
|
57450a65cf | ||
|
|
716b52ef90 | ||
|
|
6ab8552f44 | ||
|
|
9880483690 | ||
|
|
7b9b459b74 | ||
|
|
0723606120 | ||
|
|
4261e9eb29 | ||
|
|
a322556c66 | ||
|
|
b6d3efa042 | ||
|
|
4019a0615c | ||
|
|
376e486c47 | ||
|
|
5b7c47682b | ||
|
|
741a803ea7 | ||
|
|
8a886f5434 | ||
|
|
01514af188 | ||
|
|
c5d5dccc57 | ||
|
|
5e58304448 | ||
|
|
dd9c4bfa42 | ||
|
|
e6a559f0d1 | ||
|
|
f1c860f68c | ||
|
|
cd175816e2 | ||
|
|
1d74d2e241 | ||
|
|
c4479a36a9 | ||
|
|
cc2c18243e | ||
|
|
211d34fcef | ||
|
|
dc60c24d89 | ||
|
|
922e6437cf | ||
|
|
1058157827 | ||
|
|
33b38e686a | ||
|
|
a6014f30dd | ||
|
|
3fc75df55d | ||
|
|
2bcd9d78e8 | ||
|
|
723b9e9cea | ||
|
|
efb7088cd8 | ||
|
|
f2131102f5 | ||
|
|
eae04bb156 | ||
|
|
11716128df | ||
|
|
5122808189 | ||
|
|
3c1905f941 | ||
|
|
3348086c00 | ||
|
|
919efc5037 | ||
|
|
04ab0e09d5 | ||
|
|
c8862cb927 | ||
|
|
ac135ec2b6 | ||
|
|
0257000d1a | ||
|
|
608b95e941 | ||
|
|
e6a2c5b5b4 | ||
|
|
a546aadba1 | ||
|
|
5934588b2c | ||
|
|
3ad5482a30 | ||
|
|
c3902447af | ||
|
|
764aa466f4 | ||
|
|
9ffda6cd17 | ||
|
|
8281fb09fc | ||
|
|
b6988f96fb | ||
|
|
4597c13d9a | ||
|
|
acf7297c8d | ||
|
|
bbdc8298d9 | ||
|
|
4d9f102033 | ||
|
|
0056e1052c | ||
|
|
7b729e078b | ||
|
|
6a0623f1e7 | ||
|
|
542c871152 | ||
|
|
77189eeeb1 | ||
|
|
340172ab56 | ||
|
|
afcfed1c67 | ||
|
|
59ce3bb64d | ||
|
|
81c5aa73d2 | ||
|
|
12ff05208c | ||
|
|
dc0ef70699 | ||
|
|
6ce735dcc7 | ||
|
|
faf3298f7a | ||
|
|
4f1b6b4bf1 | ||
|
|
99702fdb67 | ||
|
|
7bce7691e4 | ||
|
|
7f90160936 | ||
|
|
f367ad7185 | ||
|
|
29a31476b1 | ||
|
|
b844b66614 | ||
|
|
3e6fa1ed1f | ||
|
|
e141b4eb9f | ||
|
|
c794194bb5 | ||
|
|
3a31902e78 | ||
|
|
fedafe55c3 | ||
|
|
1c0b885267 | ||
|
|
8e4791048b | ||
|
|
e28be6f2b7 | ||
|
|
55271b8e83 | ||
|
|
8b5d8679f7 | ||
|
|
51d8ced8ce | ||
|
|
1cc94dd60b | ||
|
|
6d107e79b6 | ||
|
|
6f44b4dce1 | ||
|
|
1600492780 | ||
|
|
5f396cc647 | ||
|
|
49bd45d88c | ||
|
|
c41e673346 | ||
|
|
cf8d1a490c | ||
|
|
962f20296c | ||
|
|
e9c1ae1893 | ||
|
|
5db51a2abf | ||
|
|
63be1efed9 | ||
|
|
7fe3c659e0 | ||
|
|
4d76c7685c | ||
|
|
b50bcde028 | ||
|
|
9a8b61ae47 | ||
|
|
c31880d8de | ||
|
|
1496dc8e7d | ||
|
|
cdbd513e42 | ||
|
|
653bf1764e | ||
|
|
df08acfe9e | ||
|
|
e7a5287bb4 | ||
|
|
656f26cc9d | ||
|
|
52385ddac4 | ||
|
|
50c58667ba | ||
|
|
9cc6ca5ebe | ||
|
|
34b82a3f84 | ||
|
|
d0401f3f8d | ||
|
|
f247978d12 | ||
|
|
999116c75e | ||
|
|
04e9f5b15b | ||
|
|
78b0f7798f | ||
|
|
b0727ef3cf | ||
|
|
01fb31fc15 | ||
|
|
a1187acc31 | ||
|
|
fe4a24a651 | ||
|
|
3dcce572d3 | ||
|
|
ece69014ce | ||
|
|
fc6bb67e56 | ||
|
|
968de2947b | ||
|
|
6f9ba0033f | ||
|
|
4d4672fc4d | ||
|
|
70859eb719 | ||
|
|
ae9daf7f33 | ||
|
|
ff0daa8d66 | ||
|
|
09f1a0ac92 | ||
|
|
e562be77f6 | ||
|
|
af7c6bc2a0 | ||
|
|
e49cbcf345 | ||
|
|
b4218ff0e8 | ||
|
|
4af174d27b | ||
|
|
203a7da23a | ||
|
|
9833ff20d1 | ||
|
|
638b3c0695 | ||
|
|
01ef2e1061 | ||
|
|
56aea8ad24 | ||
|
|
d530eddc57 | ||
|
|
1eab76aab8 | ||
|
|
167dbd7368 | ||
|
|
2594fb1c5f | ||
|
|
c57d21e9bc | ||
|
|
9c15bdfe41 | ||
|
|
64dedf892d | ||
|
|
d6fc456039 | ||
|
|
df606674db | ||
|
|
1e3a7ff4ba | ||
|
|
b53de8c69b | ||
|
|
0f3ffaf270 | ||
|
|
25238d5fb5 | ||
|
|
cf677bd70e | ||
|
|
42939e4922 | ||
|
|
7c4cc1334b | ||
|
|
ff4a1e0ac6 | ||
|
|
069e22049d | ||
|
|
135ed5c614 | ||
|
|
13d7d29630 | ||
|
|
889f315c0a | ||
|
|
5a0e280899 | ||
|
|
ccb5e234b3 | ||
|
|
2caccab85f | ||
|
|
085ab48f3f | ||
|
|
a28c2819fa | ||
|
|
40beec2e40 | ||
|
|
d136aeda84 | ||
|
|
fdd6c47cd5 | ||
|
|
c5a2b5b3d8 | ||
|
|
babe4739c5 | ||
|
|
49e8ee443c | ||
|
|
a5d8ce07d8 | ||
|
|
babc016b48 | ||
|
|
a5f378d755 | ||
|
|
ebf995537e | ||
|
|
49edb6c2e1 | ||
|
|
423f26852f | ||
|
|
f931412bee | ||
|
|
bef0657801 | ||
|
|
d79d5b5f33 | ||
|
|
4c5489efd3 | ||
|
|
d5753b9589 | ||
|
|
a841027d48 | ||
|
|
73bea8e63f | ||
|
|
bbc8bab4da | ||
|
|
019f6dfb8b | ||
|
|
3b6a2a2908 | ||
|
|
c2b757ad6f | ||
|
|
efeba40f2b | ||
|
|
018e4bc382 | ||
|
|
88924ea520 | ||
|
|
4461c2e4a4 | ||
|
|
1c4aceb0fb | ||
|
|
a5b396a60d | ||
|
|
efd96ed892 | ||
|
|
fe88785846 | ||
|
|
0dcb0fb325 | ||
|
|
0825843d0f | ||
|
|
8c4df134e4 | ||
|
|
dfed5067f3 | ||
|
|
2b78e8fdc1 | ||
|
|
63c7a9d926 | ||
|
|
6609481cc1 | ||
|
|
a37853def6 | ||
|
|
9f348cfa16 | ||
|
|
52293f2596 | ||
|
|
54d3a73282 | ||
|
|
ab2d3b70cb | ||
|
|
451df460f6 | ||
|
|
b4afa01887 | ||
|
|
2ea95f5bf9 | ||
|
|
22602f42f2 | ||
|
|
b2c5183043 | ||
|
|
9f6559c7fb | ||
|
|
ef04c16237 | ||
|
|
dd85bfd2ab | ||
|
|
7152a05bfd | ||
|
|
754c2fc9bf | ||
|
|
85ad0b881f | ||
|
|
db6c471cc6 | ||
|
|
300d990276 | ||
|
|
9c55b889cb | ||
|
|
735f76cc0b | ||
|
|
d1c27a4298 | ||
|
|
650f09bbc5 | ||
|
|
08bf16971a | ||
|
|
ccb149240e | ||
|
|
ae22719985 | ||
|
|
55c4d729bb | ||
|
|
429f0966f0 | ||
|
|
7a246b90b9 | ||
|
|
d2e7de5505 | ||
|
|
a9eab16502 | ||
|
|
d59cce8080 | ||
|
|
9390e71dd9 | ||
|
|
65992243fa | ||
|
|
c81b8b0171 | ||
|
|
0671d12628 | ||
|
|
a892c5e7b7 | ||
|
|
b5c21ffbf0 | ||
|
|
bb2b25cca5 | ||
|
|
b3867244ba | ||
|
|
6bf8d396e0 | ||
|
|
6394c1a7b4 | ||
|
|
ccd656845d | ||
|
|
2931e8454c | ||
|
|
112b158795 | ||
|
|
921001000f | ||
|
|
3e3a8e9f98 | ||
|
|
7440a039fd | ||
|
|
e73f9ab02f | ||
|
|
59815b858e | ||
|
|
7df7f59d93 | ||
|
|
e971bc1991 | ||
|
|
a3f0f12779 | ||
|
|
2a9c214593 | ||
|
|
3fc37f3e5e | ||
|
|
ebe4423e25 | ||
|
|
cfafb4a101 | ||
|
|
8d538a9977 | ||
|
|
cc2953d6a3 | ||
|
|
c888019068 | ||
|
|
56639d3965 | ||
|
|
09ff99823e | ||
|
|
5078e32dc7 | ||
|
|
ecaadff0d8 | ||
|
|
f2ad8cc7d1 | ||
|
|
c8d77eb213 | ||
|
|
fe3d9e8bf6 | ||
|
|
6c4171be75 | ||
|
|
4bbb466e43 | ||
|
|
c478415667 | ||
|
|
fc832b67c5 | ||
|
|
943a9ea97e | ||
|
|
2c7ab297d7 | ||
|
|
d8299f7db1 | ||
|
|
4deeb33f08 | ||
|
|
3bf4cf8c85 | ||
|
|
e0217fc6c3 | ||
|
|
62a3efa23a | ||
|
|
cc7ebe6d52 | ||
|
|
5d920e4b44 | ||
|
|
1264ea54a1 | ||
|
|
caa1d77d23 | ||
|
|
20a55b3342 | ||
|
|
8bfe67fc60 | ||
|
|
d42a1c6ab1 | ||
|
|
80a89ef6d1 | ||
|
|
1a0e605f0c | ||
|
|
573c8eb509 | ||
|
|
e676e3a14b | ||
|
|
af8c807ee0 | ||
|
|
dfaa5df965 | ||
|
|
32055ecdcc | ||
|
|
9db71c5f0c | ||
|
|
99856bf285 | ||
|
|
4d006b3e05 | ||
|
|
4e37165ba6 | ||
|
|
38a5834785 | ||
|
|
d6e1352869 | ||
|
|
bf1b7bd7a2 | ||
|
|
2306327057 | ||
|
|
2d389ba73f | ||
|
|
ce8d5bc635 | ||
|
|
8fdc2007e0 | ||
|
|
88a97769de | ||
|
|
589c761cb0 | ||
|
|
3e6787fd61 | ||
|
|
aff52ee3f5 | ||
|
|
4555b02592 | ||
|
|
e1d4599a93 | ||
|
|
1a1e141cb8 | ||
|
|
33218f41e8 | ||
|
|
8772cda47a | ||
|
|
512eb713e4 | ||
|
|
0f90d48c62 | ||
|
|
658860e396 | ||
|
|
7522dae557 | ||
|
|
e34e65a3ba | ||
|
|
5a001a2c32 | ||
|
|
13a03eb250 | ||
|
|
cd863b6cca | ||
|
|
83b182dda5 | ||
|
|
3b90d1a564 | ||
|
|
d724855dfc | ||
|
|
78008330fe | ||
|
|
e716aad224 | ||
|
|
aa0d7cb4e9 | ||
|
|
0cd43ce35c | ||
|
|
ac98c8e395 | ||
|
|
70a8fc09c6 | ||
|
|
5b00d05e2e | ||
|
|
28c1730a02 | ||
|
|
c54483d36f | ||
|
|
2dd02ff8cb | ||
|
|
46c5501b7a | ||
|
|
f154826749 | ||
|
|
96383ef985 | ||
|
|
ab4b19dbab | ||
|
|
cdc53ac570 | ||
|
|
143cc1912e | ||
|
|
0d90b676bc | ||
|
|
5fadbb3d25 | ||
|
|
0ec99a3e12 | ||
|
|
1efbc44cc4 | ||
|
|
735fcfeee2 | ||
|
|
4a77150566 | ||
|
|
180a420219 | ||
|
|
d12ba8f3ef | ||
|
|
f333ef76d9 | ||
|
|
af5ba6854e | ||
|
|
8b7ce06793 | ||
|
|
297a5e516f | ||
|
|
92b11526be | ||
|
|
299350f655 | ||
|
|
127eafc9b3 | ||
|
|
ad1ad3a997 | ||
|
|
82151c5b3f | ||
|
|
90457c89ff | ||
|
|
3f3ac86d38 | ||
|
|
aa126039e5 | ||
|
|
662815b1ee | ||
|
|
243c36849c | ||
|
|
52d5baaf3f | ||
|
|
89217f778e | ||
|
|
9bc9bc9169 | ||
|
|
6b73430473 | ||
|
|
5ca5bca3df | ||
|
|
89ab382a18 | ||
|
|
bad425c0d7 | ||
|
|
cdbbb1b94c | ||
|
|
0a9d8a9b22 | ||
|
|
e662041d06 | ||
|
|
155464bc87 | ||
|
|
06cd811ae4 | ||
|
|
1b2cd354db | ||
|
|
1b31268f59 | ||
|
|
b57ef7291f | ||
|
|
c3bf6aa3f8 | ||
|
|
d2fa14bbe2 | ||
|
|
9b6e55e90c | ||
|
|
afb07b651f | ||
|
|
e6806fdf2b | ||
|
|
e5ff2cff4e | ||
|
|
17d7d47b9a | ||
|
|
64e32061ab | ||
|
|
931110ba6c | ||
|
|
d90e7820cd | ||
|
|
824898dba5 | ||
|
|
761dd61ed4 | ||
|
|
89c63e6d87 | ||
|
|
a2361f9327 | ||
|
|
ea15205be8 | ||
|
|
0a45048535 | ||
|
|
1c51655ce3 | ||
|
|
7749f0da7c | ||
|
|
5695238f95 | ||
|
|
e1feeb7e21 | ||
|
|
84fecaf040 | ||
|
|
da77727673 | ||
|
|
f8c913a3e8 | ||
|
|
2024881ee1 | ||
|
|
35ed3a51e5 | ||
|
|
24b1c4d0a4 | ||
|
|
7ec2458fb5 | ||
|
|
175feaea23 | ||
|
|
dda6cf728b | ||
|
|
a7fd410b01 | ||
|
|
d281c36733 | ||
|
|
dc91e44c0a | ||
|
|
7967a858f4 | ||
|
|
2081407e38 | ||
|
|
976eabd527 | ||
|
|
b6d6a5de2b | ||
|
|
2d58cfe0ce | ||
|
|
9df8bdff5f | ||
|
|
c86b821951 | ||
|
|
4def086bf9 | ||
|
|
885c890d7d | ||
|
|
06060a6694 | ||
|
|
70667814f6 | ||
|
|
766b7a940c | ||
|
|
0c37586357 | ||
|
|
b4aa55ce1f | ||
|
|
109443ce77 | ||
|
|
5f38741831 | ||
|
|
c6f391501d | ||
|
|
d1f3105fbd | ||
|
|
8f88ca9d3d | ||
|
|
f9e4ca0cc2 | ||
|
|
5caf023677 | ||
|
|
35c2f4873c | ||
|
|
1ed7bab375 | ||
|
|
f0d1bfb777 | ||
|
|
42519ac843 | ||
|
|
8869e13385 | ||
|
|
8f9cbfe806 | ||
|
|
6481938626 | ||
|
|
9c7cc2acbf | ||
|
|
89a57d4ed3 | ||
|
|
732378592b | ||
|
|
19dc46660b | ||
|
|
4aad3471af | ||
|
|
533b455356 | ||
|
|
92bd305b00 | ||
|
|
f71eb09f74 | ||
|
|
83d4a7bc18 | ||
|
|
58807d9021 | ||
|
|
29595324c4 | ||
|
|
f9064e526f | ||
|
|
93ec2e8639 | ||
|
|
0e2a31709a | ||
|
|
c785b39eda | ||
|
|
8fab2f58da | ||
|
|
e44ee3bfe1 | ||
|
|
62065c9d28 | ||
|
|
c76275275f | ||
|
|
257f78879d | ||
|
|
894263809c | ||
|
|
bc9458101c | ||
|
|
c503935d6a | ||
|
|
d4756c9eb8 | ||
|
|
0004767775 | ||
|
|
74908642c7 | ||
|
|
aadfb71c98 | ||
|
|
1244af649d | ||
|
|
7bd48cc811 | ||
|
|
8f3ce38418 | ||
|
|
1b2d9b4245 | ||
|
|
c6b2b34fde | ||
|
|
e58fc13fdb | ||
|
|
922d53d2e4 | ||
|
|
fec53b3951 | ||
|
|
e72e2c6a02 | ||
|
|
08d001ee05 | ||
|
|
99d8a07f4a | ||
|
|
eef565134b | ||
|
|
9d78293437 | ||
|
|
fc0a556e5f | ||
|
|
b6b070584f | ||
|
|
e13225eee6 | ||
|
|
da20fb2922 | ||
|
|
459c2beb12 | ||
|
|
f1cc44dead | ||
|
|
d24cfdc382 | ||
|
|
ae4cc543f6 | ||
|
|
abdb3d17f9 | ||
|
|
4095c5da38 | ||
|
|
78fab728e4 | ||
|
|
52097a6867 | ||
|
|
cb990b55b5 | ||
|
|
5070fe303a | ||
|
|
b4405ebf3e | ||
|
|
d9e6bf5068 | ||
|
|
6822188f52 | ||
|
|
15858d03ff | ||
|
|
814a733258 | ||
|
|
3ce85d8ca9 | ||
|
|
d3bff2f39d | ||
|
|
f2272730ac | ||
|
|
fe19c97d86 | ||
|
|
d49556bf3d | ||
|
|
56b447493e | ||
|
|
e45b68eda7 | ||
|
|
8df1ef5986 | ||
|
|
dac34cda82 | ||
|
|
9925e30c8b | ||
|
|
dc5566b5ae | ||
|
|
8132ee651a | ||
|
|
f49a134a3d | ||
|
|
bd955cda06 | ||
|
|
c6dbc01912 | ||
|
|
fabe1aa940 | ||
|
|
ba5dbb94b8 | ||
|
|
6ccc053d7e | ||
|
|
cf21dfaa3a | ||
|
|
54ceb630de | ||
|
|
0a0c302cb2 | ||
|
|
f6eef54566 | ||
|
|
a69804f84d | ||
|
|
0b06b194b0 | ||
|
|
73f6ce304c | ||
|
|
195818a432 | ||
|
|
47c817de1c | ||
|
|
8b3894f213 | ||
|
|
a411252f07 | ||
|
|
d7626aeb3f | ||
|
|
3565098650 | ||
|
|
803fcf146b | ||
|
|
d9d646c5fb | ||
|
|
034a274b07 | ||
|
|
718d7af8bc | ||
|
|
860d3d9c8b | ||
|
|
f28b566992 | ||
|
|
1c261c7463 | ||
|
|
226b2482b1 | ||
|
|
ff346dc429 | ||
|
|
2dcef25175 | ||
|
|
46702bbb5c | ||
|
|
5600c9bc69 | ||
|
|
d7e46b1693 | ||
|
|
fe8c60ade1 | ||
|
|
288892441f | ||
|
|
e1179a8e22 | ||
|
|
4b06d0fd87 | ||
|
|
464d91f45a | ||
|
|
5cc7aa25cc | ||
|
|
20ec224070 | ||
|
|
9cbcc29ddb | ||
|
|
b9003a2f02 | ||
|
|
6b303410d1 | ||
|
|
8cae2f24b1 | ||
|
|
0a04d753ea | ||
|
|
35402c7bd3 | ||
|
|
847a97f61c | ||
|
|
fac27a6120 | ||
|
|
2e24eda00d | ||
|
|
7a653abf22 | ||
|
|
ae09229107 | ||
|
|
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 |
8
.gitignore
vendored
8
.gitignore
vendored
@@ -1,4 +1,6 @@
|
|||||||
*/target/**
|
*/target/**
|
||||||
|
# IntelliJ test run side-effects
|
||||||
|
dependency-check-core/data/
|
||||||
# Intellij project files
|
# Intellij project files
|
||||||
*.iml
|
*.iml
|
||||||
*.ipr
|
*.ipr
|
||||||
@@ -7,6 +9,10 @@
|
|||||||
# Eclipse project files
|
# Eclipse project files
|
||||||
.classpath
|
.classpath
|
||||||
.project
|
.project
|
||||||
|
.settings
|
||||||
|
maven-eclipse.xml
|
||||||
|
.externalToolBuilders
|
||||||
|
.pmd
|
||||||
# Netbeans configuration
|
# Netbeans configuration
|
||||||
nb-configuration.xml
|
nb-configuration.xml
|
||||||
/target/
|
/target/
|
||||||
@@ -19,4 +25,4 @@ _site/**
|
|||||||
#unknown as to why these are showing up... but need to be ignored.
|
#unknown as to why these are showing up... but need to be ignored.
|
||||||
.LCKpom.xml~
|
.LCKpom.xml~
|
||||||
#coverity
|
#coverity
|
||||||
/cov-int/
|
/cov-int/
|
||||||
|
|||||||
27
README.md
27
README.md
@@ -13,8 +13,10 @@ For instructions on the use of the Jenkins plugin please see the [Jenkins depend
|
|||||||
|
|
||||||
### Command Line
|
### Command Line
|
||||||
|
|
||||||
More detailed instructions can be found on the [dependency-check github pages](http://jeremylong.github.io/DependencyCheck/dependency-check-cli/installation.html).
|
More detailed instructions can be found on the
|
||||||
The latest CLI can be downloaded from bintray's [dependency-check page](https://bintray.com/jeremy-long/owasp/dependency-check).
|
[dependency-check github pages](http://jeremylong.github.io/DependencyCheck/dependency-check-cli/).
|
||||||
|
The latest CLI can be downloaded from bintray's
|
||||||
|
[dependency-check page](https://bintray.com/jeremy-long/owasp/dependency-check).
|
||||||
|
|
||||||
On *nix
|
On *nix
|
||||||
```
|
```
|
||||||
@@ -26,6 +28,12 @@ On Windows
|
|||||||
> bin/dependency-check.bat -h
|
> bin/dependency-check.bat -h
|
||||||
> bin/dependency-check.bat --app Testing --out . --scan [path to jar files to be scanned]
|
> bin/dependency-check.bat --app Testing --out . --scan [path to jar files to be scanned]
|
||||||
```
|
```
|
||||||
|
On Mac with [Homebrew](http://brew.sh)
|
||||||
|
```
|
||||||
|
$ brew update && brew install dependency-check
|
||||||
|
$ dependency-check -h
|
||||||
|
$ dependency-check --app Testing --out . --scan [path to jar files to be scanned]
|
||||||
|
```
|
||||||
|
|
||||||
### Maven Plugin
|
### Maven Plugin
|
||||||
|
|
||||||
@@ -40,7 +48,6 @@ The plugin can be configured using the following:
|
|||||||
<plugin>
|
<plugin>
|
||||||
<groupId>org.owasp</groupId>
|
<groupId>org.owasp</groupId>
|
||||||
<artifactId>dependency-check-maven</artifactId>
|
<artifactId>dependency-check-maven</artifactId>
|
||||||
<version>1.0.2</version>
|
|
||||||
<executions>
|
<executions>
|
||||||
<execution>
|
<execution>
|
||||||
<goals>
|
<goals>
|
||||||
@@ -59,15 +66,19 @@ The plugin can be configured using the following:
|
|||||||
|
|
||||||
### Ant Task
|
### 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
|
Development Usage
|
||||||
-------------
|
-------------
|
||||||
The following instructions outline how to compile and use the current snapshot. While every intention is to maintain a stable snapshot it is recommended
|
The following instructions outline how to compile and use the current snapshot. While every intention is to maintain a stable snapshot it is recommended
|
||||||
that the release versions listed above be used.
|
that the release versions listed above be used.
|
||||||
|
|
||||||
Note, currently the install goal may take a long time to execute the integration tests. However, if this takes more then 30 minutes it is likely that the
|
The repository has some large files due to test resources. The team has tried to cleanup the history as much as possible.
|
||||||
download of data from the NVD is having an issue. This issue is still being researched and a solution should be published soon.
|
However, it is recommended that you perform a shallow clone to save yourself time:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
git clone --depth 1 git@github.com:jeremylong/DependencyCheck.git
|
||||||
|
```
|
||||||
|
|
||||||
On *nix
|
On *nix
|
||||||
```
|
```
|
||||||
@@ -96,7 +107,7 @@ Archive: [google group](https://groups.google.com/forum/#!forum/dependency-check
|
|||||||
Copyright & License
|
Copyright & License
|
||||||
-
|
-
|
||||||
|
|
||||||
Dependency-Check is Copyright (c) 2012-2014 Jeremy Long. All Rights Reserved.
|
Dependency-Check is Copyright (c) 2012-2015 Jeremy Long. All Rights Reserved.
|
||||||
|
|
||||||
Permission to modify and redistribute is granted under the terms of the Apache 2.0 license. See the [LICENSE.txt](https://github.com/jeremylong/DependencyCheck/dependency-check-cli/blob/master/LICENSE.txt) file for the full license.
|
Permission to modify and redistribute is granted under the terms of the Apache 2.0 license. See the [LICENSE.txt](https://github.com/jeremylong/DependencyCheck/dependency-check-cli/blob/master/LICENSE.txt) file for the full license.
|
||||||
|
|
||||||
@@ -106,4 +117,4 @@ Dependency-Check makes use of several other open source libraries. Please see th
|
|||||||
[wiki]: https://github.com/jeremylong/DependencyCheck/wiki
|
[wiki]: https://github.com/jeremylong/DependencyCheck/wiki
|
||||||
[subscribe]: mailto:dependency-check+subscribe@googlegroups.com
|
[subscribe]: mailto:dependency-check+subscribe@googlegroups.com
|
||||||
[post]: mailto:dependency-check@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.
|
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">
|
<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>
|
<modelVersion>4.0.0</modelVersion>
|
||||||
<parent>
|
<parent>
|
||||||
<groupId>org.owasp</groupId>
|
<groupId>org.owasp</groupId>
|
||||||
<artifactId>dependency-check-parent</artifactId>
|
<artifactId>dependency-check-parent</artifactId>
|
||||||
<version>1.2.3</version>
|
<version>1.3.0</version>
|
||||||
</parent>
|
</parent>
|
||||||
|
|
||||||
<artifactId>dependency-check-ant</artifactId>
|
<artifactId>dependency-check-ant</artifactId>
|
||||||
<packaging>jar</packaging>
|
<packaging>jar</packaging>
|
||||||
|
|
||||||
<name>Dependency-Check Ant Task</name>
|
<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/ -->
|
<!-- begin copy from http://minds.coremedia.com/2012/09/11/problem-solved-deploy-multi-module-maven-project-site-as-github-pages/ -->
|
||||||
<distributionManagement>
|
<distributionManagement>
|
||||||
<site>
|
<site>
|
||||||
@@ -69,7 +68,6 @@ Copyright (c) 2013 - Jeremy Long. All Rights Reserved.
|
|||||||
<plugin>
|
<plugin>
|
||||||
<groupId>org.apache.maven.plugins</groupId>
|
<groupId>org.apache.maven.plugins</groupId>
|
||||||
<artifactId>maven-resources-plugin</artifactId>
|
<artifactId>maven-resources-plugin</artifactId>
|
||||||
<version>2.6</version>
|
|
||||||
<configuration>
|
<configuration>
|
||||||
<escapeWindowsPaths>false</escapeWindowsPaths>
|
<escapeWindowsPaths>false</escapeWindowsPaths>
|
||||||
</configuration>
|
</configuration>
|
||||||
@@ -192,10 +190,18 @@ Copyright (c) 2013 - Jeremy Long. All Rights Reserved.
|
|||||||
</execution>
|
</execution>
|
||||||
</executions>
|
</executions>
|
||||||
</plugin>
|
</plugin>
|
||||||
|
<plugin>
|
||||||
|
<groupId>org.apache.maven.plugins</groupId>
|
||||||
|
<artifactId>maven-compiler-plugin</artifactId>
|
||||||
|
</plugin>
|
||||||
|
<plugin>
|
||||||
|
<groupId>org.apache.maven.plugins</groupId>
|
||||||
|
<artifactId>maven-jar-plugin</artifactId>
|
||||||
|
</plugin>
|
||||||
<plugin>
|
<plugin>
|
||||||
<groupId>org.apache.maven.plugins</groupId>
|
<groupId>org.apache.maven.plugins</groupId>
|
||||||
<artifactId>maven-shade-plugin</artifactId>
|
<artifactId>maven-shade-plugin</artifactId>
|
||||||
<version>2.1</version>
|
<version>2.3</version>
|
||||||
<configuration>
|
<configuration>
|
||||||
<transformers>
|
<transformers>
|
||||||
<transformer implementation="org.apache.maven.plugins.shade.resource.ServicesResourceTransformer" />
|
<transformer implementation="org.apache.maven.plugins.shade.resource.ServicesResourceTransformer" />
|
||||||
@@ -219,29 +225,13 @@ Copyright (c) 2013 - Jeremy Long. All Rights Reserved.
|
|||||||
</execution>
|
</execution>
|
||||||
</executions>
|
</executions>
|
||||||
</plugin>
|
</plugin>
|
||||||
<plugin>
|
|
||||||
<groupId>org.apache.maven.plugins</groupId>
|
|
||||||
<artifactId>maven-jar-plugin</artifactId>
|
|
||||||
<version>2.4</version>
|
|
||||||
<configuration>
|
|
||||||
<archive>
|
|
||||||
<manifest>
|
|
||||||
<addDefaultImplementationEntries>true</addDefaultImplementationEntries>
|
|
||||||
</manifest>
|
|
||||||
</archive>
|
|
||||||
<excludes>
|
|
||||||
<exclude>**/checkstyle*</exclude>
|
|
||||||
</excludes>
|
|
||||||
</configuration>
|
|
||||||
</plugin>
|
|
||||||
<plugin>
|
<plugin>
|
||||||
<groupId>org.codehaus.mojo</groupId>
|
<groupId>org.codehaus.mojo</groupId>
|
||||||
<artifactId>cobertura-maven-plugin</artifactId>
|
<artifactId>cobertura-maven-plugin</artifactId>
|
||||||
<version>2.6</version>
|
|
||||||
<configuration>
|
<configuration>
|
||||||
<instrumentation>
|
<!--instrumentation>
|
||||||
<ignoreTrivial>true</ignoreTrivial>
|
<ignoreTrivial>true</ignoreTrivial>
|
||||||
</instrumentation>
|
</instrumentation-->
|
||||||
<check>
|
<check>
|
||||||
<branchRate>85</branchRate>
|
<branchRate>85</branchRate>
|
||||||
<lineRate>85</lineRate>
|
<lineRate>85</lineRate>
|
||||||
@@ -270,7 +260,6 @@ Copyright (c) 2013 - Jeremy Long. All Rights Reserved.
|
|||||||
<plugin>
|
<plugin>
|
||||||
<groupId>org.apache.maven.plugins</groupId>
|
<groupId>org.apache.maven.plugins</groupId>
|
||||||
<artifactId>maven-surefire-plugin</artifactId>
|
<artifactId>maven-surefire-plugin</artifactId>
|
||||||
<version>2.16</version>
|
|
||||||
<configuration>
|
<configuration>
|
||||||
<systemProperties>
|
<systemProperties>
|
||||||
<property>
|
<property>
|
||||||
@@ -280,159 +269,139 @@ Copyright (c) 2013 - Jeremy Long. All Rights Reserved.
|
|||||||
</systemProperties>
|
</systemProperties>
|
||||||
</configuration>
|
</configuration>
|
||||||
</plugin>
|
</plugin>
|
||||||
<plugin>
|
|
||||||
<groupId>org.apache.maven.plugins</groupId>
|
|
||||||
<artifactId>maven-compiler-plugin</artifactId>
|
|
||||||
<version>3.1</version>
|
|
||||||
<configuration>
|
|
||||||
<showDeprecation>false</showDeprecation>
|
|
||||||
<source>1.6</source>
|
|
||||||
<target>1.6</target>
|
|
||||||
</configuration>
|
|
||||||
</plugin>
|
|
||||||
|
|
||||||
<plugin>
|
|
||||||
<groupId>org.apache.maven.plugins</groupId>
|
|
||||||
<artifactId>maven-site-plugin</artifactId>
|
|
||||||
<version>3.3</version>
|
|
||||||
<dependencies>
|
|
||||||
<dependency>
|
|
||||||
<groupId>org.apache.maven.doxia</groupId>
|
|
||||||
<artifactId>doxia-module-markdown</artifactId>
|
|
||||||
<version>1.5</version>
|
|
||||||
</dependency>
|
|
||||||
</dependencies>
|
|
||||||
<configuration>
|
|
||||||
<skipDeploy>true</skipDeploy>
|
|
||||||
<reportPlugins>
|
|
||||||
<plugin>
|
|
||||||
<groupId>org.apache.maven.plugins</groupId>
|
|
||||||
<artifactId>maven-project-info-reports-plugin</artifactId>
|
|
||||||
<version>2.7</version>
|
|
||||||
<reportSets>
|
|
||||||
<reportSet>
|
|
||||||
<reports>
|
|
||||||
<report>index</report>
|
|
||||||
<report>summary</report>
|
|
||||||
<report>license</report>
|
|
||||||
<report>help</report>
|
|
||||||
</reports>
|
|
||||||
</reportSet>
|
|
||||||
</reportSets>
|
|
||||||
</plugin>
|
|
||||||
<plugin>
|
|
||||||
<groupId>org.apache.maven.plugins</groupId>
|
|
||||||
<artifactId>maven-javadoc-plugin</artifactId>
|
|
||||||
<version>2.9.1</version>
|
|
||||||
<reportSets>
|
|
||||||
<reportSet>
|
|
||||||
<id>default</id>
|
|
||||||
<reports>
|
|
||||||
<report>javadoc</report>
|
|
||||||
</reports>
|
|
||||||
</reportSet>
|
|
||||||
</reportSets>
|
|
||||||
</plugin>
|
|
||||||
<plugin>
|
|
||||||
<groupId>org.codehaus.mojo</groupId>
|
|
||||||
<artifactId>versions-maven-plugin</artifactId>
|
|
||||||
<version>2.1</version>
|
|
||||||
<reportSets>
|
|
||||||
<reportSet>
|
|
||||||
<reports>
|
|
||||||
<report>dependency-updates-report</report>
|
|
||||||
<report>plugin-updates-report</report>
|
|
||||||
</reports>
|
|
||||||
</reportSet>
|
|
||||||
</reportSets>
|
|
||||||
</plugin>
|
|
||||||
<plugin>
|
|
||||||
<groupId>org.apache.maven.plugins</groupId>
|
|
||||||
<artifactId>maven-jxr-plugin</artifactId>
|
|
||||||
<version>2.4</version>
|
|
||||||
</plugin>
|
|
||||||
<plugin>
|
|
||||||
<groupId>org.codehaus.mojo</groupId>
|
|
||||||
<artifactId>cobertura-maven-plugin</artifactId>
|
|
||||||
<version>2.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>**/generated/*.java</exclude>
|
|
||||||
</excludes>
|
|
||||||
<rulesets>
|
|
||||||
<ruleset>../src/main/config/dcrules.xml</ruleset>
|
|
||||||
<ruleset>/rulesets/java/basic.xml</ruleset>
|
|
||||||
<ruleset>/rulesets/java/imports.xml</ruleset>
|
|
||||||
<ruleset>/rulesets/java/unusedcode.xml</ruleset>
|
|
||||||
</rulesets>
|
|
||||||
</configuration>
|
|
||||||
</plugin>
|
|
||||||
<plugin>
|
|
||||||
<groupId>org.codehaus.mojo</groupId>
|
|
||||||
<artifactId>findbugs-maven-plugin</artifactId>
|
|
||||||
<version>2.5.3</version>
|
|
||||||
</plugin>
|
|
||||||
</reportPlugins>
|
|
||||||
</configuration>
|
|
||||||
</plugin>
|
|
||||||
</plugins>
|
</plugins>
|
||||||
</build>
|
</build>
|
||||||
|
<reporting>
|
||||||
|
<plugins>
|
||||||
|
<plugin>
|
||||||
|
<groupId>org.apache.maven.plugins</groupId>
|
||||||
|
<artifactId>maven-project-info-reports-plugin</artifactId>
|
||||||
|
<version>${reporting.project-info-reports-plugin.version}</version>
|
||||||
|
<reportSets>
|
||||||
|
<reportSet>
|
||||||
|
<reports>
|
||||||
|
<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>${reporting.javadoc-plugin.version}</version>
|
||||||
|
<configuration>
|
||||||
|
<failOnError>false</failOnError>
|
||||||
|
<bottom>Copyright© 2012-15 Jeremy Long. All Rights Reserved.</bottom>
|
||||||
|
</configuration>
|
||||||
|
<reportSets>
|
||||||
|
<reportSet>
|
||||||
|
<id>default</id>
|
||||||
|
<reports>
|
||||||
|
<report>javadoc</report>
|
||||||
|
</reports>
|
||||||
|
</reportSet>
|
||||||
|
</reportSets>
|
||||||
|
</plugin>
|
||||||
|
<plugin>
|
||||||
|
<groupId>org.codehaus.mojo</groupId>
|
||||||
|
<artifactId>versions-maven-plugin</artifactId>
|
||||||
|
<version>${reporting.versions-plugin.version}</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>${reporting.jxr-plugin.version}</version>
|
||||||
|
</plugin>
|
||||||
|
<plugin>
|
||||||
|
<groupId>org.codehaus.mojo</groupId>
|
||||||
|
<artifactId>cobertura-maven-plugin</artifactId>
|
||||||
|
<version>${reporting.cobertura-plugin.version}</version>
|
||||||
|
</plugin>
|
||||||
|
<plugin>
|
||||||
|
<groupId>org.apache.maven.plugins</groupId>
|
||||||
|
<artifactId>maven-surefire-report-plugin</artifactId>
|
||||||
|
<version>${reporting.surefire-report-plugin.version}</version>
|
||||||
|
<reportSets>
|
||||||
|
<reportSet>
|
||||||
|
<reports>
|
||||||
|
<report>report-only</report>
|
||||||
|
</reports>
|
||||||
|
</reportSet>
|
||||||
|
</reportSets>
|
||||||
|
</plugin>
|
||||||
|
<plugin>
|
||||||
|
<groupId>org.codehaus.mojo</groupId>
|
||||||
|
<artifactId>taglist-maven-plugin</artifactId>
|
||||||
|
<version>${reporting.taglist-plugin.version}</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>${reporting.checkstyle-plugin.version}</version>
|
||||||
|
<configuration>
|
||||||
|
<enableRulesSummary>false</enableRulesSummary>
|
||||||
|
<enableFilesSummary>false</enableFilesSummary>
|
||||||
|
<configLocation>${basedir}/../src/main/config/checkstyle-checks.xml</configLocation>
|
||||||
|
<headerLocation>${basedir}/../src/main/config/checkstyle-header.txt</headerLocation>
|
||||||
|
<suppressionsLocation>${basedir}/../src/main/config/checkstyle-suppressions.xml</suppressionsLocation>
|
||||||
|
<suppressionsFileExpression>checkstyle.suppressions.file</suppressionsFileExpression>
|
||||||
|
</configuration>
|
||||||
|
</plugin>
|
||||||
|
<plugin>
|
||||||
|
<groupId>org.apache.maven.plugins</groupId>
|
||||||
|
<artifactId>maven-pmd-plugin</artifactId>
|
||||||
|
<version>${reporting.pmd-plugin.version}</version>
|
||||||
|
<configuration>
|
||||||
|
<targetJdk>1.6</targetJdk>
|
||||||
|
<linkXref>true</linkXref>
|
||||||
|
<sourceEncoding>utf-8</sourceEncoding>
|
||||||
|
<excludes>
|
||||||
|
<exclude>**/generated/*.java</exclude>
|
||||||
|
</excludes>
|
||||||
|
<rulesets>
|
||||||
|
<ruleset>../src/main/config/dcrules.xml</ruleset>
|
||||||
|
<ruleset>/rulesets/java/basic.xml</ruleset>
|
||||||
|
<ruleset>/rulesets/java/imports.xml</ruleset>
|
||||||
|
<ruleset>/rulesets/java/unusedcode.xml</ruleset>
|
||||||
|
</rulesets>
|
||||||
|
</configuration>
|
||||||
|
</plugin>
|
||||||
|
<plugin>
|
||||||
|
<groupId>org.codehaus.mojo</groupId>
|
||||||
|
<artifactId>findbugs-maven-plugin</artifactId>
|
||||||
|
<version>${reporting.findbugs-plugin.version}</version>
|
||||||
|
</plugin>
|
||||||
|
</plugins>
|
||||||
|
</reporting>
|
||||||
<dependencies>
|
<dependencies>
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>org.owasp</groupId>
|
<groupId>org.owasp</groupId>
|
||||||
@@ -454,12 +423,10 @@ Copyright (c) 2013 - Jeremy Long. All Rights Reserved.
|
|||||||
<dependency>
|
<dependency>
|
||||||
<groupId>org.apache.ant</groupId>
|
<groupId>org.apache.ant</groupId>
|
||||||
<artifactId>ant</artifactId>
|
<artifactId>ant</artifactId>
|
||||||
<version>1.9.3</version>
|
|
||||||
</dependency>
|
</dependency>
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>org.apache.ant</groupId>
|
<groupId>org.apache.ant</groupId>
|
||||||
<artifactId>ant-testutil</artifactId>
|
<artifactId>ant-testutil</artifactId>
|
||||||
<version>1.9.3</version>
|
|
||||||
<scope>test</scope>
|
<scope>test</scope>
|
||||||
</dependency>
|
</dependency>
|
||||||
</dependencies>
|
</dependencies>
|
||||||
|
|||||||
@@ -0,0 +1,271 @@
|
|||||||
|
/*
|
||||||
|
* This file is part of dependency-check-ant.
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*
|
||||||
|
* Copyright (c) 2015 The OWASP Foundation. All Rights Reserved.
|
||||||
|
*/
|
||||||
|
package org.owasp.dependencycheck.ant.logging;
|
||||||
|
|
||||||
|
import org.apache.tools.ant.Project;
|
||||||
|
import org.apache.tools.ant.Task;
|
||||||
|
import org.slf4j.helpers.FormattingTuple;
|
||||||
|
import org.slf4j.helpers.MarkerIgnoringBase;
|
||||||
|
import org.slf4j.helpers.MessageFormatter;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* An instance of {@link org.slf4j.Logger} which simply calls the log method on the delegate Ant task
|
||||||
|
*
|
||||||
|
* @author colezlaw
|
||||||
|
*/
|
||||||
|
public class AntLoggerAdapter extends MarkerIgnoringBase {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A reference to the Ant task used for logging.
|
||||||
|
*/
|
||||||
|
private Task task;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Constructs an Ant Logger Adapter.
|
||||||
|
*
|
||||||
|
* @param task the Ant Task to use for logging
|
||||||
|
*/
|
||||||
|
public AntLoggerAdapter(Task task) {
|
||||||
|
super();
|
||||||
|
this.task = task;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets the current Ant task to use for logging.
|
||||||
|
*
|
||||||
|
* @param task the Ant task to use for logging
|
||||||
|
*/
|
||||||
|
public void setTask(Task task) {
|
||||||
|
this.task = task;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean isTraceEnabled() {
|
||||||
|
// Might be a more efficient way to do this, but Ant doesn't enable or disable
|
||||||
|
// various levels globally - it just fires things at registered Listeners.
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void trace(String msg) {
|
||||||
|
task.log(msg, Project.MSG_VERBOSE);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void trace(String format, Object arg) {
|
||||||
|
if (task != null) {
|
||||||
|
final FormattingTuple tp = MessageFormatter.format(format, arg);
|
||||||
|
task.log(tp.getMessage(), Project.MSG_VERBOSE);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void trace(String format, Object arg1, Object arg2) {
|
||||||
|
if (task != null) {
|
||||||
|
final FormattingTuple tp = MessageFormatter.format(format, arg1, arg2);
|
||||||
|
task.log(tp.getMessage(), Project.MSG_VERBOSE);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void trace(String format, Object... arguments) {
|
||||||
|
if (task != null) {
|
||||||
|
final FormattingTuple tp = MessageFormatter.format(format, arguments);
|
||||||
|
task.log(tp.getMessage(), Project.MSG_VERBOSE);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void trace(String msg, Throwable t) {
|
||||||
|
if (task != null) {
|
||||||
|
task.log(msg, t, Project.MSG_VERBOSE);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean isDebugEnabled() {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void debug(String msg) {
|
||||||
|
if (task != null) {
|
||||||
|
task.log(msg, Project.MSG_DEBUG);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void debug(String format, Object arg) {
|
||||||
|
if (task != null) {
|
||||||
|
final FormattingTuple tp = MessageFormatter.format(format, arg);
|
||||||
|
task.log(tp.getMessage(), Project.MSG_DEBUG);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void debug(String format, Object arg1, Object arg2) {
|
||||||
|
if (task != null) {
|
||||||
|
final FormattingTuple tp = MessageFormatter.format(format, arg1, arg2);
|
||||||
|
task.log(tp.getMessage(), Project.MSG_DEBUG);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void debug(String format, Object... arguments) {
|
||||||
|
if (task != null) {
|
||||||
|
final FormattingTuple tp = MessageFormatter.format(format, arguments);
|
||||||
|
task.log(tp.getMessage(), Project.MSG_DEBUG);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void debug(String msg, Throwable t) {
|
||||||
|
if (task != null) {
|
||||||
|
task.log(msg, t, Project.MSG_DEBUG);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean isInfoEnabled() {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void info(String msg) {
|
||||||
|
if (task != null) {
|
||||||
|
task.log(msg, Project.MSG_INFO);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void info(String format, Object arg) {
|
||||||
|
if (task != null) {
|
||||||
|
final FormattingTuple tp = MessageFormatter.format(format, arg);
|
||||||
|
task.log(tp.getMessage(), Project.MSG_INFO);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void info(String format, Object arg1, Object arg2) {
|
||||||
|
if (task != null) {
|
||||||
|
final FormattingTuple tp = MessageFormatter.format(format, arg1, arg2);
|
||||||
|
task.log(tp.getMessage(), Project.MSG_INFO);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void info(String format, Object... arguments) {
|
||||||
|
if (task != null) {
|
||||||
|
final FormattingTuple tp = MessageFormatter.format(format, arguments);
|
||||||
|
task.log(tp.getMessage(), Project.MSG_INFO);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void info(String msg, Throwable t) {
|
||||||
|
if (task != null) {
|
||||||
|
task.log(msg, t, Project.MSG_INFO);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean isWarnEnabled() {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void warn(String msg) {
|
||||||
|
if (task != null) {
|
||||||
|
task.log(msg, Project.MSG_WARN);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void warn(String format, Object arg) {
|
||||||
|
if (task != null) {
|
||||||
|
final FormattingTuple tp = MessageFormatter.format(format, arg);
|
||||||
|
task.log(tp.getMessage(), Project.MSG_WARN);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void warn(String format, Object... arguments) {
|
||||||
|
if (task != null) {
|
||||||
|
final FormattingTuple tp = MessageFormatter.format(format, arguments);
|
||||||
|
task.log(tp.getMessage(), Project.MSG_WARN);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void warn(String format, Object arg1, Object arg2) {
|
||||||
|
if (task != null) {
|
||||||
|
final FormattingTuple tp = MessageFormatter.format(format, arg1, arg2);
|
||||||
|
task.log(tp.getMessage(), Project.MSG_WARN);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void warn(String msg, Throwable t) {
|
||||||
|
if (task != null) {
|
||||||
|
task.log(msg, t, Project.MSG_WARN);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean isErrorEnabled() {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void error(String msg) {
|
||||||
|
if (task != null) {
|
||||||
|
task.log(msg, Project.MSG_ERR);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void error(String format, Object arg) {
|
||||||
|
if (task != null) {
|
||||||
|
final FormattingTuple tp = MessageFormatter.format(format, arg);
|
||||||
|
task.log(tp.getMessage(), Project.MSG_ERR);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void error(String format, Object arg1, Object arg2) {
|
||||||
|
if (task != null) {
|
||||||
|
final FormattingTuple tp = MessageFormatter.format(format, arg1, arg2);
|
||||||
|
task.log(tp.getMessage(), Project.MSG_ERR);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void error(String format, Object... arguments) {
|
||||||
|
if (task != null) {
|
||||||
|
final FormattingTuple tp = MessageFormatter.format(format, arguments);
|
||||||
|
task.log(tp.getMessage(), Project.MSG_ERR);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void error(String msg, Throwable t) {
|
||||||
|
if (task != null) {
|
||||||
|
task.log(msg, t, Project.MSG_ERR);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,56 @@
|
|||||||
|
/*
|
||||||
|
* This file is part of dependency-check-ant.
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*
|
||||||
|
* Copyright (c) 2015 The OWASP Foundation. All Rights Reserved.
|
||||||
|
*/
|
||||||
|
package org.owasp.dependencycheck.ant.logging;
|
||||||
|
|
||||||
|
import org.apache.tools.ant.Task;
|
||||||
|
import org.slf4j.ILoggerFactory;
|
||||||
|
import org.slf4j.Logger;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* An implementation of {@link org.slf4j.ILoggerFactory} which always returns {@link AntLoggerAdapter} instances.
|
||||||
|
*
|
||||||
|
* @author colezlaw
|
||||||
|
*/
|
||||||
|
public class AntLoggerFactory implements ILoggerFactory {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A reference to the Ant logger Adapter.
|
||||||
|
*/
|
||||||
|
private final AntLoggerAdapter antLoggerAdapter;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Constructs a new Ant Logger Factory.
|
||||||
|
*
|
||||||
|
* @param task the Ant task to use for logging
|
||||||
|
*/
|
||||||
|
public AntLoggerFactory(Task task) {
|
||||||
|
super();
|
||||||
|
this.antLoggerAdapter = new AntLoggerAdapter(task);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the Ant logger adapter.
|
||||||
|
*
|
||||||
|
* @param name ignored in this implementation
|
||||||
|
* @return the Ant logger adapter
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
public Logger getLogger(String name) {
|
||||||
|
return antLoggerAdapter;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,4 @@
|
|||||||
|
/**
|
||||||
|
* This package includes the Ant task definitions.
|
||||||
|
*/
|
||||||
|
package org.owasp.dependencycheck.ant.logging;
|
||||||
@@ -21,9 +21,8 @@ import java.io.File;
|
|||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.io.InputStream;
|
import java.io.InputStream;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.logging.Level;
|
|
||||||
import java.util.logging.Logger;
|
|
||||||
import org.apache.tools.ant.BuildException;
|
import org.apache.tools.ant.BuildException;
|
||||||
|
import org.apache.tools.ant.Project;
|
||||||
import org.apache.tools.ant.Task;
|
import org.apache.tools.ant.Task;
|
||||||
import org.apache.tools.ant.types.EnumeratedAttribute;
|
import org.apache.tools.ant.types.EnumeratedAttribute;
|
||||||
import org.apache.tools.ant.types.Reference;
|
import org.apache.tools.ant.types.Reference;
|
||||||
@@ -40,13 +39,13 @@ import org.owasp.dependencycheck.dependency.Identifier;
|
|||||||
import org.owasp.dependencycheck.dependency.Vulnerability;
|
import org.owasp.dependencycheck.dependency.Vulnerability;
|
||||||
import org.owasp.dependencycheck.reporting.ReportGenerator;
|
import org.owasp.dependencycheck.reporting.ReportGenerator;
|
||||||
import org.owasp.dependencycheck.reporting.ReportGenerator.Format;
|
import org.owasp.dependencycheck.reporting.ReportGenerator.Format;
|
||||||
import org.owasp.dependencycheck.utils.LogUtils;
|
|
||||||
import org.owasp.dependencycheck.utils.Settings;
|
import org.owasp.dependencycheck.utils.Settings;
|
||||||
|
import org.slf4j.impl.StaticLoggerBinder;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* An Ant task definition to execute dependency-check during an Ant build.
|
* An Ant task definition to execute dependency-check during an Ant build.
|
||||||
*
|
*
|
||||||
* @author Jeremy Long <jeremy.long@owasp.org>
|
* @author Jeremy Long
|
||||||
*/
|
*/
|
||||||
public class DependencyCheckTask extends Task {
|
public class DependencyCheckTask extends Task {
|
||||||
|
|
||||||
@@ -54,24 +53,19 @@ public class DependencyCheckTask extends Task {
|
|||||||
* The properties file location.
|
* The properties file location.
|
||||||
*/
|
*/
|
||||||
private static final String PROPERTIES_FILE = "task.properties";
|
private static final String PROPERTIES_FILE = "task.properties";
|
||||||
/**
|
|
||||||
* Name of the logging properties file.
|
|
||||||
*/
|
|
||||||
private static final String LOG_PROPERTIES_FILE = "log.properties";
|
|
||||||
/**
|
/**
|
||||||
* System specific new line character.
|
* System specific new line character.
|
||||||
*/
|
*/
|
||||||
private static final String NEW_LINE = System.getProperty("line.separator", "\n").intern();
|
private static final String NEW_LINE = System.getProperty("line.separator", "\n").intern();
|
||||||
/**
|
|
||||||
* The logger.
|
|
||||||
*/
|
|
||||||
private static final Logger LOGGER = Logger.getLogger(DependencyCheckTask.class.getName());
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Construct a new DependencyCheckTask.
|
* Construct a new DependencyCheckTask.
|
||||||
*/
|
*/
|
||||||
public DependencyCheckTask() {
|
public DependencyCheckTask() {
|
||||||
super();
|
super();
|
||||||
|
// Call this before Dependency Check Core starts logging anything - this way, all SLF4J messages from
|
||||||
|
// core end up coming through this tasks logger
|
||||||
|
StaticLoggerBinder.getSingleton().setTask(this);
|
||||||
}
|
}
|
||||||
//The following code was copied Apache Ant PathConvert
|
//The following code was copied Apache Ant PathConvert
|
||||||
//BEGIN COPY from org.apache.tools.ant.taskdefs.PathConvert
|
//BEGIN COPY from org.apache.tools.ant.taskdefs.PathConvert
|
||||||
@@ -98,8 +92,8 @@ public class DependencyCheckTask extends Task {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns the path. If the path has not been initialized yet, this class is synchronized, and will instantiate the
|
* Returns the path. If the path has not been initialized yet, this class is synchronized, and will instantiate the path
|
||||||
* path object.
|
* object.
|
||||||
*
|
*
|
||||||
* @return the path
|
* @return the path
|
||||||
*/
|
*/
|
||||||
@@ -215,9 +209,9 @@ public class DependencyCheckTask extends Task {
|
|||||||
this.reportOutputDirectory = reportOutputDirectory;
|
this.reportOutputDirectory = reportOutputDirectory;
|
||||||
}
|
}
|
||||||
/**
|
/**
|
||||||
* Specifies if the build should be failed if a CVSS score above a specified level is identified. The default is 11
|
* Specifies if the build should be failed if a CVSS score above a specified level is identified. The default is 11 which
|
||||||
* which means since the CVSS scores are 0-10, by default the build will never fail and the CVSS score is set to 11.
|
* means since the CVSS scores are 0-10, by default the build will never fail and the CVSS score is set to 11. The valid range
|
||||||
* The valid range for the fail build on CVSS is 0 to 11, where anything above 10 will not cause the build to fail.
|
* for the fail build on CVSS is 0 to 11, where anything above 10 will not cause the build to fail.
|
||||||
*/
|
*/
|
||||||
private float failBuildOnCVSS = 11;
|
private float failBuildOnCVSS = 11;
|
||||||
|
|
||||||
@@ -239,8 +233,8 @@ public class DependencyCheckTask extends Task {
|
|||||||
this.failBuildOnCVSS = failBuildOnCVSS;
|
this.failBuildOnCVSS = failBuildOnCVSS;
|
||||||
}
|
}
|
||||||
/**
|
/**
|
||||||
* Sets whether auto-updating of the NVD CVE/CPE data is enabled. It is not recommended that this be turned to
|
* Sets whether auto-updating of the NVD CVE/CPE data is enabled. It is not recommended that this be turned to false. Default
|
||||||
* false. Default is true.
|
* is true.
|
||||||
*/
|
*/
|
||||||
private boolean autoUpdate = true;
|
private boolean autoUpdate = true;
|
||||||
|
|
||||||
@@ -262,8 +256,31 @@ public class DependencyCheckTask extends Task {
|
|||||||
this.autoUpdate = autoUpdate;
|
this.autoUpdate = autoUpdate;
|
||||||
}
|
}
|
||||||
/**
|
/**
|
||||||
* The report format to be generated (HTML, XML, VULN, ALL). This configuration option has no affect if using this
|
* Whether only the update phase should be executed.
|
||||||
* within the Site plugin unless the externalReport is set to true. Default is HTML.
|
*/
|
||||||
|
private boolean updateOnly = false;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the value of updateOnly.
|
||||||
|
*
|
||||||
|
* @return the value of updateOnly
|
||||||
|
*/
|
||||||
|
public boolean isUpdateOnly() {
|
||||||
|
return updateOnly;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Set the value of updateOnly.
|
||||||
|
*
|
||||||
|
* @param updateOnly new value of updateOnly
|
||||||
|
*/
|
||||||
|
public void setUpdateOnly(boolean updateOnly) {
|
||||||
|
this.updateOnly = updateOnly;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The report format to be generated (HTML, XML, VULN, ALL). This configuration option has no affect if using this within the
|
||||||
|
* Site plugin unless the externalReport is set to true. Default is HTML.
|
||||||
*/
|
*/
|
||||||
private String reportFormat = "HTML";
|
private String reportFormat = "HTML";
|
||||||
|
|
||||||
@@ -322,12 +339,11 @@ public class DependencyCheckTask extends Task {
|
|||||||
* Set the value of proxyServer.
|
* Set the value of proxyServer.
|
||||||
*
|
*
|
||||||
* @param proxyUrl new value of proxyServer
|
* @param proxyUrl new value of proxyServer
|
||||||
* @deprecated use {@link org.owasp.dependencycheck.taskdefs.DependencyCheckTask#setProxyServer(java.lang.String)}
|
* @deprecated use {@link org.owasp.dependencycheck.taskdefs.DependencyCheckTask#setProxyServer(java.lang.String)} instead
|
||||||
* instead
|
|
||||||
*/
|
*/
|
||||||
@Deprecated
|
@Deprecated
|
||||||
public void setProxyUrl(String proxyUrl) {
|
public void setProxyUrl(String proxyUrl) {
|
||||||
LOGGER.warning("A deprecated configuration option 'proxyUrl' was detected; use 'proxyServer' instead.");
|
log("A deprecated configuration option 'proxyUrl' was detected; use 'proxyServer' instead.", Project.MSG_WARN);
|
||||||
this.proxyServer = proxyUrl;
|
this.proxyServer = proxyUrl;
|
||||||
}
|
}
|
||||||
/**
|
/**
|
||||||
@@ -418,28 +434,6 @@ public class DependencyCheckTask extends Task {
|
|||||||
public void setConnectionTimeout(String connectionTimeout) {
|
public void setConnectionTimeout(String connectionTimeout) {
|
||||||
this.connectionTimeout = connectionTimeout;
|
this.connectionTimeout = connectionTimeout;
|
||||||
}
|
}
|
||||||
/**
|
|
||||||
* The file path used for verbose logging.
|
|
||||||
*/
|
|
||||||
private String logFile = null;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Get the value of logFile.
|
|
||||||
*
|
|
||||||
* @return the value of logFile
|
|
||||||
*/
|
|
||||||
public String getLogFile() {
|
|
||||||
return logFile;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Set the value of logFile.
|
|
||||||
*
|
|
||||||
* @param logFile new value of logFile
|
|
||||||
*/
|
|
||||||
public void setLogFile(String logFile) {
|
|
||||||
this.logFile = logFile;
|
|
||||||
}
|
|
||||||
/**
|
/**
|
||||||
* The path to the suppression file.
|
* The path to the suppression file.
|
||||||
*/
|
*/
|
||||||
@@ -559,6 +553,28 @@ public class DependencyCheckTask extends Task {
|
|||||||
public void setNuspecAnalyzerEnabled(boolean nuspecAnalyzerEnabled) {
|
public void setNuspecAnalyzerEnabled(boolean nuspecAnalyzerEnabled) {
|
||||||
this.nuspecAnalyzerEnabled = nuspecAnalyzerEnabled;
|
this.nuspecAnalyzerEnabled = nuspecAnalyzerEnabled;
|
||||||
}
|
}
|
||||||
|
/**
|
||||||
|
* Whether or not the central analyzer is enabled.
|
||||||
|
*/
|
||||||
|
private boolean centralAnalyzerEnabled = false;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the value of centralAnalyzerEnabled.
|
||||||
|
*
|
||||||
|
* @return the value of centralAnalyzerEnabled
|
||||||
|
*/
|
||||||
|
public boolean isCentralAnalyzerEnabled() {
|
||||||
|
return centralAnalyzerEnabled;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Set the value of centralAnalyzerEnabled.
|
||||||
|
*
|
||||||
|
* @param centralAnalyzerEnabled new value of centralAnalyzerEnabled
|
||||||
|
*/
|
||||||
|
public void setCentralAnalyzerEnabled(boolean centralAnalyzerEnabled) {
|
||||||
|
this.centralAnalyzerEnabled = centralAnalyzerEnabled;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Whether or not the nexus analyzer is enabled.
|
* Whether or not the nexus analyzer is enabled.
|
||||||
@@ -584,7 +600,7 @@ public class DependencyCheckTask extends Task {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The URL of the Nexus server.
|
* The URL of a Nexus server's REST API end point (http://domain/nexus/service/local).
|
||||||
*/
|
*/
|
||||||
private String nexusUrl;
|
private String nexusUrl;
|
||||||
|
|
||||||
@@ -742,8 +758,8 @@ public class DependencyCheckTask extends Task {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Additional ZIP File extensions to add analyze. This should be a comma-separated list of file extensions to treat
|
* Additional ZIP File extensions to add analyze. This should be a comma-separated list of file extensions to treat like ZIP
|
||||||
* like ZIP files.
|
* files.
|
||||||
*/
|
*/
|
||||||
private String zipExtensions;
|
private String zipExtensions;
|
||||||
|
|
||||||
@@ -881,9 +897,6 @@ public class DependencyCheckTask extends Task {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void execute() throws BuildException {
|
public void execute() throws BuildException {
|
||||||
final InputStream in = DependencyCheckTask.class.getClassLoader().getResourceAsStream(LOG_PROPERTIES_FILE);
|
|
||||||
LogUtils.prepareLogger(in, logFile);
|
|
||||||
|
|
||||||
dealWithReferences();
|
dealWithReferences();
|
||||||
validateConfiguration();
|
validateConfiguration();
|
||||||
populateSettings();
|
populateSettings();
|
||||||
@@ -891,50 +904,54 @@ public class DependencyCheckTask extends Task {
|
|||||||
Engine engine = null;
|
Engine engine = null;
|
||||||
try {
|
try {
|
||||||
engine = new Engine(DependencyCheckTask.class.getClassLoader());
|
engine = new Engine(DependencyCheckTask.class.getClassLoader());
|
||||||
|
//todo - should this be its own task?
|
||||||
for (Resource resource : path) {
|
if (updateOnly) {
|
||||||
final FileProvider provider = resource.as(FileProvider.class);
|
engine.doUpdates();
|
||||||
if (provider != null) {
|
} else {
|
||||||
final File file = provider.getFile();
|
|
||||||
if (file != null && file.exists()) {
|
|
||||||
engine.scan(file);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
try {
|
|
||||||
engine.analyzeDependencies();
|
|
||||||
DatabaseProperties prop = null;
|
|
||||||
CveDB cve = null;
|
|
||||||
try {
|
try {
|
||||||
cve = new CveDB();
|
for (Resource resource : path) {
|
||||||
cve.open();
|
final FileProvider provider = resource.as(FileProvider.class);
|
||||||
prop = cve.getDatabaseProperties();
|
if (provider != null) {
|
||||||
} catch (DatabaseException ex) {
|
final File file = provider.getFile();
|
||||||
LOGGER.log(Level.FINE, "Unable to retrieve DB Properties", ex);
|
if (file != null && file.exists()) {
|
||||||
} finally {
|
engine.scan(file);
|
||||||
if (cve != null) {
|
}
|
||||||
cve.close();
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
final ReportGenerator reporter = new ReportGenerator(applicationName, engine.getDependencies(), engine.getAnalyzers(), prop);
|
|
||||||
reporter.generateReports(reportOutputDirectory, reportFormat);
|
|
||||||
|
|
||||||
if (this.failBuildOnCVSS <= 10) {
|
engine.analyzeDependencies();
|
||||||
checkForFailure(engine.getDependencies());
|
DatabaseProperties prop = null;
|
||||||
|
CveDB cve = null;
|
||||||
|
try {
|
||||||
|
cve = new CveDB();
|
||||||
|
cve.open();
|
||||||
|
prop = cve.getDatabaseProperties();
|
||||||
|
} catch (DatabaseException ex) {
|
||||||
|
log("Unable to retrieve DB Properties", ex, Project.MSG_DEBUG);
|
||||||
|
} finally {
|
||||||
|
if (cve != null) {
|
||||||
|
cve.close();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
final ReportGenerator reporter = new ReportGenerator(applicationName, engine.getDependencies(), engine.getAnalyzers(), prop);
|
||||||
|
reporter.generateReports(reportOutputDirectory, reportFormat);
|
||||||
|
|
||||||
|
if (this.failBuildOnCVSS <= 10) {
|
||||||
|
checkForFailure(engine.getDependencies());
|
||||||
|
}
|
||||||
|
if (this.showSummary) {
|
||||||
|
showSummary(engine.getDependencies());
|
||||||
|
}
|
||||||
|
} catch (IOException ex) {
|
||||||
|
log("Unable to generate dependency-check report", ex, Project.MSG_DEBUG);
|
||||||
|
throw new BuildException("Unable to generate dependency-check report", ex);
|
||||||
|
} catch (Exception ex) {
|
||||||
|
log("An exception occurred; unable to continue task", ex, Project.MSG_DEBUG);
|
||||||
|
throw new BuildException("An exception occurred; unable to continue task", ex);
|
||||||
}
|
}
|
||||||
if (this.showSummary) {
|
|
||||||
showSummary(engine.getDependencies());
|
|
||||||
}
|
|
||||||
} catch (IOException ex) {
|
|
||||||
LOGGER.log(Level.FINE, "Unable to generate dependency-check report", ex);
|
|
||||||
throw new BuildException("Unable to generate dependency-check report", ex);
|
|
||||||
} catch (Exception ex) {
|
|
||||||
LOGGER.log(Level.FINE, "An exception occurred; unable to continue task", ex);
|
|
||||||
throw new BuildException("An exception occurred; unable to continue task", ex);
|
|
||||||
}
|
}
|
||||||
} catch (DatabaseException ex) {
|
} catch (DatabaseException ex) {
|
||||||
LOGGER.log(Level.SEVERE, "Unable to connect to the dependency-check database; analysis has stopped");
|
log("Unable to connect to the dependency-check database; analysis has stopped", ex, Project.MSG_ERR);
|
||||||
LOGGER.log(Level.FINE, "", ex);
|
|
||||||
} finally {
|
} finally {
|
||||||
Settings.cleanup(true);
|
Settings.cleanup(true);
|
||||||
if (engine != null) {
|
if (engine != null) {
|
||||||
@@ -958,8 +975,8 @@ public class DependencyCheckTask extends Task {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Takes the properties supplied and updates the dependency-check settings. Additionally, this sets the system
|
* Takes the properties supplied and updates the dependency-check settings. Additionally, this sets the system properties
|
||||||
* properties required to change the proxy server, port, and connection timeout.
|
* required to change the proxy server, port, and connection timeout.
|
||||||
*/
|
*/
|
||||||
private void populateSettings() {
|
private void populateSettings() {
|
||||||
Settings.initialize();
|
Settings.initialize();
|
||||||
@@ -968,14 +985,13 @@ public class DependencyCheckTask extends Task {
|
|||||||
taskProperties = this.getClass().getClassLoader().getResourceAsStream(PROPERTIES_FILE);
|
taskProperties = this.getClass().getClassLoader().getResourceAsStream(PROPERTIES_FILE);
|
||||||
Settings.mergeProperties(taskProperties);
|
Settings.mergeProperties(taskProperties);
|
||||||
} catch (IOException ex) {
|
} catch (IOException ex) {
|
||||||
LOGGER.log(Level.WARNING, "Unable to load the dependency-check ant task.properties file.");
|
log("Unable to load the dependency-check ant task.properties file.", ex, Project.MSG_WARN);
|
||||||
LOGGER.log(Level.FINE, null, ex);
|
|
||||||
} finally {
|
} finally {
|
||||||
if (taskProperties != null) {
|
if (taskProperties != null) {
|
||||||
try {
|
try {
|
||||||
taskProperties.close();
|
taskProperties.close();
|
||||||
} catch (IOException ex) {
|
} catch (IOException ex) {
|
||||||
LOGGER.log(Level.FINEST, null, ex);
|
log("", ex, Project.MSG_DEBUG);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1015,6 +1031,8 @@ public class DependencyCheckTask extends Task {
|
|||||||
Settings.setBoolean(Settings.KEYS.ANALYZER_JAR_ENABLED, jarAnalyzerEnabled);
|
Settings.setBoolean(Settings.KEYS.ANALYZER_JAR_ENABLED, jarAnalyzerEnabled);
|
||||||
//NUSPEC ANALYZER
|
//NUSPEC ANALYZER
|
||||||
Settings.setBoolean(Settings.KEYS.ANALYZER_NUSPEC_ENABLED, nuspecAnalyzerEnabled);
|
Settings.setBoolean(Settings.KEYS.ANALYZER_NUSPEC_ENABLED, nuspecAnalyzerEnabled);
|
||||||
|
//CENTRAL ANALYZER
|
||||||
|
Settings.setBoolean(Settings.KEYS.ANALYZER_CENTRAL_ENABLED, centralAnalyzerEnabled);
|
||||||
//NEXUS ANALYZER
|
//NEXUS ANALYZER
|
||||||
Settings.setBoolean(Settings.KEYS.ANALYZER_NEXUS_ENABLED, nexusAnalyzerEnabled);
|
Settings.setBoolean(Settings.KEYS.ANALYZER_NEXUS_ENABLED, nexusAnalyzerEnabled);
|
||||||
if (nexusUrl != null && !nexusUrl.isEmpty()) {
|
if (nexusUrl != null && !nexusUrl.isEmpty()) {
|
||||||
@@ -1125,7 +1143,7 @@ public class DependencyCheckTask extends Task {
|
|||||||
final String msg = String.format("%n%n"
|
final String msg = String.format("%n%n"
|
||||||
+ "One or more dependencies were identified with known vulnerabilities:%n%n%s"
|
+ "One or more dependencies were identified with known vulnerabilities:%n%n%s"
|
||||||
+ "%n%nSee the dependency-check report for more details.%n%n", summary.toString());
|
+ "%n%nSee the dependency-check report for more details.%n%n", summary.toString());
|
||||||
LOGGER.log(Level.WARNING, msg);
|
log(msg, Project.MSG_WARN);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,11 +1,4 @@
|
|||||||
/**
|
/**
|
||||||
* <html>
|
* This package includes the a slf4j logging implementation that wraps the Ant logger.
|
||||||
* <head>
|
|
||||||
* <title>org.owasp.dependencycheck.taskdefs</title>
|
|
||||||
* </head>
|
|
||||||
* <body>
|
|
||||||
* This package includes the Ant task definitions.
|
|
||||||
* </body>
|
|
||||||
* </html>
|
|
||||||
*/
|
*/
|
||||||
package org.owasp.dependencycheck.taskdefs;
|
package org.owasp.dependencycheck.taskdefs;
|
||||||
|
|||||||
@@ -0,0 +1,103 @@
|
|||||||
|
/*
|
||||||
|
* This file is part of dependency-check-ant.
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*
|
||||||
|
* Copyright (c) 2015 The OWASP Foundation. All Rights Reserved.
|
||||||
|
*/
|
||||||
|
package org.slf4j.impl;
|
||||||
|
|
||||||
|
import org.apache.tools.ant.Task;
|
||||||
|
import org.owasp.dependencycheck.ant.logging.AntLoggerFactory;
|
||||||
|
import org.slf4j.ILoggerFactory;
|
||||||
|
import org.slf4j.spi.LoggerFactoryBinder;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The binding of {@link LoggerFactory} class with an actual instance of {@link ILoggerFactory} is performed using information
|
||||||
|
* returned by this class.
|
||||||
|
*
|
||||||
|
* @author colezlaw
|
||||||
|
*/
|
||||||
|
public class StaticLoggerBinder implements LoggerFactoryBinder {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The unique instance of this class
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
private static final StaticLoggerBinder SINGLETON = new StaticLoggerBinder();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Return the singleton of this class.
|
||||||
|
*
|
||||||
|
* @return the StaticLoggerBinder singleton
|
||||||
|
*/
|
||||||
|
public static final StaticLoggerBinder getSingleton() {
|
||||||
|
return SINGLETON;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Ant tasks have the log method we actually want to call. So we hang onto the task as a delegate
|
||||||
|
*/
|
||||||
|
private Task task = null;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Set the Task which will this is to log through.
|
||||||
|
*
|
||||||
|
* @param task the task through which to log
|
||||||
|
*/
|
||||||
|
public void setTask(Task task) {
|
||||||
|
this.task = task;
|
||||||
|
loggerFactory = new AntLoggerFactory(task);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Declare the version of the SLF4J API this implementation is compiled against. The value of this filed is usually modified
|
||||||
|
* with each release.
|
||||||
|
*/
|
||||||
|
// to avoid constant folding by the compiler, this field must *not* be final
|
||||||
|
public static String REQUESTED_API_VERSION = "1.7.12"; // final
|
||||||
|
|
||||||
|
private static final String LOGGER_FACTORY_CLASS = AntLoggerFactory.class.getName();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The ILoggerFactory instance returned by the {@link #getLoggerFactory} method should always be the smae object
|
||||||
|
*/
|
||||||
|
private ILoggerFactory loggerFactory;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Constructs a new static logger binder.
|
||||||
|
*/
|
||||||
|
private StaticLoggerBinder() {
|
||||||
|
loggerFactory = new AntLoggerFactory(task);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the logger factory.
|
||||||
|
*
|
||||||
|
* @return the logger factory
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
public ILoggerFactory getLoggerFactory() {
|
||||||
|
return loggerFactory;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the logger factory class string.
|
||||||
|
*
|
||||||
|
* @return the logger factory class string
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
public String getLoggerFactoryClassStr() {
|
||||||
|
return LOGGER_FACTORY_CLASS;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,4 @@
|
|||||||
|
/**
|
||||||
|
* This package contains the static binder for the slf4j-ant logger.
|
||||||
|
*/
|
||||||
|
package org.slf4j.impl;
|
||||||
@@ -1,23 +0,0 @@
|
|||||||
handlers=java.util.logging.ConsoleHandler, java.util.logging.FileHandler
|
|
||||||
|
|
||||||
# logging levels
|
|
||||||
# FINEST, FINER, FINE, CONFIG, INFO, WARNING and SEVERE.
|
|
||||||
|
|
||||||
# Configure the ConsoleHandler.
|
|
||||||
java.util.logging.ConsoleHandler.level=INFO
|
|
||||||
|
|
||||||
#org.owasp.dependencycheck.data.nvdcve.xml
|
|
||||||
|
|
||||||
# Configure the FileHandler.
|
|
||||||
#java.util.logging.FileHandler.formatter=java.util.logging.SimpleFormatter
|
|
||||||
#java.util.logging.FileHandler.level=FINEST
|
|
||||||
|
|
||||||
# The following special tokens can be used in the pattern property
|
|
||||||
# which specifies the location and name of the log file.
|
|
||||||
# / - standard path separator
|
|
||||||
# %t - system temporary directory
|
|
||||||
# %h - value of the user.home system property
|
|
||||||
# %g - generation number for rotating logs
|
|
||||||
# %u - unique number to avoid conflicts
|
|
||||||
# FileHandler writes to %h/demo0.log by default.
|
|
||||||
#java.util.logging.FileHandler.pattern=./target/dependency-check.log
|
|
||||||
@@ -23,20 +23,20 @@ Configuration
|
|||||||
====================
|
====================
|
||||||
The following properties can be set on the dependency-check-maven plugin.
|
The following properties can be set on the dependency-check-maven plugin.
|
||||||
|
|
||||||
Property | Description | Default Value
|
Property | Description | Default Value
|
||||||
---------------------|------------------------------------|------------------
|
----------------------|------------------------------------|------------------
|
||||||
autoUpdate | Sets whether auto-updating of the NVD CVE/CPE data is enabled. It is not recommended that this be turned to false. | true
|
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
|
updateOnly | If set to true only the update phase of dependency-check will be executed; no scan will be executed and no report will be generated. | 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'
|
externalReport | When using as a Site plugin this parameter sets whether or not the external report format should be used. | false
|
||||||
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
|
reportOutputDirectory | The location to write the report(s). Note, this is not used if generating the report as part of a `mvn site` build | 'target'
|
||||||
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
|
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
|
||||||
logFile | The file path to write verbose logging information. |
|
reportFormat | 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
|
||||||
suppressionFile | The file path to the XML suppression file \- used to suppress [false positives](../suppression.html) |
|
suppressionFile | The file path to the XML suppression file \- used to suppress [false positives](../general/suppression.html) |
|
||||||
proxyServer | The Proxy Server. |
|
proxyServer | The Proxy Server. |
|
||||||
proxyPort | The Proxy Port. |
|
proxyPort | The Proxy Port. |
|
||||||
proxyUsername | Defines the proxy user name. |
|
proxyUsername | Defines the proxy user name. |
|
||||||
proxyPassword | Defines the proxy password. |
|
proxyPassword | Defines the proxy password. |
|
||||||
connectionTimeout | The URL Connection Timeout. |
|
connectionTimeout | The URL Connection Timeout. |
|
||||||
|
|
||||||
Analyzer Configuration
|
Analyzer Configuration
|
||||||
====================
|
====================
|
||||||
@@ -46,29 +46,30 @@ Note, that specific analyzers will automatically disable themselves if no file
|
|||||||
types that they support are detected - so specifically disabling them may not
|
types that they support are detected - so specifically disabling them may not
|
||||||
be needed.
|
be needed.
|
||||||
|
|
||||||
Property | Description | Default Value
|
Property | Description | Default Value
|
||||||
------------------------|------------------------------------|------------------
|
------------------------|---------------------------------------------------------------------------|------------------
|
||||||
archiveAnalyzerEnabled | Sets whether the Archive Analyzer will be used. | true
|
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. |
|
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
|
jarAnalyzer | Sets whether the Jar Analyzer will be used. | true
|
||||||
nexusAnalyzerEnabled | Sets whether Nexus Analyzer will be used. | true
|
centralAnalyzerEnabled | Sets whether the Central Analyzer will be used. **Disabling this analyzer is not recommended as it could lead to false negatives (e.g. libraries that have vulnerabilities may not be reported correctly).** If this analyzer is being disabled there is a good chance you also want to disable the Nexus Analyzer (see below). | true
|
||||||
nexusUrl | Defines the Nexus URL. | https://repository.sonatype.org/service/local/
|
nexusAnalyzerEnabled | Sets whether Nexus Analyzer will be used. This analyzer is superceded by the Central Analyzer; however, you can configure this to run against a Nexus Pro installation. | true
|
||||||
|
nexusUrl | Defines the Nexus web service endpoint (example http://domain.enterprise/nexus/service/local/). If not set the Nexus Analyzer will be disabled. |
|
||||||
nexusUsesProxy | Whether or not the defined proxy should be used when connecting to Nexus. | true
|
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
|
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
|
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 |
|
pathToMono | The path to Mono for .NET assembly analysis on non-windows systems. |
|
||||||
|
|
||||||
Advanced Configuration
|
Advanced Configuration
|
||||||
====================
|
====================
|
||||||
The following properties can be configured in the plugin. However, they are less frequently changed. One exception
|
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.
|
may be the cvedUrl properties, which can be used to host a mirror of the NVD within an enterprise environment.
|
||||||
|
|
||||||
Property | Description | Default Value
|
Property | Description | Default Value
|
||||||
---------------------|-------------------------------------------------------------------------|------------------
|
---------------------|--------------------------------------------------------------------------|------------------
|
||||||
cveUrl12Modified | URL for the modified CVE 1.2 | http://nvd.nist.gov/download/nvdcve-modified.xml
|
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
|
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
|
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
|
cveUrl20Base | Base URL for each year's CVE 2.0, the %d will be replaced with the year. | http://static.nvd.nist.gov/feeds/xml/cve/nvdcve-2.0-%d.xml
|
||||||
dataDirectory | Data directory to hold SQL CVEs contents. This should generally not be changed. |
|
dataDirectory | Data directory to hold SQL CVEs contents. This should generally not be changed. |
|
||||||
databaseDriverName | The name of the database driver. Example: org.h2.Driver. |
|
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. |
|
databaseDriverPath | The path to the database driver JAR file; only used if the driver is not in the class path. |
|
||||||
|
|||||||
33
dependency-check-ant/src/site/markdown/index.md.vm
Normal file
33
dependency-check-ant/src/site/markdown/index.md.vm
Normal file
@@ -0,0 +1,33 @@
|
|||||||
|
About
|
||||||
|
====================
|
||||||
|
OWASP 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.
|
||||||
|
|
||||||
|
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:
|
||||||
|
|
||||||
|
```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 10 minutes or more as it downloads and processes the data from the National
|
||||||
|
Vulnerability Database (NVD) hosted by NIST: https://nvd.nist.gov
|
||||||
|
|
||||||
|
After the first batch download, as long as the task is executed at least once every
|
||||||
|
seven days the update will only take a few seconds.
|
||||||
@@ -1,13 +0,0 @@
|
|||||||
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.
|
|
||||||
|
|
||||||
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
|
|
||||||
Vulnerability Database (NVD) hosted by NIST: https://nvd.nist.gov
|
|
||||||
|
|
||||||
After the first batch download, as long as the task is executed at least once every
|
|
||||||
seven days the update will only take a few seconds.
|
|
||||||
@@ -1,11 +1,19 @@
|
|||||||
Usage
|
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
|
```xml
|
||||||
<taskdef name="dependency-check" classname="org.owasp.dependencycheck.taskdefs.DependencyCheckTask"/>
|
<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:
|
Next, add the task to a target of your choosing:
|
||||||
|
|
||||||
```xml
|
```xml
|
||||||
File diff suppressed because one or more lines are too long
|
After Width: | Height: | Size: 10 KiB |
@@ -18,7 +18,9 @@ Copyright (c) 2013 Jeremy Long. All Rights Reserved.
|
|||||||
-->
|
-->
|
||||||
<project name="dependency-check-ant">
|
<project name="dependency-check-ant">
|
||||||
<bannerLeft>
|
<bannerLeft>
|
||||||
<name>dependency-check-ant</name>
|
<name>OWASP dependency-check-ant</name>
|
||||||
|
<alt>OWASP dependency-check-ant</alt>
|
||||||
|
<src>./images/dc-ant.svg</src>
|
||||||
</bannerLeft>
|
</bannerLeft>
|
||||||
<body>
|
<body>
|
||||||
<breadcrumbs>
|
<breadcrumbs>
|
||||||
@@ -29,7 +31,6 @@ Copyright (c) 2013 Jeremy Long. All Rights Reserved.
|
|||||||
<item name="Usage" href="usage.html"/>
|
<item name="Usage" href="usage.html"/>
|
||||||
<item name="Configuration" href="configuration.html"/>
|
<item name="Configuration" href="configuration.html"/>
|
||||||
</menu>
|
</menu>
|
||||||
<menu ref="Project Documentation" />
|
|
||||||
<menu ref="reports" />
|
<menu ref="reports" />
|
||||||
</body>
|
</body>
|
||||||
</project>
|
</project>
|
||||||
@@ -18,30 +18,41 @@
|
|||||||
package org.owasp.dependencycheck.taskdefs;
|
package org.owasp.dependencycheck.taskdefs;
|
||||||
|
|
||||||
import java.io.File;
|
import java.io.File;
|
||||||
import org.apache.tools.ant.BuildFileTest;
|
|
||||||
|
import org.apache.tools.ant.BuildException;
|
||||||
|
import org.apache.tools.ant.BuildFileRule;
|
||||||
import org.junit.After;
|
import org.junit.After;
|
||||||
import org.junit.Before;
|
import org.junit.Before;
|
||||||
|
import org.junit.Rule;
|
||||||
import org.junit.Test;
|
import org.junit.Test;
|
||||||
|
import org.junit.rules.ExpectedException;
|
||||||
import org.owasp.dependencycheck.data.nvdcve.BaseDBTestCase;
|
import org.owasp.dependencycheck.data.nvdcve.BaseDBTestCase;
|
||||||
import org.owasp.dependencycheck.utils.Settings;
|
import org.owasp.dependencycheck.utils.Settings;
|
||||||
|
|
||||||
|
import static org.junit.Assert.assertTrue;
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
*
|
*
|
||||||
* @author Jeremy Long <jeremy.long@owasp.org>
|
* @author Jeremy Long
|
||||||
*/
|
*/
|
||||||
public class DependencyCheckTaskTest extends BuildFileTest {
|
public class DependencyCheckTaskTest {
|
||||||
|
|
||||||
|
@Rule
|
||||||
|
public BuildFileRule buildFileRule = new BuildFileRule();
|
||||||
|
|
||||||
|
@Rule
|
||||||
|
public ExpectedException expectedException = ExpectedException.none();
|
||||||
|
|
||||||
@Before
|
@Before
|
||||||
@Override
|
|
||||||
public void setUp() throws Exception {
|
public void setUp() throws Exception {
|
||||||
Settings.initialize();
|
Settings.initialize();
|
||||||
BaseDBTestCase.ensureDBExists();
|
BaseDBTestCase.ensureDBExists();
|
||||||
final String buildFile = this.getClass().getClassLoader().getResource("build.xml").getPath();
|
final String buildFile = this.getClass().getClassLoader().getResource("build.xml").getPath();
|
||||||
configureProject(buildFile);
|
buildFileRule.configureProject(buildFile);
|
||||||
}
|
}
|
||||||
|
|
||||||
@After
|
@After
|
||||||
@Override
|
|
||||||
public void tearDown() {
|
public void tearDown() {
|
||||||
//no cleanup...
|
//no cleanup...
|
||||||
//executeTarget("cleanup");
|
//executeTarget("cleanup");
|
||||||
@@ -59,7 +70,7 @@ public class DependencyCheckTaskTest extends BuildFileTest {
|
|||||||
throw new Exception("Unable to delete 'target/DependencyCheck-Report.html' prior to test.");
|
throw new Exception("Unable to delete 'target/DependencyCheck-Report.html' prior to test.");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
executeTarget("test.fileset");
|
buildFileRule.executeTarget("test.fileset");
|
||||||
|
|
||||||
assertTrue("DependencyCheck report was not generated", report.exists());
|
assertTrue("DependencyCheck report was not generated", report.exists());
|
||||||
|
|
||||||
@@ -78,7 +89,7 @@ public class DependencyCheckTaskTest extends BuildFileTest {
|
|||||||
throw new Exception("Unable to delete 'target/DependencyCheck-Report.xml' prior to test.");
|
throw new Exception("Unable to delete 'target/DependencyCheck-Report.xml' prior to test.");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
executeTarget("test.filelist");
|
buildFileRule.executeTarget("test.filelist");
|
||||||
|
|
||||||
assertTrue("DependencyCheck report was not generated", report.exists());
|
assertTrue("DependencyCheck report was not generated", report.exists());
|
||||||
}
|
}
|
||||||
@@ -96,7 +107,7 @@ public class DependencyCheckTaskTest extends BuildFileTest {
|
|||||||
throw new Exception("Unable to delete 'target/DependencyCheck-Vulnerability.html' prior to test.");
|
throw new Exception("Unable to delete 'target/DependencyCheck-Vulnerability.html' prior to test.");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
executeTarget("test.dirset");
|
buildFileRule.executeTarget("test.dirset");
|
||||||
assertTrue("DependencyCheck report was not generated", report.exists());
|
assertTrue("DependencyCheck report was not generated", report.exists());
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -105,7 +116,7 @@ public class DependencyCheckTaskTest extends BuildFileTest {
|
|||||||
*/
|
*/
|
||||||
@Test
|
@Test
|
||||||
public void testGetFailBuildOnCVSS() {
|
public void testGetFailBuildOnCVSS() {
|
||||||
expectBuildException("failCVSS", "asdfasdfscore");
|
expectedException.expect(BuildException.class);
|
||||||
System.out.println(this.getOutput());
|
buildFileRule.executeTarget("failCVSS");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -15,20 +15,19 @@ limitations under the License.
|
|||||||
|
|
||||||
Copyright (c) 2012 - Jeremy Long. All Rights Reserved.
|
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">
|
<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>
|
<modelVersion>4.0.0</modelVersion>
|
||||||
<parent>
|
<parent>
|
||||||
<groupId>org.owasp</groupId>
|
<groupId>org.owasp</groupId>
|
||||||
<artifactId>dependency-check-parent</artifactId>
|
<artifactId>dependency-check-parent</artifactId>
|
||||||
<version>1.2.3</version>
|
<version>1.3.0</version>
|
||||||
</parent>
|
</parent>
|
||||||
|
|
||||||
<artifactId>dependency-check-cli</artifactId>
|
<artifactId>dependency-check-cli</artifactId>
|
||||||
<packaging>jar</packaging>
|
<packaging>jar</packaging>
|
||||||
|
|
||||||
<name>Dependency-Check Command Line</name>
|
<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/ -->
|
<!-- begin copy from http://minds.coremedia.com/2012/09/11/problem-solved-deploy-multi-module-maven-project-site-as-github-pages/ -->
|
||||||
<distributionManagement>
|
<distributionManagement>
|
||||||
<site>
|
<site>
|
||||||
@@ -45,6 +44,7 @@ Copyright (c) 2012 - Jeremy Long. All Rights Reserved.
|
|||||||
<directory>src/main/resources</directory>
|
<directory>src/main/resources</directory>
|
||||||
<includes>
|
<includes>
|
||||||
<include>**/*.properties</include>
|
<include>**/*.properties</include>
|
||||||
|
<include>logback.xml</include>
|
||||||
</includes>
|
</includes>
|
||||||
<filtering>true</filtering>
|
<filtering>true</filtering>
|
||||||
</resource>
|
</resource>
|
||||||
@@ -61,27 +61,21 @@ Copyright (c) 2012 - Jeremy Long. All Rights Reserved.
|
|||||||
<plugin>
|
<plugin>
|
||||||
<groupId>org.apache.maven.plugins</groupId>
|
<groupId>org.apache.maven.plugins</groupId>
|
||||||
<artifactId>maven-jar-plugin</artifactId>
|
<artifactId>maven-jar-plugin</artifactId>
|
||||||
<version>2.4</version>
|
|
||||||
<configuration>
|
<configuration>
|
||||||
<archive>
|
<archive>
|
||||||
<manifest>
|
<manifest>
|
||||||
<mainClass>org.owasp.dependencycheck.App</mainClass>
|
<mainClass>org.owasp.dependencycheck.App</mainClass>
|
||||||
<addDefaultImplementationEntries>true</addDefaultImplementationEntries>
|
|
||||||
</manifest>
|
</manifest>
|
||||||
</archive>
|
</archive>
|
||||||
<excludes>
|
|
||||||
<exclude>**/checkstyle*</exclude>
|
|
||||||
</excludes>
|
|
||||||
</configuration>
|
</configuration>
|
||||||
</plugin>
|
</plugin>
|
||||||
<plugin>
|
<plugin>
|
||||||
<groupId>org.codehaus.mojo</groupId>
|
<groupId>org.codehaus.mojo</groupId>
|
||||||
<artifactId>cobertura-maven-plugin</artifactId>
|
<artifactId>cobertura-maven-plugin</artifactId>
|
||||||
<version>2.6</version>
|
|
||||||
<configuration>
|
<configuration>
|
||||||
<instrumentation>
|
<!--instrumentation>
|
||||||
<ignoreTrivial>true</ignoreTrivial>
|
<ignoreTrivial>true</ignoreTrivial>
|
||||||
</instrumentation>
|
</instrumentation-->
|
||||||
<check>
|
<check>
|
||||||
<branchRate>85</branchRate>
|
<branchRate>85</branchRate>
|
||||||
<lineRate>85</lineRate>
|
<lineRate>85</lineRate>
|
||||||
@@ -115,7 +109,6 @@ Copyright (c) 2012 - Jeremy Long. All Rights Reserved.
|
|||||||
<plugin>
|
<plugin>
|
||||||
<groupId>org.apache.maven.plugins</groupId>
|
<groupId>org.apache.maven.plugins</groupId>
|
||||||
<artifactId>maven-surefire-plugin</artifactId>
|
<artifactId>maven-surefire-plugin</artifactId>
|
||||||
<version>2.16</version>
|
|
||||||
<configuration>
|
<configuration>
|
||||||
<systemProperties>
|
<systemProperties>
|
||||||
<property>
|
<property>
|
||||||
@@ -134,162 +127,15 @@ Copyright (c) 2012 - Jeremy Long. All Rights Reserved.
|
|||||||
<plugin>
|
<plugin>
|
||||||
<groupId>org.apache.maven.plugins</groupId>
|
<groupId>org.apache.maven.plugins</groupId>
|
||||||
<artifactId>maven-compiler-plugin</artifactId>
|
<artifactId>maven-compiler-plugin</artifactId>
|
||||||
<version>3.1</version>
|
|
||||||
<configuration>
|
|
||||||
<showDeprecation>false</showDeprecation>
|
|
||||||
<source>1.6</source>
|
|
||||||
<target>1.6</target>
|
|
||||||
</configuration>
|
|
||||||
</plugin>
|
|
||||||
<plugin>
|
|
||||||
<groupId>org.apache.maven.plugins</groupId>
|
|
||||||
<artifactId>maven-site-plugin</artifactId>
|
|
||||||
<version>3.3</version>
|
|
||||||
<dependencies>
|
|
||||||
<dependency>
|
|
||||||
<groupId>org.apache.maven.doxia</groupId>
|
|
||||||
<artifactId>doxia-module-markdown</artifactId>
|
|
||||||
<version>1.5</version>
|
|
||||||
</dependency>
|
|
||||||
</dependencies>
|
|
||||||
<configuration>
|
|
||||||
<skipDeploy>true</skipDeploy>
|
|
||||||
<reportPlugins>
|
|
||||||
<plugin>
|
|
||||||
<groupId>org.apache.maven.plugins</groupId>
|
|
||||||
<artifactId>maven-project-info-reports-plugin</artifactId>
|
|
||||||
<version>2.7</version>
|
|
||||||
<reportSets>
|
|
||||||
<reportSet>
|
|
||||||
<reports>
|
|
||||||
<report>index</report>
|
|
||||||
<report>summary</report>
|
|
||||||
<report>license</report>
|
|
||||||
<report>help</report>
|
|
||||||
</reports>
|
|
||||||
</reportSet>
|
|
||||||
</reportSets>
|
|
||||||
</plugin>
|
|
||||||
<plugin>
|
|
||||||
<groupId>org.apache.maven.plugins</groupId>
|
|
||||||
<artifactId>maven-javadoc-plugin</artifactId>
|
|
||||||
<version>2.9.1</version>
|
|
||||||
<reportSets>
|
|
||||||
<reportSet>
|
|
||||||
<id>default</id>
|
|
||||||
<reports>
|
|
||||||
<report>javadoc</report>
|
|
||||||
</reports>
|
|
||||||
</reportSet>
|
|
||||||
</reportSets>
|
|
||||||
</plugin>
|
|
||||||
<plugin>
|
|
||||||
<groupId>org.codehaus.mojo</groupId>
|
|
||||||
<artifactId>versions-maven-plugin</artifactId>
|
|
||||||
<version>2.1</version>
|
|
||||||
<reportSets>
|
|
||||||
<reportSet>
|
|
||||||
<reports>
|
|
||||||
<report>dependency-updates-report</report>
|
|
||||||
<report>plugin-updates-report</report>
|
|
||||||
</reports>
|
|
||||||
</reportSet>
|
|
||||||
</reportSets>
|
|
||||||
</plugin>
|
|
||||||
<plugin>
|
|
||||||
<groupId>org.apache.maven.plugins</groupId>
|
|
||||||
<artifactId>maven-jxr-plugin</artifactId>
|
|
||||||
<version>2.4</version>
|
|
||||||
</plugin>
|
|
||||||
<plugin>
|
|
||||||
<groupId>org.codehaus.mojo</groupId>
|
|
||||||
<artifactId>cobertura-maven-plugin</artifactId>
|
|
||||||
<version>2.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.1</version>
|
|
||||||
<configuration>
|
|
||||||
<targetJdk>1.6</targetJdk>
|
|
||||||
<linkXref>true</linkXref>
|
|
||||||
<sourceEncoding>utf-8</sourceEncoding>
|
|
||||||
<excludes>
|
|
||||||
<exclude>**/generated/*.java</exclude>
|
|
||||||
</excludes>
|
|
||||||
<rulesets>
|
|
||||||
<ruleset>../src/main/config/dcrules.xml</ruleset>
|
|
||||||
<ruleset>/rulesets/java/basic.xml</ruleset>
|
|
||||||
<ruleset>/rulesets/java/imports.xml</ruleset>
|
|
||||||
<ruleset>/rulesets/java/unusedcode.xml</ruleset>
|
|
||||||
</rulesets>
|
|
||||||
</configuration>
|
|
||||||
</plugin>
|
|
||||||
<plugin>
|
|
||||||
<groupId>org.codehaus.mojo</groupId>
|
|
||||||
<artifactId>findbugs-maven-plugin</artifactId>
|
|
||||||
<version>2.5.3</version>
|
|
||||||
</plugin>
|
|
||||||
</reportPlugins>
|
|
||||||
</configuration>
|
|
||||||
</plugin>
|
</plugin>
|
||||||
<plugin>
|
<plugin>
|
||||||
<groupId>org.codehaus.mojo</groupId>
|
<groupId>org.codehaus.mojo</groupId>
|
||||||
<artifactId>appassembler-maven-plugin</artifactId>
|
<artifactId>appassembler-maven-plugin</artifactId>
|
||||||
<version>1.7</version>
|
|
||||||
<configuration>
|
<configuration>
|
||||||
<programs>
|
<programs>
|
||||||
<program>
|
<program>
|
||||||
<mainClass>org.owasp.dependencycheck.App</mainClass>
|
<mainClass>org.owasp.dependencycheck.App</mainClass>
|
||||||
<name>dependency-check</name>
|
<id>dependency-check</id>
|
||||||
</program>
|
</program>
|
||||||
</programs>
|
</programs>
|
||||||
<assembleDirectory>${project.build.directory}/release</assembleDirectory>
|
<assembleDirectory>${project.build.directory}/release</assembleDirectory>
|
||||||
@@ -330,11 +176,141 @@ Copyright (c) 2012 - Jeremy Long. All Rights Reserved.
|
|||||||
</plugin>
|
</plugin>
|
||||||
</plugins>
|
</plugins>
|
||||||
</build>
|
</build>
|
||||||
|
<reporting>
|
||||||
|
<plugins>
|
||||||
|
<plugin>
|
||||||
|
<groupId>org.apache.maven.plugins</groupId>
|
||||||
|
<artifactId>maven-project-info-reports-plugin</artifactId>
|
||||||
|
<version>${reporting.project-info-reports-plugin.version}</version>
|
||||||
|
<reportSets>
|
||||||
|
<reportSet>
|
||||||
|
<reports>
|
||||||
|
<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>${reporting.javadoc-plugin.version}</version>
|
||||||
|
<configuration>
|
||||||
|
<failOnError>false</failOnError>
|
||||||
|
<bottom>Copyright<EFBFBD> 2012-15 Jeremy Long. All Rights Reserved.</bottom>
|
||||||
|
</configuration>
|
||||||
|
<reportSets>
|
||||||
|
<reportSet>
|
||||||
|
<id>default</id>
|
||||||
|
<reports>
|
||||||
|
<report>javadoc</report>
|
||||||
|
</reports>
|
||||||
|
</reportSet>
|
||||||
|
</reportSets>
|
||||||
|
</plugin>
|
||||||
|
<plugin>
|
||||||
|
<groupId>org.codehaus.mojo</groupId>
|
||||||
|
<artifactId>versions-maven-plugin</artifactId>
|
||||||
|
<version>${reporting.versions-plugin.version}</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>${reporting.jxr-plugin.version}</version>
|
||||||
|
</plugin>
|
||||||
|
<plugin>
|
||||||
|
<groupId>org.codehaus.mojo</groupId>
|
||||||
|
<artifactId>cobertura-maven-plugin</artifactId>
|
||||||
|
<version>${reporting.cobertura-plugin.version}</version>
|
||||||
|
</plugin>
|
||||||
|
<plugin>
|
||||||
|
<groupId>org.apache.maven.plugins</groupId>
|
||||||
|
<artifactId>maven-surefire-report-plugin</artifactId>
|
||||||
|
<version>${reporting.surefire-report-plugin.version}</version>
|
||||||
|
<reportSets>
|
||||||
|
<reportSet>
|
||||||
|
<reports>
|
||||||
|
<report>report-only</report>
|
||||||
|
</reports>
|
||||||
|
</reportSet>
|
||||||
|
</reportSets>
|
||||||
|
</plugin>
|
||||||
|
<plugin>
|
||||||
|
<groupId>org.codehaus.mojo</groupId>
|
||||||
|
<artifactId>taglist-maven-plugin</artifactId>
|
||||||
|
<version>${reporting.taglist-plugin.version}</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>${reporting.checkstyle-plugin.version}</version>
|
||||||
|
<configuration>
|
||||||
|
<enableRulesSummary>false</enableRulesSummary>
|
||||||
|
<enableFilesSummary>false</enableFilesSummary>
|
||||||
|
<configLocation>${basedir}/../src/main/config/checkstyle-checks.xml</configLocation>
|
||||||
|
<headerLocation>${basedir}/../src/main/config/checkstyle-header.txt</headerLocation>
|
||||||
|
<suppressionsLocation>${basedir}/../src/main/config/checkstyle-suppressions.xml</suppressionsLocation>
|
||||||
|
<suppressionsFileExpression>checkstyle.suppressions.file</suppressionsFileExpression>
|
||||||
|
</configuration>
|
||||||
|
</plugin>
|
||||||
|
<plugin>
|
||||||
|
<groupId>org.apache.maven.plugins</groupId>
|
||||||
|
<artifactId>maven-pmd-plugin</artifactId>
|
||||||
|
<version>${reporting.pmd-plugin.version}</version>
|
||||||
|
<configuration>
|
||||||
|
<targetJdk>1.6</targetJdk>
|
||||||
|
<linkXref>true</linkXref>
|
||||||
|
<sourceEncoding>utf-8</sourceEncoding>
|
||||||
|
<excludes>
|
||||||
|
<exclude>**/generated/*.java</exclude>
|
||||||
|
</excludes>
|
||||||
|
<rulesets>
|
||||||
|
<ruleset>../src/main/config/dcrules.xml</ruleset>
|
||||||
|
<ruleset>/rulesets/java/basic.xml</ruleset>
|
||||||
|
<ruleset>/rulesets/java/imports.xml</ruleset>
|
||||||
|
<ruleset>/rulesets/java/unusedcode.xml</ruleset>
|
||||||
|
</rulesets>
|
||||||
|
</configuration>
|
||||||
|
</plugin>
|
||||||
|
<plugin>
|
||||||
|
<groupId>org.codehaus.mojo</groupId>
|
||||||
|
<artifactId>findbugs-maven-plugin</artifactId>
|
||||||
|
<version>${reporting.findbugs-plugin.version}</version>
|
||||||
|
</plugin>
|
||||||
|
</plugins>
|
||||||
|
</reporting>
|
||||||
<dependencies>
|
<dependencies>
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>commons-cli</groupId>
|
<groupId>commons-cli</groupId>
|
||||||
<artifactId>commons-cli</artifactId>
|
<artifactId>commons-cli</artifactId>
|
||||||
<version>1.2</version>
|
|
||||||
</dependency>
|
</dependency>
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>org.owasp</groupId>
|
<groupId>org.owasp</groupId>
|
||||||
@@ -346,5 +322,17 @@ Copyright (c) 2012 - Jeremy Long. All Rights Reserved.
|
|||||||
<artifactId>dependency-check-utils</artifactId>
|
<artifactId>dependency-check-utils</artifactId>
|
||||||
<version>${project.parent.version}</version>
|
<version>${project.parent.version}</version>
|
||||||
</dependency>
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.slf4j</groupId>
|
||||||
|
<artifactId>slf4j-api</artifactId>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>ch.qos.logback</groupId>
|
||||||
|
<artifactId>logback-core</artifactId>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>ch.qos.logback</groupId>
|
||||||
|
<artifactId>logback-classic</artifactId>
|
||||||
|
</dependency>
|
||||||
</dependencies>
|
</dependencies>
|
||||||
</project>
|
</project>
|
||||||
|
|||||||
@@ -2,11 +2,8 @@
|
|||||||
<assembly
|
<assembly
|
||||||
xmlns="http://maven.apache.org/plugins/maven-assembly-plugin/assembly/1.1.2"
|
xmlns="http://maven.apache.org/plugins/maven-assembly-plugin/assembly/1.1.2"
|
||||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||||
xsi:schemaLocation="
|
xsi:schemaLocation="http://maven.apache.org/plugins/maven-assembly-plugin/assembly/1.1.2
|
||||||
http://maven.apache.org/plugins/maven-assembly-plugin/assembly/1.1.2
|
http://maven.apache.org/xsd/assembly-1.1.2.xsd">
|
||||||
http://maven.apache.org/xsd/assembly-1.1.2.xsd
|
|
||||||
"
|
|
||||||
>
|
|
||||||
<id>release</id>
|
<id>release</id>
|
||||||
<formats>
|
<formats>
|
||||||
<format>zip</format>
|
<format>zip</format>
|
||||||
@@ -14,25 +11,41 @@
|
|||||||
<includeBaseDirectory>false</includeBaseDirectory>
|
<includeBaseDirectory>false</includeBaseDirectory>
|
||||||
<fileSets>
|
<fileSets>
|
||||||
<fileSet>
|
<fileSet>
|
||||||
<outputDirectory>/</outputDirectory>
|
<outputDirectory>dependency-check/bin</outputDirectory>
|
||||||
<directory>${project.build.directory}/release</directory>
|
<directory>${project.build.directory}/release/bin</directory>
|
||||||
|
<includes>
|
||||||
|
<include>*.sh</include>
|
||||||
|
</includes>
|
||||||
|
<fileMode>0755</fileMode>
|
||||||
</fileSet>
|
</fileSet>
|
||||||
<fileSet>
|
<fileSet>
|
||||||
|
<outputDirectory>dependency-check/bin</outputDirectory>
|
||||||
|
<directory>${project.build.directory}/release/bin</directory>
|
||||||
|
<includes>
|
||||||
|
<include>*.bat</include>
|
||||||
|
</includes>
|
||||||
|
</fileSet>
|
||||||
|
<fileSet>
|
||||||
|
<outputDirectory>dependency-check/repo</outputDirectory>
|
||||||
|
<directory>${project.build.directory}/release/repo</directory>
|
||||||
|
</fileSet>
|
||||||
|
<fileSet>
|
||||||
|
<outputDirectory>dependency-check</outputDirectory>
|
||||||
<includes>
|
<includes>
|
||||||
<include>LICENSE*</include>
|
<include>LICENSE*</include>
|
||||||
<include>NOTICE*</include>
|
<include>NOTICE*</include>
|
||||||
</includes>
|
</includes>
|
||||||
</fileSet>
|
</fileSet>
|
||||||
<fileSet>
|
<fileSet>
|
||||||
<outputDirectory>licenses</outputDirectory>
|
<outputDirectory>dependency-check/licenses</outputDirectory>
|
||||||
<directory>${basedir}/src/main/resources/META-INF/licenses</directory>
|
<directory>${basedir}/src/main/resources/META-INF/licenses</directory>
|
||||||
</fileSet>
|
</fileSet>
|
||||||
<fileSet>
|
<fileSet>
|
||||||
<outputDirectory>licenses</outputDirectory>
|
<outputDirectory>dependency-check/licenses</outputDirectory>
|
||||||
<directory>${basedir}/../dependency-check-core/src/main/resources/META-INF/licenses</directory>
|
<directory>${basedir}/../dependency-check-core/src/main/resources/META-INF/licenses</directory>
|
||||||
</fileSet>
|
</fileSet>
|
||||||
<fileSet>
|
<fileSet>
|
||||||
<outputDirectory>/</outputDirectory>
|
<outputDirectory>dependency-check</outputDirectory>
|
||||||
<directory>${basedir}</directory>
|
<directory>${basedir}</directory>
|
||||||
<includes>
|
<includes>
|
||||||
<include>README.md</include>
|
<include>README.md</include>
|
||||||
|
|||||||
@@ -17,39 +17,39 @@
|
|||||||
*/
|
*/
|
||||||
package org.owasp.dependencycheck;
|
package org.owasp.dependencycheck;
|
||||||
|
|
||||||
|
import ch.qos.logback.classic.LoggerContext;
|
||||||
|
import ch.qos.logback.classic.encoder.PatternLayoutEncoder;
|
||||||
import java.io.File;
|
import java.io.File;
|
||||||
import java.io.FileNotFoundException;
|
import java.io.FileNotFoundException;
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.io.InputStream;
|
import java.util.ArrayList;
|
||||||
|
import java.util.HashSet;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.logging.Level;
|
import java.util.Set;
|
||||||
import java.util.logging.Logger;
|
|
||||||
import org.apache.commons.cli.ParseException;
|
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.CveDB;
|
||||||
import org.owasp.dependencycheck.data.nvdcve.DatabaseException;
|
import org.owasp.dependencycheck.data.nvdcve.DatabaseException;
|
||||||
import org.owasp.dependencycheck.data.nvdcve.DatabaseProperties;
|
import org.owasp.dependencycheck.data.nvdcve.DatabaseProperties;
|
||||||
import org.owasp.dependencycheck.dependency.Dependency;
|
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.reporting.ReportGenerator;
|
||||||
import org.owasp.dependencycheck.utils.LogUtils;
|
|
||||||
import org.owasp.dependencycheck.utils.Settings;
|
import org.owasp.dependencycheck.utils.Settings;
|
||||||
|
import org.slf4j.Logger;
|
||||||
|
import org.slf4j.LoggerFactory;
|
||||||
|
import ch.qos.logback.core.FileAppender;
|
||||||
|
import org.slf4j.impl.StaticLoggerBinder;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The command line interface for the DependencyCheck application.
|
* The command line interface for the DependencyCheck application.
|
||||||
*
|
*
|
||||||
* @author Jeremy Long <jeremy.long@owasp.org>
|
* @author Jeremy Long
|
||||||
*/
|
*/
|
||||||
public class App {
|
public class App {
|
||||||
|
|
||||||
/**
|
|
||||||
* The location of the log properties configuration file.
|
|
||||||
*/
|
|
||||||
private static final String LOG_PROPERTIES_FILE = "log.properties";
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The logger.
|
* The logger.
|
||||||
*/
|
*/
|
||||||
private static final Logger LOGGER = Logger.getLogger(App.class.getName());
|
private static final Logger LOGGER = LoggerFactory.getLogger(App.class);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The main method for the application.
|
* The main method for the application.
|
||||||
@@ -86,14 +86,23 @@ public class App {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
final InputStream in = App.class.getClassLoader().getResourceAsStream(LOG_PROPERTIES_FILE);
|
if (cli.getVerboseLog() != null) {
|
||||||
LogUtils.prepareLogger(in, cli.getVerboseLog());
|
prepareLogger(cli.getVerboseLog());
|
||||||
|
}
|
||||||
|
|
||||||
if (cli.isGetVersion()) {
|
if (cli.isGetVersion()) {
|
||||||
cli.printVersionInfo();
|
cli.printVersionInfo();
|
||||||
|
} else if (cli.isUpdateOnly()) {
|
||||||
|
populateSettings(cli);
|
||||||
|
runUpdateOnly();
|
||||||
} else if (cli.isRunScan()) {
|
} else if (cli.isRunScan()) {
|
||||||
populateSettings(cli);
|
populateSettings(cli);
|
||||||
runScan(cli.getReportDirectory(), cli.getReportFormat(), cli.getApplicationName(), cli.getScanFiles());
|
try {
|
||||||
|
runScan(cli.getReportDirectory(), cli.getReportFormat(), cli.getApplicationName(), cli.getScanFiles(),
|
||||||
|
cli.getExcludeList(), cli.getSymLinkDepth());
|
||||||
|
} catch (InvalidScanPathException ex) {
|
||||||
|
LOGGER.error("An invalid scan path was detected; unable to scan '//*' paths");
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
cli.printHelp();
|
cli.printHelp();
|
||||||
}
|
}
|
||||||
@@ -106,18 +115,68 @@ public class App {
|
|||||||
* @param outputFormat the output format of the report
|
* @param outputFormat the output format of the report
|
||||||
* @param applicationName the application name for the report
|
* @param applicationName the application name for the report
|
||||||
* @param files the files/directories to scan
|
* @param files the files/directories to scan
|
||||||
|
* @param excludes the patterns for files/directories to exclude
|
||||||
|
* @param symLinkDepth the depth that symbolic links will be followed
|
||||||
|
*
|
||||||
|
* @throws InvalidScanPathException thrown if the path to scan starts with "//"
|
||||||
*/
|
*/
|
||||||
private void runScan(String reportDirectory, String outputFormat, String applicationName, String[] files) {
|
private void runScan(String reportDirectory, String outputFormat, String applicationName, String[] files,
|
||||||
Engine scanner = null;
|
String[] excludes, int symLinkDepth) throws InvalidScanPathException {
|
||||||
|
Engine engine = null;
|
||||||
try {
|
try {
|
||||||
scanner = new Engine();
|
engine = new Engine();
|
||||||
|
final List<String> antStylePaths = new ArrayList<String>();
|
||||||
for (String file : files) {
|
for (String file : files) {
|
||||||
scanner.scan(file);
|
final String antPath = ensureCanonicalPath(file);
|
||||||
|
antStylePaths.add(antPath);
|
||||||
}
|
}
|
||||||
|
|
||||||
scanner.analyzeDependencies();
|
final Set<File> paths = new HashSet<File>();
|
||||||
final List<Dependency> dependencies = scanner.getDependencies();
|
for (String file : antStylePaths) {
|
||||||
|
LOGGER.debug("Scanning {}", file);
|
||||||
|
final DirectoryScanner scanner = new DirectoryScanner();
|
||||||
|
String include = file.replace('\\', '/');
|
||||||
|
File baseDir;
|
||||||
|
|
||||||
|
if (include.startsWith("//")) {
|
||||||
|
throw new InvalidScanPathException("Unable to scan paths specified by //");
|
||||||
|
} else {
|
||||||
|
final int pos = getLastFileSeparator(include);
|
||||||
|
final String tmpBase = include.substring(0, pos);
|
||||||
|
final String tmpInclude = include.substring(pos + 1);
|
||||||
|
if (tmpInclude.indexOf('*') >= 0 || tmpInclude.indexOf('?') >= 0
|
||||||
|
|| (new File(include)).isFile()) {
|
||||||
|
baseDir = new File(tmpBase);
|
||||||
|
include = tmpInclude;
|
||||||
|
} else {
|
||||||
|
baseDir = new File(tmpBase, tmpInclude);
|
||||||
|
include = "**/*";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
//LOGGER.debug("baseDir: {}", baseDir);
|
||||||
|
//LOGGER.debug("include: {}", include);
|
||||||
|
scanner.setBasedir(baseDir);
|
||||||
|
scanner.setIncludes(include);
|
||||||
|
scanner.setMaxLevelsOfSymlinks(symLinkDepth);
|
||||||
|
if (symLinkDepth <= 0) {
|
||||||
|
scanner.setFollowSymlinks(false);
|
||||||
|
}
|
||||||
|
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);
|
||||||
|
LOGGER.debug("Found file {}", f.toString());
|
||||||
|
paths.add(f);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
engine.scan(paths);
|
||||||
|
|
||||||
|
engine.analyzeDependencies();
|
||||||
|
final List<Dependency> dependencies = engine.getDependencies();
|
||||||
DatabaseProperties prop = null;
|
DatabaseProperties prop = null;
|
||||||
CveDB cve = null;
|
CveDB cve = null;
|
||||||
try {
|
try {
|
||||||
@@ -125,28 +184,46 @@ public class App {
|
|||||||
cve.open();
|
cve.open();
|
||||||
prop = cve.getDatabaseProperties();
|
prop = cve.getDatabaseProperties();
|
||||||
} catch (DatabaseException ex) {
|
} catch (DatabaseException ex) {
|
||||||
LOGGER.log(Level.FINE, "Unable to retrieve DB Properties", ex);
|
LOGGER.debug("Unable to retrieve DB Properties", ex);
|
||||||
} finally {
|
} finally {
|
||||||
if (cve != null) {
|
if (cve != null) {
|
||||||
cve.close();
|
cve.close();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
final ReportGenerator report = new ReportGenerator(applicationName, dependencies, scanner.getAnalyzers(), prop);
|
final ReportGenerator report = new ReportGenerator(applicationName, dependencies, engine.getAnalyzers(), prop);
|
||||||
try {
|
try {
|
||||||
report.generateReports(reportDirectory, outputFormat);
|
report.generateReports(reportDirectory, outputFormat);
|
||||||
} catch (IOException ex) {
|
} catch (IOException ex) {
|
||||||
LOGGER.log(Level.SEVERE, "There was an IO error while attempting to generate the report.");
|
LOGGER.error("There was an IO error while attempting to generate the report.");
|
||||||
LOGGER.log(Level.FINE, null, ex);
|
LOGGER.debug("", ex);
|
||||||
} catch (Throwable ex) {
|
} catch (Throwable ex) {
|
||||||
LOGGER.log(Level.SEVERE, "There was an error while attempting to generate the report.");
|
LOGGER.error("There was an error while attempting to generate the report.");
|
||||||
LOGGER.log(Level.FINE, null, ex);
|
LOGGER.debug("", ex);
|
||||||
}
|
}
|
||||||
} catch (DatabaseException ex) {
|
} catch (DatabaseException ex) {
|
||||||
LOGGER.log(Level.SEVERE, "Unable to connect to the dependency-check database; analysis has stopped");
|
LOGGER.error("Unable to connect to the dependency-check database; analysis has stopped");
|
||||||
LOGGER.log(Level.FINE, "", ex);
|
LOGGER.debug("", ex);
|
||||||
} finally {
|
} finally {
|
||||||
if (scanner != null) {
|
if (engine != null) {
|
||||||
scanner.cleanup();
|
engine.cleanup();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Only executes the update phase of dependency-check.
|
||||||
|
*/
|
||||||
|
private void runUpdateOnly() {
|
||||||
|
Engine engine = null;
|
||||||
|
try {
|
||||||
|
engine = new Engine();
|
||||||
|
engine.doUpdates();
|
||||||
|
} catch (DatabaseException ex) {
|
||||||
|
LOGGER.error("Unable to connect to the dependency-check database; analysis has stopped");
|
||||||
|
LOGGER.debug("", ex);
|
||||||
|
} finally {
|
||||||
|
if (engine != null) {
|
||||||
|
engine.cleanup();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -154,8 +231,8 @@ public class App {
|
|||||||
/**
|
/**
|
||||||
* Updates the global Settings.
|
* Updates the global Settings.
|
||||||
*
|
*
|
||||||
* @param cli a reference to the CLI Parser that contains the command line arguments used to set the corresponding
|
* @param cli a reference to the CLI Parser that contains the command line arguments used to set the corresponding settings in
|
||||||
* settings in the core engine.
|
* the core engine.
|
||||||
*/
|
*/
|
||||||
private void populateSettings(CliParser cli) {
|
private void populateSettings(CliParser cli) {
|
||||||
|
|
||||||
@@ -170,8 +247,13 @@ public class App {
|
|||||||
final String suppressionFile = cli.getSuppressionFile();
|
final String suppressionFile = cli.getSuppressionFile();
|
||||||
final boolean jarDisabled = cli.isJarDisabled();
|
final boolean jarDisabled = cli.isJarDisabled();
|
||||||
final boolean archiveDisabled = cli.isArchiveDisabled();
|
final boolean archiveDisabled = cli.isArchiveDisabled();
|
||||||
|
final boolean pyDistDisabled = cli.isPythonDistributionDisabled();
|
||||||
|
final boolean cMakeDisabled = cli.isCmakeDisabled();
|
||||||
|
final boolean pyPkgDisabled = cli.isPythonPackageDisabled();
|
||||||
|
final boolean autoconfDisabled = cli.isAutoconfDisabled();
|
||||||
final boolean assemblyDisabled = cli.isAssemblyDisabled();
|
final boolean assemblyDisabled = cli.isAssemblyDisabled();
|
||||||
final boolean nuspecDisabled = cli.isNuspecDisabled();
|
final boolean nuspecDisabled = cli.isNuspecDisabled();
|
||||||
|
final boolean centralDisabled = cli.isCentralDisabled();
|
||||||
final boolean nexusDisabled = cli.isNexusDisabled();
|
final boolean nexusDisabled = cli.isNexusDisabled();
|
||||||
final String nexusUrl = cli.getNexusUrl();
|
final String nexusUrl = cli.getNexusUrl();
|
||||||
final String databaseDriverName = cli.getDatabaseDriverName();
|
final String databaseDriverName = cli.getDatabaseDriverName();
|
||||||
@@ -181,18 +263,20 @@ public class App {
|
|||||||
final String databasePassword = cli.getDatabasePassword();
|
final String databasePassword = cli.getDatabasePassword();
|
||||||
final String additionalZipExtensions = cli.getAdditionalZipExtensions();
|
final String additionalZipExtensions = cli.getAdditionalZipExtensions();
|
||||||
final String pathToMono = cli.getPathToMono();
|
final String pathToMono = cli.getPathToMono();
|
||||||
|
final String cveMod12 = cli.getModifiedCve12Url();
|
||||||
|
final String cveMod20 = cli.getModifiedCve20Url();
|
||||||
|
final String cveBase12 = cli.getBaseCve12Url();
|
||||||
|
final String cveBase20 = cli.getBaseCve20Url();
|
||||||
|
|
||||||
if (propertiesFile != null) {
|
if (propertiesFile != null) {
|
||||||
try {
|
try {
|
||||||
Settings.mergeProperties(propertiesFile);
|
Settings.mergeProperties(propertiesFile);
|
||||||
} catch (FileNotFoundException ex) {
|
} catch (FileNotFoundException ex) {
|
||||||
final String msg = String.format("Unable to load properties file '%s'", propertiesFile.getPath());
|
LOGGER.error("Unable to load properties file '{}'", propertiesFile.getPath());
|
||||||
LOGGER.log(Level.SEVERE, msg);
|
LOGGER.debug("", ex);
|
||||||
LOGGER.log(Level.FINE, null, ex);
|
|
||||||
} catch (IOException ex) {
|
} catch (IOException ex) {
|
||||||
final String msg = String.format("Unable to find properties file '%s'", propertiesFile.getPath());
|
LOGGER.error("Unable to find properties file '{}'", propertiesFile.getPath());
|
||||||
LOGGER.log(Level.SEVERE, msg);
|
LOGGER.debug("", ex);
|
||||||
LOGGER.log(Level.FINE, null, ex);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// We have to wait until we've merged the properties before attempting to set whether we use
|
// We have to wait until we've merged the properties before attempting to set whether we use
|
||||||
@@ -234,9 +318,15 @@ public class App {
|
|||||||
//File Type Analyzer Settings
|
//File Type Analyzer Settings
|
||||||
Settings.setBoolean(Settings.KEYS.ANALYZER_JAR_ENABLED, !jarDisabled);
|
Settings.setBoolean(Settings.KEYS.ANALYZER_JAR_ENABLED, !jarDisabled);
|
||||||
Settings.setBoolean(Settings.KEYS.ANALYZER_ARCHIVE_ENABLED, !archiveDisabled);
|
Settings.setBoolean(Settings.KEYS.ANALYZER_ARCHIVE_ENABLED, !archiveDisabled);
|
||||||
|
Settings.setBoolean(Settings.KEYS.ANALYZER_PYTHON_DISTRIBUTION_ENABLED, !pyDistDisabled);
|
||||||
|
Settings.setBoolean(Settings.KEYS.ANALYZER_PYTHON_PACKAGE_ENABLED, !pyPkgDisabled);
|
||||||
|
Settings.setBoolean(Settings.KEYS.ANALYZER_AUTOCONF_ENABLED, !autoconfDisabled);
|
||||||
|
Settings.setBoolean(Settings.KEYS.ANALYZER_CMAKE_ENABLED, !cMakeDisabled);
|
||||||
Settings.setBoolean(Settings.KEYS.ANALYZER_NUSPEC_ENABLED, !nuspecDisabled);
|
Settings.setBoolean(Settings.KEYS.ANALYZER_NUSPEC_ENABLED, !nuspecDisabled);
|
||||||
Settings.setBoolean(Settings.KEYS.ANALYZER_ASSEMBLY_ENABLED, !assemblyDisabled);
|
Settings.setBoolean(Settings.KEYS.ANALYZER_ASSEMBLY_ENABLED, !assemblyDisabled);
|
||||||
|
Settings.setBoolean(Settings.KEYS.ANALYZER_OPENSSL_ENABLED, !cli.isOpenSSLDisabled());
|
||||||
|
|
||||||
|
Settings.setBoolean(Settings.KEYS.ANALYZER_CENTRAL_ENABLED, !centralDisabled);
|
||||||
Settings.setBoolean(Settings.KEYS.ANALYZER_NEXUS_ENABLED, !nexusDisabled);
|
Settings.setBoolean(Settings.KEYS.ANALYZER_NEXUS_ENABLED, !nexusDisabled);
|
||||||
if (nexusUrl != null && !nexusUrl.isEmpty()) {
|
if (nexusUrl != null && !nexusUrl.isEmpty()) {
|
||||||
Settings.setString(Settings.KEYS.ANALYZER_NEXUS_URL, nexusUrl);
|
Settings.setString(Settings.KEYS.ANALYZER_NEXUS_URL, nexusUrl);
|
||||||
@@ -263,5 +353,99 @@ public class App {
|
|||||||
if (pathToMono != null && !pathToMono.isEmpty()) {
|
if (pathToMono != null && !pathToMono.isEmpty()) {
|
||||||
Settings.setString(Settings.KEYS.ANALYZER_ASSEMBLY_MONO_PATH, pathToMono);
|
Settings.setString(Settings.KEYS.ANALYZER_ASSEMBLY_MONO_PATH, pathToMono);
|
||||||
}
|
}
|
||||||
|
if (cveBase12 != null && !cveBase12.isEmpty()) {
|
||||||
|
Settings.setString(Settings.KEYS.CVE_SCHEMA_1_2, cveBase12);
|
||||||
|
Settings.setString(Settings.KEYS.CVE_SCHEMA_2_0, cveBase20);
|
||||||
|
Settings.setString(Settings.KEYS.CVE_MODIFIED_12_URL, cveMod12);
|
||||||
|
Settings.setString(Settings.KEYS.CVE_MODIFIED_20_URL, cveMod20);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates a file appender and adds it to logback.
|
||||||
|
*
|
||||||
|
* @param verboseLog the path to the verbose log file
|
||||||
|
*/
|
||||||
|
private void prepareLogger(String verboseLog) {
|
||||||
|
final StaticLoggerBinder loggerBinder = StaticLoggerBinder.getSingleton();
|
||||||
|
final LoggerContext context = (LoggerContext) loggerBinder.getLoggerFactory();
|
||||||
|
|
||||||
|
final PatternLayoutEncoder encoder = new PatternLayoutEncoder();
|
||||||
|
encoder.setPattern("%d %C:%L%n%-5level - %msg%n");
|
||||||
|
encoder.setContext(context);
|
||||||
|
encoder.start();
|
||||||
|
final FileAppender fa = new FileAppender();
|
||||||
|
fa.setAppend(true);
|
||||||
|
fa.setEncoder(encoder);
|
||||||
|
fa.setContext(context);
|
||||||
|
fa.setFile(verboseLog);
|
||||||
|
final File f = new File(verboseLog);
|
||||||
|
String name = f.getName();
|
||||||
|
final int i = name.lastIndexOf('.');
|
||||||
|
if (i > 1) {
|
||||||
|
name = name.substring(0, i);
|
||||||
|
}
|
||||||
|
fa.setName(name);
|
||||||
|
fa.start();
|
||||||
|
final ch.qos.logback.classic.Logger rootLogger = context.getLogger(ch.qos.logback.classic.Logger.ROOT_LOGGER_NAME);
|
||||||
|
rootLogger.addAppender(fa);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Takes a path and resolves it to be a canonical & absolute path. The caveats are that this method will take an Ant style
|
||||||
|
* file selector path (../someDir/**\/*.jar) and convert it to an absolute/canonical path (at least to the left of the first *
|
||||||
|
* or ?).
|
||||||
|
*
|
||||||
|
* @param path the path to canonicalize
|
||||||
|
* @return the canonical path
|
||||||
|
*/
|
||||||
|
protected String ensureCanonicalPath(String path) {
|
||||||
|
String basePath = null;
|
||||||
|
String wildCards = null;
|
||||||
|
final String file = path.replace('\\', '/');
|
||||||
|
if (file.contains("*") || file.contains("?")) {
|
||||||
|
|
||||||
|
int pos = getLastFileSeparator(file);
|
||||||
|
if (pos < 0) {
|
||||||
|
return file;
|
||||||
|
}
|
||||||
|
pos += 1;
|
||||||
|
basePath = file.substring(0, pos);
|
||||||
|
wildCards = file.substring(pos);
|
||||||
|
} else {
|
||||||
|
basePath = file;
|
||||||
|
}
|
||||||
|
|
||||||
|
File f = new File(basePath);
|
||||||
|
try {
|
||||||
|
f = f.getCanonicalFile();
|
||||||
|
if (wildCards != null) {
|
||||||
|
f = new File(f, wildCards);
|
||||||
|
}
|
||||||
|
} catch (IOException ex) {
|
||||||
|
LOGGER.warn("Invalid path '{}' was provided.", path);
|
||||||
|
LOGGER.debug("Invalid path provided", ex);
|
||||||
|
}
|
||||||
|
return f.getAbsolutePath().replace('\\', '/');
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the position of the last file separator.
|
||||||
|
*
|
||||||
|
* @param file a file path
|
||||||
|
* @return the position of the last file separator
|
||||||
|
*/
|
||||||
|
private int getLastFileSeparator(String file) {
|
||||||
|
if (file.contains("*") || file.contains("?")) {
|
||||||
|
int p1 = file.indexOf('*');
|
||||||
|
int p2 = file.indexOf('?');
|
||||||
|
p1 = p1 > 0 ? p1 : file.length();
|
||||||
|
p2 = p2 > 0 ? p2 : file.length();
|
||||||
|
int pos = p1 < p2 ? p1 : p2;
|
||||||
|
pos = file.lastIndexOf('/', pos);
|
||||||
|
return pos;
|
||||||
|
} else {
|
||||||
|
return file.lastIndexOf('/');
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -15,11 +15,11 @@
|
|||||||
*
|
*
|
||||||
* Copyright (c) 2012 Jeremy Long. All Rights Reserved.
|
* Copyright (c) 2012 Jeremy Long. All Rights Reserved.
|
||||||
*/
|
*/
|
||||||
package org.owasp.dependencycheck.cli;
|
package org.owasp.dependencycheck;
|
||||||
|
|
||||||
import java.io.File;
|
import java.io.File;
|
||||||
import java.io.FileNotFoundException;
|
import java.io.FileNotFoundException;
|
||||||
import java.util.logging.Logger;
|
|
||||||
import org.apache.commons.cli.CommandLine;
|
import org.apache.commons.cli.CommandLine;
|
||||||
import org.apache.commons.cli.CommandLineParser;
|
import org.apache.commons.cli.CommandLineParser;
|
||||||
import org.apache.commons.cli.HelpFormatter;
|
import org.apache.commons.cli.HelpFormatter;
|
||||||
@@ -32,18 +32,20 @@ import org.apache.commons.cli.PosixParser;
|
|||||||
import org.owasp.dependencycheck.reporting.ReportGenerator.Format;
|
import org.owasp.dependencycheck.reporting.ReportGenerator.Format;
|
||||||
import org.owasp.dependencycheck.utils.InvalidSettingException;
|
import org.owasp.dependencycheck.utils.InvalidSettingException;
|
||||||
import org.owasp.dependencycheck.utils.Settings;
|
import org.owasp.dependencycheck.utils.Settings;
|
||||||
|
import org.slf4j.Logger;
|
||||||
|
import org.slf4j.LoggerFactory;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A utility to parse command line arguments for the DependencyCheck.
|
* A utility to parse command line arguments for the DependencyCheck.
|
||||||
*
|
*
|
||||||
* @author Jeremy Long <jeremy.long@owasp.org>
|
* @author Jeremy Long
|
||||||
*/
|
*/
|
||||||
public final class CliParser {
|
public final class CliParser {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The logger.
|
* The logger.
|
||||||
*/
|
*/
|
||||||
private static final Logger LOGGER = Logger.getLogger(CliParser.class.getName());
|
private static final Logger LOGGER = LoggerFactory.getLogger(CliParser.class);
|
||||||
/**
|
/**
|
||||||
* The command line.
|
* The command line.
|
||||||
*/
|
*/
|
||||||
@@ -84,8 +86,8 @@ public final class CliParser {
|
|||||||
/**
|
/**
|
||||||
* Validates that the command line arguments are valid.
|
* Validates that the command line arguments are valid.
|
||||||
*
|
*
|
||||||
* @throws FileNotFoundException if there is a file specified by either the SCAN or CPE command line arguments that
|
* @throws FileNotFoundException if there is a file specified by either the SCAN or CPE command line arguments that does not
|
||||||
* does not exist.
|
* exist.
|
||||||
* @throws ParseException is thrown if there is an exception parsing the command line.
|
* @throws ParseException is thrown if there is an exception parsing the command line.
|
||||||
*/
|
*/
|
||||||
private void validateArgs() throws FileNotFoundException, ParseException {
|
private void validateArgs() throws FileNotFoundException, ParseException {
|
||||||
@@ -108,12 +110,27 @@ public final class CliParser {
|
|||||||
throw new ParseException(msg);
|
throw new ParseException(msg);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
if ((getBaseCve12Url() != null || getBaseCve20Url() != null || getModifiedCve12Url() != null || getModifiedCve20Url() != null)
|
||||||
|
&& (getBaseCve12Url() == null || getBaseCve20Url() == null || getModifiedCve12Url() == null || getModifiedCve20Url() == null)) {
|
||||||
|
final String msg = "If one of the CVE URLs is specified they must all be specified; please add the missing CVE URL.";
|
||||||
|
throw new ParseException(msg);
|
||||||
|
}
|
||||||
|
if (line.hasOption((ARGUMENT.SYM_LINK_DEPTH))) {
|
||||||
|
try {
|
||||||
|
final int i = Integer.parseInt(line.getOptionValue(ARGUMENT.SYM_LINK_DEPTH));
|
||||||
|
if (i < 0) {
|
||||||
|
throw new ParseException("Symbolic Link Depth (symLink) must be greater than zero.");
|
||||||
|
}
|
||||||
|
} catch (NumberFormatException ex) {
|
||||||
|
throw new ParseException("Symbolic Link Depth (symLink) is not a number.");
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Validates whether or not the path(s) points at a file that exists; if the path(s) does not point to an existing
|
* Validates whether or not the path(s) points at a file that exists; if the path(s) does not point to an existing file a
|
||||||
* file a FileNotFoundException is thrown.
|
* FileNotFoundException is thrown.
|
||||||
*
|
*
|
||||||
* @param paths the paths to validate if they exists
|
* @param paths the paths to validate if they exists
|
||||||
* @param optType the option being validated (e.g. scan, out, etc.)
|
* @param optType the option being validated (e.g. scan, out, etc.)
|
||||||
@@ -134,14 +151,36 @@ public final class CliParser {
|
|||||||
* @throws FileNotFoundException is thrown if the path being validated does not exist.
|
* @throws FileNotFoundException is thrown if the path being validated does not exist.
|
||||||
*/
|
*/
|
||||||
private void validatePathExists(String path, String argumentName) throws FileNotFoundException {
|
private void validatePathExists(String path, String argumentName) throws FileNotFoundException {
|
||||||
if (!path.contains("*.")) {
|
if (path == null) {
|
||||||
final File f = new File(path);
|
isValid = false;
|
||||||
if (!f.exists()) {
|
final String msg = String.format("Invalid '%s' argument: null", argumentName);
|
||||||
isValid = false;
|
throw new FileNotFoundException(msg);
|
||||||
final String msg = String.format("Invalid '%s' argument: '%s'", argumentName, path);
|
} else if (!path.contains("*") && !path.contains("?")) {
|
||||||
throw new FileNotFoundException(msg);
|
File f = new File(path);
|
||||||
|
if ("o".equalsIgnoreCase(argumentName.substring(0, 1)) && !"ALL".equalsIgnoreCase(this.getReportFormat())) {
|
||||||
|
final String checkPath = path.toLowerCase();
|
||||||
|
if (checkPath.endsWith(".html") || checkPath.endsWith(".xml") || checkPath.endsWith(".htm")) {
|
||||||
|
if (f.getParentFile() == null) {
|
||||||
|
f = new File(".", path);
|
||||||
|
}
|
||||||
|
if (!f.getParentFile().isDirectory()) {
|
||||||
|
isValid = false;
|
||||||
|
final String msg = String.format("Invalid '%s' argument: '%s'", argumentName, path);
|
||||||
|
throw new FileNotFoundException(msg);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if (!f.exists()) {
|
||||||
|
isValid = false;
|
||||||
|
final String msg = String.format("Invalid '%s' argument: '%s'", argumentName, path);
|
||||||
|
throw new FileNotFoundException(msg);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
} // else { // 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);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -151,7 +190,6 @@ public final class CliParser {
|
|||||||
*/
|
*/
|
||||||
@SuppressWarnings("static-access")
|
@SuppressWarnings("static-access")
|
||||||
private Options createCommandLineOptions() {
|
private Options createCommandLineOptions() {
|
||||||
|
|
||||||
final Options options = new Options();
|
final Options options = new Options();
|
||||||
addStandardOptions(options);
|
addStandardOptions(options);
|
||||||
addAdvancedOptions(options);
|
addAdvancedOptions(options);
|
||||||
@@ -184,16 +222,22 @@ public final class CliParser {
|
|||||||
.create(ARGUMENT.APP_NAME_SHORT);
|
.create(ARGUMENT.APP_NAME_SHORT);
|
||||||
|
|
||||||
final Option path = OptionBuilder.withArgName("path").hasArg().withLongOpt(ARGUMENT.SCAN)
|
final Option path = OptionBuilder.withArgName("path").hasArg().withLongOpt(ARGUMENT.SCAN)
|
||||||
.withDescription("The path to scan - this option can be specified multiple times. To limit the scan"
|
.withDescription("The path to scan - this option can be specified multiple times. Ant style"
|
||||||
+ " to specific file types *.[ext] can be added to the end of the path.")
|
+ " paths are supported (e.g. path/**/*.jar).")
|
||||||
.create(ARGUMENT.SCAN_SHORT);
|
.create(ARGUMENT.SCAN_SHORT);
|
||||||
|
|
||||||
|
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)
|
final Option props = OptionBuilder.withArgName("file").hasArg().withLongOpt(ARGUMENT.PROP)
|
||||||
.withDescription("A property file to load.")
|
.withDescription("A property file to load.")
|
||||||
.create(ARGUMENT.PROP_SHORT);
|
.create(ARGUMENT.PROP_SHORT);
|
||||||
|
|
||||||
final Option out = OptionBuilder.withArgName("folder").hasArg().withLongOpt(ARGUMENT.OUT)
|
final Option out = OptionBuilder.withArgName("path").hasArg().withLongOpt(ARGUMENT.OUT)
|
||||||
.withDescription("The folder to write reports to. This defaults to the current directory.")
|
.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);
|
.create(ARGUMENT.OUT_SHORT);
|
||||||
|
|
||||||
final Option outputFormat = OptionBuilder.withArgName("format").hasArg().withLongOpt(ARGUMENT.OUTPUT_FORMAT)
|
final Option outputFormat = OptionBuilder.withArgName("format").hasArg().withLongOpt(ARGUMENT.OUTPUT_FORMAT)
|
||||||
@@ -204,6 +248,10 @@ public final class CliParser {
|
|||||||
.withDescription("The file path to write verbose logging information.")
|
.withDescription("The file path to write verbose logging information.")
|
||||||
.create(ARGUMENT.VERBOSE_LOG_SHORT);
|
.create(ARGUMENT.VERBOSE_LOG_SHORT);
|
||||||
|
|
||||||
|
final Option symLinkDepth = OptionBuilder.withArgName("depth").hasArg().withLongOpt(ARGUMENT.SYM_LINK_DEPTH)
|
||||||
|
.withDescription("Sets how deep nested symbolic links will be followed; 0 indicates symbolic links will not be followed.")
|
||||||
|
.create();
|
||||||
|
|
||||||
final Option suppressionFile = OptionBuilder.withArgName("file").hasArg().withLongOpt(ARGUMENT.SUPPRESSION_FILE)
|
final Option suppressionFile = OptionBuilder.withArgName("file").hasArg().withLongOpt(ARGUMENT.SUPPRESSION_FILE)
|
||||||
.withDescription("The file path to the suppression XML file.")
|
.withDescription("The file path to the suppression XML file.")
|
||||||
.create();
|
.create();
|
||||||
@@ -212,7 +260,11 @@ public final class CliParser {
|
|||||||
final OptionGroup og = new OptionGroup();
|
final OptionGroup og = new OptionGroup();
|
||||||
og.addOption(path);
|
og.addOption(path);
|
||||||
|
|
||||||
|
final OptionGroup exog = new OptionGroup();
|
||||||
|
exog.addOption(excludes);
|
||||||
|
|
||||||
options.addOptionGroup(og)
|
options.addOptionGroup(og)
|
||||||
|
.addOptionGroup(exog)
|
||||||
.addOption(out)
|
.addOption(out)
|
||||||
.addOption(outputFormat)
|
.addOption(outputFormat)
|
||||||
.addOption(appName)
|
.addOption(appName)
|
||||||
@@ -220,14 +272,15 @@ public final class CliParser {
|
|||||||
.addOption(help)
|
.addOption(help)
|
||||||
.addOption(advancedHelp)
|
.addOption(advancedHelp)
|
||||||
.addOption(noUpdate)
|
.addOption(noUpdate)
|
||||||
|
.addOption(symLinkDepth)
|
||||||
.addOption(props)
|
.addOption(props)
|
||||||
.addOption(verboseLog)
|
.addOption(verboseLog)
|
||||||
.addOption(suppressionFile);
|
.addOption(suppressionFile);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Adds the advanced command line options to the given options collection. These are split out for purposes of being
|
* Adds the advanced command line options to the given options collection. These are split out for purposes of being able to
|
||||||
* able to display two different help messages.
|
* display two different help messages.
|
||||||
*
|
*
|
||||||
* @param options a collection of command line arguments
|
* @param options a collection of command line arguments
|
||||||
* @throws IllegalArgumentException thrown if there is an exception
|
* @throws IllegalArgumentException thrown if there is an exception
|
||||||
@@ -235,70 +288,32 @@ public final class CliParser {
|
|||||||
@SuppressWarnings("static-access")
|
@SuppressWarnings("static-access")
|
||||||
private void addAdvancedOptions(final Options options) throws IllegalArgumentException {
|
private void addAdvancedOptions(final Options options) throws IllegalArgumentException {
|
||||||
|
|
||||||
|
final Option cve12Base = OptionBuilder.withArgName("url").hasArg().withLongOpt(ARGUMENT.CVE_BASE_12)
|
||||||
|
.withDescription("Base URL for each year’s CVE 1.2, the %d will be replaced with the year. ")
|
||||||
|
.create();
|
||||||
|
|
||||||
|
final Option cve20Base = OptionBuilder.withArgName("url").hasArg().withLongOpt(ARGUMENT.CVE_BASE_20)
|
||||||
|
.withDescription("Base URL for each year’s CVE 2.0, the %d will be replaced with the year.")
|
||||||
|
.create();
|
||||||
|
|
||||||
|
final Option cve12Modified = OptionBuilder.withArgName("url").hasArg().withLongOpt(ARGUMENT.CVE_MOD_12)
|
||||||
|
.withDescription("URL for the modified CVE 1.2.")
|
||||||
|
.create();
|
||||||
|
|
||||||
|
final Option cve20Modified = OptionBuilder.withArgName("url").hasArg().withLongOpt(ARGUMENT.CVE_MOD_20)
|
||||||
|
.withDescription("URL for the modified CVE 2.0.")
|
||||||
|
.create();
|
||||||
|
|
||||||
|
final Option updateOnly = OptionBuilder.withLongOpt(ARGUMENT.UPDATE_ONLY)
|
||||||
|
.withDescription("Only update the local NVD data cache; no scan will be executed.").create();
|
||||||
|
|
||||||
final Option data = OptionBuilder.withArgName("path").hasArg().withLongOpt(ARGUMENT.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.")
|
.withDescription("The location of the H2 Database file. This option should generally not be set.")
|
||||||
.create(ARGUMENT.DATA_DIRECTORY_SHORT);
|
.create(ARGUMENT.DATA_DIRECTORY_SHORT);
|
||||||
|
|
||||||
final Option connectionTimeout = OptionBuilder.withArgName("timeout").hasArg().withLongOpt(ARGUMENT.CONNECTION_TIMEOUT)
|
|
||||||
.withDescription("The connection timeout (in milliseconds) to use when downloading resources.")
|
|
||||||
.create(ARGUMENT.CONNECTION_TIMEOUT_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(ARGUMENT.PROXY_PORT)
|
|
||||||
.withDescription("The proxy port to use when downloading resources.")
|
|
||||||
.create();
|
|
||||||
|
|
||||||
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(ARGUMENT.PROXY_PASSWORD)
|
|
||||||
.withDescription("The proxy password to use when downloading resources.")
|
|
||||||
.create();
|
|
||||||
|
|
||||||
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(ARGUMENT.DB_NAME)
|
|
||||||
.withDescription("The username used to connect to the database.")
|
|
||||||
.create();
|
|
||||||
|
|
||||||
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(ARGUMENT.DB_DRIVER)
|
|
||||||
.withDescription("The database driver name.")
|
|
||||||
.create();
|
|
||||||
|
|
||||||
final Option dbDriverPath = OptionBuilder.withArgName("path").hasArg().withLongOpt(ARGUMENT.DB_DRIVER_PATH)
|
|
||||||
.withDescription("The path to the database driver; note, this does not need to be set unless the JAR is outside of the classpath.")
|
|
||||||
.create();
|
|
||||||
|
|
||||||
final Option disableJarAnalyzer = OptionBuilder.withLongOpt(ARGUMENT.DISABLE_JAR)
|
|
||||||
.withDescription("Disable the Jar Analyzer.")
|
|
||||||
.create();
|
|
||||||
final Option disableArchiveAnalyzer = OptionBuilder.withLongOpt(ARGUMENT.DISABLE_ARCHIVE)
|
|
||||||
.withDescription("Disable the Archive Analyzer.")
|
|
||||||
.create();
|
|
||||||
final Option disableNuspecAnalyzer = OptionBuilder.withLongOpt(ARGUMENT.DISABLE_NUSPEC)
|
|
||||||
.withDescription("Disable the Nuspec Analyzer.")
|
|
||||||
.create();
|
|
||||||
final Option disableAssemblyAnalyzer = OptionBuilder.withLongOpt(ARGUMENT.DISABLE_ASSEMBLY)
|
|
||||||
.withDescription("Disable the .NET Assembly Analyzer.")
|
|
||||||
.create();
|
|
||||||
|
|
||||||
final Option disableNexusAnalyzer = OptionBuilder.withLongOpt(ARGUMENT.DISABLE_NEXUS)
|
|
||||||
.withDescription("Disable the Nexus Analyzer.")
|
|
||||||
.create();
|
|
||||||
|
|
||||||
final Option nexusUrl = OptionBuilder.withArgName("url").hasArg().withLongOpt(ARGUMENT.NEXUS_URL)
|
final Option nexusUrl = OptionBuilder.withArgName("url").hasArg().withLongOpt(ARGUMENT.NEXUS_URL)
|
||||||
.withDescription("The url to the Nexus Server.")
|
.withDescription("The url to the Nexus Server's REST API Endpoint (http://domain/nexus/service/local). "
|
||||||
.create();
|
+ "If not set the Nexus Analyzer will be disabled.").create();
|
||||||
|
|
||||||
final Option nexusUsesProxy = OptionBuilder.withArgName("true/false").hasArg().withLongOpt(ARGUMENT.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.")
|
.withDescription("Whether or not the configured proxy should be used when connecting to Nexus.")
|
||||||
@@ -307,14 +322,84 @@ public final class CliParser {
|
|||||||
final Option additionalZipExtensions = OptionBuilder.withArgName("extensions").hasArg()
|
final Option additionalZipExtensions = OptionBuilder.withArgName("extensions").hasArg()
|
||||||
.withLongOpt(ARGUMENT.ADDITIONAL_ZIP_EXTENSIONS)
|
.withLongOpt(ARGUMENT.ADDITIONAL_ZIP_EXTENSIONS)
|
||||||
.withDescription("A comma separated list of additional extensions to be scanned as ZIP files "
|
.withDescription("A comma separated list of additional extensions to be scanned as ZIP files "
|
||||||
+ "(ZIP, EAR, WAR are already treated as zip files)")
|
+ "(ZIP, EAR, WAR are already treated as zip files)").create();
|
||||||
.create();
|
|
||||||
|
|
||||||
final Option pathToMono = OptionBuilder.withArgName("path").hasArg().withLongOpt(ARGUMENT.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.")
|
.withDescription("The path to Mono for .NET Assembly analysis on non-windows systems.")
|
||||||
.create();
|
.create();
|
||||||
|
|
||||||
options.addOption(proxyPort)
|
final Option connectionTimeout = OptionBuilder.withArgName("timeout").hasArg().withLongOpt(ARGUMENT.CONNECTION_TIMEOUT)
|
||||||
|
.withDescription("The connection timeout (in milliseconds) to use when downloading resources.")
|
||||||
|
.create(ARGUMENT.CONNECTION_TIMEOUT_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(ARGUMENT.PROXY_PORT)
|
||||||
|
.withDescription("The proxy port to use when downloading resources.").create();
|
||||||
|
|
||||||
|
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(ARGUMENT.PROXY_PASSWORD)
|
||||||
|
.withDescription("The proxy password to use when downloading resources.").create();
|
||||||
|
|
||||||
|
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(ARGUMENT.DB_NAME)
|
||||||
|
.withDescription("The username used to connect to the database.").create();
|
||||||
|
|
||||||
|
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(ARGUMENT.DB_DRIVER)
|
||||||
|
.withDescription("The database driver name.").create();
|
||||||
|
|
||||||
|
final Option dbDriverPath = OptionBuilder.withArgName("path").hasArg().withLongOpt(ARGUMENT.DB_DRIVER_PATH)
|
||||||
|
.withDescription("The path to the database driver; note, this does not need to be set unless the JAR is outside of the classpath.")
|
||||||
|
.create();
|
||||||
|
|
||||||
|
final Option disableJarAnalyzer = OptionBuilder.withLongOpt(ARGUMENT.DISABLE_JAR)
|
||||||
|
.withDescription("Disable the Jar Analyzer.").create();
|
||||||
|
|
||||||
|
final Option disableArchiveAnalyzer = OptionBuilder.withLongOpt(ARGUMENT.DISABLE_ARCHIVE)
|
||||||
|
.withDescription("Disable the Archive Analyzer.").create();
|
||||||
|
|
||||||
|
final Option disableNuspecAnalyzer = OptionBuilder.withLongOpt(ARGUMENT.DISABLE_NUSPEC)
|
||||||
|
.withDescription("Disable the Nuspec Analyzer.").create();
|
||||||
|
|
||||||
|
final Option disableAssemblyAnalyzer = OptionBuilder.withLongOpt(ARGUMENT.DISABLE_ASSEMBLY)
|
||||||
|
.withDescription("Disable the .NET Assembly Analyzer.").create();
|
||||||
|
|
||||||
|
final Option disablePythonDistributionAnalyzer = OptionBuilder.withLongOpt(ARGUMENT.DISABLE_PY_DIST)
|
||||||
|
.withDescription("Disable the Python Distribution Analyzer.").create();
|
||||||
|
|
||||||
|
final Option disablePythonPackageAnalyzer = OptionBuilder.withLongOpt(ARGUMENT.DISABLE_PY_PKG)
|
||||||
|
.withDescription("Disable the Python Package Analyzer.").create();
|
||||||
|
|
||||||
|
final Option disableAutoconfAnalyzer = OptionBuilder
|
||||||
|
.withLongOpt(ARGUMENT.DISABLE_AUTOCONF)
|
||||||
|
.withDescription("Disable the Autoconf Analyzer.").create();
|
||||||
|
|
||||||
|
final Option disableOpenSSLAnalyzer = OptionBuilder.withLongOpt(ARGUMENT.DISABLE_OPENSSL)
|
||||||
|
.withDescription("Disable the OpenSSL Analyzer.").create();
|
||||||
|
final Option disableCmakeAnalyzer = OptionBuilder.withLongOpt(ARGUMENT.DISABLE_CMAKE).
|
||||||
|
withDescription("Disable the Cmake Analyzer.").create();
|
||||||
|
|
||||||
|
final Option disableCentralAnalyzer = OptionBuilder.withLongOpt(ARGUMENT.DISABLE_CENTRAL)
|
||||||
|
.withDescription("Disable the Central Analyzer. If this analyzer is disabled it is likely you also want to disable "
|
||||||
|
+ "the Nexus Analyzer.").create();
|
||||||
|
|
||||||
|
final Option disableNexusAnalyzer = OptionBuilder.withLongOpt(ARGUMENT.DISABLE_NEXUS)
|
||||||
|
.withDescription("Disable the Nexus Analyzer.").create();
|
||||||
|
|
||||||
|
options.addOption(updateOnly)
|
||||||
|
.addOption(cve12Base)
|
||||||
|
.addOption(cve20Base)
|
||||||
|
.addOption(cve12Modified)
|
||||||
|
.addOption(cve20Modified)
|
||||||
|
.addOption(proxyPort)
|
||||||
.addOption(proxyServer)
|
.addOption(proxyServer)
|
||||||
.addOption(proxyUsername)
|
.addOption(proxyUsername)
|
||||||
.addOption(proxyPassword)
|
.addOption(proxyPassword)
|
||||||
@@ -328,7 +413,13 @@ public final class CliParser {
|
|||||||
.addOption(disableJarAnalyzer)
|
.addOption(disableJarAnalyzer)
|
||||||
.addOption(disableArchiveAnalyzer)
|
.addOption(disableArchiveAnalyzer)
|
||||||
.addOption(disableAssemblyAnalyzer)
|
.addOption(disableAssemblyAnalyzer)
|
||||||
|
.addOption(disablePythonDistributionAnalyzer)
|
||||||
|
.addOption(disableCmakeAnalyzer)
|
||||||
|
.addOption(disablePythonPackageAnalyzer)
|
||||||
|
.addOption(disableAutoconfAnalyzer)
|
||||||
|
.addOption(disableOpenSSLAnalyzer)
|
||||||
.addOption(disableNuspecAnalyzer)
|
.addOption(disableNuspecAnalyzer)
|
||||||
|
.addOption(disableCentralAnalyzer)
|
||||||
.addOption(disableNexusAnalyzer)
|
.addOption(disableNexusAnalyzer)
|
||||||
.addOption(nexusUrl)
|
.addOption(nexusUrl)
|
||||||
.addOption(nexusUsesProxy)
|
.addOption(nexusUsesProxy)
|
||||||
@@ -337,13 +428,13 @@ public final class CliParser {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Adds the deprecated command line options to the given options collection. These are split out for purposes of not
|
* Adds the deprecated command line options to the given options collection. These are split out for purposes of not including
|
||||||
* including them in the help message. We need to add the deprecated options so as not to break existing scripts.
|
* 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
|
* @param options a collection of command line arguments
|
||||||
* @throws IllegalArgumentException thrown if there is an exception
|
* @throws IllegalArgumentException thrown if there is an exception
|
||||||
*/
|
*/
|
||||||
@SuppressWarnings("static-access")
|
@SuppressWarnings({"static-access", "deprecation"})
|
||||||
private void addDeprecatedOptions(final Options options) throws IllegalArgumentException {
|
private void addDeprecatedOptions(final Options options) throws IllegalArgumentException {
|
||||||
|
|
||||||
final Option proxyServer = OptionBuilder.withArgName("url").hasArg().withLongOpt(ARGUMENT.PROXY_URL)
|
final Option proxyServer = OptionBuilder.withArgName("url").hasArg().withLongOpt(ARGUMENT.PROXY_URL)
|
||||||
@@ -380,6 +471,24 @@ public final class CliParser {
|
|||||||
return (line != null) && isValid && line.hasOption(ARGUMENT.SCAN);
|
return (line != null) && isValid && line.hasOption(ARGUMENT.SCAN);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the symbolic link depth (how deeply symbolic links will be followed).
|
||||||
|
*
|
||||||
|
* @return the symbolic link depth
|
||||||
|
*/
|
||||||
|
public int getSymLinkDepth() {
|
||||||
|
int value = 0;
|
||||||
|
try {
|
||||||
|
value = Integer.parseInt(line.getOptionValue(ARGUMENT.SYM_LINK_DEPTH, "0"));
|
||||||
|
if (value < 0) {
|
||||||
|
value = 0;
|
||||||
|
}
|
||||||
|
} catch (NumberFormatException ex) {
|
||||||
|
LOGGER.debug("Symbolic link was not a number");
|
||||||
|
}
|
||||||
|
return value;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns true if the disableJar command line argument was specified.
|
* Returns true if the disableJar command line argument was specified.
|
||||||
*
|
*
|
||||||
@@ -416,6 +525,42 @@ public final class CliParser {
|
|||||||
return (line != null) && line.hasOption(ARGUMENT.DISABLE_ASSEMBLY);
|
return (line != null) && line.hasOption(ARGUMENT.DISABLE_ASSEMBLY);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns true if the disablePyDist command line argument was specified.
|
||||||
|
*
|
||||||
|
* @return true if the disablePyDist command line argument was specified; otherwise false
|
||||||
|
*/
|
||||||
|
public boolean isPythonDistributionDisabled() {
|
||||||
|
return (line != null) && line.hasOption(ARGUMENT.DISABLE_PY_DIST);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns true if the disablePyPkg command line argument was specified.
|
||||||
|
*
|
||||||
|
* @return true if the disablePyPkg command line argument was specified; otherwise false
|
||||||
|
*/
|
||||||
|
public boolean isPythonPackageDisabled() {
|
||||||
|
return (line != null) && line.hasOption(ARGUMENT.DISABLE_PY_PKG);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns true if the disableCmake command line argument was specified.
|
||||||
|
*
|
||||||
|
* @return true if the disableCmake command line argument was specified; otherwise false
|
||||||
|
*/
|
||||||
|
public boolean isCmakeDisabled() {
|
||||||
|
return (line != null) && line.hasOption(ARGUMENT.DISABLE_CMAKE);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns true if the disableAutoconf command line argument was specified.
|
||||||
|
*
|
||||||
|
* @return true if the disableAutoconf command line argument was specified; otherwise false
|
||||||
|
*/
|
||||||
|
public boolean isAutoconfDisabled() {
|
||||||
|
return (line != null) && line.hasOption(ARGUMENT.DISABLE_AUTOCONF);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns true if the disableNexus command line argument was specified.
|
* Returns true if the disableNexus command line argument was specified.
|
||||||
*
|
*
|
||||||
@@ -425,6 +570,24 @@ public final class CliParser {
|
|||||||
return (line != null) && line.hasOption(ARGUMENT.DISABLE_NEXUS);
|
return (line != null) && line.hasOption(ARGUMENT.DISABLE_NEXUS);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns true if the disableOpenSSL command line argument was specified.
|
||||||
|
*
|
||||||
|
* @return true if the disableOpenSSL command line argument was specified; otherwise false
|
||||||
|
*/
|
||||||
|
public boolean isOpenSSLDisabled() {
|
||||||
|
return (line != null) && line.hasOption(ARGUMENT.DISABLE_OPENSSL);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns true if the disableCentral command line argument was specified.
|
||||||
|
*
|
||||||
|
* @return true if the disableCentral command line argument was specified; otherwise false
|
||||||
|
*/
|
||||||
|
public boolean isCentralDisabled() {
|
||||||
|
return (line != null) && line.hasOption(ARGUMENT.DISABLE_CENTRAL);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns the url to the nexus server if one was specified.
|
* Returns the url to the nexus server if one was specified.
|
||||||
*
|
*
|
||||||
@@ -439,8 +602,7 @@ public final class CliParser {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns true if the Nexus Analyzer should use the configured proxy to connect to Nexus; otherwise false is
|
* Returns true if the Nexus Analyzer should use the configured proxy to connect to Nexus; otherwise false is returned.
|
||||||
* returned.
|
|
||||||
*
|
*
|
||||||
* @return true if the Nexus Analyzer should use the configured proxy to connect to Nexus; otherwise false
|
* @return true if the Nexus Analyzer should use the configured proxy to connect to Nexus; otherwise false
|
||||||
*/
|
*/
|
||||||
@@ -479,7 +641,6 @@ public final class CliParser {
|
|||||||
options,
|
options,
|
||||||
"",
|
"",
|
||||||
true);
|
true);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -491,6 +652,15 @@ public final class CliParser {
|
|||||||
return line.getOptionValues(ARGUMENT.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);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns the directory to write the reports to specified on the command line.
|
* Returns the directory to write the reports to specified on the command line.
|
||||||
*
|
*
|
||||||
@@ -527,6 +697,42 @@ public final class CliParser {
|
|||||||
return line.getOptionValue(ARGUMENT.APP_NAME);
|
return line.getOptionValue(ARGUMENT.APP_NAME);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the base URL for the CVE 1.2 XMl file.
|
||||||
|
*
|
||||||
|
* @return the URL to the CVE 1.2 XML file.
|
||||||
|
*/
|
||||||
|
public String getBaseCve12Url() {
|
||||||
|
return line.getOptionValue(ARGUMENT.CVE_BASE_12);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the base URL for the CVE 2.0 XMl file.
|
||||||
|
*
|
||||||
|
* @return the URL to the CVE 2.0 XML file.
|
||||||
|
*/
|
||||||
|
public String getBaseCve20Url() {
|
||||||
|
return line.getOptionValue(ARGUMENT.CVE_BASE_20);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the URL for the modified CVE 1.2 XMl file.
|
||||||
|
*
|
||||||
|
* @return the URL to the modified CVE 1.2 XML file.
|
||||||
|
*/
|
||||||
|
public String getModifiedCve12Url() {
|
||||||
|
return line.getOptionValue(ARGUMENT.CVE_MOD_12);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the URL for the modified CVE 2.0 XMl file.
|
||||||
|
*
|
||||||
|
* @return the URL to the modified CVE 2.0 XML file.
|
||||||
|
*/
|
||||||
|
public String getModifiedCve20Url() {
|
||||||
|
return line.getOptionValue(ARGUMENT.CVE_MOD_20);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns the connection timeout.
|
* Returns the connection timeout.
|
||||||
*
|
*
|
||||||
@@ -541,13 +747,14 @@ public final class CliParser {
|
|||||||
*
|
*
|
||||||
* @return the proxy server
|
* @return the proxy server
|
||||||
*/
|
*/
|
||||||
|
@SuppressWarnings("deprecation")
|
||||||
public String getProxyServer() {
|
public String getProxyServer() {
|
||||||
|
|
||||||
String server = line.getOptionValue(ARGUMENT.PROXY_SERVER);
|
String server = line.getOptionValue(ARGUMENT.PROXY_SERVER);
|
||||||
if (server == null) {
|
if (server == null) {
|
||||||
server = line.getOptionValue(ARGUMENT.PROXY_URL);
|
server = line.getOptionValue(ARGUMENT.PROXY_URL);
|
||||||
if (server != null) {
|
if (server != null) {
|
||||||
LOGGER.warning("An old command line argument 'proxyurl' was detected; use proxyserver instead");
|
LOGGER.warn("An old command line argument 'proxyurl' was detected; use proxyserver instead");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return server;
|
return server;
|
||||||
@@ -628,21 +835,29 @@ public final class CliParser {
|
|||||||
*/
|
*/
|
||||||
public void printVersionInfo() {
|
public void printVersionInfo() {
|
||||||
final String version = String.format("%s version %s",
|
final String version = String.format("%s version %s",
|
||||||
Settings.getString("application.name", "DependencyCheck"),
|
Settings.getString(Settings.KEYS.APPLICATION_VAME, "dependency-check"),
|
||||||
Settings.getString("application.version", "Unknown"));
|
Settings.getString(Settings.KEYS.APPLICATION_VERSION, "Unknown"));
|
||||||
System.out.println(version);
|
System.out.println(version);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Checks if the auto update feature has been disabled. If it has been disabled via the command line this will
|
* Checks if the auto update feature has been disabled. If it has been disabled via the command line this will return false.
|
||||||
* return false.
|
|
||||||
*
|
*
|
||||||
* @return if auto-update is allowed.
|
* @return <code>true</code> if auto-update is allowed; otherwise <code>false</code>
|
||||||
*/
|
*/
|
||||||
public boolean isAutoUpdate() {
|
public boolean isAutoUpdate() {
|
||||||
return (line == null) || !line.hasOption(ARGUMENT.DISABLE_AUTO_UPDATE);
|
return (line == null) || !line.hasOption(ARGUMENT.DISABLE_AUTO_UPDATE);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Checks if the update only flag has been set.
|
||||||
|
*
|
||||||
|
* @return <code>true</code> if the update only flag has been set; otherwise <code>false</code>.
|
||||||
|
*/
|
||||||
|
public boolean isUpdateOnly() {
|
||||||
|
return (line == null) || line.hasOption(ARGUMENT.UPDATE_ONLY);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns the database driver name if specified; otherwise null is returned.
|
* Returns the database driver name if specified; otherwise null is returned.
|
||||||
*
|
*
|
||||||
@@ -718,6 +933,10 @@ public final class CliParser {
|
|||||||
* The short CLI argument name specifying that the CPE/CVE/etc. data should not be automatically updated.
|
* The short CLI argument name specifying that the CPE/CVE/etc. data should not be automatically updated.
|
||||||
*/
|
*/
|
||||||
public static final String DISABLE_AUTO_UPDATE_SHORT = "n";
|
public static final String DISABLE_AUTO_UPDATE_SHORT = "n";
|
||||||
|
/**
|
||||||
|
* The long CLI argument name specifying that only the update phase should be executed; no scan should be run.
|
||||||
|
*/
|
||||||
|
public static final String UPDATE_ONLY = "updateonly";
|
||||||
/**
|
/**
|
||||||
* The long CLI argument name specifying the directory to write the reports to.
|
* The long CLI argument name specifying the directory to write the reports to.
|
||||||
*/
|
*/
|
||||||
@@ -773,7 +992,7 @@ public final class CliParser {
|
|||||||
/**
|
/**
|
||||||
* The CLI argument name indicating the proxy url.
|
* The CLI argument name indicating the proxy url.
|
||||||
*
|
*
|
||||||
* @deprecated use {@link org.owasp.dependencycheck.cli.CliParser.ArgumentName#PROXY_SERVER} instead
|
* @deprecated use {@link #PROXY_SERVER} instead
|
||||||
*/
|
*/
|
||||||
@Deprecated
|
@Deprecated
|
||||||
public static final String PROXY_URL = "proxyurl";
|
public static final String PROXY_URL = "proxyurl";
|
||||||
@@ -805,6 +1024,22 @@ public final class CliParser {
|
|||||||
* The CLI argument name for setting the location of the data directory.
|
* The CLI argument name for setting the location of the data directory.
|
||||||
*/
|
*/
|
||||||
public static final String DATA_DIRECTORY = "data";
|
public static final String DATA_DIRECTORY = "data";
|
||||||
|
/**
|
||||||
|
* The CLI argument name for setting the URL for the CVE Data Files.
|
||||||
|
*/
|
||||||
|
public static final String CVE_MOD_12 = "cveUrl12Modified";
|
||||||
|
/**
|
||||||
|
* The CLI argument name for setting the URL for the CVE Data Files.
|
||||||
|
*/
|
||||||
|
public static final String CVE_MOD_20 = "cveUrl20Modified";
|
||||||
|
/**
|
||||||
|
* The CLI argument name for setting the URL for the CVE Data Files.
|
||||||
|
*/
|
||||||
|
public static final String CVE_BASE_12 = "cveUrl12Base";
|
||||||
|
/**
|
||||||
|
* The CLI argument name for setting the URL for the CVE Data Files.
|
||||||
|
*/
|
||||||
|
public static final String CVE_BASE_20 = "cveUrl20Base";
|
||||||
/**
|
/**
|
||||||
* The short CLI argument name for setting the location of the data directory.
|
* The short CLI argument name for setting the location of the data directory.
|
||||||
*/
|
*/
|
||||||
@@ -817,6 +1052,11 @@ public final class CliParser {
|
|||||||
* The short CLI argument name for setting the location of the data directory.
|
* The short CLI argument name for setting the location of the data directory.
|
||||||
*/
|
*/
|
||||||
public static final String VERBOSE_LOG_SHORT = "l";
|
public static final String VERBOSE_LOG_SHORT = "l";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The CLI argument name for setting the depth of symbolic links that will be followed.
|
||||||
|
*/
|
||||||
|
public static final String SYM_LINK_DEPTH = "symLink";
|
||||||
/**
|
/**
|
||||||
* The CLI argument name for setting the location of the suppression file.
|
* The CLI argument name for setting the location of the suppression file.
|
||||||
*/
|
*/
|
||||||
@@ -829,6 +1069,22 @@ public final class CliParser {
|
|||||||
* Disables the Archive Analyzer.
|
* Disables the Archive Analyzer.
|
||||||
*/
|
*/
|
||||||
public static final String DISABLE_ARCHIVE = "disableArchive";
|
public static final String DISABLE_ARCHIVE = "disableArchive";
|
||||||
|
/**
|
||||||
|
* Disables the Python Distribution Analyzer.
|
||||||
|
*/
|
||||||
|
public static final String DISABLE_PY_DIST = "disablePyDist";
|
||||||
|
/**
|
||||||
|
* Disables the Python Package Analyzer.
|
||||||
|
*/
|
||||||
|
public static final String DISABLE_PY_PKG = "disablePyPkg";
|
||||||
|
/**
|
||||||
|
* Disables the Autoconf Analyzer.
|
||||||
|
*/
|
||||||
|
public static final String DISABLE_AUTOCONF = "disableAutoconf";
|
||||||
|
/**
|
||||||
|
* Disables the Cmake Analyzer.
|
||||||
|
*/
|
||||||
|
public static final String DISABLE_CMAKE = "disableCmake";
|
||||||
/**
|
/**
|
||||||
* Disables the Assembly Analyzer.
|
* Disables the Assembly Analyzer.
|
||||||
*/
|
*/
|
||||||
@@ -837,10 +1093,18 @@ public final class CliParser {
|
|||||||
* Disables the Nuspec Analyzer.
|
* Disables the Nuspec Analyzer.
|
||||||
*/
|
*/
|
||||||
public static final String DISABLE_NUSPEC = "disableNuspec";
|
public static final String DISABLE_NUSPEC = "disableNuspec";
|
||||||
|
/**
|
||||||
|
* Disables the Central Analyzer.
|
||||||
|
*/
|
||||||
|
public static final String DISABLE_CENTRAL = "disableCentral";
|
||||||
/**
|
/**
|
||||||
* Disables the Nexus Analyzer.
|
* Disables the Nexus Analyzer.
|
||||||
*/
|
*/
|
||||||
public static final String DISABLE_NEXUS = "disableNexus";
|
public static final String DISABLE_NEXUS = "disableNexus";
|
||||||
|
/**
|
||||||
|
* Disables the OpenSSL Analyzer.
|
||||||
|
*/
|
||||||
|
public static final String DISABLE_OPENSSL = "disableOpenSSL";
|
||||||
/**
|
/**
|
||||||
* The URL of the nexus server.
|
* The URL of the nexus server.
|
||||||
*/
|
*/
|
||||||
@@ -877,5 +1141,9 @@ public final class CliParser {
|
|||||||
* The CLI argument name for setting extra extensions.
|
* The CLI argument name for setting extra extensions.
|
||||||
*/
|
*/
|
||||||
public static final String ADDITIONAL_ZIP_EXTENSIONS = "zipExtensions";
|
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
|
||||||
|
*/
|
||||||
|
class InvalidScanPathException extends Exception {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates a new InvalidScanPathException.
|
||||||
|
*/
|
||||||
|
public InvalidScanPathException() {
|
||||||
|
super();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates a new InvalidScanPathException.
|
||||||
|
*
|
||||||
|
* @param msg a message for the exception
|
||||||
|
*/
|
||||||
|
public InvalidScanPathException(String msg) {
|
||||||
|
super(msg);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates a new InvalidScanPathException.
|
||||||
|
*
|
||||||
|
* @param ex the cause of the exception
|
||||||
|
*/
|
||||||
|
public InvalidScanPathException(Throwable ex) {
|
||||||
|
super(ex);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates a new InvalidScanPathException.
|
||||||
|
*
|
||||||
|
* @param msg a message for the exception
|
||||||
|
* @param ex the cause of the exception
|
||||||
|
*/
|
||||||
|
public InvalidScanPathException(String msg, Throwable ex) {
|
||||||
|
super(msg, ex);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,12 +0,0 @@
|
|||||||
/**
|
|
||||||
* <html>
|
|
||||||
* <head>
|
|
||||||
* <title>org.owasp.dependencycheck.cli</title>
|
|
||||||
* </head>
|
|
||||||
* <body>
|
|
||||||
* Includes utility classes such as the CLI Parser,
|
|
||||||
* </body>
|
|
||||||
* </html>
|
|
||||||
*/
|
|
||||||
|
|
||||||
package org.owasp.dependencycheck.cli;
|
|
||||||
@@ -1,12 +1,4 @@
|
|||||||
/**
|
/**
|
||||||
* <html>
|
|
||||||
* <head>
|
|
||||||
* <title>org.owasp.dependencycheck</title>
|
|
||||||
* </head>
|
|
||||||
* <body>
|
|
||||||
* Includes the main entry point for the DependencyChecker.
|
* Includes the main entry point for the DependencyChecker.
|
||||||
* </body>
|
*/
|
||||||
* </html>
|
|
||||||
*/
|
|
||||||
|
|
||||||
package org.owasp.dependencycheck;
|
package org.owasp.dependencycheck;
|
||||||
|
|||||||
@@ -1,22 +0,0 @@
|
|||||||
handlers=java.util.logging.ConsoleHandler
|
|
||||||
#, java.util.logging.FileHandler
|
|
||||||
|
|
||||||
# logging levels
|
|
||||||
# FINEST, FINER, FINE, CONFIG, INFO, WARNING and SEVERE.
|
|
||||||
|
|
||||||
# Configure the ConsoleHandler.
|
|
||||||
java.util.logging.ConsoleHandler.level=INFO
|
|
||||||
|
|
||||||
# Configure the FileHandler.
|
|
||||||
java.util.logging.FileHandler.formatter=java.util.logging.SimpleFormatter
|
|
||||||
java.util.logging.FileHandler.level=FINE
|
|
||||||
|
|
||||||
# The following special tokens can be used in the pattern property
|
|
||||||
# which specifies the location and name of the log file.
|
|
||||||
# / - standard path separator
|
|
||||||
# %t - system temporary directory
|
|
||||||
# %h - value of the user.home system property
|
|
||||||
# %g - generation number for rotating logs
|
|
||||||
# %u - unique number to avoid conflicts
|
|
||||||
# FileHandler writes to %h/demo0.log by default.
|
|
||||||
java.util.logging.FileHandler.pattern=./dependency-check.log
|
|
||||||
16
dependency-check-cli/src/main/resources/logback.xml
Normal file
16
dependency-check-cli/src/main/resources/logback.xml
Normal file
@@ -0,0 +1,16 @@
|
|||||||
|
<configuration>
|
||||||
|
<contextName>dependency-check</contextName>
|
||||||
|
<!-- Logging configuration -->
|
||||||
|
<appender name="console" class="ch.qos.logback.core.ConsoleAppender">
|
||||||
|
<Target>System.out</Target>
|
||||||
|
<filter class="ch.qos.logback.classic.filter.ThresholdFilter">
|
||||||
|
<level>INFO</level>
|
||||||
|
</filter>
|
||||||
|
<encoder>
|
||||||
|
<pattern>[%level] %msg%n</pattern>
|
||||||
|
</encoder>
|
||||||
|
</appender>
|
||||||
|
<root level="DEBUG">
|
||||||
|
<appender-ref ref="console"/>
|
||||||
|
</root>
|
||||||
|
</configuration>
|
||||||
@@ -6,8 +6,10 @@ 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
|
\-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
|
\-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
|
||||||
\-o | \-\-out | \<folder\> | The folder to write reports to. This defaults to the current directory. | Optional
|
| \-\-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
|
||||||
|
| \-\-symLink | \<depth\> | The depth that symbolic links will be followed; the default is 0 meaning symbolic links will not be followed. | 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
|
\-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
|
\-l | \-\-log | \<file\> | The file path to write verbose logging information. | Optional
|
||||||
\-n | \-\-noupdate | | Disables the automatic updating of the CPE data. | Optional
|
\-n | \-\-noupdate | | Disables the automatic updating of the CPE data. | Optional
|
||||||
@@ -18,26 +20,37 @@ Short | Argument Name | Parameter | Description | Requir
|
|||||||
|
|
||||||
Advanced Options
|
Advanced Options
|
||||||
================
|
================
|
||||||
Short | Argument Name | Parameter | Description | Default Value
|
Short | Argument Name | Parameter | Description | Default Value
|
||||||
-------|-----------------------|-----------------|-------------|---------------
|
-------|-----------------------|-----------------|----------------------------------------------------------------------------------|-------------------
|
||||||
| \-\-disableArchive | | Sets whether the Archive Analyzer will be used. | false
|
| \-\-cveUrl12Modified | \<url\> | URL for the modified CVE 1.2 | http://nvd.nist.gov/download/nvdcve-modified.xml
|
||||||
|
| \-\-cveUrl20Modified | \<url\> | URL for the modified CVE 2.0 | http://static.nvd.nist.gov/feeds/xml/cve/nvdcve-2.0-modified.xml
|
||||||
|
| \-\-cveUrl12Base | \<url\> | 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 | \<url\> | 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
|
||||||
|
\-P | \-\-propertyfile | \<file\> | Specifies a file that contains properties to use instead of applicaion defaults. |
|
||||||
|
| \-\-updateonly | | If set only the update phase of dependency-check will be executed; no scan will be executed and no report will be generated. |
|
||||||
|
| \-\-disablePyDist | | Sets whether the Python Distribution Analyzer will be used. | false
|
||||||
|
| \-\-disablePyPkg | | Sets whether the Python Package Analyzer will be used. | false
|
||||||
|
| \-\-disableAutoconf | | Sets whether the Autoconf Analyzer will be used. | false
|
||||||
|
| \-\-disableOpenSSL | | Sets whether the OpenSSL Analyzer will be used. | false
|
||||||
|
| \-\-disableCmake | | Sets whether the Cmake Analyzer will be used. | false
|
||||||
|
| \-\-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. |
|
| \-\-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
|
| \-\-disableJar | | Sets whether the Jar Analyzer will be used. | false
|
||||||
| \-\-disableNexus | | Sets whether Nexus Analyzer will be used. | false
|
| \-\-disableCentral | | Sets whether the Central Analyzer will be used. **Disabling this analyzer is not recommended as it could lead to false negatives (e.g. libraries that have vulnerabilities may not be reported correctly).** If this analyzer is being disabled there is a good chance you also want to disable the Nexus Analyzer. | false
|
||||||
| \-\-disableNexus | | Disable the Nexus Analyzer. |
|
| \-\-disableNexus | | Sets whether the Nexus Analyzer will be used. Note, this has been superceded by the Central Analyzer. However, you can configure the Nexus URL to utilize an internally hosted Nexus Pro server. | false
|
||||||
| \-\-nexus | \<url\> | The url to the Nexus Server. | https://repository.sonatype.org/service/local/
|
| \-\-nexus | \<url\> | The url to the Nexus Server's web service end point (example: http://domain.enterprise/nexus/service/local/). 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
|
| \-\-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
|
| \-\-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
|
| \-\-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. |
|
| \-\-mono | \<path\> | The path to Mono for .NET Assembly analysis on non-windows systems. |
|
||||||
| \-\-proxyserver | \<server\> | The proxy server to use when downloading resources. |
|
| \-\-proxyserver | \<server\> | The proxy server to use when downloading resources. |
|
||||||
| \-\-proxyport | \<port\> | The proxy port 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. |
|
| \-\-connectiontimeout | \<timeout\> | The connection timeout (in milliseconds) to use when downloading resources. |
|
||||||
| \-\-proxypass | \<pass\> | The proxy password 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. |
|
| \-\-proxyuser | \<user\> | The proxy username to use when downloading resources. |
|
||||||
| \-\-connectionString | \<connStr\> | The connection string to the database. |
|
| \-\-connectionString | \<connStr\> | The connection string to the database. |
|
||||||
| \-\-dbDriverName | \<driver\> | The database driver name. |
|
| \-\-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. |
|
| \-\-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. |
|
| \-\-dbPassword | \<password\> | The password for connecting to the database. |
|
||||||
| \-\-dbUser | \<user\> | The username used to connect 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. |
|
\-d | \-\-data | \<path\> | The location of the data directory used to store persistent data. This option should generally not be set. |
|
||||||
|
|||||||
@@ -1,3 +1,10 @@
|
|||||||
|
About
|
||||||
|
====================
|
||||||
|
OWASP 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.
|
||||||
|
|
||||||
Installation & Usage
|
Installation & Usage
|
||||||
====================
|
====================
|
||||||
Download the dependency-check command line tool [here](http://dl.bintray.com/jeremy-long/owasp/dependency-check-${project.version}-release.zip).
|
Download the dependency-check command line tool [here](http://dl.bintray.com/jeremy-long/owasp/dependency-check-${project.version}-release.zip).
|
||||||
File diff suppressed because one or more lines are too long
|
After Width: | Height: | Size: 10 KiB |
@@ -18,17 +18,18 @@ Copyright (c) 2013 Jeremy Long. All Rights Reserved.
|
|||||||
-->
|
-->
|
||||||
<project name="dependency-check-cli">
|
<project name="dependency-check-cli">
|
||||||
<bannerLeft>
|
<bannerLeft>
|
||||||
<name>dependency-check-cli</name>
|
<name>OWASP dependency-check-cli</name>
|
||||||
|
<alt>OWASP dependency-check-cli</alt>
|
||||||
|
<src>./images/dc-cli.svg</src>
|
||||||
</bannerLeft>
|
</bannerLeft>
|
||||||
<body>
|
<body>
|
||||||
<breadcrumbs>
|
<breadcrumbs>
|
||||||
<item name="dependency-check" href="../index.html"/>
|
<item name="dependency-check" href="../index.html"/>
|
||||||
</breadcrumbs>
|
</breadcrumbs>
|
||||||
<menu name="Getting Started">
|
<menu name="Getting Started">
|
||||||
<item name="Installation" href="installation.html"/>
|
<item name="Installation" href="index.html"/>
|
||||||
<item name="Configuration" href="arguments.html"/>
|
<item name="Configuration" href="arguments.html"/>
|
||||||
</menu>
|
</menu>
|
||||||
<menu ref="Project Documentation" />
|
|
||||||
<menu ref="reports" />
|
<menu ref="reports" />
|
||||||
</body>
|
</body>
|
||||||
</project>
|
</project>
|
||||||
@@ -0,0 +1,73 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2015 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;
|
||||||
|
|
||||||
|
import org.junit.After;
|
||||||
|
import org.junit.AfterClass;
|
||||||
|
import org.junit.Before;
|
||||||
|
import org.junit.BeforeClass;
|
||||||
|
import org.junit.Test;
|
||||||
|
import static org.junit.Assert.*;
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* @author jeremy
|
||||||
|
*/
|
||||||
|
public class AppTest {
|
||||||
|
|
||||||
|
public AppTest() {
|
||||||
|
}
|
||||||
|
|
||||||
|
@BeforeClass
|
||||||
|
public static void setUpClass() {
|
||||||
|
}
|
||||||
|
|
||||||
|
@AfterClass
|
||||||
|
public static void tearDownClass() {
|
||||||
|
}
|
||||||
|
|
||||||
|
@Before
|
||||||
|
public void setUp() {
|
||||||
|
}
|
||||||
|
|
||||||
|
@After
|
||||||
|
public void tearDown() {
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Test of ensureCanonicalPath method, of class App.
|
||||||
|
*/
|
||||||
|
@Test
|
||||||
|
public void testEnsureCanonicalPath() {
|
||||||
|
String file = "../*.jar";
|
||||||
|
App instance = new App();
|
||||||
|
String result = instance.ensureCanonicalPath(file);
|
||||||
|
assertFalse(result.contains(".."));
|
||||||
|
assertTrue(result.endsWith("*.jar"));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Test of ensureCanonicalPath method, of class App.
|
||||||
|
*/
|
||||||
|
@Test
|
||||||
|
public void testEnsureCanonicalPath2() {
|
||||||
|
String file = "../some/skip/../path/file.txt";
|
||||||
|
App instance = new App();
|
||||||
|
String expResult = "/some/path/file.txt";
|
||||||
|
String result = instance.ensureCanonicalPath(file);
|
||||||
|
assertTrue("result=" + result, result.endsWith(expResult));
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -15,8 +15,9 @@
|
|||||||
*
|
*
|
||||||
* Copyright (c) 2012 Jeremy Long. All Rights Reserved.
|
* 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.ByteArrayOutputStream;
|
||||||
import java.io.File;
|
import java.io.File;
|
||||||
import java.io.FileNotFoundException;
|
import java.io.FileNotFoundException;
|
||||||
@@ -33,7 +34,7 @@ import org.owasp.dependencycheck.utils.Settings;
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
*
|
*
|
||||||
* @author Jeremy Long <jeremy.long@owasp.org>
|
* @author Jeremy Long
|
||||||
*/
|
*/
|
||||||
public class CliParserTest {
|
public class CliParserTest {
|
||||||
|
|
||||||
@@ -20,13 +20,14 @@ Copyright (c) 2012 Jeremy Long. All Rights Reserved.
|
|||||||
<parent>
|
<parent>
|
||||||
<groupId>org.owasp</groupId>
|
<groupId>org.owasp</groupId>
|
||||||
<artifactId>dependency-check-parent</artifactId>
|
<artifactId>dependency-check-parent</artifactId>
|
||||||
<version>1.2.3</version>
|
<version>1.3.0</version>
|
||||||
</parent>
|
</parent>
|
||||||
|
|
||||||
<artifactId>dependency-check-core</artifactId>
|
<artifactId>dependency-check-core</artifactId>
|
||||||
<packaging>jar</packaging>
|
<packaging>jar</packaging>
|
||||||
|
|
||||||
<name>Dependency-Check Core</name>
|
<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/ -->
|
<!-- begin copy from http://minds.coremedia.com/2012/09/11/problem-solved-deploy-multi-module-maven-project-site-as-github-pages/ -->
|
||||||
<distributionManagement>
|
<distributionManagement>
|
||||||
<site>
|
<site>
|
||||||
@@ -92,7 +93,6 @@ Copyright (c) 2012 Jeremy Long. All Rights Reserved.
|
|||||||
<plugin>
|
<plugin>
|
||||||
<groupId>org.apache.maven.plugins</groupId>
|
<groupId>org.apache.maven.plugins</groupId>
|
||||||
<artifactId>maven-dependency-plugin</artifactId>
|
<artifactId>maven-dependency-plugin</artifactId>
|
||||||
<version>2.8</version>
|
|
||||||
<executions>
|
<executions>
|
||||||
<execution>
|
<execution>
|
||||||
<phase>generate-resources</phase>
|
<phase>generate-resources</phase>
|
||||||
@@ -101,7 +101,7 @@ Copyright (c) 2012 Jeremy Long. All Rights Reserved.
|
|||||||
</goals>
|
</goals>
|
||||||
<configuration>
|
<configuration>
|
||||||
<outputDirectory>${project.build.directory}/test-classes</outputDirectory>
|
<outputDirectory>${project.build.directory}/test-classes</outputDirectory>
|
||||||
<includeScope>provided</includeScope>
|
<includeScope>test</includeScope>
|
||||||
</configuration>
|
</configuration>
|
||||||
</execution>
|
</execution>
|
||||||
</executions>
|
</executions>
|
||||||
@@ -109,7 +109,6 @@ Copyright (c) 2012 Jeremy Long. All Rights Reserved.
|
|||||||
<plugin>
|
<plugin>
|
||||||
<groupId>org.apache.maven.plugins</groupId>
|
<groupId>org.apache.maven.plugins</groupId>
|
||||||
<artifactId>maven-jar-plugin</artifactId>
|
<artifactId>maven-jar-plugin</artifactId>
|
||||||
<version>2.4</version>
|
|
||||||
<executions>
|
<executions>
|
||||||
<execution>
|
<execution>
|
||||||
<id>jar</id>
|
<id>jar</id>
|
||||||
@@ -126,24 +125,13 @@ Copyright (c) 2012 Jeremy Long. All Rights Reserved.
|
|||||||
</goals>
|
</goals>
|
||||||
</execution>
|
</execution>
|
||||||
</executions>
|
</executions>
|
||||||
<configuration>
|
|
||||||
<archive>
|
|
||||||
<manifest>
|
|
||||||
<addDefaultImplementationEntries>true</addDefaultImplementationEntries>
|
|
||||||
</manifest>
|
|
||||||
</archive>
|
|
||||||
<excludes>
|
|
||||||
<exclude>**/checkstyle*</exclude>
|
|
||||||
</excludes>
|
|
||||||
</configuration>
|
|
||||||
</plugin>
|
</plugin>
|
||||||
<plugin>
|
<plugin>
|
||||||
<groupId>org.codehaus.mojo</groupId>
|
<groupId>org.codehaus.mojo</groupId>
|
||||||
<artifactId>cobertura-maven-plugin</artifactId>
|
<artifactId>cobertura-maven-plugin</artifactId>
|
||||||
<version>2.6</version>
|
|
||||||
<configuration>
|
<configuration>
|
||||||
<instrumentation>
|
<instrumentation>
|
||||||
<ignoreTrivial>true</ignoreTrivial>
|
<!--ignoreTrivial>true</ignoreTrivial-->
|
||||||
<ignores>
|
<ignores>
|
||||||
<ignore>.*\$KEYS\.class</ignore>
|
<ignore>.*\$KEYS\.class</ignore>
|
||||||
<ignore>.*\$Element\.class</ignore>
|
<ignore>.*\$Element\.class</ignore>
|
||||||
@@ -191,7 +179,6 @@ Copyright (c) 2012 Jeremy Long. All Rights Reserved.
|
|||||||
<plugin>
|
<plugin>
|
||||||
<groupId>org.apache.maven.plugins</groupId>
|
<groupId>org.apache.maven.plugins</groupId>
|
||||||
<artifactId>maven-surefire-plugin</artifactId>
|
<artifactId>maven-surefire-plugin</artifactId>
|
||||||
<version>2.16</version>
|
|
||||||
<configuration>
|
<configuration>
|
||||||
<systemProperties>
|
<systemProperties>
|
||||||
<property>
|
<property>
|
||||||
@@ -212,7 +199,6 @@ Copyright (c) 2012 Jeremy Long. All Rights Reserved.
|
|||||||
<plugin>
|
<plugin>
|
||||||
<groupId>org.apache.maven.plugins</groupId>
|
<groupId>org.apache.maven.plugins</groupId>
|
||||||
<artifactId>maven-failsafe-plugin</artifactId>
|
<artifactId>maven-failsafe-plugin</artifactId>
|
||||||
<version>2.16</version>
|
|
||||||
<configuration>
|
<configuration>
|
||||||
<systemProperties>
|
<systemProperties>
|
||||||
<property>
|
<property>
|
||||||
@@ -223,186 +209,184 @@ Copyright (c) 2012 Jeremy Long. All Rights Reserved.
|
|||||||
<name>temp.directory</name>
|
<name>temp.directory</name>
|
||||||
<value>${project.build.directory}/temp</value>
|
<value>${project.build.directory}/temp</value>
|
||||||
</property>
|
</property>
|
||||||
|
|
||||||
</systemProperties>
|
</systemProperties>
|
||||||
<includes>
|
|
||||||
<include>**/*IntegrationTest.java</include>
|
|
||||||
</includes>
|
|
||||||
</configuration>
|
|
||||||
<executions>
|
|
||||||
<execution>
|
|
||||||
<goals>
|
|
||||||
<goal>integration-test</goal>
|
|
||||||
<goal>verify</goal>
|
|
||||||
</goals>
|
|
||||||
</execution>
|
|
||||||
</executions>
|
|
||||||
</plugin>
|
|
||||||
<plugin>
|
|
||||||
<groupId>org.apache.maven.plugins</groupId>
|
|
||||||
<artifactId>maven-site-plugin</artifactId>
|
|
||||||
<version>3.3</version>
|
|
||||||
<dependencies>
|
|
||||||
<dependency>
|
|
||||||
<groupId>org.apache.maven.doxia</groupId>
|
|
||||||
<artifactId>doxia-module-markdown</artifactId>
|
|
||||||
<version>1.5</version>
|
|
||||||
</dependency>
|
|
||||||
</dependencies>
|
|
||||||
<configuration>
|
|
||||||
<skipDeploy>true</skipDeploy>
|
|
||||||
<reportPlugins>
|
|
||||||
<plugin>
|
|
||||||
<groupId>org.apache.maven.plugins</groupId>
|
|
||||||
<artifactId>maven-project-info-reports-plugin</artifactId>
|
|
||||||
<version>2.7</version>
|
|
||||||
<reportSets>
|
|
||||||
<reportSet>
|
|
||||||
<reports>
|
|
||||||
<report>index</report>
|
|
||||||
<report>summary</report>
|
|
||||||
<report>license</report>
|
|
||||||
<report>help</report>
|
|
||||||
</reports>
|
|
||||||
</reportSet>
|
|
||||||
</reportSets>
|
|
||||||
</plugin>
|
|
||||||
<plugin>
|
|
||||||
<groupId>org.apache.maven.plugins</groupId>
|
|
||||||
<artifactId>maven-javadoc-plugin</artifactId>
|
|
||||||
<version>2.9.1</version>
|
|
||||||
<reportSets>
|
|
||||||
<reportSet>
|
|
||||||
<id>default</id>
|
|
||||||
<reports>
|
|
||||||
<report>javadoc</report>
|
|
||||||
</reports>
|
|
||||||
</reportSet>
|
|
||||||
</reportSets>
|
|
||||||
</plugin>
|
|
||||||
<plugin>
|
|
||||||
<groupId>org.codehaus.mojo</groupId>
|
|
||||||
<artifactId>versions-maven-plugin</artifactId>
|
|
||||||
<version>2.1</version>
|
|
||||||
<reportSets>
|
|
||||||
<reportSet>
|
|
||||||
<reports>
|
|
||||||
<report>dependency-updates-report</report>
|
|
||||||
<report>plugin-updates-report</report>
|
|
||||||
</reports>
|
|
||||||
</reportSet>
|
|
||||||
</reportSets>
|
|
||||||
</plugin>
|
|
||||||
<plugin>
|
|
||||||
<groupId>org.apache.maven.plugins</groupId>
|
|
||||||
<artifactId>maven-jxr-plugin</artifactId>
|
|
||||||
<version>2.4</version>
|
|
||||||
</plugin>
|
|
||||||
<plugin>
|
|
||||||
<groupId>org.codehaus.mojo</groupId>
|
|
||||||
<artifactId>cobertura-maven-plugin</artifactId>
|
|
||||||
<version>2.6</version>
|
|
||||||
</plugin>
|
|
||||||
<plugin>
|
|
||||||
<groupId>org.apache.maven.plugins</groupId>
|
|
||||||
<artifactId>maven-surefire-report-plugin</artifactId>
|
|
||||||
<version>2.16</version>
|
|
||||||
<reportSets>
|
|
||||||
<reportSet>
|
|
||||||
<reports>
|
|
||||||
<report>report-only</report>
|
|
||||||
</reports>
|
|
||||||
</reportSet>
|
|
||||||
<reportSet>
|
|
||||||
<id>integration-tests</id>
|
|
||||||
<reports>
|
|
||||||
<report>report-only</report>
|
|
||||||
<report>failsafe-report-only</report>
|
|
||||||
</reports>
|
|
||||||
</reportSet>
|
|
||||||
</reportSets>
|
|
||||||
</plugin>
|
|
||||||
<plugin>
|
|
||||||
<groupId>org.codehaus.mojo</groupId>
|
|
||||||
<artifactId>taglist-maven-plugin</artifactId>
|
|
||||||
<version>2.4</version>
|
|
||||||
<configuration>
|
|
||||||
<tagListOptions>
|
|
||||||
<tagClasses>
|
|
||||||
<tagClass>
|
|
||||||
<displayName>Todo Work</displayName>
|
|
||||||
<tags>
|
|
||||||
<tag>
|
|
||||||
<matchString>todo</matchString>
|
|
||||||
<matchType>ignoreCase</matchType>
|
|
||||||
</tag>
|
|
||||||
<tag>
|
|
||||||
<matchString>FIXME</matchString>
|
|
||||||
<matchType>exact</matchType>
|
|
||||||
</tag>
|
|
||||||
</tags>
|
|
||||||
</tagClass>
|
|
||||||
</tagClasses>
|
|
||||||
</tagListOptions>
|
|
||||||
</configuration>
|
|
||||||
</plugin>
|
|
||||||
<plugin>
|
|
||||||
<groupId>org.apache.maven.plugins</groupId>
|
|
||||||
<artifactId>maven-checkstyle-plugin</artifactId>
|
|
||||||
<version>2.11</version>
|
|
||||||
<configuration>
|
|
||||||
<enableRulesSummary>false</enableRulesSummary>
|
|
||||||
<configLocation>${basedir}/../src/main/config/checkstyle-checks.xml</configLocation>
|
|
||||||
<headerLocation>${basedir}/../src/main/config/checkstyle-header.txt</headerLocation>
|
|
||||||
<suppressionsLocation>${basedir}/../src/main/config/checkstyle-suppressions.xml</suppressionsLocation>
|
|
||||||
<suppressionsFileExpression>checkstyle.suppressions.file</suppressionsFileExpression>
|
|
||||||
</configuration>
|
|
||||||
</plugin>
|
|
||||||
<plugin>
|
|
||||||
<groupId>org.apache.maven.plugins</groupId>
|
|
||||||
<artifactId>maven-pmd-plugin</artifactId>
|
|
||||||
<version>3.1</version>
|
|
||||||
<configuration>
|
|
||||||
<targetJdk>1.6</targetJdk>
|
|
||||||
<linkXref>true</linkXref>
|
|
||||||
<sourceEncoding>utf-8</sourceEncoding>
|
|
||||||
<excludes>
|
|
||||||
<exclude>**/generated/*.java</exclude>
|
|
||||||
</excludes>
|
|
||||||
<rulesets>
|
|
||||||
<ruleset>../src/main/config/dcrules.xml</ruleset>
|
|
||||||
<ruleset>/rulesets/java/basic.xml</ruleset>
|
|
||||||
<ruleset>/rulesets/java/imports.xml</ruleset>
|
|
||||||
<ruleset>/rulesets/java/unusedcode.xml</ruleset>
|
|
||||||
</rulesets>
|
|
||||||
</configuration>
|
|
||||||
</plugin>
|
|
||||||
<plugin>
|
|
||||||
<groupId>org.codehaus.mojo</groupId>
|
|
||||||
<artifactId>findbugs-maven-plugin</artifactId>
|
|
||||||
<version>2.5.3</version>
|
|
||||||
</plugin>
|
|
||||||
<dependency>
|
|
||||||
<groupId>org.codehaus.mojo</groupId>
|
|
||||||
<artifactId>javancss-maven-plugin</artifactId>
|
|
||||||
<version>2.0</version>
|
|
||||||
</dependency>
|
|
||||||
</reportPlugins>
|
|
||||||
</configuration>
|
</configuration>
|
||||||
</plugin>
|
</plugin>
|
||||||
<plugin>
|
<plugin>
|
||||||
<groupId>org.apache.maven.plugins</groupId>
|
<groupId>org.apache.maven.plugins</groupId>
|
||||||
<artifactId>maven-compiler-plugin</artifactId>
|
<artifactId>maven-compiler-plugin</artifactId>
|
||||||
<version>3.1</version>
|
|
||||||
<configuration>
|
<configuration>
|
||||||
<showDeprecation>false</showDeprecation>
|
<compilerArgument>-Xlint:unchecked</compilerArgument>
|
||||||
<source>1.6</source>
|
|
||||||
<target>1.6</target>
|
|
||||||
</configuration>
|
</configuration>
|
||||||
</plugin>
|
</plugin>
|
||||||
</plugins>
|
</plugins>
|
||||||
</build>
|
</build>
|
||||||
|
<reporting>
|
||||||
|
<plugins>
|
||||||
|
<plugin>
|
||||||
|
<groupId>org.apache.maven.plugins</groupId>
|
||||||
|
<artifactId>maven-project-info-reports-plugin</artifactId>
|
||||||
|
<version>${reporting.project-info-reports-plugin.version}</version>
|
||||||
|
<reportSets>
|
||||||
|
<reportSet>
|
||||||
|
<reports>
|
||||||
|
<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>${reporting.javadoc-plugin.version}</version>
|
||||||
|
<configuration>
|
||||||
|
<failOnError>false</failOnError>
|
||||||
|
<bottom>Copyright© 2012-15 Jeremy Long. All Rights Reserved.</bottom>
|
||||||
|
</configuration>
|
||||||
|
<reportSets>
|
||||||
|
<reportSet>
|
||||||
|
<id>default</id>
|
||||||
|
<reports>
|
||||||
|
<report>javadoc</report>
|
||||||
|
</reports>
|
||||||
|
</reportSet>
|
||||||
|
</reportSets>
|
||||||
|
</plugin>
|
||||||
|
<plugin>
|
||||||
|
<groupId>org.codehaus.mojo</groupId>
|
||||||
|
<artifactId>versions-maven-plugin</artifactId>
|
||||||
|
<version>${reporting.versions-plugin.version}</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>${reporting.jxr-plugin.version}</version>
|
||||||
|
</plugin>
|
||||||
|
<plugin>
|
||||||
|
<groupId>org.codehaus.mojo</groupId>
|
||||||
|
<artifactId>cobertura-maven-plugin</artifactId>
|
||||||
|
<version>${reporting.cobertura-plugin.version}</version>
|
||||||
|
</plugin>
|
||||||
|
<plugin>
|
||||||
|
<groupId>org.apache.maven.plugins</groupId>
|
||||||
|
<artifactId>maven-surefire-report-plugin</artifactId>
|
||||||
|
<version>${reporting.surefire-report-plugin.version}</version>
|
||||||
|
<reportSets>
|
||||||
|
<reportSet>
|
||||||
|
<reports>
|
||||||
|
<report>report-only</report>
|
||||||
|
</reports>
|
||||||
|
</reportSet>
|
||||||
|
<reportSet>
|
||||||
|
<id>integration-tests</id>
|
||||||
|
<reports>
|
||||||
|
<report>report-only</report>
|
||||||
|
<report>failsafe-report-only</report>
|
||||||
|
</reports>
|
||||||
|
</reportSet>
|
||||||
|
</reportSets>
|
||||||
|
</plugin>
|
||||||
|
<plugin>
|
||||||
|
<groupId>org.codehaus.mojo</groupId>
|
||||||
|
<artifactId>taglist-maven-plugin</artifactId>
|
||||||
|
<version>${reporting.taglist-plugin.version}</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>${reporting.checkstyle-plugin.version}</version>
|
||||||
|
<configuration>
|
||||||
|
<enableRulesSummary>false</enableRulesSummary>
|
||||||
|
<enableFilesSummary>false</enableFilesSummary>
|
||||||
|
<configLocation>${basedir}/../src/main/config/checkstyle-checks.xml</configLocation>
|
||||||
|
<headerLocation>${basedir}/../src/main/config/checkstyle-header.txt</headerLocation>
|
||||||
|
<suppressionsLocation>${basedir}/../src/main/config/checkstyle-suppressions.xml</suppressionsLocation>
|
||||||
|
<suppressionsFileExpression>checkstyle.suppressions.file</suppressionsFileExpression>
|
||||||
|
</configuration>
|
||||||
|
</plugin>
|
||||||
|
<plugin>
|
||||||
|
<groupId>org.apache.maven.plugins</groupId>
|
||||||
|
<artifactId>maven-pmd-plugin</artifactId>
|
||||||
|
<version>${reporting.pmd-plugin.version}</version>
|
||||||
|
<configuration>
|
||||||
|
<targetJdk>1.6</targetJdk>
|
||||||
|
<linkXref>true</linkXref>
|
||||||
|
<sourceEncoding>utf-8</sourceEncoding>
|
||||||
|
<excludes>
|
||||||
|
<exclude>**/generated/*.java</exclude>
|
||||||
|
</excludes>
|
||||||
|
<rulesets>
|
||||||
|
<ruleset>../src/main/config/dcrules.xml</ruleset>
|
||||||
|
<ruleset>/rulesets/java/basic.xml</ruleset>
|
||||||
|
<ruleset>/rulesets/java/imports.xml</ruleset>
|
||||||
|
<ruleset>/rulesets/java/unusedcode.xml</ruleset>
|
||||||
|
</rulesets>
|
||||||
|
</configuration>
|
||||||
|
</plugin>
|
||||||
|
<plugin>
|
||||||
|
<groupId>org.codehaus.mojo</groupId>
|
||||||
|
<artifactId>findbugs-maven-plugin</artifactId>
|
||||||
|
<version>${reporting.findbugs-plugin.version}</version>
|
||||||
|
</plugin>
|
||||||
|
</plugins>
|
||||||
|
</reporting>
|
||||||
<dependencies>
|
<dependencies>
|
||||||
|
<!-- Note, to stay compatible with Jenkins installations only JARs compiled to 1.6 can be used -->
|
||||||
|
<dependency>
|
||||||
|
<groupId>com.google.code.findbugs</groupId>
|
||||||
|
<artifactId>annotations</artifactId>
|
||||||
|
<optional>true</optional>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.slf4j</groupId>
|
||||||
|
<artifactId>slf4j-api</artifactId>
|
||||||
|
</dependency>
|
||||||
|
<!-- Set this to test so that each project that uses this has to have its own implementation of SLF4J -->
|
||||||
|
<dependency>
|
||||||
|
<groupId>ch.qos.logback</groupId>
|
||||||
|
<artifactId>logback-core</artifactId>
|
||||||
|
<scope>test</scope>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>ch.qos.logback</groupId>
|
||||||
|
<artifactId>logback-classic</artifactId>
|
||||||
|
<scope>test</scope>
|
||||||
|
</dependency>
|
||||||
|
<!-- For the CAL10N support -->
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.slf4j</groupId>
|
||||||
|
<artifactId>slf4j-ext</artifactId>
|
||||||
|
<scope>compile</scope>
|
||||||
|
</dependency>
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>org.owasp</groupId>
|
<groupId>org.owasp</groupId>
|
||||||
<artifactId>dependency-check-utils</artifactId>
|
<artifactId>dependency-check-utils</artifactId>
|
||||||
@@ -411,172 +395,116 @@ Copyright (c) 2012 Jeremy Long. All Rights Reserved.
|
|||||||
<dependency>
|
<dependency>
|
||||||
<groupId>org.apache.lucene</groupId>
|
<groupId>org.apache.lucene</groupId>
|
||||||
<artifactId>lucene-test-framework</artifactId>
|
<artifactId>lucene-test-framework</artifactId>
|
||||||
<version>4.3.1</version>
|
|
||||||
<scope>test</scope>
|
<scope>test</scope>
|
||||||
</dependency>
|
</dependency>
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>com.google.code.findbugs</groupId>
|
<groupId>org.jmockit</groupId>
|
||||||
<artifactId>annotations</artifactId>
|
<artifactId>jmockit</artifactId>
|
||||||
<version>2.0.1</version>
|
<scope>test</scope>
|
||||||
<optional>true</optional>
|
|
||||||
</dependency>
|
|
||||||
<dependency>
|
|
||||||
<groupId>commons-cli</groupId>
|
|
||||||
<artifactId>commons-cli</artifactId>
|
|
||||||
<version>1.2</version>
|
|
||||||
</dependency>
|
</dependency>
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>org.apache.commons</groupId>
|
<groupId>org.apache.commons</groupId>
|
||||||
<artifactId>commons-compress</artifactId>
|
<artifactId>commons-compress</artifactId>
|
||||||
<version>1.8</version>
|
|
||||||
</dependency>
|
</dependency>
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>commons-io</groupId>
|
<groupId>commons-io</groupId>
|
||||||
<artifactId>commons-io</artifactId>
|
<artifactId>commons-io</artifactId>
|
||||||
<version>2.4</version>
|
|
||||||
</dependency>
|
</dependency>
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>commons-lang</groupId>
|
<groupId>commons-lang</groupId>
|
||||||
<artifactId>commons-lang</artifactId>
|
<artifactId>commons-lang</artifactId>
|
||||||
<version>2.5</version>
|
|
||||||
</dependency>
|
</dependency>
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>org.apache.lucene</groupId>
|
<groupId>org.apache.lucene</groupId>
|
||||||
<artifactId>lucene-core</artifactId>
|
<artifactId>lucene-core</artifactId>
|
||||||
<version>4.5.1</version>
|
|
||||||
</dependency>
|
</dependency>
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>org.apache.lucene</groupId>
|
<groupId>org.apache.lucene</groupId>
|
||||||
<artifactId>lucene-analyzers-common</artifactId>
|
<artifactId>lucene-analyzers-common</artifactId>
|
||||||
<version>4.5.1</version>
|
|
||||||
</dependency>
|
</dependency>
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>org.apache.lucene</groupId>
|
<groupId>org.apache.lucene</groupId>
|
||||||
<artifactId>lucene-queryparser</artifactId>
|
<artifactId>lucene-queryparser</artifactId>
|
||||||
<version>4.5.1</version>
|
|
||||||
</dependency>
|
</dependency>
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>org.apache.velocity</groupId>
|
<groupId>org.apache.velocity</groupId>
|
||||||
<artifactId>velocity</artifactId>
|
<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>
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>com.h2database</groupId>
|
<groupId>com.h2database</groupId>
|
||||||
<artifactId>h2</artifactId>
|
<artifactId>h2</artifactId>
|
||||||
<version>1.3.172</version>
|
|
||||||
</dependency>
|
</dependency>
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>org.jsoup</groupId>
|
<groupId>org.jsoup</groupId>
|
||||||
<artifactId>jsoup</artifactId>
|
<artifactId>jsoup</artifactId>
|
||||||
<version>1.7.2</version>
|
|
||||||
<type>jar</type>
|
<type>jar</type>
|
||||||
</dependency>
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>com.sun.mail</groupId>
|
||||||
|
<artifactId>mailapi</artifactId>
|
||||||
|
</dependency>
|
||||||
<!-- The following dependencies are only used during testing -->
|
<!-- The following dependencies are only used during testing -->
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>org.apache.maven.scm</groupId>
|
<groupId>org.apache.maven.scm</groupId>
|
||||||
<artifactId>maven-scm-provider-cvsexe</artifactId>
|
<artifactId>maven-scm-provider-cvsexe</artifactId>
|
||||||
<version>1.8.1</version>
|
<version>1.8.1</version>
|
||||||
<scope>provided</scope>
|
<scope>test</scope>
|
||||||
<optional>true</optional>
|
<optional>true</optional>
|
||||||
</dependency>
|
</dependency>
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>org.springframework</groupId>
|
<groupId>org.springframework</groupId>
|
||||||
<artifactId>spring-webmvc</artifactId>
|
<artifactId>spring-webmvc</artifactId>
|
||||||
<version>2.5.5</version>
|
<version>2.5.5</version>
|
||||||
<scope>provided</scope>
|
<scope>test</scope>
|
||||||
<optional>true</optional>
|
<optional>true</optional>
|
||||||
</dependency>
|
</dependency>
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>org.springframework.security</groupId>
|
<groupId>org.springframework.security</groupId>
|
||||||
<artifactId>spring-security-web</artifactId>
|
<artifactId>spring-security-web</artifactId>
|
||||||
<version>3.0.0.RELEASE</version>
|
<version>3.0.0.RELEASE</version>
|
||||||
<scope>provided</scope>
|
<scope>test</scope>
|
||||||
<optional>true</optional>
|
<optional>true</optional>
|
||||||
</dependency>
|
</dependency>
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>com.hazelcast</groupId>
|
<groupId>com.hazelcast</groupId>
|
||||||
<artifactId>hazelcast</artifactId>
|
<artifactId>hazelcast</artifactId>
|
||||||
<version>2.5</version>
|
<version>2.5</version>
|
||||||
<scope>provided</scope>
|
<scope>test</scope>
|
||||||
<optional>true</optional>
|
<optional>true</optional>
|
||||||
</dependency>
|
</dependency>
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>net.sf.ehcache</groupId>
|
<groupId>net.sf.ehcache</groupId>
|
||||||
<artifactId>ehcache-core</artifactId>
|
<artifactId>ehcache-core</artifactId>
|
||||||
<version>2.2.0</version>
|
<version>2.2.0</version>
|
||||||
<scope>provided</scope>
|
<scope>test</scope>
|
||||||
<optional>true</optional>
|
<optional>true</optional>
|
||||||
</dependency>
|
</dependency>
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>org.apache.struts</groupId>
|
<groupId>org.apache.struts</groupId>
|
||||||
<artifactId>struts2-core</artifactId>
|
<artifactId>struts2-core</artifactId>
|
||||||
<version>2.1.2</version>
|
<version>2.1.2</version>
|
||||||
<scope>provided</scope>
|
<scope>test</scope>
|
||||||
<optional>true</optional>
|
<optional>true</optional>
|
||||||
</dependency>
|
</dependency>
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>org.mortbay.jetty</groupId>
|
<groupId>org.mortbay.jetty</groupId>
|
||||||
<artifactId>jetty</artifactId>
|
<artifactId>jetty</artifactId>
|
||||||
<version>6.1.0</version>
|
<version>6.1.0</version>
|
||||||
<scope>provided</scope>
|
<scope>test</scope>
|
||||||
<optional>true</optional>
|
<optional>true</optional>
|
||||||
</dependency>
|
</dependency>
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>org.apache.axis2</groupId>
|
<groupId>org.apache.axis2</groupId>
|
||||||
<artifactId>axis2-spring</artifactId>
|
<artifactId>axis2-spring</artifactId>
|
||||||
<version>1.4.1</version>
|
<version>1.4.1</version>
|
||||||
<scope>provided</scope>
|
<scope>test</scope>
|
||||||
<optional>true</optional>
|
<optional>true</optional>
|
||||||
</dependency>
|
</dependency>
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>org.apache.axis2</groupId>
|
<groupId>org.apache.axis2</groupId>
|
||||||
<artifactId>axis2-adb</artifactId>
|
<artifactId>axis2-adb</artifactId>
|
||||||
<version>1.4.1</version>
|
<version>1.4.1</version>
|
||||||
<scope>provided</scope>
|
<scope>test</scope>
|
||||||
<optional>true</optional>
|
<optional>true</optional>
|
||||||
</dependency>
|
</dependency>
|
||||||
<dependency>
|
<dependency>
|
||||||
@@ -584,7 +512,7 @@ Copyright (c) 2012 Jeremy Long. All Rights Reserved.
|
|||||||
<artifactId>daytrader-ear</artifactId>
|
<artifactId>daytrader-ear</artifactId>
|
||||||
<version>2.1.7</version>
|
<version>2.1.7</version>
|
||||||
<type>ear</type>
|
<type>ear</type>
|
||||||
<scope>provided</scope>
|
<scope>test</scope>
|
||||||
<optional>true</optional>
|
<optional>true</optional>
|
||||||
</dependency>
|
</dependency>
|
||||||
<dependency>
|
<dependency>
|
||||||
@@ -592,7 +520,7 @@ Copyright (c) 2012 Jeremy Long. All Rights Reserved.
|
|||||||
<artifactId>war</artifactId>
|
<artifactId>war</artifactId>
|
||||||
<version>4.0</version>
|
<version>4.0</version>
|
||||||
<type>war</type>
|
<type>war</type>
|
||||||
<scope>provided</scope>
|
<scope>test</scope>
|
||||||
<optional>true</optional>
|
<optional>true</optional>
|
||||||
</dependency>
|
</dependency>
|
||||||
<dependency>
|
<dependency>
|
||||||
@@ -600,21 +528,35 @@ Copyright (c) 2012 Jeremy Long. All Rights Reserved.
|
|||||||
<artifactId>dojo-war</artifactId>
|
<artifactId>dojo-war</artifactId>
|
||||||
<version>1.3.0</version>
|
<version>1.3.0</version>
|
||||||
<type>war</type>
|
<type>war</type>
|
||||||
<scope>provided</scope>
|
<scope>test</scope>
|
||||||
<optional>true</optional>
|
<optional>true</optional>
|
||||||
</dependency>
|
</dependency>
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>org.apache.openjpa</groupId>
|
<groupId>org.apache.openjpa</groupId>
|
||||||
<artifactId>openjpa</artifactId>
|
<artifactId>openjpa</artifactId>
|
||||||
<version>2.0.1</version>
|
<version>2.0.1</version>
|
||||||
<scope>provided</scope>
|
<scope>test</scope>
|
||||||
<optional>true</optional>
|
<optional>true</optional>
|
||||||
</dependency>
|
</dependency>
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>com.google.inject</groupId>
|
<groupId>com.google.inject</groupId>
|
||||||
<artifactId>guice</artifactId>
|
<artifactId>guice</artifactId>
|
||||||
<version>3.0</version>
|
<version>3.0</version>
|
||||||
<scope>provided</scope>
|
<scope>test</scope>
|
||||||
|
<optional>true</optional>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.springframework.retry</groupId>
|
||||||
|
<artifactId>spring-retry</artifactId>
|
||||||
|
<version>1.1.0.RELEASE</version>
|
||||||
|
<scope>test</scope>
|
||||||
|
<optional>true</optional>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>uk.ltd.getahead</groupId>
|
||||||
|
<artifactId>dwr</artifactId>
|
||||||
|
<version>1.1.1</version>
|
||||||
|
<scope>test</scope>
|
||||||
<optional>true</optional>
|
<optional>true</optional>
|
||||||
</dependency>
|
</dependency>
|
||||||
</dependencies>
|
</dependencies>
|
||||||
@@ -624,7 +566,6 @@ Copyright (c) 2012 Jeremy Long. All Rights Reserved.
|
|||||||
<activation>
|
<activation>
|
||||||
<property>
|
<property>
|
||||||
<name>mysql</name>
|
<name>mysql</name>
|
||||||
<!--value>test</value-->
|
|
||||||
</property>
|
</property>
|
||||||
</activation>
|
</activation>
|
||||||
<build>
|
<build>
|
||||||
@@ -632,7 +573,7 @@ Copyright (c) 2012 Jeremy Long. All Rights Reserved.
|
|||||||
<plugin>
|
<plugin>
|
||||||
<groupId>org.apache.maven.plugins</groupId>
|
<groupId>org.apache.maven.plugins</groupId>
|
||||||
<artifactId>maven-surefire-plugin</artifactId>
|
<artifactId>maven-surefire-plugin</artifactId>
|
||||||
<version>2.16</version>
|
<version>2.18.1</version>
|
||||||
<configuration>
|
<configuration>
|
||||||
<skip>true</skip>
|
<skip>true</skip>
|
||||||
</configuration>
|
</configuration>
|
||||||
@@ -640,7 +581,7 @@ Copyright (c) 2012 Jeremy Long. All Rights Reserved.
|
|||||||
<plugin>
|
<plugin>
|
||||||
<groupId>org.apache.maven.plugins</groupId>
|
<groupId>org.apache.maven.plugins</groupId>
|
||||||
<artifactId>maven-failsafe-plugin</artifactId>
|
<artifactId>maven-failsafe-plugin</artifactId>
|
||||||
<version>2.16</version>
|
<version>2.18.1</version>
|
||||||
<configuration>
|
<configuration>
|
||||||
<systemProperties>
|
<systemProperties>
|
||||||
<property>
|
<property>
|
||||||
@@ -688,49 +629,147 @@ Copyright (c) 2012 Jeremy Long. All Rights Reserved.
|
|||||||
<groupId>org.apache.xmlgraphics</groupId>
|
<groupId>org.apache.xmlgraphics</groupId>
|
||||||
<artifactId>batik-util</artifactId>
|
<artifactId>batik-util</artifactId>
|
||||||
<version>1.7</version>
|
<version>1.7</version>
|
||||||
<scope>provided</scope>
|
<scope>test</scope>
|
||||||
<optional>true</optional>
|
<optional>true</optional>
|
||||||
</dependency>
|
</dependency>
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>com.thoughtworks.xstream</groupId>
|
<groupId>com.thoughtworks.xstream</groupId>
|
||||||
<artifactId>xstream</artifactId>
|
<artifactId>xstream</artifactId>
|
||||||
<version>1.4.2</version>
|
<version>1.4.2</version>
|
||||||
<scope>provided</scope>
|
<scope>test</scope>
|
||||||
<optional>true</optional>
|
<optional>true</optional>
|
||||||
</dependency>
|
</dependency>
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>org.apache.ws.security</groupId>
|
<groupId>org.apache.ws.security</groupId>
|
||||||
<artifactId>wss4j</artifactId>
|
<artifactId>wss4j</artifactId>
|
||||||
<version>1.5.7</version>
|
<version>1.5.7</version>
|
||||||
<scope>provided</scope>
|
<scope>test</scope>
|
||||||
<optional>true</optional>
|
<optional>true</optional>
|
||||||
</dependency>
|
</dependency>
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>com.ganyo</groupId>
|
<groupId>com.ganyo</groupId>
|
||||||
<artifactId>gcm-server</artifactId>
|
<artifactId>gcm-server</artifactId>
|
||||||
<version>1.0.2</version>
|
<version>1.0.2</version>
|
||||||
<scope>provided</scope>
|
<scope>test</scope>
|
||||||
<optional>true</optional>
|
<optional>true</optional>
|
||||||
</dependency>
|
</dependency>
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>org.python</groupId>
|
<groupId>org.python</groupId>
|
||||||
<artifactId>jython-standalone</artifactId>
|
<artifactId>jython-standalone</artifactId>
|
||||||
<version>2.7-b1</version>
|
<version>2.7-b1</version>
|
||||||
<scope>provided</scope>
|
<scope>test</scope>
|
||||||
<optional>true</optional>
|
<optional>true</optional>
|
||||||
</dependency>
|
</dependency>
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>org.jruby</groupId>
|
<groupId>org.jruby</groupId>
|
||||||
<artifactId>jruby-complete</artifactId>
|
<artifactId>jruby-complete</artifactId>
|
||||||
<version>1.7.4</version>
|
<version>1.7.4</version>
|
||||||
<scope>provided</scope>
|
<scope>test</scope>
|
||||||
<optional>true</optional>
|
<optional>true</optional>
|
||||||
</dependency>
|
</dependency>
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>org.jruby</groupId>
|
<groupId>org.jruby</groupId>
|
||||||
<artifactId>jruby</artifactId>
|
<artifactId>jruby</artifactId>
|
||||||
<version>1.6.3</version>
|
<version>1.6.3</version>
|
||||||
<scope>provided</scope>
|
<scope>test</scope>
|
||||||
|
<optional>true</optional>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.glassfish.jersey.core</groupId>
|
||||||
|
<artifactId>jersey-client</artifactId>
|
||||||
|
<version>2.12</version>
|
||||||
|
<scope>test</scope>
|
||||||
|
<optional>true</optional>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>com.sun.jersey</groupId>
|
||||||
|
<artifactId>jersey-client</artifactId>
|
||||||
|
<version>1.11.1</version>
|
||||||
|
<scope>test</scope>
|
||||||
|
<optional>true</optional>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>com.sun.faces</groupId>
|
||||||
|
<artifactId>jsf-impl</artifactId>
|
||||||
|
<version>2.2.8-02</version>
|
||||||
|
<scope>test</scope>
|
||||||
|
<optional>true</optional>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>com.google.inject</groupId>
|
||||||
|
<artifactId>guice</artifactId>
|
||||||
|
<version>3.0</version>
|
||||||
|
<scope>test</scope>
|
||||||
|
<optional>true</optional>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.opensaml</groupId>
|
||||||
|
<artifactId>xmltooling</artifactId>
|
||||||
|
<version>1.4.1</version>
|
||||||
|
<scope>test</scope>
|
||||||
|
<optional>true</optional>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.springframework</groupId>
|
||||||
|
<artifactId>spring-webmvc</artifactId>
|
||||||
|
<version>3.2.12.RELEASE</version>
|
||||||
|
<scope>test</scope>
|
||||||
|
<optional>true</optional>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>com.google.code.gson</groupId>
|
||||||
|
<artifactId>gson</artifactId>
|
||||||
|
<version>2.3.1</version>
|
||||||
|
<scope>test</scope>
|
||||||
|
<optional>true</optional>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>com.google.gerrit</groupId>
|
||||||
|
<artifactId>gerrit-extension-api</artifactId>
|
||||||
|
<version>2.11</version>
|
||||||
|
<scope>test</scope>
|
||||||
|
<optional>true</optional>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>com.google.apis</groupId>
|
||||||
|
<artifactId>google-api-services-sqladmin</artifactId>
|
||||||
|
<version>v1beta4-rev5-1.20.0</version>
|
||||||
|
<scope>test</scope>
|
||||||
|
<optional>true</optional>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>com.google.gwt.google-apis</groupId>
|
||||||
|
<artifactId>gwt-gears</artifactId>
|
||||||
|
<version>1.2.1</version>
|
||||||
|
<scope>test</scope>
|
||||||
|
<optional>true</optional>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.mozilla</groupId>
|
||||||
|
<artifactId>rhino</artifactId>
|
||||||
|
<version>1.7.6</version>
|
||||||
|
<scope>test</scope>
|
||||||
|
<optional>true</optional>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>com.microsoft.windowsazure</groupId>
|
||||||
|
<artifactId>microsoft-azure-api-media</artifactId>
|
||||||
|
<version>0.5.0</version>
|
||||||
|
<scope>test</scope>
|
||||||
|
<optional>true</optional>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>com.microsoft.windowsazure</groupId>
|
||||||
|
<artifactId>microsoft-azure-api-management-sql</artifactId>
|
||||||
|
<version>0.5.0</version>
|
||||||
|
<scope>test</scope>
|
||||||
|
<optional>true</optional>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>com.microsoft.bingads</groupId>
|
||||||
|
<artifactId>microsoft.bingads</artifactId>
|
||||||
|
<version>9.3.4</version>
|
||||||
|
<scope>test</scope>
|
||||||
<optional>true</optional>
|
<optional>true</optional>
|
||||||
</dependency>
|
</dependency>
|
||||||
</dependencies>
|
</dependencies>
|
||||||
|
|||||||
@@ -17,22 +17,11 @@
|
|||||||
*/
|
*/
|
||||||
package org.owasp.dependencycheck;
|
package org.owasp.dependencycheck;
|
||||||
|
|
||||||
import java.io.File;
|
|
||||||
import java.util.ArrayList;
|
|
||||||
import java.util.EnumMap;
|
|
||||||
import java.util.HashSet;
|
|
||||||
import java.util.Iterator;
|
|
||||||
import java.util.List;
|
|
||||||
import java.util.Set;
|
|
||||||
import java.util.logging.Level;
|
|
||||||
import java.util.logging.Logger;
|
|
||||||
import org.owasp.dependencycheck.analyzer.AnalysisPhase;
|
import org.owasp.dependencycheck.analyzer.AnalysisPhase;
|
||||||
import org.owasp.dependencycheck.analyzer.Analyzer;
|
import org.owasp.dependencycheck.analyzer.Analyzer;
|
||||||
import org.owasp.dependencycheck.analyzer.AnalyzerService;
|
import org.owasp.dependencycheck.analyzer.AnalyzerService;
|
||||||
import org.owasp.dependencycheck.analyzer.FileTypeAnalyzer;
|
import org.owasp.dependencycheck.analyzer.FileTypeAnalyzer;
|
||||||
import org.owasp.dependencycheck.analyzer.exception.AnalysisException;
|
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.ConnectionFactory;
|
||||||
import org.owasp.dependencycheck.data.nvdcve.CveDB;
|
import org.owasp.dependencycheck.data.nvdcve.CveDB;
|
||||||
import org.owasp.dependencycheck.data.nvdcve.DatabaseException;
|
import org.owasp.dependencycheck.data.nvdcve.DatabaseException;
|
||||||
@@ -41,39 +30,50 @@ import org.owasp.dependencycheck.data.update.UpdateService;
|
|||||||
import org.owasp.dependencycheck.data.update.exception.UpdateException;
|
import org.owasp.dependencycheck.data.update.exception.UpdateException;
|
||||||
import org.owasp.dependencycheck.dependency.Dependency;
|
import org.owasp.dependencycheck.dependency.Dependency;
|
||||||
import org.owasp.dependencycheck.exception.NoDataException;
|
import org.owasp.dependencycheck.exception.NoDataException;
|
||||||
import org.owasp.dependencycheck.utils.FileUtils;
|
|
||||||
import org.owasp.dependencycheck.utils.InvalidSettingException;
|
import org.owasp.dependencycheck.utils.InvalidSettingException;
|
||||||
import org.owasp.dependencycheck.utils.Settings;
|
import org.owasp.dependencycheck.utils.Settings;
|
||||||
|
import org.slf4j.Logger;
|
||||||
|
import org.slf4j.LoggerFactory;
|
||||||
|
|
||||||
|
import java.io.File;
|
||||||
|
import java.io.FileFilter;
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.EnumMap;
|
||||||
|
import java.util.HashSet;
|
||||||
|
import java.util.Iterator;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Set;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Scans files, directories, etc. for Dependencies. Analyzers are loaded and used to process the files found by the
|
* Scans files, directories, etc. for Dependencies. Analyzers are loaded and used to process the files found by the scan, if a
|
||||||
* scan, if a file is encountered and an Analyzer is associated with the file type then the file is turned into a
|
* file is encountered and an Analyzer is associated with the file type then the file is turned into a dependency.
|
||||||
* dependency.
|
|
||||||
*
|
*
|
||||||
* @author Jeremy Long <jeremy.long@owasp.org>
|
* @author Jeremy Long
|
||||||
*/
|
*/
|
||||||
public class Engine {
|
public class Engine implements FileFilter {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The list of dependencies.
|
* The list of dependencies.
|
||||||
*/
|
*/
|
||||||
private List<Dependency> dependencies;
|
private List<Dependency> dependencies = new ArrayList<Dependency>();
|
||||||
/**
|
/**
|
||||||
* A Map of analyzers grouped by Analysis phase.
|
* 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.
|
* 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.
|
* 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.
|
* The Logger for use throughout the class.
|
||||||
*/
|
*/
|
||||||
private static final Logger LOGGER = Logger.getLogger(Engine.class.getName());
|
private static final Logger LOGGER = LoggerFactory.getLogger(Engine.class);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Creates a new Engine.
|
* Creates a new Engine.
|
||||||
@@ -81,32 +81,27 @@ public class Engine {
|
|||||||
* @throws DatabaseException thrown if there is an error connecting to the database
|
* @throws DatabaseException thrown if there is an error connecting to the database
|
||||||
*/
|
*/
|
||||||
public Engine() throws DatabaseException {
|
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.
|
* 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
|
* @throws DatabaseException thrown if there is an error connecting to the database
|
||||||
*/
|
*/
|
||||||
public Engine(ClassLoader serviceClassLoader) throws DatabaseException {
|
protected final void initializeEngine() throws DatabaseException {
|
||||||
this.dependencies = new ArrayList<Dependency>();
|
|
||||||
this.analyzers = new EnumMap<AnalysisPhase, List<Analyzer>>(AnalysisPhase.class);
|
|
||||||
this.fileTypeAnalyzers = new HashSet<FileTypeAnalyzer>();
|
|
||||||
this.serviceClassLoader = serviceClassLoader;
|
|
||||||
|
|
||||||
ConnectionFactory.initialize();
|
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();
|
loadAnalyzers();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -121,7 +116,9 @@ public class Engine {
|
|||||||
* Loads the analyzers specified in the configuration file (or system properties).
|
* Loads the analyzers specified in the configuration file (or system properties).
|
||||||
*/
|
*/
|
||||||
private void loadAnalyzers() {
|
private void loadAnalyzers() {
|
||||||
|
if (!analyzers.isEmpty()) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
for (AnalysisPhase phase : AnalysisPhase.values()) {
|
for (AnalysisPhase phase : AnalysisPhase.values()) {
|
||||||
analyzers.put(phase, new ArrayList<Analyzer>());
|
analyzers.put(phase, new ArrayList<Analyzer>());
|
||||||
}
|
}
|
||||||
@@ -156,217 +153,237 @@ public class Engine {
|
|||||||
return dependencies;
|
return dependencies;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets the dependencies.
|
||||||
|
*
|
||||||
|
* @param dependencies the dependencies
|
||||||
|
*/
|
||||||
public void setDependencies(List<Dependency> dependencies) {
|
public void setDependencies(List<Dependency> dependencies) {
|
||||||
this.dependencies = 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
|
* Scans an array of files or directories. If a directory is specified, it will be scanned recursively. Any dependencies
|
||||||
* dependencies identified are added to the dependency collection.
|
* identified are added to the dependency collection.
|
||||||
*
|
*
|
||||||
|
* @param paths an array of paths to files or directories to be analyzed
|
||||||
|
* @return the list of dependencies scanned
|
||||||
* @since v0.3.2.5
|
* @since v0.3.2.5
|
||||||
*
|
|
||||||
* @param paths an array of paths to files or directories to be analyzed.
|
|
||||||
*/
|
*/
|
||||||
public void scan(String[] paths) {
|
public List<Dependency> scan(String[] paths) {
|
||||||
|
final List<Dependency> deps = new ArrayList<Dependency>();
|
||||||
for (String path : paths) {
|
for (String path : paths) {
|
||||||
final File file = new File(path);
|
final File file = new File(path);
|
||||||
scan(file);
|
final List<Dependency> d = scan(file);
|
||||||
}
|
if (d != null) {
|
||||||
}
|
deps.addAll(d);
|
||||||
|
|
||||||
/**
|
|
||||||
* 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.
|
|
||||||
*/
|
|
||||||
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);
|
|
||||||
}
|
}
|
||||||
|
return deps;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Scans an array of files or directories. If a directory is specified, it will be scanned recursively. Any
|
* Scans a given file or directory. If a directory is specified, it will be scanned recursively. Any dependencies identified
|
||||||
* dependencies identified are added to the dependency collection.
|
* are added to the dependency collection.
|
||||||
*
|
*
|
||||||
* @since v0.3.2.5
|
* @param path the path to a file or directory to be analyzed
|
||||||
|
* @return the list of dependencies scanned
|
||||||
|
*/
|
||||||
|
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.
|
||||||
*
|
*
|
||||||
* @param files an array of paths to files or directories to be analyzed.
|
* @param files an array of paths to files or directories to be analyzed.
|
||||||
*/
|
* @return the list of dependencies
|
||||||
public void scan(File[] files) {
|
|
||||||
for (File file : files) {
|
|
||||||
scan(file);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 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
|
* @since v0.3.2.5
|
||||||
*
|
|
||||||
* @param files a set of paths to files or directories to be analyzed.
|
|
||||||
*/
|
*/
|
||||||
public void scan(Set<File> files) {
|
public List<Dependency> scan(File[] files) {
|
||||||
|
final List<Dependency> deps = new ArrayList<Dependency>();
|
||||||
for (File file : files) {
|
for (File file : files) {
|
||||||
scan(file);
|
final List<Dependency> d = scan(file);
|
||||||
}
|
if (d != null) {
|
||||||
}
|
deps.addAll(d);
|
||||||
|
|
||||||
/**
|
|
||||||
* 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.
|
|
||||||
*/
|
|
||||||
public void scan(List<File> files) {
|
|
||||||
for (File file : files) {
|
|
||||||
scan(file);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 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.
|
|
||||||
*
|
|
||||||
* @since v0.3.2.4
|
|
||||||
*
|
|
||||||
* @param file the path to a file or directory to be analyzed.
|
|
||||||
*/
|
|
||||||
public void scan(File file) {
|
|
||||||
if (file.exists()) {
|
|
||||||
if (file.isDirectory()) {
|
|
||||||
scanDirectory(file);
|
|
||||||
} else {
|
|
||||||
scanFile(file);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
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.
|
||||||
|
*
|
||||||
|
* @param files a set of paths to files or directories to be analyzed
|
||||||
|
* @return the list of dependencies scanned
|
||||||
|
* @since v0.3.2.5
|
||||||
|
*/
|
||||||
|
public List<Dependency> scan(Set<File> files) {
|
||||||
|
final List<Dependency> deps = new ArrayList<Dependency>();
|
||||||
|
for (File file : files) {
|
||||||
|
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.
|
||||||
|
*
|
||||||
|
* @param files a set of paths to files or directories to be analyzed
|
||||||
|
* @return the list of dependencies scanned
|
||||||
|
* @since v0.3.2.5
|
||||||
|
*/
|
||||||
|
public List<Dependency> scan(List<File> files) {
|
||||||
|
final List<Dependency> deps = new ArrayList<Dependency>();
|
||||||
|
for (File file : files) {
|
||||||
|
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
|
||||||
|
*/
|
||||||
|
public List<Dependency> scan(File file) {
|
||||||
|
if (file.exists()) {
|
||||||
|
if (file.isDirectory()) {
|
||||||
|
return scanDirectory(file);
|
||||||
|
} else {
|
||||||
|
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.
|
* 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 File[] files = dir.listFiles();
|
||||||
|
final List<Dependency> deps = new ArrayList<Dependency>();
|
||||||
if (files != null) {
|
if (files != null) {
|
||||||
for (File f : files) {
|
for (File f : files) {
|
||||||
if (f.isDirectory()) {
|
if (f.isDirectory()) {
|
||||||
scanDirectory(f);
|
final List<Dependency> d = scanDirectory(f);
|
||||||
|
if (d != null) {
|
||||||
|
deps.addAll(d);
|
||||||
|
}
|
||||||
} else {
|
} 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.
|
* 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()) {
|
Dependency dependency = null;
|
||||||
final String msg = String.format("Path passed to scanFile(File) is not a file: %s. Skipping the file.", file.toString());
|
if (file.isFile()) {
|
||||||
LOGGER.log(Level.FINE, msg);
|
if (accept(file)) {
|
||||||
return;
|
dependency = new Dependency(file);
|
||||||
}
|
|
||||||
final String fileName = file.getName();
|
|
||||||
final String extension = FileUtils.getFileExtension(fileName);
|
|
||||||
if (extension != null) {
|
|
||||||
if (supportsExtension(extension)) {
|
|
||||||
final Dependency dependency = new Dependency(file);
|
|
||||||
dependencies.add(dependency);
|
dependencies.add(dependency);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
final String msg = String.format("No file extension found on file '%s'. The file was not analyzed.",
|
LOGGER.debug("Path passed to scanFile(File) is not a file: {}. Skipping the file.", file);
|
||||||
file.toString());
|
|
||||||
LOGGER.log(Level.FINEST, msg);
|
|
||||||
}
|
}
|
||||||
|
return dependency;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Runs the analyzers against all of the dependencies.
|
* Runs the analyzers against all of the dependencies. Since the mutable dependencies list is exposed via
|
||||||
|
* {@link #getDependencies()}, this method iterates over a copy of the dependencies list. Thus, the potential for
|
||||||
|
* {@link java.util.ConcurrentModificationException}s is avoided, and analyzers may safely add or remove entries from the
|
||||||
|
* dependencies list.
|
||||||
*/
|
*/
|
||||||
public void analyzeDependencies() {
|
public void analyzeDependencies() {
|
||||||
|
boolean autoUpdate = true;
|
||||||
|
try {
|
||||||
|
autoUpdate = Settings.getBoolean(Settings.KEYS.AUTO_UPDATE);
|
||||||
|
} catch (InvalidSettingException ex) {
|
||||||
|
LOGGER.debug("Invalid setting for auto-update; using true.");
|
||||||
|
}
|
||||||
|
if (autoUpdate) {
|
||||||
|
doUpdates();
|
||||||
|
}
|
||||||
|
|
||||||
//need to ensure that data exists
|
//need to ensure that data exists
|
||||||
try {
|
try {
|
||||||
ensureDataExists();
|
ensureDataExists();
|
||||||
} catch (NoDataException ex) {
|
} catch (NoDataException ex) {
|
||||||
final String msg = String.format("%s%n%nUnable to continue dependency-check analysis.", ex.getMessage());
|
LOGGER.error("{}\n\nUnable to continue dependency-check analysis.", ex.getMessage());
|
||||||
LOGGER.log(Level.SEVERE, msg);
|
LOGGER.debug("", ex);
|
||||||
LOGGER.log(Level.FINE, null, ex);
|
|
||||||
return;
|
return;
|
||||||
} catch (DatabaseException ex) {
|
} catch (DatabaseException ex) {
|
||||||
final String msg = String.format("%s%n%nUnable to continue dependency-check analysis.", ex.getMessage());
|
LOGGER.error("{}\n\nUnable to continue dependency-check analysis.", ex.getMessage());
|
||||||
LOGGER.log(Level.SEVERE, msg);
|
LOGGER.debug("", ex);
|
||||||
LOGGER.log(Level.FINE, null, ex);
|
|
||||||
return;
|
return;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
final String logHeader = String.format("%n"
|
LOGGER.debug("\n----------------------------------------------------\nBEGIN ANALYSIS\n----------------------------------------------------");
|
||||||
+ "----------------------------------------------------%n"
|
LOGGER.info("Analysis Starting");
|
||||||
+ "BEGIN ANALYSIS%n"
|
|
||||||
+ "----------------------------------------------------");
|
|
||||||
LOGGER.log(Level.FINE, logHeader);
|
|
||||||
LOGGER.log(Level.INFO, "Analysis Starting");
|
|
||||||
|
|
||||||
// analysis phases
|
// analysis phases
|
||||||
for (AnalysisPhase phase : AnalysisPhase.values()) {
|
for (AnalysisPhase phase : AnalysisPhase.values()) {
|
||||||
final List<Analyzer> analyzerList = analyzers.get(phase);
|
final List<Analyzer> analyzerList = analyzers.get(phase);
|
||||||
|
|
||||||
for (Analyzer a : analyzerList) {
|
for (Analyzer a : analyzerList) {
|
||||||
initializeAnalyzer(a);
|
a = initializeAnalyzer(a);
|
||||||
|
|
||||||
/* need to create a copy of the collection because some of the
|
/* need to create a copy of the collection because some of the
|
||||||
* analyzers may modify it. This prevents ConcurrentModificationExceptions.
|
* analyzers may modify it. This prevents ConcurrentModificationExceptions.
|
||||||
* This is okay for adds/deletes because it happens per analyzer.
|
* This is okay for adds/deletes because it happens per analyzer.
|
||||||
*/
|
*/
|
||||||
final String msg = String.format("Begin Analyzer '%s'", a.getName());
|
LOGGER.debug("Begin Analyzer '{}'", a.getName());
|
||||||
LOGGER.log(Level.FINE, msg);
|
|
||||||
final Set<Dependency> dependencySet = new HashSet<Dependency>();
|
final Set<Dependency> dependencySet = new HashSet<Dependency>();
|
||||||
dependencySet.addAll(dependencies);
|
dependencySet.addAll(dependencies);
|
||||||
for (Dependency d : dependencySet) {
|
for (Dependency d : dependencySet) {
|
||||||
boolean shouldAnalyze = true;
|
boolean shouldAnalyze = true;
|
||||||
if (a instanceof FileTypeAnalyzer) {
|
if (a instanceof FileTypeAnalyzer) {
|
||||||
final FileTypeAnalyzer fAnalyzer = (FileTypeAnalyzer) a;
|
final FileTypeAnalyzer fAnalyzer = (FileTypeAnalyzer) a;
|
||||||
shouldAnalyze = fAnalyzer.supportsExtension(d.getFileExtension());
|
shouldAnalyze = fAnalyzer.accept(d.getActualFile());
|
||||||
}
|
}
|
||||||
if (shouldAnalyze) {
|
if (shouldAnalyze) {
|
||||||
final String msgFile = String.format("Begin Analysis of '%s'", d.getActualFilePath());
|
LOGGER.debug("Begin Analysis of '{}'", d.getActualFilePath());
|
||||||
LOGGER.log(Level.FINE, msgFile);
|
|
||||||
try {
|
try {
|
||||||
a.analyze(d, this);
|
a.analyze(d, this);
|
||||||
} catch (AnalysisException ex) {
|
} catch (AnalysisException ex) {
|
||||||
final String exMsg = String.format("An error occurred while analyzing '%s'.", d.getActualFilePath());
|
LOGGER.warn("An error occurred while analyzing '{}'.", d.getActualFilePath());
|
||||||
LOGGER.log(Level.WARNING, exMsg);
|
LOGGER.debug("", ex);
|
||||||
LOGGER.log(Level.FINE, "", ex);
|
|
||||||
} catch (Throwable ex) {
|
} catch (Throwable ex) {
|
||||||
final String axMsg = String.format("An unexpected error occurred during analysis of '%s'", d.getActualFilePath());
|
|
||||||
//final AnalysisException ax = new AnalysisException(axMsg, ex);
|
//final AnalysisException ax = new AnalysisException(axMsg, ex);
|
||||||
LOGGER.log(Level.WARNING, axMsg);
|
LOGGER.warn("An unexpected error occurred during analysis of '{}'", d.getActualFilePath());
|
||||||
LOGGER.log(Level.FINE, "", ex);
|
LOGGER.debug("", ex);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -380,34 +397,30 @@ public class Engine {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
final String logFooter = String.format("%n"
|
LOGGER.debug("\n----------------------------------------------------\nEND ANALYSIS\n----------------------------------------------------");
|
||||||
+ "----------------------------------------------------%n"
|
LOGGER.info("Analysis Complete");
|
||||||
+ "END ANALYSIS%n"
|
|
||||||
+ "----------------------------------------------------");
|
|
||||||
LOGGER.log(Level.FINE, logFooter);
|
|
||||||
LOGGER.log(Level.INFO, "Analysis Complete");
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Initializes the given analyzer.
|
* Initializes the given analyzer.
|
||||||
*
|
*
|
||||||
* @param analyzer the analyzer to initialize
|
* @param analyzer the analyzer to initialize
|
||||||
|
* @return the initialized analyzer
|
||||||
*/
|
*/
|
||||||
private void initializeAnalyzer(Analyzer analyzer) {
|
protected Analyzer initializeAnalyzer(Analyzer analyzer) {
|
||||||
try {
|
try {
|
||||||
final String msg = String.format("Initializing %s", analyzer.getName());
|
LOGGER.debug("Initializing {}", analyzer.getName());
|
||||||
LOGGER.log(Level.FINE, msg);
|
|
||||||
analyzer.initialize();
|
analyzer.initialize();
|
||||||
} catch (Throwable ex) {
|
} catch (Throwable ex) {
|
||||||
final String msg = String.format("Exception occurred initializing %s.", analyzer.getName());
|
LOGGER.error("Exception occurred initializing {}.", analyzer.getName());
|
||||||
LOGGER.log(Level.SEVERE, msg);
|
LOGGER.debug("", ex);
|
||||||
LOGGER.log(Level.FINE, null, ex);
|
|
||||||
try {
|
try {
|
||||||
analyzer.close();
|
analyzer.close();
|
||||||
} catch (Throwable ex1) {
|
} catch (Throwable ex1) {
|
||||||
LOGGER.log(Level.FINEST, null, ex1);
|
LOGGER.trace("", ex1);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
return analyzer;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -415,20 +428,20 @@ public class Engine {
|
|||||||
*
|
*
|
||||||
* @param analyzer the analyzer to close
|
* @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.debug("Closing Analyzer '{}'", analyzer.getName());
|
||||||
LOGGER.log(Level.FINE, msg);
|
|
||||||
try {
|
try {
|
||||||
analyzer.close();
|
analyzer.close();
|
||||||
} catch (Throwable ex) {
|
} catch (Throwable ex) {
|
||||||
LOGGER.log(Level.FINEST, null, ex);
|
LOGGER.trace("", ex);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Cycles through the cached web data sources and calls update on all of them.
|
* Cycles through the cached web data sources and calls update on all of them.
|
||||||
*/
|
*/
|
||||||
private void doUpdates() {
|
public void doUpdates() {
|
||||||
|
LOGGER.info("Checking for updates");
|
||||||
final UpdateService service = new UpdateService(serviceClassLoader);
|
final UpdateService service = new UpdateService(serviceClassLoader);
|
||||||
final Iterator<CachedWebDataSource> iterator = service.getDataSources();
|
final Iterator<CachedWebDataSource> iterator = service.getDataSources();
|
||||||
while (iterator.hasNext()) {
|
while (iterator.hasNext()) {
|
||||||
@@ -436,12 +449,12 @@ public class Engine {
|
|||||||
try {
|
try {
|
||||||
source.update();
|
source.update();
|
||||||
} catch (UpdateException ex) {
|
} catch (UpdateException ex) {
|
||||||
LOGGER.log(Level.WARNING,
|
LOGGER.warn(
|
||||||
"Unable to update Cached Web DataSource, using local data instead. Results may not include recent vulnerabilities.");
|
"Unable to update Cached Web DataSource, using local data instead. Results may not include recent vulnerabilities.");
|
||||||
LOGGER.log(Level.FINE,
|
LOGGER.debug("Unable to update details for {}", source.getClass().getName(), ex);
|
||||||
String.format("Unable to update details for %s", source.getClass().getName()), ex);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
LOGGER.info("Check for updates complete");
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -461,22 +474,31 @@ public class Engine {
|
|||||||
/**
|
/**
|
||||||
* Checks all analyzers to see if an extension is supported.
|
* Checks all analyzers to see if an extension is supported.
|
||||||
*
|
*
|
||||||
* @param ext a file extension
|
* @param file a file extension
|
||||||
* @return true or false depending on whether or not the file extension is supported
|
* @return true or false depending on whether or not the file extension is supported
|
||||||
*/
|
*/
|
||||||
public boolean supportsExtension(String ext) {
|
public boolean accept(File file) {
|
||||||
if (ext == null) {
|
if (file == null) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
boolean scan = false;
|
boolean scan = false;
|
||||||
for (FileTypeAnalyzer a : this.fileTypeAnalyzers) {
|
for (FileTypeAnalyzer a : this.fileTypeAnalyzers) {
|
||||||
/* note, we can't break early on this loop as the analyzers need to know if
|
/* note, we can't break early on this loop as the analyzers need to know if
|
||||||
they have files to work on prior to initialization */
|
they have files to work on prior to initialization */
|
||||||
scan |= a.supportsExtension(ext);
|
scan |= a.accept(file);
|
||||||
}
|
}
|
||||||
return scan;
|
return scan;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the set of file type analyzers.
|
||||||
|
*
|
||||||
|
* @return the set of file type analyzers
|
||||||
|
*/
|
||||||
|
public Set<FileTypeAnalyzer> getFileTypeAnalyzers() {
|
||||||
|
return this.fileTypeAnalyzers;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Checks the CPE Index to ensure documents exists. If none exist a NoDataException is thrown.
|
* Checks the CPE Index to ensure documents exists. If none exist a NoDataException is thrown.
|
||||||
*
|
*
|
||||||
@@ -484,22 +506,16 @@ public class Engine {
|
|||||||
* @throws DatabaseException thrown if there is an exception opening the database
|
* @throws DatabaseException thrown if there is an exception opening the database
|
||||||
*/
|
*/
|
||||||
private void ensureDataExists() throws NoDataException, DatabaseException {
|
private void ensureDataExists() throws NoDataException, DatabaseException {
|
||||||
final CpeMemoryIndex cpe = CpeMemoryIndex.getInstance();
|
|
||||||
final CveDB cve = new CveDB();
|
final CveDB cve = new CveDB();
|
||||||
|
|
||||||
try {
|
try {
|
||||||
cve.open();
|
cve.open();
|
||||||
cpe.open(cve);
|
if (!cve.dataExists()) {
|
||||||
} catch (IndexException ex) {
|
throw new NoDataException("No documents exist");
|
||||||
throw new NoDataException(ex.getMessage(), ex);
|
}
|
||||||
} catch (DatabaseException ex) {
|
} catch (DatabaseException ex) {
|
||||||
throw new NoDataException(ex.getMessage(), ex);
|
throw new NoDataException(ex.getMessage(), ex);
|
||||||
} finally {
|
} finally {
|
||||||
cve.close();
|
cve.close();
|
||||||
}
|
}
|
||||||
if (cpe.numDocs() <= 0) {
|
|
||||||
cpe.close();
|
|
||||||
throw new NoDataException("No documents exist");
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -20,8 +20,6 @@ package org.owasp.dependencycheck.agent;
|
|||||||
import java.io.File;
|
import java.io.File;
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.logging.Level;
|
|
||||||
import java.util.logging.Logger;
|
|
||||||
import org.owasp.dependencycheck.Engine;
|
import org.owasp.dependencycheck.Engine;
|
||||||
import org.owasp.dependencycheck.data.nvdcve.CveDB;
|
import org.owasp.dependencycheck.data.nvdcve.CveDB;
|
||||||
import org.owasp.dependencycheck.data.nvdcve.DatabaseException;
|
import org.owasp.dependencycheck.data.nvdcve.DatabaseException;
|
||||||
@@ -32,12 +30,14 @@ import org.owasp.dependencycheck.dependency.Vulnerability;
|
|||||||
import org.owasp.dependencycheck.exception.ScanAgentException;
|
import org.owasp.dependencycheck.exception.ScanAgentException;
|
||||||
import org.owasp.dependencycheck.reporting.ReportGenerator;
|
import org.owasp.dependencycheck.reporting.ReportGenerator;
|
||||||
import org.owasp.dependencycheck.utils.Settings;
|
import org.owasp.dependencycheck.utils.Settings;
|
||||||
|
import org.slf4j.Logger;
|
||||||
|
import org.slf4j.LoggerFactory;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* This class provides a way to easily conduct a scan solely based on existing evidence metadata rather than collecting
|
* This class provides a way to easily conduct a scan solely based on existing evidence metadata rather than collecting evidence
|
||||||
* evidence from the files themselves. This class is based on the Ant task and Maven plugin with the exception that it
|
* from the files themselves. This class is based on the Ant task and Maven plugin with the exception that it takes a list of
|
||||||
* takes a list of dependencies that can be programmatically added from data in a spreadsheet, database or some other
|
* dependencies that can be programmatically added from data in a spreadsheet, database or some other datasource and conduct a
|
||||||
* datasource and conduct a scan based on this pre-defined evidence.
|
* scan based on this pre-defined evidence.
|
||||||
*
|
*
|
||||||
* <h2>Example:</h2>
|
* <h2>Example:</h2>
|
||||||
* <pre>
|
* <pre>
|
||||||
@@ -67,7 +67,7 @@ public class DependencyCheckScanAgent {
|
|||||||
/**
|
/**
|
||||||
* Logger for use throughout the class.
|
* Logger for use throughout the class.
|
||||||
*/
|
*/
|
||||||
private static final Logger LOGGER = Logger.getLogger(DependencyCheckScanAgent.class.getName());
|
private static final Logger LOGGER = LoggerFactory.getLogger(DependencyCheckScanAgent.class);
|
||||||
/**
|
/**
|
||||||
* The application name for the report.
|
* The application name for the report.
|
||||||
*/
|
*/
|
||||||
@@ -161,9 +161,9 @@ public class DependencyCheckScanAgent {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Specifies if the build should be failed if a CVSS score above a specified level is identified. The default is 11
|
* Specifies if the build should be failed if a CVSS score above a specified level is identified. The default is 11 which
|
||||||
* which means since the CVSS scores are 0-10, by default the build will never fail and the CVSS score is set to 11.
|
* means since the CVSS scores are 0-10, by default the build will never fail and the CVSS score is set to 11. The valid range
|
||||||
* The valid range for the fail build on CVSS is 0 to 11, where anything above 10 will not cause the build to fail.
|
* for the fail build on CVSS is 0 to 11, where anything above 10 will not cause the build to fail.
|
||||||
*/
|
*/
|
||||||
private float failBuildOnCVSS = 11;
|
private float failBuildOnCVSS = 11;
|
||||||
|
|
||||||
@@ -186,8 +186,8 @@ public class DependencyCheckScanAgent {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Sets whether auto-updating of the NVD CVE/CPE data is enabled. It is not recommended that this be turned to
|
* Sets whether auto-updating of the NVD CVE/CPE data is enabled. It is not recommended that this be turned to false. Default
|
||||||
* false. Default is true.
|
* is true.
|
||||||
*/
|
*/
|
||||||
private boolean autoUpdate = true;
|
private boolean autoUpdate = true;
|
||||||
|
|
||||||
@@ -210,8 +210,31 @@ public class DependencyCheckScanAgent {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The report format to be generated (HTML, XML, VULN, ALL). This configuration option has no affect if using this
|
* flag indicating whether or not to generate a report of findings.
|
||||||
* within the Site plugin unless the externalReport is set to true. Default is HTML.
|
*/
|
||||||
|
private boolean generateReport = true;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the value of generateReport.
|
||||||
|
*
|
||||||
|
* @return the value of generateReport
|
||||||
|
*/
|
||||||
|
public boolean isGenerateReport() {
|
||||||
|
return generateReport;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Set the value of generateReport.
|
||||||
|
*
|
||||||
|
* @param generateReport new value of generateReport
|
||||||
|
*/
|
||||||
|
public void setGenerateReport(boolean generateReport) {
|
||||||
|
this.generateReport = generateReport;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The report format to be generated (HTML, XML, VULN, ALL). This configuration option has no affect if using this within the
|
||||||
|
* Site plugin unless the externalReport is set to true. Default is HTML.
|
||||||
*/
|
*/
|
||||||
private ReportGenerator.Format reportFormat = ReportGenerator.Format.HTML;
|
private ReportGenerator.Format reportFormat = ReportGenerator.Format.HTML;
|
||||||
|
|
||||||
@@ -440,6 +463,52 @@ public class DependencyCheckScanAgent {
|
|||||||
this.showSummary = showSummary;
|
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.
|
* Whether or not the nexus analyzer is enabled.
|
||||||
*/
|
*/
|
||||||
@@ -625,8 +694,8 @@ public class DependencyCheckScanAgent {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Additional ZIP File extensions to add analyze. This should be a comma-separated list of file extensions to treat
|
* Additional ZIP File extensions to add analyze. This should be a comma-separated list of file extensions to treat like ZIP
|
||||||
* like ZIP files.
|
* files.
|
||||||
*/
|
*/
|
||||||
private String zipExtensions;
|
private String zipExtensions;
|
||||||
|
|
||||||
@@ -767,8 +836,7 @@ public class DependencyCheckScanAgent {
|
|||||||
* Executes the Dependency-Check on the dependent libraries.
|
* Executes the Dependency-Check on the dependent libraries.
|
||||||
*
|
*
|
||||||
* @return the Engine used to scan the dependencies.
|
* @return the Engine used to scan the dependencies.
|
||||||
* @throws org.owasp.dependencycheck.data.nvdcve.DatabaseException thrown if there is an exception connecting to the
|
* @throws org.owasp.dependencycheck.data.nvdcve.DatabaseException thrown if there is an exception connecting to the database
|
||||||
* database
|
|
||||||
*/
|
*/
|
||||||
private Engine executeDependencyCheck() throws DatabaseException {
|
private Engine executeDependencyCheck() throws DatabaseException {
|
||||||
populateSettings();
|
populateSettings();
|
||||||
@@ -793,7 +861,7 @@ public class DependencyCheckScanAgent {
|
|||||||
cve.open();
|
cve.open();
|
||||||
prop = cve.getDatabaseProperties();
|
prop = cve.getDatabaseProperties();
|
||||||
} catch (DatabaseException ex) {
|
} catch (DatabaseException ex) {
|
||||||
LOGGER.log(Level.FINE, "Unable to retrieve DB Properties", ex);
|
LOGGER.debug("Unable to retrieve DB Properties", ex);
|
||||||
} finally {
|
} finally {
|
||||||
if (cve != null) {
|
if (cve != null) {
|
||||||
cve.close();
|
cve.close();
|
||||||
@@ -803,19 +871,19 @@ public class DependencyCheckScanAgent {
|
|||||||
try {
|
try {
|
||||||
r.generateReports(outDirectory.getCanonicalPath(), this.reportFormat.name());
|
r.generateReports(outDirectory.getCanonicalPath(), this.reportFormat.name());
|
||||||
} catch (IOException ex) {
|
} catch (IOException ex) {
|
||||||
LOGGER.log(Level.SEVERE,
|
LOGGER.error(
|
||||||
"Unexpected exception occurred during analysis; please see the verbose error log for more details.");
|
"Unexpected exception occurred during analysis; please see the verbose error log for more details.");
|
||||||
LOGGER.log(Level.FINE, null, ex);
|
LOGGER.debug("", ex);
|
||||||
} catch (Throwable ex) {
|
} catch (Throwable ex) {
|
||||||
LOGGER.log(Level.SEVERE,
|
LOGGER.error(
|
||||||
"Unexpected exception occurred during analysis; please see the verbose error log for more details.");
|
"Unexpected exception occurred during analysis; please see the verbose error log for more details.");
|
||||||
LOGGER.log(Level.FINE, null, ex);
|
LOGGER.debug("", ex);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Takes the properties supplied and updates the dependency-check settings. Additionally, this sets the system
|
* Takes the properties supplied and updates the dependency-check settings. Additionally, this sets the system properties
|
||||||
* properties required to change the proxy server, port, and connection timeout.
|
* required to change the proxy server, port, and connection timeout.
|
||||||
*/
|
*/
|
||||||
private void populateSettings() {
|
private void populateSettings() {
|
||||||
Settings.initialize();
|
Settings.initialize();
|
||||||
@@ -849,6 +917,10 @@ public class DependencyCheckScanAgent {
|
|||||||
if (suppressionFile != null && !suppressionFile.isEmpty()) {
|
if (suppressionFile != null && !suppressionFile.isEmpty()) {
|
||||||
Settings.setString(Settings.KEYS.SUPPRESSION_FILE, suppressionFile);
|
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);
|
Settings.setBoolean(Settings.KEYS.ANALYZER_NEXUS_ENABLED, nexusAnalyzerEnabled);
|
||||||
if (nexusUrl != null && !nexusUrl.isEmpty()) {
|
if (nexusUrl != null && !nexusUrl.isEmpty()) {
|
||||||
Settings.setString(Settings.KEYS.ANALYZER_NEXUS_URL, nexusUrl);
|
Settings.setString(Settings.KEYS.ANALYZER_NEXUS_URL, nexusUrl);
|
||||||
@@ -892,14 +964,16 @@ public class DependencyCheckScanAgent {
|
|||||||
/**
|
/**
|
||||||
* Executes the dependency-check and generates the report.
|
* Executes the dependency-check and generates the report.
|
||||||
*
|
*
|
||||||
* @throws org.owasp.dependencycheck.exception.ScanAgentException thrown if there is an exception executing the
|
* @return a reference to the engine used to perform the scan.
|
||||||
* scan.
|
* @throws org.owasp.dependencycheck.exception.ScanAgentException thrown if there is an exception executing the scan.
|
||||||
*/
|
*/
|
||||||
public void execute() throws ScanAgentException {
|
public Engine execute() throws ScanAgentException {
|
||||||
Engine engine = null;
|
Engine engine = null;
|
||||||
try {
|
try {
|
||||||
engine = executeDependencyCheck();
|
engine = executeDependencyCheck();
|
||||||
generateExternalReports(engine, new File(this.reportOutputDirectory));
|
if (this.generateReport) {
|
||||||
|
generateExternalReports(engine, new File(this.reportOutputDirectory));
|
||||||
|
}
|
||||||
if (this.showSummary) {
|
if (this.showSummary) {
|
||||||
showSummary(engine.getDependencies());
|
showSummary(engine.getDependencies());
|
||||||
}
|
}
|
||||||
@@ -907,15 +981,16 @@ public class DependencyCheckScanAgent {
|
|||||||
checkForFailure(engine.getDependencies());
|
checkForFailure(engine.getDependencies());
|
||||||
}
|
}
|
||||||
} catch (DatabaseException ex) {
|
} catch (DatabaseException ex) {
|
||||||
LOGGER.log(Level.SEVERE,
|
LOGGER.error(
|
||||||
"Unable to connect to the dependency-check database; analysis has stopped");
|
"Unable to connect to the dependency-check database; analysis has stopped");
|
||||||
LOGGER.log(Level.FINE, "", ex);
|
LOGGER.debug("", ex);
|
||||||
} finally {
|
} finally {
|
||||||
Settings.cleanup(true);
|
Settings.cleanup(true);
|
||||||
if (engine != null) {
|
if (engine != null) {
|
||||||
engine.cleanup();
|
engine.cleanup();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
return engine;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -923,8 +998,7 @@ public class DependencyCheckScanAgent {
|
|||||||
* configuration.
|
* configuration.
|
||||||
*
|
*
|
||||||
* @param dependencies the list of dependency objects
|
* @param dependencies the list of dependency objects
|
||||||
* @throws org.owasp.dependencycheck.exception.ScanAgentException thrown if there is an exception executing the
|
* @throws org.owasp.dependencycheck.exception.ScanAgentException thrown if there is an exception executing the scan.
|
||||||
* scan.
|
|
||||||
*/
|
*/
|
||||||
private void checkForFailure(List<Dependency> dependencies) throws ScanAgentException {
|
private void checkForFailure(List<Dependency> dependencies) throws ScanAgentException {
|
||||||
final StringBuilder ids = new StringBuilder();
|
final StringBuilder ids = new StringBuilder();
|
||||||
@@ -984,10 +1058,9 @@ public class DependencyCheckScanAgent {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (summary.length() > 0) {
|
if (summary.length() > 0) {
|
||||||
final String msg = String.format("%n%n"
|
LOGGER.warn("\n\nOne or more dependencies were identified with known vulnerabilities:\n\n{}\n\n"
|
||||||
+ "One or more dependencies were identified with known vulnerabilities:%n%n%s"
|
+ "See the dependency-check report for more details.\n\n",
|
||||||
+ "%n%nSee the dependency-check report for more details.%n%n", summary.toString());
|
summary.toString());
|
||||||
LOGGER.log(Level.WARNING, msg);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,13 +1,6 @@
|
|||||||
/**
|
/**
|
||||||
* <html>
|
* The agent package holds an agent API that can be used by other applications that have information about dependencies; but would
|
||||||
* <head>
|
* rather implement something in their code directly rather then spawn a process to run the entire dependency-check engine. This
|
||||||
* <title>org.owasp.dependencycheck.agent</title>
|
* basically provides programmatic access to running a scan.
|
||||||
* </head>
|
|
||||||
* <body>
|
|
||||||
* The agent package holds an agent API that can be used by other applications that have information about dependencies;
|
|
||||||
* but would rather implement something in their code directly rather then spawn a process to run the entire
|
|
||||||
* dependency-check engine. This basically provides programmatic access to running a scan.
|
|
||||||
* </body>
|
|
||||||
* </html>
|
|
||||||
*/
|
*/
|
||||||
package org.owasp.dependencycheck.agent;
|
package org.owasp.dependencycheck.agent;
|
||||||
|
|||||||
@@ -19,7 +19,7 @@ package org.owasp.dependencycheck.analyzer;
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
*
|
*
|
||||||
* @author Jeremy Long <jeremy.long@owasp.org>
|
* @author Jeremy Long
|
||||||
*/
|
*/
|
||||||
public abstract class AbstractAnalyzer implements Analyzer {
|
public abstract class AbstractAnalyzer implements Analyzer {
|
||||||
|
|
||||||
|
|||||||
@@ -17,40 +17,33 @@
|
|||||||
*/
|
*/
|
||||||
package org.owasp.dependencycheck.analyzer;
|
package org.owasp.dependencycheck.analyzer;
|
||||||
|
|
||||||
import java.util.Collections;
|
|
||||||
import java.util.HashSet;
|
|
||||||
import java.util.Set;
|
|
||||||
import java.util.logging.Level;
|
|
||||||
import java.util.logging.Logger;
|
|
||||||
import org.owasp.dependencycheck.Engine;
|
import org.owasp.dependencycheck.Engine;
|
||||||
import org.owasp.dependencycheck.analyzer.exception.AnalysisException;
|
import org.owasp.dependencycheck.analyzer.exception.AnalysisException;
|
||||||
import org.owasp.dependencycheck.dependency.Dependency;
|
import org.owasp.dependencycheck.dependency.Dependency;
|
||||||
import org.owasp.dependencycheck.utils.InvalidSettingException;
|
import org.owasp.dependencycheck.utils.InvalidSettingException;
|
||||||
import org.owasp.dependencycheck.utils.Settings;
|
import org.owasp.dependencycheck.utils.Settings;
|
||||||
|
import org.slf4j.Logger;
|
||||||
|
import org.slf4j.LoggerFactory;
|
||||||
|
|
||||||
|
import java.io.File;
|
||||||
|
import java.io.FileFilter;
|
||||||
|
import java.util.Collections;
|
||||||
|
import java.util.HashSet;
|
||||||
|
import java.util.Set;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The base FileTypeAnalyzer that all analyzers that have specific file types they analyze should extend.
|
* The base FileTypeAnalyzer that all analyzers that have specific file types they analyze should extend.
|
||||||
*
|
*
|
||||||
* @author Jeremy Long <jeremy.long@owasp.org>
|
* @author Jeremy Long
|
||||||
*/
|
*/
|
||||||
public abstract class AbstractFileTypeAnalyzer extends AbstractAnalyzer implements FileTypeAnalyzer {
|
public abstract class AbstractFileTypeAnalyzer extends AbstractAnalyzer implements FileTypeAnalyzer {
|
||||||
|
|
||||||
//<editor-fold defaultstate="collapsed" desc="Constructor">
|
//<editor-fold defaultstate="collapsed" desc="Constructor">
|
||||||
/**
|
/**
|
||||||
* Base constructor that all children must call. This checks the configuration to determine if the analyzer is
|
* Base constructor that all children must call. This checks the configuration to determine if the analyzer is enabled.
|
||||||
* enabled.
|
|
||||||
*/
|
*/
|
||||||
public AbstractFileTypeAnalyzer() {
|
public AbstractFileTypeAnalyzer() {
|
||||||
final String key = getAnalyzerEnabledSettingKey();
|
reset();
|
||||||
try {
|
|
||||||
enabled = Settings.getBoolean(key, true);
|
|
||||||
} catch (InvalidSettingException ex) {
|
|
||||||
String msg = String.format("Invalid setting for property '%s'", key);
|
|
||||||
LOGGER.log(Level.WARNING, msg);
|
|
||||||
LOGGER.log(Level.FINE, "", ex);
|
|
||||||
msg = String.format("%s has been disabled", getName());
|
|
||||||
LOGGER.log(Level.WARNING, msg);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
//</editor-fold>
|
//</editor-fold>
|
||||||
|
|
||||||
@@ -58,7 +51,7 @@ public abstract class AbstractFileTypeAnalyzer extends AbstractAnalyzer implemen
|
|||||||
/**
|
/**
|
||||||
* The logger.
|
* The logger.
|
||||||
*/
|
*/
|
||||||
private static final Logger LOGGER = Logger.getLogger(AbstractFileTypeAnalyzer.class.getName());
|
private static final Logger LOGGER = LoggerFactory.getLogger(AbstractFileTypeAnalyzer.class);
|
||||||
/**
|
/**
|
||||||
* Whether the file type analyzer detected any files it needs to analyze.
|
* Whether the file type analyzer detected any files it needs to analyze.
|
||||||
*/
|
*/
|
||||||
@@ -109,19 +102,16 @@ public abstract class AbstractFileTypeAnalyzer extends AbstractAnalyzer implemen
|
|||||||
//<editor-fold defaultstate="collapsed" desc="Abstract methods children must implement">
|
//<editor-fold defaultstate="collapsed" desc="Abstract methods children must implement">
|
||||||
/**
|
/**
|
||||||
* <p>
|
* <p>
|
||||||
* Returns a list of supported file extensions. An example would be an analyzer that inspected java jar files. The
|
* Returns the {@link java.io.FileFilter} used to determine which files are to be analyzed. An example would be an analyzer
|
||||||
* getSupportedExtensions function would return a set with a single element "jar".</p>
|
* that inspected Java jar files. Implementors may use {@link org.owasp.dependencycheck.utils.FileFilterBuilder}.</p>
|
||||||
*
|
*
|
||||||
|
* @return the file filter used to determine which files are to be analyzed
|
||||||
|
* <p/>
|
||||||
* <p>
|
* <p>
|
||||||
* <b>Note:</b> when implementing this the extensions returned MUST be lowercase.</p>
|
* If the analyzer returns null it will not cause additional files to be analyzed, but will be executed against every file
|
||||||
*
|
* loaded.</p>
|
||||||
* @return The file extensions supported by this analyzer.
|
|
||||||
*
|
|
||||||
* <p>
|
|
||||||
* If the analyzer returns null it will not cause additional files to be analyzed but will be executed against every
|
|
||||||
* file loaded</p>
|
|
||||||
*/
|
*/
|
||||||
protected abstract Set<String> getSupportedExtensions();
|
protected abstract FileFilter getFileFilter();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Initializes the file type analyzer.
|
* Initializes the file type analyzer.
|
||||||
@@ -131,8 +121,8 @@ public abstract class AbstractFileTypeAnalyzer extends AbstractAnalyzer implemen
|
|||||||
protected abstract void initializeFileTypeAnalyzer() throws Exception;
|
protected abstract void initializeFileTypeAnalyzer() throws Exception;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Analyzes a given dependency. If the dependency is an archive, such as a WAR or EAR, the contents are extracted,
|
* Analyzes a given dependency. If the dependency is an archive, such as a WAR or EAR, the contents are extracted, scanned,
|
||||||
* scanned, and added to the list of dependencies within the engine.
|
* and added to the list of dependencies within the engine.
|
||||||
*
|
*
|
||||||
* @param dependency the dependency to analyze
|
* @param dependency the dependency to analyze
|
||||||
* @param engine the engine scanning
|
* @param engine the engine scanning
|
||||||
@@ -165,8 +155,23 @@ public abstract class AbstractFileTypeAnalyzer extends AbstractAnalyzer implemen
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Analyzes a given dependency. If the dependency is an archive, such as a WAR or EAR, the contents are extracted,
|
* Resets the enabled flag on the analyzer.
|
||||||
* scanned, and added to the list of dependencies within the engine.
|
*/
|
||||||
|
@Override
|
||||||
|
public final void reset() {
|
||||||
|
final String key = getAnalyzerEnabledSettingKey();
|
||||||
|
try {
|
||||||
|
enabled = Settings.getBoolean(key, true);
|
||||||
|
} catch (InvalidSettingException ex) {
|
||||||
|
LOGGER.warn("Invalid setting for property '{}'", key);
|
||||||
|
LOGGER.debug("", ex);
|
||||||
|
LOGGER.warn("{} has been disabled", getName());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Analyzes a given dependency. If the dependency is an archive, such as a WAR or EAR, the contents are extracted, scanned,
|
||||||
|
* and added to the list of dependencies within the engine.
|
||||||
*
|
*
|
||||||
* @param dependency the dependency to analyze
|
* @param dependency the dependency to analyze
|
||||||
* @param engine the engine scanning
|
* @param engine the engine scanning
|
||||||
@@ -179,39 +184,28 @@ public abstract class AbstractFileTypeAnalyzer extends AbstractAnalyzer implemen
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Returns whether or not this analyzer can process the given extension.
|
|
||||||
*
|
|
||||||
* @param extension the file extension to test for support.
|
|
||||||
* @return whether or not the specified file extension is supported by this analyzer.
|
|
||||||
*/
|
|
||||||
@Override
|
@Override
|
||||||
public final boolean supportsExtension(String extension) {
|
public boolean accept(File pathname) {
|
||||||
if (!enabled) {
|
final FileFilter filter = getFileFilter();
|
||||||
return false;
|
boolean accepted = false;
|
||||||
}
|
if (null == filter) {
|
||||||
final Set<String> ext = getSupportedExtensions();
|
LOGGER.error("The '{}' analyzer is misconfigured and does not have a file filter; it will be disabled", getName());
|
||||||
if (ext == null) {
|
} else if (enabled) {
|
||||||
final String msg = String.format("The '%s' analyzer is misconfigured and does not have any file extensions;"
|
accepted = filter.accept(pathname);
|
||||||
+ " it will be disabled", getName());
|
if (accepted) {
|
||||||
LOGGER.log(Level.SEVERE, msg);
|
filesMatched = true;
|
||||||
return false;
|
|
||||||
} else {
|
|
||||||
final boolean match = ext.contains(extension);
|
|
||||||
if (match) {
|
|
||||||
filesMatched = match;
|
|
||||||
}
|
}
|
||||||
return match;
|
|
||||||
}
|
}
|
||||||
|
return accepted;
|
||||||
}
|
}
|
||||||
//</editor-fold>
|
|
||||||
|
|
||||||
|
//</editor-fold>
|
||||||
//<editor-fold defaultstate="collapsed" desc="Static utility methods">
|
//<editor-fold defaultstate="collapsed" desc="Static utility methods">
|
||||||
/**
|
/**
|
||||||
* <p>
|
* <p>
|
||||||
* Utility method to help in the creation of the extensions set. This constructs a new Set that can be used in a
|
* Utility method to help in the creation of the extensions set. This constructs a new Set that can be used in a final static
|
||||||
* final static declaration.</p>
|
* declaration.</p>
|
||||||
*
|
* <p/>
|
||||||
* <p>
|
* <p>
|
||||||
* This implementation was copied from
|
* This implementation was copied from
|
||||||
* http://stackoverflow.com/questions/2041778/initialize-java-hashset-values-by-construction</p>
|
* http://stackoverflow.com/questions/2041778/initialize-java-hashset-values-by-construction</p>
|
||||||
@@ -221,9 +215,9 @@ public abstract class AbstractFileTypeAnalyzer extends AbstractAnalyzer implemen
|
|||||||
*/
|
*/
|
||||||
protected static Set<String> newHashSet(String... strings) {
|
protected static Set<String> newHashSet(String... strings) {
|
||||||
final Set<String> set = new HashSet<String>();
|
final Set<String> set = new HashSet<String>();
|
||||||
|
|
||||||
Collections.addAll(set, strings);
|
Collections.addAll(set, strings);
|
||||||
return set;
|
return set;
|
||||||
}
|
}
|
||||||
|
|
||||||
//</editor-fold>
|
//</editor-fold>
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -24,8 +24,6 @@ import java.net.MalformedURLException;
|
|||||||
import java.net.URL;
|
import java.net.URL;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Set;
|
import java.util.Set;
|
||||||
import java.util.logging.Level;
|
|
||||||
import java.util.logging.Logger;
|
|
||||||
import java.util.regex.Pattern;
|
import java.util.regex.Pattern;
|
||||||
import org.owasp.dependencycheck.suppression.SuppressionParseException;
|
import org.owasp.dependencycheck.suppression.SuppressionParseException;
|
||||||
import org.owasp.dependencycheck.suppression.SuppressionParser;
|
import org.owasp.dependencycheck.suppression.SuppressionParser;
|
||||||
@@ -34,18 +32,20 @@ import org.owasp.dependencycheck.utils.DownloadFailedException;
|
|||||||
import org.owasp.dependencycheck.utils.Downloader;
|
import org.owasp.dependencycheck.utils.Downloader;
|
||||||
import org.owasp.dependencycheck.utils.FileUtils;
|
import org.owasp.dependencycheck.utils.FileUtils;
|
||||||
import org.owasp.dependencycheck.utils.Settings;
|
import org.owasp.dependencycheck.utils.Settings;
|
||||||
|
import org.slf4j.Logger;
|
||||||
|
import org.slf4j.LoggerFactory;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Abstract base suppression analyzer that contains methods for parsing the suppression xml file.
|
* Abstract base suppression analyzer that contains methods for parsing the suppression xml file.
|
||||||
*
|
*
|
||||||
* @author Jeremy Long <jeremy.long@owasp.org>
|
* @author Jeremy Long
|
||||||
*/
|
*/
|
||||||
public abstract class AbstractSuppressionAnalyzer extends AbstractAnalyzer {
|
public abstract class AbstractSuppressionAnalyzer extends AbstractAnalyzer {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The Logger for use throughout the class
|
* The Logger for use throughout the class
|
||||||
*/
|
*/
|
||||||
private static final Logger LOGGER = Logger.getLogger(AbstractSuppressionAnalyzer.class.getName());
|
private static final Logger LOGGER = LoggerFactory.getLogger(AbstractSuppressionAnalyzer.class);
|
||||||
|
|
||||||
//<editor-fold defaultstate="collapsed" desc="All standard implementation details of Analyzer">
|
//<editor-fold defaultstate="collapsed" desc="All standard implementation details of Analyzer">
|
||||||
/**
|
/**
|
||||||
@@ -103,7 +103,7 @@ public abstract class AbstractSuppressionAnalyzer extends AbstractAnalyzer {
|
|||||||
try {
|
try {
|
||||||
rules = parser.parseSuppressionRules(this.getClass().getClassLoader().getResourceAsStream("dependencycheck-base-suppression.xml"));
|
rules = parser.parseSuppressionRules(this.getClass().getClassLoader().getResourceAsStream("dependencycheck-base-suppression.xml"));
|
||||||
} catch (SuppressionParseException ex) {
|
} catch (SuppressionParseException ex) {
|
||||||
LOGGER.log(Level.FINE, "Unable to parse the base suppression data file", ex);
|
LOGGER.debug("Unable to parse the base suppression data file", ex);
|
||||||
}
|
}
|
||||||
final String suppressionFilePath = Settings.getString(Settings.KEYS.SUPPRESSION_FILE);
|
final String suppressionFilePath = Settings.getString(Settings.KEYS.SUPPRESSION_FILE);
|
||||||
if (suppressionFilePath == null) {
|
if (suppressionFilePath == null) {
|
||||||
@@ -141,12 +141,11 @@ public abstract class AbstractSuppressionAnalyzer extends AbstractAnalyzer {
|
|||||||
try {
|
try {
|
||||||
//rules = parser.parseSuppressionRules(file);
|
//rules = parser.parseSuppressionRules(file);
|
||||||
rules.addAll(parser.parseSuppressionRules(file));
|
rules.addAll(parser.parseSuppressionRules(file));
|
||||||
LOGGER.log(Level.FINE, rules.size() + " suppression rules were loaded.");
|
LOGGER.debug("{} suppression rules were loaded.", rules.size());
|
||||||
} catch (SuppressionParseException ex) {
|
} catch (SuppressionParseException ex) {
|
||||||
final String msg = String.format("Unable to parse suppression xml file '%s'", file.getPath());
|
LOGGER.warn("Unable to parse suppression xml file '{}'", file.getPath());
|
||||||
LOGGER.log(Level.WARNING, msg);
|
LOGGER.warn(ex.getMessage());
|
||||||
LOGGER.log(Level.WARNING, ex.getMessage());
|
LOGGER.debug("", ex);
|
||||||
LOGGER.log(Level.FINE, "", ex);
|
|
||||||
throw ex;
|
throw ex;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -171,8 +170,8 @@ public abstract class AbstractSuppressionAnalyzer extends AbstractAnalyzer {
|
|||||||
* @throws SuppressionParseException throws the generated SuppressionParseException
|
* @throws SuppressionParseException throws the generated SuppressionParseException
|
||||||
*/
|
*/
|
||||||
private void throwSuppressionParseException(String message, Exception exception) throws SuppressionParseException {
|
private void throwSuppressionParseException(String message, Exception exception) throws SuppressionParseException {
|
||||||
LOGGER.log(Level.WARNING, message);
|
LOGGER.warn(message);
|
||||||
LOGGER.log(Level.FINE, "", exception);
|
LOGGER.debug("", exception);
|
||||||
throw new SuppressionParseException(message, exception);
|
throw new SuppressionParseException(message, exception);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -20,7 +20,7 @@ package org.owasp.dependencycheck.analyzer;
|
|||||||
/**
|
/**
|
||||||
* An enumeration defining the phases of analysis.
|
* An enumeration defining the phases of analysis.
|
||||||
*
|
*
|
||||||
* @author Jeremy Long <jeremy.long@owasp.org>
|
* @author Jeremy Long
|
||||||
*/
|
*/
|
||||||
public enum AnalysisPhase {
|
public enum AnalysisPhase {
|
||||||
|
|
||||||
|
|||||||
@@ -25,7 +25,7 @@ import org.owasp.dependencycheck.dependency.Dependency;
|
|||||||
* An interface that defines an Analyzer that is used to identify Dependencies. An analyzer will collect information
|
* An interface that defines an Analyzer that is used to identify Dependencies. An analyzer will collect information
|
||||||
* about the dependency in the form of Evidence.
|
* about the dependency in the form of Evidence.
|
||||||
*
|
*
|
||||||
* @author Jeremy Long <jeremy.long@owasp.org>
|
* @author Jeremy Long
|
||||||
*/
|
*/
|
||||||
public interface Analyzer {
|
public interface Analyzer {
|
||||||
|
|
||||||
|
|||||||
@@ -24,7 +24,7 @@ import java.util.ServiceLoader;
|
|||||||
* The Analyzer Service Loader. This class loads all services that implement
|
* The Analyzer Service Loader. This class loads all services that implement
|
||||||
* org.owasp.dependencycheck.analyzer.Analyzer.
|
* org.owasp.dependencycheck.analyzer.Analyzer.
|
||||||
*
|
*
|
||||||
* @author Jeremy Long <jeremy.long@owasp.org>
|
* @author Jeremy Long
|
||||||
*/
|
*/
|
||||||
public class AnalyzerService {
|
public class AnalyzerService {
|
||||||
|
|
||||||
|
|||||||
@@ -20,6 +20,7 @@ package org.owasp.dependencycheck.analyzer;
|
|||||||
import java.io.BufferedInputStream;
|
import java.io.BufferedInputStream;
|
||||||
import java.io.BufferedOutputStream;
|
import java.io.BufferedOutputStream;
|
||||||
import java.io.File;
|
import java.io.File;
|
||||||
|
import java.io.FileFilter;
|
||||||
import java.io.FileInputStream;
|
import java.io.FileInputStream;
|
||||||
import java.io.FileNotFoundException;
|
import java.io.FileNotFoundException;
|
||||||
import java.io.FileOutputStream;
|
import java.io.FileOutputStream;
|
||||||
@@ -31,8 +32,7 @@ import java.util.Enumeration;
|
|||||||
import java.util.HashSet;
|
import java.util.HashSet;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Set;
|
import java.util.Set;
|
||||||
import java.util.logging.Level;
|
|
||||||
import java.util.logging.Logger;
|
|
||||||
import org.apache.commons.compress.archivers.ArchiveEntry;
|
import org.apache.commons.compress.archivers.ArchiveEntry;
|
||||||
import org.apache.commons.compress.archivers.ArchiveInputStream;
|
import org.apache.commons.compress.archivers.ArchiveInputStream;
|
||||||
import org.apache.commons.compress.archivers.tar.TarArchiveInputStream;
|
import org.apache.commons.compress.archivers.tar.TarArchiveInputStream;
|
||||||
@@ -46,22 +46,25 @@ import org.owasp.dependencycheck.Engine;
|
|||||||
import org.owasp.dependencycheck.analyzer.exception.AnalysisException;
|
import org.owasp.dependencycheck.analyzer.exception.AnalysisException;
|
||||||
import org.owasp.dependencycheck.analyzer.exception.ArchiveExtractionException;
|
import org.owasp.dependencycheck.analyzer.exception.ArchiveExtractionException;
|
||||||
import org.owasp.dependencycheck.dependency.Dependency;
|
import org.owasp.dependencycheck.dependency.Dependency;
|
||||||
|
import org.owasp.dependencycheck.utils.FileFilterBuilder;
|
||||||
import org.owasp.dependencycheck.utils.FileUtils;
|
import org.owasp.dependencycheck.utils.FileUtils;
|
||||||
import org.owasp.dependencycheck.utils.Settings;
|
import org.owasp.dependencycheck.utils.Settings;
|
||||||
|
import org.slf4j.Logger;
|
||||||
|
import org.slf4j.LoggerFactory;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* <p>
|
* <p>
|
||||||
* An analyzer that extracts files from archives and ensures any supported files contained within the archive are added
|
* An analyzer that extracts files from archives and ensures any supported files contained within the archive are added to the
|
||||||
* to the dependency list.</p>
|
* dependency list.</p>
|
||||||
*
|
*
|
||||||
* @author Jeremy Long <jeremy.long@owasp.org>
|
* @author Jeremy Long
|
||||||
*/
|
*/
|
||||||
public class ArchiveAnalyzer extends AbstractFileTypeAnalyzer {
|
public class ArchiveAnalyzer extends AbstractFileTypeAnalyzer {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The logger.
|
* The logger.
|
||||||
*/
|
*/
|
||||||
private static final Logger LOGGER = Logger.getLogger(ArchiveAnalyzer.class.getName());
|
private static final Logger LOGGER = LoggerFactory.getLogger(ArchiveAnalyzer.class);
|
||||||
/**
|
/**
|
||||||
* The buffer size to use when extracting files from the archive.
|
* The buffer size to use when extracting files from the archive.
|
||||||
*/
|
*/
|
||||||
@@ -97,35 +100,40 @@ public class ArchiveAnalyzer extends AbstractFileTypeAnalyzer {
|
|||||||
*/
|
*/
|
||||||
private static final Set<String> ZIPPABLES = newHashSet("zip", "ear", "war", "jar", "sar", "apk", "nupkg");
|
private static final Set<String> ZIPPABLES = newHashSet("zip", "ear", "war", "jar", "sar", "apk", "nupkg");
|
||||||
/**
|
/**
|
||||||
* The set of file extensions supported by this analyzer. Note for developers, any additions to this list will need
|
* The set of file extensions supported by this analyzer. Note for developers, any additions to this list will need to be
|
||||||
* to be explicitly handled in extractFiles().
|
* explicitly handled in extractFiles().
|
||||||
*/
|
*/
|
||||||
private static final Set<String> EXTENSIONS = newHashSet("tar", "gz", "tgz");
|
private static final Set<String> EXTENSIONS = newHashSet("tar", "gz", "tgz");
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The set of file extensions to remove from the engine's collection of dependencies.
|
* Detects files with extensions to remove from the engine's collection of dependencies.
|
||||||
*/
|
*/
|
||||||
private static final Set<String> REMOVE_FROM_ANALYSIS = newHashSet("zip", "tar", "gz", "tgz"); //TODO add nupkg, apk, sar?
|
private static final FileFilter REMOVE_FROM_ANALYSIS = FileFilterBuilder.newInstance().addExtensions("zip", "tar", "gz", "tgz").build();
|
||||||
|
|
||||||
static {
|
static {
|
||||||
final String additionalZipExt = Settings.getString(Settings.KEYS.ADDITIONAL_ZIP_EXTENSIONS);
|
final String additionalZipExt = Settings.getString(Settings.KEYS.ADDITIONAL_ZIP_EXTENSIONS);
|
||||||
if (additionalZipExt != null) {
|
if (additionalZipExt != null) {
|
||||||
final HashSet ext = new HashSet<String>(Arrays.asList(additionalZipExt));
|
final Set<String> ext = new HashSet<String>(Arrays.asList(additionalZipExt));
|
||||||
ZIPPABLES.addAll(ext);
|
ZIPPABLES.addAll(ext);
|
||||||
}
|
}
|
||||||
EXTENSIONS.addAll(ZIPPABLES);
|
EXTENSIONS.addAll(ZIPPABLES);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns a list of file EXTENSIONS supported by this analyzer.
|
* The file filter used to filter supported files.
|
||||||
*
|
|
||||||
* @return a list of file EXTENSIONS supported by this analyzer.
|
|
||||||
*/
|
*/
|
||||||
|
private static final FileFilter FILTER = FileFilterBuilder.newInstance().addExtensions(EXTENSIONS).build();
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Set<String> getSupportedExtensions() {
|
protected FileFilter getFileFilter() {
|
||||||
return EXTENSIONS;
|
return FILTER;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Detects files with .zip extension.
|
||||||
|
*/
|
||||||
|
private static final FileFilter ZIP_FILTER = FileFilterBuilder.newInstance().addExtensions("zip").build();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns the name of the analyzer.
|
* Returns the name of the analyzer.
|
||||||
*
|
*
|
||||||
@@ -184,17 +192,17 @@ public class ArchiveAnalyzer extends AbstractFileTypeAnalyzer {
|
|||||||
@Override
|
@Override
|
||||||
public void close() throws Exception {
|
public void close() throws Exception {
|
||||||
if (tempFileLocation != null && tempFileLocation.exists()) {
|
if (tempFileLocation != null && tempFileLocation.exists()) {
|
||||||
LOGGER.log(Level.FINE, "Attempting to delete temporary files");
|
LOGGER.debug("Attempting to delete temporary files");
|
||||||
final boolean success = FileUtils.delete(tempFileLocation);
|
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");
|
LOGGER.warn("Failed to delete some temporary files, see the log for more details");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Analyzes a given dependency. If the dependency is an archive, such as a WAR or EAR, the contents are extracted,
|
* Analyzes a given dependency. If the dependency is an archive, such as a WAR or EAR, the contents are extracted, scanned,
|
||||||
* scanned, and added to the list of dependencies within the engine.
|
* and added to the list of dependencies within the engine.
|
||||||
*
|
*
|
||||||
* @param dependency the dependency to analyze
|
* @param dependency the dependency to analyze
|
||||||
* @param engine the engine scanning
|
* @param engine the engine scanning
|
||||||
@@ -221,28 +229,27 @@ public class ArchiveAnalyzer extends AbstractFileTypeAnalyzer {
|
|||||||
final String displayPath = String.format("%s%s",
|
final String displayPath = String.format("%s%s",
|
||||||
dependency.getFilePath(),
|
dependency.getFilePath(),
|
||||||
d.getActualFilePath().substring(tmpDir.getAbsolutePath().length()));
|
d.getActualFilePath().substring(tmpDir.getAbsolutePath().length()));
|
||||||
final String displayName = String.format("%s%s%s",
|
final String displayName = String.format("%s: %s",
|
||||||
dependency.getFileName(),
|
dependency.getFileName(),
|
||||||
File.separator,
|
|
||||||
d.getFileName());
|
d.getFileName());
|
||||||
d.setFilePath(displayPath);
|
d.setFilePath(displayPath);
|
||||||
d.setFileName(displayName);
|
d.setFileName(displayName);
|
||||||
|
|
||||||
//TODO - can we get more evidence from the parent? EAR contains module name, etc.
|
//TODO - can we get more evidence from the parent? EAR contains module name, etc.
|
||||||
//analyze the dependency (i.e. extract files) if it is a supported type.
|
//analyze the dependency (i.e. extract files) if it is a supported type.
|
||||||
if (this.supportsExtension(d.getFileExtension()) && scanDepth < MAX_SCAN_DEPTH) {
|
if (this.accept(d.getActualFile()) && scanDepth < MAX_SCAN_DEPTH) {
|
||||||
scanDepth += 1;
|
scanDepth += 1;
|
||||||
analyze(d, engine);
|
analyze(d, engine);
|
||||||
scanDepth -= 1;
|
scanDepth -= 1;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (this.REMOVE_FROM_ANALYSIS.contains(dependency.getFileExtension())) {
|
if (REMOVE_FROM_ANALYSIS.accept(dependency.getActualFile())) {
|
||||||
if ("zip".equals(dependency.getFileExtension()) && isZipFileActuallyJarFile(dependency)) {
|
if (ZIP_FILTER.accept(dependency.getActualFile()) && isZipFileActuallyJarFile(dependency)) {
|
||||||
final File tdir = getNextTempDirectory();
|
final File tdir = getNextTempDirectory();
|
||||||
final String fileName = dependency.getFileName();
|
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");
|
final File tmpLoc = new File(tdir, fileName.substring(0, fileName.length() - 3) + "jar");
|
||||||
try {
|
try {
|
||||||
@@ -265,8 +272,7 @@ public class ArchiveAnalyzer extends AbstractFileTypeAnalyzer {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
} catch (IOException ex) {
|
} catch (IOException ex) {
|
||||||
final String msg = String.format("Unable to perform deep copy on '%s'", dependency.getActualFile().getPath());
|
LOGGER.debug("Unable to perform deep copy on '{}'", dependency.getActualFile().getPath(), ex);
|
||||||
LOGGER.log(Level.FINE, msg, ex);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
engine.getDependencies().remove(dependency);
|
engine.getDependencies().remove(dependency);
|
||||||
@@ -311,7 +317,7 @@ public class ArchiveAnalyzer extends AbstractFileTypeAnalyzer {
|
|||||||
try {
|
try {
|
||||||
fis = new FileInputStream(archive);
|
fis = new FileInputStream(archive);
|
||||||
} catch (FileNotFoundException ex) {
|
} catch (FileNotFoundException ex) {
|
||||||
LOGGER.log(Level.FINE, null, ex);
|
LOGGER.debug("", ex);
|
||||||
throw new AnalysisException("Archive file was not found.", ex);
|
throw new AnalysisException("Archive file was not found.", ex);
|
||||||
}
|
}
|
||||||
final String archiveExt = FileUtils.getFileExtension(archive.getName()).toLowerCase();
|
final String archiveExt = FileUtils.getFileExtension(archive.getName()).toLowerCase();
|
||||||
@@ -322,24 +328,22 @@ public class ArchiveAnalyzer extends AbstractFileTypeAnalyzer {
|
|||||||
extractArchive(new TarArchiveInputStream(new BufferedInputStream(fis)), destination, engine);
|
extractArchive(new TarArchiveInputStream(new BufferedInputStream(fis)), destination, engine);
|
||||||
} else if ("gz".equals(archiveExt) || "tgz".equals(archiveExt)) {
|
} else if ("gz".equals(archiveExt) || "tgz".equals(archiveExt)) {
|
||||||
final String uncompressedName = GzipUtils.getUncompressedFilename(archive.getName());
|
final String uncompressedName = GzipUtils.getUncompressedFilename(archive.getName());
|
||||||
final String uncompressedExt = FileUtils.getFileExtension(uncompressedName).toLowerCase();
|
final File f = new File(destination, uncompressedName);
|
||||||
if (engine.supportsExtension(uncompressedExt)) {
|
if (engine.accept(f)) {
|
||||||
decompressFile(new GzipCompressorInputStream(new BufferedInputStream(fis)), new File(destination, uncompressedName));
|
decompressFile(new GzipCompressorInputStream(new BufferedInputStream(fis)), f);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} catch (ArchiveExtractionException ex) {
|
} catch (ArchiveExtractionException ex) {
|
||||||
final String msg = String.format("Exception extracting archive '%s'.", archive.getName());
|
LOGGER.warn("Exception extracting archive '{}'.", archive.getName());
|
||||||
LOGGER.log(Level.WARNING, msg);
|
LOGGER.debug("", ex);
|
||||||
LOGGER.log(Level.FINE, null, ex);
|
|
||||||
} catch (IOException ex) {
|
} catch (IOException ex) {
|
||||||
final String msg = String.format("Exception reading archive '%s'.", archive.getName());
|
LOGGER.warn("Exception reading archive '{}'.", archive.getName());
|
||||||
LOGGER.log(Level.WARNING, msg);
|
LOGGER.debug("", ex);
|
||||||
LOGGER.log(Level.FINE, null, ex);
|
|
||||||
} finally {
|
} finally {
|
||||||
try {
|
try {
|
||||||
fis.close();
|
fis.close();
|
||||||
} catch (IOException ex) {
|
} catch (IOException ex) {
|
||||||
LOGGER.log(Level.FINEST, null, ex);
|
LOGGER.debug("", ex);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -366,10 +370,10 @@ public class ArchiveAnalyzer extends AbstractFileTypeAnalyzer {
|
|||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
final File file = new File(destination, entry.getName());
|
final File file = new File(destination, entry.getName());
|
||||||
final String ext = FileUtils.getFileExtension(file.getName());
|
if (engine.accept(file)) {
|
||||||
if (engine.supportsExtension(ext)) {
|
LOGGER.debug("Extracting '{}'", file.getPath());
|
||||||
BufferedOutputStream bos = null;
|
BufferedOutputStream bos = null;
|
||||||
FileOutputStream fos;
|
FileOutputStream fos = null;
|
||||||
try {
|
try {
|
||||||
final File parent = file.getParentFile();
|
final File parent = file.getParentFile();
|
||||||
if (!parent.isDirectory()) {
|
if (!parent.isDirectory()) {
|
||||||
@@ -381,17 +385,17 @@ public class ArchiveAnalyzer extends AbstractFileTypeAnalyzer {
|
|||||||
fos = new FileOutputStream(file);
|
fos = new FileOutputStream(file);
|
||||||
bos = new BufferedOutputStream(fos, BUFFER_SIZE);
|
bos = new BufferedOutputStream(fos, BUFFER_SIZE);
|
||||||
int count;
|
int count;
|
||||||
final byte data[] = new byte[BUFFER_SIZE];
|
final byte[] data = new byte[BUFFER_SIZE];
|
||||||
while ((count = input.read(data, 0, BUFFER_SIZE)) != -1) {
|
while ((count = input.read(data, 0, BUFFER_SIZE)) != -1) {
|
||||||
bos.write(data, 0, count);
|
bos.write(data, 0, count);
|
||||||
}
|
}
|
||||||
bos.flush();
|
bos.flush();
|
||||||
} catch (FileNotFoundException ex) {
|
} catch (FileNotFoundException ex) {
|
||||||
LOGGER.log(Level.FINE, null, ex);
|
LOGGER.debug("", ex);
|
||||||
final String msg = String.format("Unable to find file '%s'.", file.getName());
|
final String msg = String.format("Unable to find file '%s'.", file.getName());
|
||||||
throw new AnalysisException(msg, ex);
|
throw new AnalysisException(msg, ex);
|
||||||
} catch (IOException ex) {
|
} catch (IOException ex) {
|
||||||
LOGGER.log(Level.FINE, null, ex);
|
LOGGER.debug("", ex);
|
||||||
final String msg = String.format("IO Exception while parsing file '%s'.", file.getName());
|
final String msg = String.format("IO Exception while parsing file '%s'.", file.getName());
|
||||||
throw new AnalysisException(msg, ex);
|
throw new AnalysisException(msg, ex);
|
||||||
} finally {
|
} finally {
|
||||||
@@ -399,7 +403,14 @@ public class ArchiveAnalyzer extends AbstractFileTypeAnalyzer {
|
|||||||
try {
|
try {
|
||||||
bos.close();
|
bos.close();
|
||||||
} catch (IOException ex) {
|
} catch (IOException ex) {
|
||||||
LOGGER.log(Level.FINEST, null, ex);
|
LOGGER.trace("", ex);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (fos != null) {
|
||||||
|
try {
|
||||||
|
fos.close();
|
||||||
|
} catch (IOException ex) {
|
||||||
|
LOGGER.trace("", ex);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -415,7 +426,7 @@ public class ArchiveAnalyzer extends AbstractFileTypeAnalyzer {
|
|||||||
try {
|
try {
|
||||||
input.close();
|
input.close();
|
||||||
} catch (IOException ex) {
|
} catch (IOException ex) {
|
||||||
LOGGER.log(Level.FINEST, null, ex);
|
LOGGER.trace("", ex);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -429,6 +440,7 @@ public class ArchiveAnalyzer extends AbstractFileTypeAnalyzer {
|
|||||||
* @throws ArchiveExtractionException thrown if there is an exception decompressing the file
|
* @throws ArchiveExtractionException thrown if there is an exception decompressing the file
|
||||||
*/
|
*/
|
||||||
private void decompressFile(CompressorInputStream inputStream, File outputFile) throws ArchiveExtractionException {
|
private void decompressFile(CompressorInputStream inputStream, File outputFile) throws ArchiveExtractionException {
|
||||||
|
LOGGER.debug("Decompressing '{}'", outputFile.getPath());
|
||||||
FileOutputStream out = null;
|
FileOutputStream out = null;
|
||||||
try {
|
try {
|
||||||
out = new FileOutputStream(outputFile);
|
out = new FileOutputStream(outputFile);
|
||||||
@@ -438,17 +450,17 @@ public class ArchiveAnalyzer extends AbstractFileTypeAnalyzer {
|
|||||||
out.write(buffer, 0, n);
|
out.write(buffer, 0, n);
|
||||||
}
|
}
|
||||||
} catch (FileNotFoundException ex) {
|
} catch (FileNotFoundException ex) {
|
||||||
LOGGER.log(Level.FINE, null, ex);
|
LOGGER.debug("", ex);
|
||||||
throw new ArchiveExtractionException(ex);
|
throw new ArchiveExtractionException(ex);
|
||||||
} catch (IOException ex) {
|
} catch (IOException ex) {
|
||||||
LOGGER.log(Level.FINE, null, ex);
|
LOGGER.debug("", ex);
|
||||||
throw new ArchiveExtractionException(ex);
|
throw new ArchiveExtractionException(ex);
|
||||||
} finally {
|
} finally {
|
||||||
if (out != null) {
|
if (out != null) {
|
||||||
try {
|
try {
|
||||||
out.close();
|
out.close();
|
||||||
} catch (IOException ex) {
|
} catch (IOException ex) {
|
||||||
LOGGER.log(Level.FINEST, null, ex);
|
LOGGER.trace("", ex);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -480,7 +492,7 @@ public class ArchiveAnalyzer extends AbstractFileTypeAnalyzer {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
} catch (IOException ex) {
|
} catch (IOException ex) {
|
||||||
LOGGER.log(Level.FINE, String.format("Unable to unzip zip file '%s'", dependency.getFilePath()), ex);
|
LOGGER.debug("Unable to unzip zip file '{}'", dependency.getFilePath(), ex);
|
||||||
} finally {
|
} finally {
|
||||||
ZipFile.closeQuietly(zip);
|
ZipFile.closeQuietly(zip);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -17,31 +17,36 @@
|
|||||||
*/
|
*/
|
||||||
package org.owasp.dependencycheck.analyzer;
|
package org.owasp.dependencycheck.analyzer;
|
||||||
|
|
||||||
|
import ch.qos.cal10n.IMessageConveyor;
|
||||||
|
import ch.qos.cal10n.MessageConveyor;
|
||||||
import java.io.BufferedReader;
|
import java.io.BufferedReader;
|
||||||
import java.io.File;
|
import java.io.File;
|
||||||
|
import java.io.FileFilter;
|
||||||
import java.io.FileOutputStream;
|
import java.io.FileOutputStream;
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.io.InputStream;
|
import java.io.InputStream;
|
||||||
import java.io.InputStreamReader;
|
import java.io.InputStreamReader;
|
||||||
import java.util.ArrayList;
|
|
||||||
import java.util.List;
|
|
||||||
import java.util.Set;
|
|
||||||
import java.util.logging.Level;
|
|
||||||
import java.util.logging.Logger;
|
|
||||||
import javax.xml.parsers.DocumentBuilder;
|
|
||||||
import javax.xml.parsers.DocumentBuilderFactory;
|
|
||||||
import javax.xml.xpath.XPath;
|
|
||||||
import javax.xml.xpath.XPathExpressionException;
|
|
||||||
import javax.xml.xpath.XPathFactory;
|
|
||||||
import org.owasp.dependencycheck.Engine;
|
import org.owasp.dependencycheck.Engine;
|
||||||
import org.owasp.dependencycheck.analyzer.exception.AnalysisException;
|
import org.owasp.dependencycheck.analyzer.exception.AnalysisException;
|
||||||
import org.owasp.dependencycheck.dependency.Confidence;
|
import org.owasp.dependencycheck.dependency.Confidence;
|
||||||
import org.owasp.dependencycheck.dependency.Dependency;
|
import org.owasp.dependencycheck.dependency.Dependency;
|
||||||
import org.owasp.dependencycheck.dependency.Evidence;
|
import org.owasp.dependencycheck.dependency.Evidence;
|
||||||
|
import org.owasp.dependencycheck.utils.FileFilterBuilder;
|
||||||
import org.owasp.dependencycheck.utils.Settings;
|
import org.owasp.dependencycheck.utils.Settings;
|
||||||
|
import org.slf4j.Logger;
|
||||||
|
import org.slf4j.LoggerFactory;
|
||||||
import org.w3c.dom.Document;
|
import org.w3c.dom.Document;
|
||||||
import org.xml.sax.SAXException;
|
import org.xml.sax.SAXException;
|
||||||
|
|
||||||
|
import javax.xml.parsers.DocumentBuilder;
|
||||||
|
import javax.xml.parsers.DocumentBuilderFactory;
|
||||||
|
import javax.xml.xpath.XPath;
|
||||||
|
import javax.xml.xpath.XPathExpressionException;
|
||||||
|
import javax.xml.xpath.XPathFactory;
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Locale;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Analyzer for getting company, product, and version information from a .NET assembly.
|
* Analyzer for getting company, product, and version information from a .NET assembly.
|
||||||
*
|
*
|
||||||
@@ -61,7 +66,7 @@ public class AssemblyAnalyzer extends AbstractFileTypeAnalyzer {
|
|||||||
/**
|
/**
|
||||||
* The list of supported extensions
|
* The list of supported extensions
|
||||||
*/
|
*/
|
||||||
private static final Set<String> SUPPORTED_EXTENSIONS = newHashSet("dll", "exe");
|
private static final String[] SUPPORTED_EXTENSIONS = {"dll", "exe"};
|
||||||
/**
|
/**
|
||||||
* The temp value for GrokAssembly.exe
|
* The temp value for GrokAssembly.exe
|
||||||
*/
|
*/
|
||||||
@@ -70,10 +75,14 @@ public class AssemblyAnalyzer extends AbstractFileTypeAnalyzer {
|
|||||||
* The DocumentBuilder for parsing the XML
|
* The DocumentBuilder for parsing the XML
|
||||||
*/
|
*/
|
||||||
private DocumentBuilder builder;
|
private DocumentBuilder builder;
|
||||||
|
/**
|
||||||
|
* Message Conveyer
|
||||||
|
*/
|
||||||
|
private static final IMessageConveyor MESSAGE_CONVERYOR = new MessageConveyor(Locale.getDefault());
|
||||||
/**
|
/**
|
||||||
* Logger
|
* Logger
|
||||||
*/
|
*/
|
||||||
private static final Logger LOGGER = Logger.getLogger(AssemblyAnalyzer.class.getName(), "dependencycheck-resources");
|
private static final Logger LOGGER = LoggerFactory.getLogger(AssemblyAnalyzer.class);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Builds the beginnings of a List for ProcessBuilder
|
* Builds the beginnings of a List for ProcessBuilder
|
||||||
@@ -106,7 +115,7 @@ public class AssemblyAnalyzer extends AbstractFileTypeAnalyzer {
|
|||||||
public void analyzeFileType(Dependency dependency, Engine engine)
|
public void analyzeFileType(Dependency dependency, Engine engine)
|
||||||
throws AnalysisException {
|
throws AnalysisException {
|
||||||
if (grokAssemblyExe == null) {
|
if (grokAssemblyExe == null) {
|
||||||
LOGGER.warning("analyzer.AssemblyAnalyzer.notdeployed");
|
LOGGER.warn("GrokAssembly didn't get deployed");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -120,9 +129,11 @@ public class AssemblyAnalyzer extends AbstractFileTypeAnalyzer {
|
|||||||
// Try evacuating the error stream
|
// Try evacuating the error stream
|
||||||
rdr = new BufferedReader(new InputStreamReader(proc.getErrorStream(), "UTF-8"));
|
rdr = new BufferedReader(new InputStreamReader(proc.getErrorStream(), "UTF-8"));
|
||||||
String line = null;
|
String line = null;
|
||||||
|
// CHECKSTYLE:OFF
|
||||||
while (rdr.ready() && (line = rdr.readLine()) != null) {
|
while (rdr.ready() && (line = rdr.readLine()) != null) {
|
||||||
LOGGER.log(Level.WARNING, "analyzer.AssemblyAnalyzer.grokassembly.stderr", line);
|
LOGGER.warn("Error from GrokAssembly: {}", line);
|
||||||
}
|
}
|
||||||
|
// CHECKSTYLE:ON
|
||||||
int rc = 0;
|
int rc = 0;
|
||||||
doc = builder.parse(proc.getInputStream());
|
doc = builder.parse(proc.getInputStream());
|
||||||
|
|
||||||
@@ -132,10 +143,11 @@ public class AssemblyAnalyzer extends AbstractFileTypeAnalyzer {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if (rc == 3) {
|
if (rc == 3) {
|
||||||
LOGGER.log(Level.FINE, "analyzer.AssemblyAnalyzer.notassembly", dependency.getActualFilePath());
|
LOGGER.debug("{} is not a .NET assembly or executable and as such cannot be analyzed by dependency-check",
|
||||||
|
dependency.getActualFilePath());
|
||||||
return;
|
return;
|
||||||
} else if (rc != 0) {
|
} else if (rc != 0) {
|
||||||
LOGGER.log(Level.WARNING, "analyzer.AssemblyAnalyzer.grokassembly.rc", rc);
|
LOGGER.warn("Return code {} from GrokAssembly", rc);
|
||||||
}
|
}
|
||||||
|
|
||||||
final XPath xpath = XPathFactory.newInstance().newXPath();
|
final XPath xpath = XPathFactory.newInstance().newXPath();
|
||||||
@@ -176,7 +188,7 @@ public class AssemblyAnalyzer extends AbstractFileTypeAnalyzer {
|
|||||||
try {
|
try {
|
||||||
rdr.close();
|
rdr.close();
|
||||||
} catch (IOException ex) {
|
} catch (IOException ex) {
|
||||||
LOGGER.log(Level.FINEST, "ignore", ex);
|
LOGGER.debug("ignore", ex);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -203,24 +215,24 @@ public class AssemblyAnalyzer extends AbstractFileTypeAnalyzer {
|
|||||||
grokAssemblyExe = tempFile;
|
grokAssemblyExe = tempFile;
|
||||||
// Set the temp file to get deleted when we're done
|
// Set the temp file to get deleted when we're done
|
||||||
grokAssemblyExe.deleteOnExit();
|
grokAssemblyExe.deleteOnExit();
|
||||||
LOGGER.log(Level.FINE, "analyzer.AssemblyAnalyzer.grokassembly.deployed", grokAssemblyExe.getPath());
|
LOGGER.debug("Extracted GrokAssembly.exe to {}", grokAssemblyExe.getPath());
|
||||||
} catch (IOException ioe) {
|
} catch (IOException ioe) {
|
||||||
this.setEnabled(false);
|
this.setEnabled(false);
|
||||||
LOGGER.log(Level.WARNING, "analyzer.AssemblyAnalyzer.grokassembly.notdeployed", ioe.getMessage());
|
LOGGER.warn("Could not extract GrokAssembly.exe: {}", ioe.getMessage());
|
||||||
throw new AnalysisException("Could not extract GrokAssembly.exe", ioe);
|
throw new AnalysisException("Could not extract GrokAssembly.exe", ioe);
|
||||||
} finally {
|
} finally {
|
||||||
if (fos != null) {
|
if (fos != null) {
|
||||||
try {
|
try {
|
||||||
fos.close();
|
fos.close();
|
||||||
} catch (Throwable e) {
|
} catch (Throwable e) {
|
||||||
LOGGER.fine("Error closing output stream");
|
LOGGER.debug("Error closing output stream");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (is != null) {
|
if (is != null) {
|
||||||
try {
|
try {
|
||||||
is.close();
|
is.close();
|
||||||
} catch (Throwable e) {
|
} catch (Throwable e) {
|
||||||
LOGGER.fine("Error closing input stream");
|
LOGGER.debug("Error closing input stream");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -233,15 +245,17 @@ public class AssemblyAnalyzer extends AbstractFileTypeAnalyzer {
|
|||||||
final Process p = pb.start();
|
final Process p = pb.start();
|
||||||
// Try evacuating the error stream
|
// Try evacuating the error stream
|
||||||
rdr = new BufferedReader(new InputStreamReader(p.getErrorStream(), "UTF-8"));
|
rdr = new BufferedReader(new InputStreamReader(p.getErrorStream(), "UTF-8"));
|
||||||
|
// CHECKSTYLE:OFF
|
||||||
while (rdr.ready() && rdr.readLine() != null) {
|
while (rdr.ready() && rdr.readLine() != null) {
|
||||||
// We expect this to complain
|
// We expect this to complain
|
||||||
}
|
}
|
||||||
|
// CHECKSTYLE:ON
|
||||||
final Document doc = DocumentBuilderFactory.newInstance().newDocumentBuilder().parse(p.getInputStream());
|
final Document doc = DocumentBuilderFactory.newInstance().newDocumentBuilder().parse(p.getInputStream());
|
||||||
final XPath xpath = XPathFactory.newInstance().newXPath();
|
final XPath xpath = XPathFactory.newInstance().newXPath();
|
||||||
final String error = xpath.evaluate("/assembly/error", doc);
|
final String error = xpath.evaluate("/assembly/error", doc);
|
||||||
if (p.waitFor() != 1 || error == null || "".equals(error)) {
|
if (p.waitFor() != 1 || error == null || "".equals(error)) {
|
||||||
LOGGER.warning("An error occurred with the .NET AssemblyAnalyzer, please see the log for more details.");
|
LOGGER.warn("An error occurred with the .NET AssemblyAnalyzer, please see the log for more details.");
|
||||||
LOGGER.fine("GrokAssembly.exe is not working properly");
|
LOGGER.debug("GrokAssembly.exe is not working properly");
|
||||||
grokAssemblyExe = null;
|
grokAssemblyExe = null;
|
||||||
this.setEnabled(false);
|
this.setEnabled(false);
|
||||||
throw new AnalysisException("Could not execute .NET AssemblyAnalyzer");
|
throw new AnalysisException("Could not execute .NET AssemblyAnalyzer");
|
||||||
@@ -250,8 +264,9 @@ public class AssemblyAnalyzer extends AbstractFileTypeAnalyzer {
|
|||||||
if (e instanceof AnalysisException) {
|
if (e instanceof AnalysisException) {
|
||||||
throw (AnalysisException) e;
|
throw (AnalysisException) e;
|
||||||
} else {
|
} else {
|
||||||
LOGGER.warning("analyzer.AssemblyAnalyzer.grokassembly.initialization.failed");
|
LOGGER.warn("An error occurred with the .NET AssemblyAnalyzer;\n"
|
||||||
LOGGER.log(Level.FINE, "analyzer.AssemblyAnalyzer.grokassembly.initialization.message", e.getMessage());
|
+ "this can be ignored unless you are scanning .NET DLLs. Please see the log for more details.");
|
||||||
|
LOGGER.debug("Could not execute GrokAssembly {}", e.getMessage());
|
||||||
this.setEnabled(false);
|
this.setEnabled(false);
|
||||||
throw new AnalysisException("An error occured with the .NET AssemblyAnalyzer", e);
|
throw new AnalysisException("An error occured with the .NET AssemblyAnalyzer", e);
|
||||||
}
|
}
|
||||||
@@ -260,13 +275,18 @@ public class AssemblyAnalyzer extends AbstractFileTypeAnalyzer {
|
|||||||
try {
|
try {
|
||||||
rdr.close();
|
rdr.close();
|
||||||
} catch (IOException ex) {
|
} catch (IOException ex) {
|
||||||
LOGGER.log(Level.FINEST, "ignore", ex);
|
LOGGER.trace("ignore", ex);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
builder = DocumentBuilderFactory.newInstance().newDocumentBuilder();
|
builder = DocumentBuilderFactory.newInstance().newDocumentBuilder();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Removes resources used from the local file system.
|
||||||
|
*
|
||||||
|
* @throws Exception thrown if there is a problem closing the analyzer
|
||||||
|
*/
|
||||||
@Override
|
@Override
|
||||||
public void close() throws Exception {
|
public void close() throws Exception {
|
||||||
super.close();
|
super.close();
|
||||||
@@ -275,18 +295,19 @@ public class AssemblyAnalyzer extends AbstractFileTypeAnalyzer {
|
|||||||
grokAssemblyExe.deleteOnExit();
|
grokAssemblyExe.deleteOnExit();
|
||||||
}
|
}
|
||||||
} catch (SecurityException se) {
|
} catch (SecurityException se) {
|
||||||
LOGGER.fine("analyzer.AssemblyAnalyzer.grokassembly.notdeleted");
|
LOGGER.debug("Can't delete temporary GrokAssembly.exe");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Gets the set of extensions supported by this analyzer.
|
* The File Filter used to filter supported extensions.
|
||||||
*
|
|
||||||
* @return the list of supported extensions
|
|
||||||
*/
|
*/
|
||||||
|
private static final FileFilter FILTER = FileFilterBuilder.newInstance().addExtensions(
|
||||||
|
SUPPORTED_EXTENSIONS).build();
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Set<String> getSupportedExtensions() {
|
protected FileFilter getFileFilter() {
|
||||||
return SUPPORTED_EXTENSIONS;
|
return FILTER;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
@@ -0,0 +1,279 @@
|
|||||||
|
/*
|
||||||
|
* This file is part of dependency-check-core.
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*
|
||||||
|
* Copyright (c) 2015 Institute for Defense Analyses. All Rights Reserved.
|
||||||
|
*/
|
||||||
|
package org.owasp.dependencycheck.analyzer;
|
||||||
|
|
||||||
|
import org.apache.commons.io.FileUtils;
|
||||||
|
import org.owasp.dependencycheck.Engine;
|
||||||
|
import org.owasp.dependencycheck.analyzer.exception.AnalysisException;
|
||||||
|
import org.owasp.dependencycheck.dependency.Confidence;
|
||||||
|
import org.owasp.dependencycheck.dependency.Dependency;
|
||||||
|
import org.owasp.dependencycheck.dependency.EvidenceCollection;
|
||||||
|
import org.owasp.dependencycheck.utils.FileFilterBuilder;
|
||||||
|
import org.owasp.dependencycheck.utils.Settings;
|
||||||
|
import org.owasp.dependencycheck.utils.UrlStringUtils;
|
||||||
|
|
||||||
|
import java.io.File;
|
||||||
|
import java.io.FileFilter;
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.regex.Matcher;
|
||||||
|
import java.util.regex.Pattern;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Used to analyze Autoconf input files named configure.ac or configure.in. Files simply named "configure" are also analyzed,
|
||||||
|
* assuming they are generated by Autoconf, and contain certain special package descriptor variables.
|
||||||
|
*
|
||||||
|
* @author Dale Visser <dvisser@ida.org>
|
||||||
|
* @see <a href="https://www.gnu.org/software/autoconf/">Autoconf - GNU Project - Free Software Foundation (FSF)</a>
|
||||||
|
*/
|
||||||
|
public class AutoconfAnalyzer extends AbstractFileTypeAnalyzer {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Autoconf output filename.
|
||||||
|
*/
|
||||||
|
private static final String CONFIGURE = "configure";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Autoconf input filename.
|
||||||
|
*/
|
||||||
|
private static final String CONFIGURE_IN = "configure.in";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Autoconf input filename.
|
||||||
|
*/
|
||||||
|
private static final String CONFIGURE_AC = "configure.ac";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The name of the analyzer.
|
||||||
|
*/
|
||||||
|
private static final String ANALYZER_NAME = "Autoconf Analyzer";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The phase that this analyzer is intended to run in.
|
||||||
|
*/
|
||||||
|
private static final AnalysisPhase ANALYSIS_PHASE = AnalysisPhase.INFORMATION_COLLECTION;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The set of file extensions supported by this analyzer.
|
||||||
|
*/
|
||||||
|
private static final String[] EXTENSIONS = {"ac", "in"};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Matches AC_INIT variables in the output configure script.
|
||||||
|
*/
|
||||||
|
private static final Pattern PACKAGE_VAR = Pattern.compile(
|
||||||
|
"PACKAGE_(.+?)='(.*?)'", Pattern.DOTALL | Pattern.CASE_INSENSITIVE);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Matches AC_INIT statement in configure.ac file.
|
||||||
|
*/
|
||||||
|
private static final Pattern AC_INIT_PATTERN;
|
||||||
|
|
||||||
|
static {
|
||||||
|
// each instance of param or sep_param has a capture group
|
||||||
|
final String param = "\\[{0,2}(.+?)\\]{0,2}";
|
||||||
|
final String sepParam = "\\s*,\\s*" + param;
|
||||||
|
// Group 1: Package
|
||||||
|
// Group 2: Version
|
||||||
|
// Group 3: optional
|
||||||
|
// Group 4: Bug report address (if it exists)
|
||||||
|
// Group 5: optional
|
||||||
|
// Group 6: Tarname (if it exists)
|
||||||
|
// Group 7: optional
|
||||||
|
// Group 8: URL (if it exists)
|
||||||
|
AC_INIT_PATTERN = Pattern.compile(String.format(
|
||||||
|
"AC_INIT\\(%s%s(%s)?(%s)?(%s)?\\s*\\)", param, sepParam,
|
||||||
|
sepParam, sepParam, sepParam), Pattern.DOTALL
|
||||||
|
| Pattern.CASE_INSENSITIVE);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The file filter used to determine which files this analyzer supports.
|
||||||
|
*/
|
||||||
|
private static final FileFilter FILTER = FileFilterBuilder.newInstance().addFilenames(CONFIGURE).addExtensions(
|
||||||
|
EXTENSIONS).build();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the FileFilter
|
||||||
|
*
|
||||||
|
* @return the FileFilter
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
protected FileFilter getFileFilter() {
|
||||||
|
return FILTER;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the name of the analyzer.
|
||||||
|
*
|
||||||
|
* @return the name of the analyzer.
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
public String getName() {
|
||||||
|
return ANALYZER_NAME;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the phase that the analyzer is intended to run in.
|
||||||
|
*
|
||||||
|
* @return the phase that the analyzer is intended to run in.
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
public AnalysisPhase getAnalysisPhase() {
|
||||||
|
return ANALYSIS_PHASE;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the key used in the properties file to reference the analyzer's enabled property.
|
||||||
|
*
|
||||||
|
* @return the analyzer's enabled property setting key
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
protected String getAnalyzerEnabledSettingKey() {
|
||||||
|
return Settings.KEYS.ANALYZER_PYTHON_DISTRIBUTION_ENABLED;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void analyzeFileType(Dependency dependency, Engine engine)
|
||||||
|
throws AnalysisException {
|
||||||
|
final File actualFile = dependency.getActualFile();
|
||||||
|
final String name = actualFile.getName();
|
||||||
|
if (name.startsWith(CONFIGURE)) {
|
||||||
|
final File parent = actualFile.getParentFile();
|
||||||
|
final String parentName = parent.getName();
|
||||||
|
dependency.setDisplayFileName(parentName + "/" + name);
|
||||||
|
final boolean isOutputScript = CONFIGURE.equals(name);
|
||||||
|
if (isOutputScript || CONFIGURE_AC.equals(name)
|
||||||
|
|| CONFIGURE_IN.equals(name)) {
|
||||||
|
final String contents = getFileContents(actualFile);
|
||||||
|
if (!contents.isEmpty()) {
|
||||||
|
if (isOutputScript) {
|
||||||
|
extractConfigureScriptEvidence(dependency, name,
|
||||||
|
contents);
|
||||||
|
} else {
|
||||||
|
gatherEvidence(dependency, name, contents);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
// copy, alter and set in case some other thread is iterating over
|
||||||
|
final List<Dependency> deps = new ArrayList<Dependency>(
|
||||||
|
engine.getDependencies());
|
||||||
|
deps.remove(dependency);
|
||||||
|
engine.setDependencies(deps);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Extracts evidence from the configuration.
|
||||||
|
*
|
||||||
|
* @param dependency the dependency being analyzed
|
||||||
|
* @param name the name of the source of evidence
|
||||||
|
* @param contents the contents to analyze for evidence
|
||||||
|
*/
|
||||||
|
private void extractConfigureScriptEvidence(Dependency dependency,
|
||||||
|
final String name, final String contents) {
|
||||||
|
final Matcher matcher = PACKAGE_VAR.matcher(contents);
|
||||||
|
while (matcher.find()) {
|
||||||
|
final String variable = matcher.group(1);
|
||||||
|
final String value = matcher.group(2);
|
||||||
|
if (!value.isEmpty()) {
|
||||||
|
if (variable.endsWith("NAME")) {
|
||||||
|
dependency.getProductEvidence().addEvidence(name, variable,
|
||||||
|
value, Confidence.HIGHEST);
|
||||||
|
} else if ("VERSION".equals(variable)) {
|
||||||
|
dependency.getVersionEvidence().addEvidence(name, variable,
|
||||||
|
value, Confidence.HIGHEST);
|
||||||
|
} else if ("BUGREPORT".equals(variable)) {
|
||||||
|
dependency.getVendorEvidence().addEvidence(name, variable,
|
||||||
|
value, Confidence.HIGH);
|
||||||
|
} else if ("URL".equals(variable)) {
|
||||||
|
dependency.getVendorEvidence().addEvidence(name, variable,
|
||||||
|
value, Confidence.HIGH);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Retrieves the contents of a given file.
|
||||||
|
*
|
||||||
|
* @param actualFile the file to read
|
||||||
|
* @return the contents of the file
|
||||||
|
* @throws AnalysisException thrown if there is an IO Exception
|
||||||
|
*/
|
||||||
|
private String getFileContents(final File actualFile)
|
||||||
|
throws AnalysisException {
|
||||||
|
String contents = "";
|
||||||
|
try {
|
||||||
|
contents = FileUtils.readFileToString(actualFile).trim();
|
||||||
|
} catch (IOException e) {
|
||||||
|
throw new AnalysisException(
|
||||||
|
"Problem occured while reading dependency file.", e);
|
||||||
|
}
|
||||||
|
return contents;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gathers evidence from a given file
|
||||||
|
*
|
||||||
|
* @param dependency the dependency to add evidence to
|
||||||
|
* @param name the source of the evidence
|
||||||
|
* @param contents the evidence to analyze
|
||||||
|
*/
|
||||||
|
private void gatherEvidence(Dependency dependency, final String name,
|
||||||
|
String contents) {
|
||||||
|
final Matcher matcher = AC_INIT_PATTERN.matcher(contents);
|
||||||
|
if (matcher.find()) {
|
||||||
|
final EvidenceCollection productEvidence = dependency
|
||||||
|
.getProductEvidence();
|
||||||
|
productEvidence.addEvidence(name, "Package", matcher.group(1),
|
||||||
|
Confidence.HIGHEST);
|
||||||
|
dependency.getVersionEvidence().addEvidence(name,
|
||||||
|
"Package Version", matcher.group(2), Confidence.HIGHEST);
|
||||||
|
final EvidenceCollection vendorEvidence = dependency
|
||||||
|
.getVendorEvidence();
|
||||||
|
if (null != matcher.group(3)) {
|
||||||
|
vendorEvidence.addEvidence(name, "Bug report address",
|
||||||
|
matcher.group(4), Confidence.HIGH);
|
||||||
|
}
|
||||||
|
if (null != matcher.group(5)) {
|
||||||
|
productEvidence.addEvidence(name, "Tarname", matcher.group(6),
|
||||||
|
Confidence.HIGH);
|
||||||
|
}
|
||||||
|
if (null != matcher.group(7)) {
|
||||||
|
final String url = matcher.group(8);
|
||||||
|
if (UrlStringUtils.isUrl(url)) {
|
||||||
|
vendorEvidence.addEvidence(name, "URL", url,
|
||||||
|
Confidence.HIGH);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Initializes the file type analyzer.
|
||||||
|
*
|
||||||
|
* @throws Exception thrown if there is an exception during initialization
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
protected void initializeFileTypeAnalyzer() throws Exception {
|
||||||
|
// No initialization needed.
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,216 @@
|
|||||||
|
/*
|
||||||
|
* This file is part of dependency-check-core.
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*
|
||||||
|
* Copyright (c) 2015 Institute for Defense Analyses. All Rights Reserved.
|
||||||
|
*/
|
||||||
|
package org.owasp.dependencycheck.analyzer;
|
||||||
|
|
||||||
|
import org.apache.commons.io.FileUtils;
|
||||||
|
import org.apache.commons.lang.StringUtils;
|
||||||
|
import org.owasp.dependencycheck.Engine;
|
||||||
|
import org.owasp.dependencycheck.analyzer.exception.AnalysisException;
|
||||||
|
import org.owasp.dependencycheck.dependency.Confidence;
|
||||||
|
import org.owasp.dependencycheck.dependency.Dependency;
|
||||||
|
import org.owasp.dependencycheck.utils.Checksum;
|
||||||
|
import org.owasp.dependencycheck.utils.FileFilterBuilder;
|
||||||
|
import org.owasp.dependencycheck.utils.Settings;
|
||||||
|
import org.slf4j.Logger;
|
||||||
|
import org.slf4j.LoggerFactory;
|
||||||
|
|
||||||
|
import java.io.File;
|
||||||
|
import java.io.FileFilter;
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.security.MessageDigest;
|
||||||
|
import java.security.NoSuchAlgorithmException;
|
||||||
|
import java.util.regex.Matcher;
|
||||||
|
import java.util.regex.Pattern;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* <p>
|
||||||
|
* Used to analyze CMake build files, and collect information that can be used to determine the associated CPE.</p>
|
||||||
|
* <p/>
|
||||||
|
* <p>
|
||||||
|
* Note: This analyzer catches straightforward invocations of the project command, plus some other observed patterns of version
|
||||||
|
* inclusion in real CMake projects. Many projects make use of older versions of CMake and/or use custom "homebrew" ways to insert
|
||||||
|
* version information. Hopefully as the newer CMake call pattern grows in usage, this analyzer allow more CPEs to be
|
||||||
|
* identified.</p>
|
||||||
|
*
|
||||||
|
* @author Dale Visser <dvisser@ida.org>
|
||||||
|
*/
|
||||||
|
public class CMakeAnalyzer extends AbstractFileTypeAnalyzer {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The logger.
|
||||||
|
*/
|
||||||
|
private static final Logger LOGGER = LoggerFactory.getLogger(CMakeAnalyzer.class);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Used when compiling file scanning regex patterns.
|
||||||
|
*/
|
||||||
|
private static final int REGEX_OPTIONS = Pattern.DOTALL
|
||||||
|
| Pattern.CASE_INSENSITIVE | Pattern.MULTILINE;
|
||||||
|
|
||||||
|
private static final Pattern PROJECT = Pattern.compile(
|
||||||
|
"^ *project *\\([ \\n]*(\\w+)[ \\n]*.*?\\)", REGEX_OPTIONS);
|
||||||
|
|
||||||
|
// Group 1: Product
|
||||||
|
// Group 2: Version
|
||||||
|
private static final Pattern SET_VERSION = Pattern
|
||||||
|
.compile(
|
||||||
|
"^ *set\\s*\\(\\s*(\\w+)_version\\s+\"?(\\d+(?:\\.\\d+)+)[\\s\"]?\\)",
|
||||||
|
REGEX_OPTIONS);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Detects files that can be analyzed.
|
||||||
|
*/
|
||||||
|
private static final FileFilter FILTER = FileFilterBuilder.newInstance().addExtensions(".cmake")
|
||||||
|
.addFilenames("CMakeLists.txt").build();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A reference to SHA1 message digest.
|
||||||
|
*/
|
||||||
|
private static MessageDigest sha1 = null;
|
||||||
|
|
||||||
|
static {
|
||||||
|
try {
|
||||||
|
sha1 = MessageDigest.getInstance("SHA1");
|
||||||
|
} catch (NoSuchAlgorithmException e) {
|
||||||
|
LOGGER.error(e.getMessage());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the name of the CMake analyzer.
|
||||||
|
*
|
||||||
|
* @return the name of the analyzer
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
public String getName() {
|
||||||
|
return "CMake Analyzer";
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Tell that we are used for information collection.
|
||||||
|
*
|
||||||
|
* @return INFORMATION_COLLECTION
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
public AnalysisPhase getAnalysisPhase() {
|
||||||
|
return AnalysisPhase.INFORMATION_COLLECTION;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the set of supported file extensions.
|
||||||
|
*
|
||||||
|
* @return the set of supported file extensions
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
protected FileFilter getFileFilter() {
|
||||||
|
return FILTER;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* No-op initializer implementation.
|
||||||
|
*
|
||||||
|
* @throws Exception never thrown
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
protected void initializeFileTypeAnalyzer() throws Exception {
|
||||||
|
// Nothing to do here.
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Analyzes python packages and adds evidence to the dependency.
|
||||||
|
*
|
||||||
|
* @param dependency the dependency being analyzed
|
||||||
|
* @param engine the engine being used to perform the scan
|
||||||
|
* @throws AnalysisException thrown if there is an unrecoverable error analyzing the dependency
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
protected void analyzeFileType(Dependency dependency, Engine engine)
|
||||||
|
throws AnalysisException {
|
||||||
|
final File file = dependency.getActualFile();
|
||||||
|
final String parentName = file.getParentFile().getName();
|
||||||
|
final String name = file.getName();
|
||||||
|
dependency.setDisplayFileName(String.format("%s%c%s", parentName, File.separatorChar, name));
|
||||||
|
String contents;
|
||||||
|
try {
|
||||||
|
contents = FileUtils.readFileToString(file).trim();
|
||||||
|
} catch (IOException e) {
|
||||||
|
throw new AnalysisException(
|
||||||
|
"Problem occurred while reading dependency file.", e);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (StringUtils.isNotBlank(contents)) {
|
||||||
|
final Matcher m = PROJECT.matcher(contents);
|
||||||
|
int count = 0;
|
||||||
|
while (m.find()) {
|
||||||
|
count++;
|
||||||
|
LOGGER.debug(String.format(
|
||||||
|
"Found project command match with %d groups: %s",
|
||||||
|
m.groupCount(), m.group(0)));
|
||||||
|
final String group = m.group(1);
|
||||||
|
LOGGER.debug("Group 1: " + group);
|
||||||
|
dependency.getProductEvidence().addEvidence(name, "Project",
|
||||||
|
group, Confidence.HIGH);
|
||||||
|
}
|
||||||
|
LOGGER.debug(String.format("Found %d matches.", count));
|
||||||
|
analyzeSetVersionCommand(dependency, engine, contents);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void analyzeSetVersionCommand(Dependency dependency, Engine engine, String contents) {
|
||||||
|
final Dependency orig = dependency;
|
||||||
|
final Matcher m = SET_VERSION.matcher(contents);
|
||||||
|
int count = 0;
|
||||||
|
while (m.find()) {
|
||||||
|
count++;
|
||||||
|
LOGGER.debug(String.format(
|
||||||
|
"Found project command match with %d groups: %s",
|
||||||
|
m.groupCount(), m.group(0)));
|
||||||
|
String product = m.group(1);
|
||||||
|
final String version = m.group(2);
|
||||||
|
LOGGER.debug("Group 1: " + product);
|
||||||
|
LOGGER.debug("Group 2: " + version);
|
||||||
|
final String aliasPrefix = "ALIASOF_";
|
||||||
|
if (product.startsWith(aliasPrefix)) {
|
||||||
|
product = product.replaceFirst(aliasPrefix, "");
|
||||||
|
}
|
||||||
|
if (count > 1) {
|
||||||
|
//TODO - refactor so we do not assign to the parameter (checkstyle)
|
||||||
|
dependency = new Dependency(orig.getActualFile());
|
||||||
|
dependency.setDisplayFileName(String.format("%s:%s", orig.getDisplayFileName(), product));
|
||||||
|
final String filePath = String.format("%s:%s", orig.getFilePath(), product);
|
||||||
|
dependency.setFilePath(filePath);
|
||||||
|
|
||||||
|
// prevents coalescing into the dependency provided by engine
|
||||||
|
dependency.setSha1sum(Checksum.getHex(sha1.digest(filePath.getBytes())));
|
||||||
|
engine.getDependencies().add(dependency);
|
||||||
|
}
|
||||||
|
final String source = dependency.getDisplayFileName();
|
||||||
|
dependency.getProductEvidence().addEvidence(source, "Product",
|
||||||
|
product, Confidence.MEDIUM);
|
||||||
|
dependency.getVersionEvidence().addEvidence(source, "Version",
|
||||||
|
version, Confidence.MEDIUM);
|
||||||
|
}
|
||||||
|
LOGGER.debug(String.format("Found %d matches.", count));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected String getAnalyzerEnabledSettingKey() {
|
||||||
|
return Settings.KEYS.ANALYZER_CMAKE_ENABLED;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -25,8 +25,6 @@ import java.util.Collections;
|
|||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Set;
|
import java.util.Set;
|
||||||
import java.util.StringTokenizer;
|
import java.util.StringTokenizer;
|
||||||
import java.util.logging.Level;
|
|
||||||
import java.util.logging.Logger;
|
|
||||||
import org.apache.lucene.document.Document;
|
import org.apache.lucene.document.Document;
|
||||||
import org.apache.lucene.index.CorruptIndexException;
|
import org.apache.lucene.index.CorruptIndexException;
|
||||||
import org.apache.lucene.queryparser.classic.ParseException;
|
import org.apache.lucene.queryparser.classic.ParseException;
|
||||||
@@ -49,19 +47,21 @@ import org.owasp.dependencycheck.dependency.Identifier;
|
|||||||
import org.owasp.dependencycheck.dependency.VulnerableSoftware;
|
import org.owasp.dependencycheck.dependency.VulnerableSoftware;
|
||||||
import org.owasp.dependencycheck.utils.DependencyVersion;
|
import org.owasp.dependencycheck.utils.DependencyVersion;
|
||||||
import org.owasp.dependencycheck.utils.DependencyVersionUtil;
|
import org.owasp.dependencycheck.utils.DependencyVersionUtil;
|
||||||
|
import org.slf4j.Logger;
|
||||||
|
import org.slf4j.LoggerFactory;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* CPEAnalyzer is a utility class that takes a project dependency and attempts to discern if there is an associated CPE.
|
* CPEAnalyzer is a utility class that takes a project dependency and attempts to discern if there is an associated CPE. It uses
|
||||||
* It uses the evidence contained within the dependency to search the Lucene index.
|
* the evidence contained within the dependency to search the Lucene index.
|
||||||
*
|
*
|
||||||
* @author Jeremy Long <jeremy.long@owasp.org>
|
* @author Jeremy Long
|
||||||
*/
|
*/
|
||||||
public class CPEAnalyzer implements Analyzer {
|
public class CPEAnalyzer implements Analyzer {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The Logger.
|
* The Logger.
|
||||||
*/
|
*/
|
||||||
private static final Logger LOGGER = Logger.getLogger(CPEAnalyzer.class.getName());
|
private static final Logger LOGGER = LoggerFactory.getLogger(CPEAnalyzer.class);
|
||||||
/**
|
/**
|
||||||
* The maximum number of query results to return.
|
* The maximum number of query results to return.
|
||||||
*/
|
*/
|
||||||
@@ -130,19 +130,19 @@ public class CPEAnalyzer implements Analyzer {
|
|||||||
* Opens the data source.
|
* Opens the data source.
|
||||||
*
|
*
|
||||||
* @throws IOException when the Lucene directory to be queried does not exist or is corrupt.
|
* @throws IOException when the Lucene directory to be queried does not exist or is corrupt.
|
||||||
* @throws DatabaseException when the database throws an exception. This usually occurs when the database is in use
|
* @throws DatabaseException when the database throws an exception. This usually occurs when the database is in use by another
|
||||||
* by another process.
|
* process.
|
||||||
*/
|
*/
|
||||||
public void open() throws IOException, DatabaseException {
|
public void open() throws IOException, DatabaseException {
|
||||||
LOGGER.log(Level.FINE, "Opening the CVE Database");
|
LOGGER.debug("Opening the CVE Database");
|
||||||
cve = new CveDB();
|
cve = new CveDB();
|
||||||
cve.open();
|
cve.open();
|
||||||
LOGGER.log(Level.FINE, "Creating the Lucene CPE Index");
|
LOGGER.debug("Creating the Lucene CPE Index");
|
||||||
cpe = CpeMemoryIndex.getInstance();
|
cpe = CpeMemoryIndex.getInstance();
|
||||||
try {
|
try {
|
||||||
cpe.open(cve);
|
cpe.open(cve);
|
||||||
} catch (IndexException ex) {
|
} catch (IndexException ex) {
|
||||||
LOGGER.log(Level.FINE, "IndexException", ex);
|
LOGGER.debug("IndexException", ex);
|
||||||
throw new DatabaseException(ex);
|
throw new DatabaseException(ex);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -154,15 +154,21 @@ public class CPEAnalyzer implements Analyzer {
|
|||||||
public void close() {
|
public void close() {
|
||||||
if (cpe != null) {
|
if (cpe != null) {
|
||||||
cpe.close();
|
cpe.close();
|
||||||
|
cpe = null;
|
||||||
}
|
}
|
||||||
if (cve != null) {
|
if (cve != null) {
|
||||||
cve.close();
|
cve.close();
|
||||||
|
cve = null;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public boolean isOpen() {
|
||||||
|
return cpe != null && cpe.isOpen();
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Searches the data store of CPE entries, trying to identify the CPE for the given dependency based on the evidence
|
* Searches the data store of CPE entries, trying to identify the CPE for the given dependency based on the evidence contained
|
||||||
* contained within. The dependency passed in is updated with any identified CPE values.
|
* within. The dependency passed in is updated with any identified CPE values.
|
||||||
*
|
*
|
||||||
* @param dependency the dependency to search for CPE entries on.
|
* @param dependency the dependency to search for CPE entries on.
|
||||||
* @throws CorruptIndexException is thrown when the Lucene index is corrupt.
|
* @throws CorruptIndexException is thrown when the Lucene index is corrupt.
|
||||||
@@ -170,47 +176,45 @@ public class CPEAnalyzer implements Analyzer {
|
|||||||
* @throws ParseException is thrown when the Lucene query cannot be parsed.
|
* @throws ParseException is thrown when the Lucene query cannot be parsed.
|
||||||
*/
|
*/
|
||||||
protected void determineCPE(Dependency dependency) throws CorruptIndexException, IOException, ParseException {
|
protected void determineCPE(Dependency dependency) throws CorruptIndexException, IOException, ParseException {
|
||||||
Confidence confidence = Confidence.HIGHEST;
|
//TODO test dojo-war against this. we shold get dojo-toolkit:dojo-toolkit AND dojo-toolkit:toolkit
|
||||||
|
String vendors = "";
|
||||||
String vendors = addEvidenceWithoutDuplicateTerms("", dependency.getVendorEvidence(), confidence);
|
String products = "";
|
||||||
String products = addEvidenceWithoutDuplicateTerms("", dependency.getProductEvidence(), confidence);
|
for (Confidence confidence : Confidence.values()) {
|
||||||
/* 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);
|
|
||||||
if (dependency.getVendorEvidence().contains(confidence)) {
|
if (dependency.getVendorEvidence().contains(confidence)) {
|
||||||
vendors = addEvidenceWithoutDuplicateTerms(vendors, dependency.getVendorEvidence(), confidence);
|
vendors = addEvidenceWithoutDuplicateTerms(vendors, dependency.getVendorEvidence(), confidence);
|
||||||
|
LOGGER.debug("vendor search: {}", vendors);
|
||||||
}
|
}
|
||||||
if (dependency.getProductEvidence().contains(confidence)) {
|
if (dependency.getProductEvidence().contains(confidence)) {
|
||||||
products = addEvidenceWithoutDuplicateTerms(products, dependency.getProductEvidence(), confidence);
|
products = addEvidenceWithoutDuplicateTerms(products, dependency.getProductEvidence(), confidence);
|
||||||
|
LOGGER.debug("product search: {}", products);
|
||||||
}
|
}
|
||||||
/* bug fix for #40 - version evidence is not showing up as "used" in the reports if there is no
|
if (!vendors.isEmpty() && !products.isEmpty()) {
|
||||||
* CPE identified. As such, we are "using" the evidence and ignoring the results. */
|
final List<IndexEntry> entries = searchCPE(vendors, products, dependency.getProductEvidence().getWeighting(),
|
||||||
if (dependency.getVersionEvidence().contains(confidence)) {
|
dependency.getVendorEvidence().getWeighting());
|
||||||
addEvidenceWithoutDuplicateTerms("", dependency.getVersionEvidence(), confidence);
|
if (entries == null) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
boolean identifierAdded = false;
|
||||||
|
for (IndexEntry e : entries) {
|
||||||
|
LOGGER.debug("Verifying entry: {}", e);
|
||||||
|
if (verifyEntry(e, dependency)) {
|
||||||
|
final String vendor = e.getVendor();
|
||||||
|
final String product = e.getProduct();
|
||||||
|
LOGGER.debug("identified vendor/product: {}/{}", vendor, product);
|
||||||
|
identifierAdded |= determineIdentifiers(dependency, vendor, product, confidence);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (identifierAdded) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
} while ((++ctr) < 4);
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns the text created by concatenating the text and the values from the EvidenceCollection (filtered for a
|
* Returns the text created by concatenating the text and the values from the EvidenceCollection (filtered for a specific
|
||||||
* specific confidence). This attempts to prevent duplicate terms from being added.<br/<br/> Note, if the evidence
|
* confidence). This attempts to prevent duplicate terms from being added.<br/<br/> Note, if the evidence is longer then 200
|
||||||
* is longer then 200 characters it will be truncated.
|
* characters it will be truncated.
|
||||||
*
|
*
|
||||||
* @param text the base text.
|
* @param text the base text.
|
||||||
* @param ec an EvidenceCollection
|
* @param ec an EvidenceCollection
|
||||||
@@ -239,71 +243,53 @@ public class CPEAnalyzer implements Analyzer {
|
|||||||
return sb.toString().trim();
|
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>
|
* <p>
|
||||||
* Searches the Lucene CPE index to identify possible CPE entries associated with the supplied vendor, product, and
|
* Searches the Lucene CPE index to identify possible CPE entries associated with the supplied vendor, product, and
|
||||||
* version.</p>
|
* version.</p>
|
||||||
*
|
*
|
||||||
* <p>
|
* <p>
|
||||||
* If either the vendorWeightings or productWeightings lists have been populated this data is used to add weighting
|
* If either the vendorWeightings or productWeightings lists have been populated this data is used to add weighting factors to
|
||||||
* factors to the search.</p>
|
* the search.</p>
|
||||||
*
|
*
|
||||||
* @param vendor the text used to search the vendor field
|
* @param vendor the text used to search the vendor field
|
||||||
* @param product the text used to search the product field
|
* @param product the text used to search the product field
|
||||||
* @param vendorWeightings a list of strings to use to add weighting factors to the vendor field
|
* @param 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
|
* @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
|
* @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,
|
protected List<IndexEntry> searchCPE(String vendor, String product,
|
||||||
Set<String> vendorWeightings, Set<String> productWeightings)
|
Set<String> vendorWeightings, Set<String> productWeightings) {
|
||||||
throws CorruptIndexException, IOException, ParseException {
|
|
||||||
final ArrayList<IndexEntry> ret = new ArrayList<IndexEntry>(MAX_QUERY_RESULTS);
|
final List<IndexEntry> ret = new ArrayList<IndexEntry>(MAX_QUERY_RESULTS);
|
||||||
|
|
||||||
final String searchString = buildSearch(vendor, product, vendorWeightings, productWeightings);
|
final String searchString = buildSearch(vendor, product, vendorWeightings, productWeightings);
|
||||||
if (searchString == null) {
|
if (searchString == null) {
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
try {
|
||||||
final TopDocs docs = cpe.search(searchString, MAX_QUERY_RESULTS);
|
final TopDocs docs = cpe.search(searchString, MAX_QUERY_RESULTS);
|
||||||
for (ScoreDoc d : docs.scoreDocs) {
|
for (ScoreDoc d : docs.scoreDocs) {
|
||||||
if (d.score >= 0.08) {
|
if (d.score >= 0.08) {
|
||||||
final Document doc = cpe.getDocument(d.doc);
|
final Document doc = cpe.getDocument(d.doc);
|
||||||
final IndexEntry entry = new IndexEntry();
|
final IndexEntry entry = new IndexEntry();
|
||||||
entry.setVendor(doc.get(Fields.VENDOR));
|
entry.setVendor(doc.get(Fields.VENDOR));
|
||||||
entry.setProduct(doc.get(Fields.PRODUCT));
|
entry.setProduct(doc.get(Fields.PRODUCT));
|
||||||
// if (d.score < 0.08) {
|
entry.setSearchScore(d.score);
|
||||||
// System.out.print(entry.getVendor());
|
if (!ret.contains(entry)) {
|
||||||
// System.out.print(":");
|
ret.add(entry);
|
||||||
// System.out.print(entry.getProduct());
|
}
|
||||||
// System.out.print(":");
|
|
||||||
// System.out.println(d.score);
|
|
||||||
// }
|
|
||||||
entry.setSearchScore(d.score);
|
|
||||||
if (!ret.contains(entry)) {
|
|
||||||
ret.add(entry);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
return ret;
|
||||||
|
} catch (ParseException ex) {
|
||||||
|
LOGGER.warn("An error occured querying the CPE data. See the log for more details.");
|
||||||
|
LOGGER.info("Unable to parse: {}", searchString, ex);
|
||||||
|
} catch (IOException ex) {
|
||||||
|
LOGGER.warn("An error occured reading CPE data. See the log for more details.");
|
||||||
|
LOGGER.info("IO Error with search string: {}", searchString, ex);
|
||||||
}
|
}
|
||||||
return ret;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -311,8 +297,8 @@ public class CPEAnalyzer implements Analyzer {
|
|||||||
* Builds a Lucene search string by properly escaping data and constructing a valid search query.</p>
|
* Builds a Lucene search string by properly escaping data and constructing a valid search query.</p>
|
||||||
*
|
*
|
||||||
* <p>
|
* <p>
|
||||||
* If either the possibleVendor or possibleProducts lists have been populated this data is used to add weighting
|
* If either the possibleVendor or possibleProducts lists have been populated this data is used to add weighting factors to
|
||||||
* factors to the search string generated.</p>
|
* the search string generated.</p>
|
||||||
*
|
*
|
||||||
* @param vendor text to search the vendor field
|
* @param vendor text to search the vendor field
|
||||||
* @param product text to search the product field
|
* @param product text to search the product field
|
||||||
@@ -338,9 +324,8 @@ public class CPEAnalyzer implements Analyzer {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* This method constructs a Lucene query for a given field. The searchText is split into separate words and if the
|
* This method constructs a Lucene query for a given field. The searchText is split into separate words and if the word is
|
||||||
* word is within the list of weighted words then an additional weighting is applied to the term as it is appended
|
* within the list of weighted words then an additional weighting is applied to the term as it is appended into the query.
|
||||||
* into the query.
|
|
||||||
*
|
*
|
||||||
* @param sb a StringBuilder that the query text will be appended to.
|
* @param sb a StringBuilder that the query text will be appended to.
|
||||||
* @param field the field within the Lucene index that the query is searching.
|
* @param field the field within the Lucene index that the query is searching.
|
||||||
@@ -411,8 +396,8 @@ public class CPEAnalyzer implements Analyzer {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Ensures that the CPE Identified matches the dependency. This validates that the product, vendor, and version
|
* Ensures that the CPE Identified matches the dependency. This validates that the product, vendor, and version information
|
||||||
* information for the CPE are contained within the dependencies evidence.
|
* for the CPE are contained within the dependencies evidence.
|
||||||
*
|
*
|
||||||
* @param entry a CPE entry.
|
* @param entry a CPE entry.
|
||||||
* @param dependency the dependency that the CPE entries could be for.
|
* @param dependency the dependency that the CPE entries could be for.
|
||||||
@@ -421,6 +406,8 @@ public class CPEAnalyzer implements Analyzer {
|
|||||||
private boolean verifyEntry(final IndexEntry entry, final Dependency dependency) {
|
private boolean verifyEntry(final IndexEntry entry, final Dependency dependency) {
|
||||||
boolean isValid = false;
|
boolean isValid = false;
|
||||||
|
|
||||||
|
//TODO - does this nullify some of the fuzzy matching that happens in the lucene search?
|
||||||
|
// for instance CPE some-component and in the evidence we have SomeComponent.
|
||||||
if (collectionContainsString(dependency.getProductEvidence(), entry.getProduct())
|
if (collectionContainsString(dependency.getProductEvidence(), entry.getProduct())
|
||||||
&& collectionContainsString(dependency.getVendorEvidence(), entry.getVendor())) {
|
&& collectionContainsString(dependency.getVendorEvidence(), entry.getVendor())) {
|
||||||
//&& collectionContainsVersion(dependency.getVersionEvidence(), entry.getVersion())
|
//&& collectionContainsVersion(dependency.getVersionEvidence(), entry.getVersion())
|
||||||
@@ -437,17 +424,6 @@ public class CPEAnalyzer implements Analyzer {
|
|||||||
* @return whether or not the EvidenceCollection contains the string
|
* @return whether or not the EvidenceCollection contains the string
|
||||||
*/
|
*/
|
||||||
private boolean collectionContainsString(EvidenceCollection ec, String text) {
|
private boolean collectionContainsString(EvidenceCollection ec, String text) {
|
||||||
|
|
||||||
//<editor-fold defaultstate="collapsed" desc="This code fold contains an old version of the code, delete once more testing is done">
|
|
||||||
// String[] splitText = text.split("[\\s_-]");
|
|
||||||
//
|
|
||||||
// for (String search : splitText) {
|
|
||||||
// //final String search = text.replaceAll("[\\s_-]", "").toLowerCase();
|
|
||||||
// if (ec.containsUsedString(search)) {
|
|
||||||
// return true;
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
//</editor-fold>
|
|
||||||
//TODO - likely need to change the split... not sure if this will work for CPE with special chars
|
//TODO - likely need to change the split... not sure if this will work for CPE with special chars
|
||||||
if (text == null) {
|
if (text == null) {
|
||||||
return false;
|
return false;
|
||||||
@@ -469,9 +445,16 @@ public class CPEAnalyzer implements Analyzer {
|
|||||||
list.add(word);
|
list.add(word);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (tempWord != null && !list.isEmpty()) {
|
if (tempWord != null) {
|
||||||
final String tmp = list.get(list.size() - 1) + tempWord;
|
if (!list.isEmpty()) {
|
||||||
list.add(tmp);
|
final String tmp = list.get(list.size() - 1) + tempWord;
|
||||||
|
list.add(tmp);
|
||||||
|
} else {
|
||||||
|
list.add(tempWord);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (list.isEmpty()) {
|
||||||
|
return false;
|
||||||
}
|
}
|
||||||
boolean contains = true;
|
boolean contains = true;
|
||||||
for (String word : list) {
|
for (String word : list) {
|
||||||
@@ -501,21 +484,28 @@ public class CPEAnalyzer implements Analyzer {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Retrieves a list of CPE values from the CveDB based on the vendor and product passed in. The list is then
|
* Retrieves a list of CPE values from the CveDB based on the vendor and product passed in. The list is then validated to find
|
||||||
* validated to find only CPEs that are valid for the given dependency. It is possible that the CPE identified is a
|
* only CPEs that are valid for the given dependency. It is possible that the CPE identified is a best effort "guess" based on
|
||||||
* best effort "guess" based on the vendor, product, and version information.
|
* the vendor, product, and version information.
|
||||||
*
|
*
|
||||||
* @param dependency the Dependency being analyzed
|
* @param dependency the Dependency being analyzed
|
||||||
* @param vendor the vendor for the CPE being analyzed
|
* @param vendor the vendor for the CPE being analyzed
|
||||||
* @param product the product 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
|
* @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);
|
final Set<VulnerableSoftware> cpes = cve.getCPEs(vendor, product);
|
||||||
DependencyVersion bestGuess = new DependencyVersion("-");
|
DependencyVersion bestGuess = new DependencyVersion("-");
|
||||||
Confidence bestGuessConf = null;
|
Confidence bestGuessConf = null;
|
||||||
|
boolean hasBroadMatch = false;
|
||||||
final List<IdentifierMatch> collected = new ArrayList<IdentifierMatch>();
|
final List<IdentifierMatch> collected = new ArrayList<IdentifierMatch>();
|
||||||
for (Confidence conf : Confidence.values()) {
|
for (Confidence conf : Confidence.values()) {
|
||||||
|
// if (conf.compareTo(currentConfidence) > 0) {
|
||||||
|
// break;
|
||||||
|
// }
|
||||||
for (Evidence evidence : dependency.getVersionEvidence().iterator(conf)) {
|
for (Evidence evidence : dependency.getVersionEvidence().iterator(conf)) {
|
||||||
final DependencyVersion evVer = DependencyVersionUtil.parseVersion(evidence.getValue());
|
final DependencyVersion evVer = DependencyVersionUtil.parseVersion(evidence.getValue());
|
||||||
if (evVer == null) {
|
if (evVer == null) {
|
||||||
@@ -523,14 +513,17 @@ public class CPEAnalyzer implements Analyzer {
|
|||||||
}
|
}
|
||||||
for (VulnerableSoftware vs : cpes) {
|
for (VulnerableSoftware vs : cpes) {
|
||||||
DependencyVersion dbVer;
|
DependencyVersion dbVer;
|
||||||
if (vs.getRevision() != null && !vs.getRevision().isEmpty()) {
|
if (vs.getUpdate() != null && !vs.getUpdate().isEmpty()) {
|
||||||
dbVer = DependencyVersionUtil.parseVersion(vs.getVersion() + "." + vs.getRevision());
|
dbVer = DependencyVersionUtil.parseVersion(vs.getVersion() + "." + vs.getUpdate());
|
||||||
} else {
|
} else {
|
||||||
dbVer = DependencyVersionUtil.parseVersion(vs.getVersion());
|
dbVer = DependencyVersionUtil.parseVersion(vs.getVersion());
|
||||||
}
|
}
|
||||||
if (dbVer == null //special case, no version specified - everything is vulnerable
|
if (dbVer == null) { //special case, no version specified - everything is vulnerable
|
||||||
|| evVer.equals(dbVer)) { //yeah! exact match
|
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 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);
|
final IdentifierMatch match = new IdentifierMatch("cpe", vs.getName(), url, IdentifierConfidence.EXACT_MATCH, conf);
|
||||||
collected.add(match);
|
collected.add(match);
|
||||||
@@ -556,7 +549,11 @@ public class CPEAnalyzer implements Analyzer {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
final String cpeName = String.format("cpe:/a:%s:%s:%s", vendor, product, bestGuess.toString());
|
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) {
|
if (bestGuessConf == null) {
|
||||||
bestGuessConf = Confidence.LOW;
|
bestGuessConf = Confidence.LOW;
|
||||||
}
|
}
|
||||||
@@ -566,6 +563,7 @@ public class CPEAnalyzer implements Analyzer {
|
|||||||
Collections.sort(collected);
|
Collections.sort(collected);
|
||||||
final IdentifierConfidence bestIdentifierQuality = collected.get(0).getConfidence();
|
final IdentifierConfidence bestIdentifierQuality = collected.get(0).getConfidence();
|
||||||
final Confidence bestEvidenceQuality = collected.get(0).getEvidenceConfidence();
|
final Confidence bestEvidenceQuality = collected.get(0).getEvidenceConfidence();
|
||||||
|
boolean identifierAdded = false;
|
||||||
for (IdentifierMatch m : collected) {
|
for (IdentifierMatch m : collected) {
|
||||||
if (bestIdentifierQuality.equals(m.getConfidence())
|
if (bestIdentifierQuality.equals(m.getConfidence())
|
||||||
&& bestEvidenceQuality.equals(m.getEvidenceConfidence())) {
|
&& bestEvidenceQuality.equals(m.getEvidenceConfidence())) {
|
||||||
@@ -576,8 +574,10 @@ public class CPEAnalyzer implements Analyzer {
|
|||||||
i.setConfidence(bestEvidenceQuality);
|
i.setConfidence(bestEvidenceQuality);
|
||||||
}
|
}
|
||||||
dependency.addIdentifier(i);
|
dependency.addIdentifier(i);
|
||||||
|
identifierAdded = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
return identifierAdded;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -592,7 +592,12 @@ public class CPEAnalyzer implements Analyzer {
|
|||||||
/**
|
/**
|
||||||
* A best guess for the CPE.
|
* 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
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -738,8 +743,7 @@ public class CPEAnalyzer implements Analyzer {
|
|||||||
//</editor-fold>
|
//</editor-fold>
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Standard implementation of compareTo that compares identifier confidence, evidence confidence, and then the
|
* Standard implementation of compareTo that compares identifier confidence, evidence confidence, and then the identifier.
|
||||||
* identifier.
|
|
||||||
*
|
*
|
||||||
* @param o the IdentifierMatch to compare to
|
* @param o the IdentifierMatch to compare to
|
||||||
* @return the natural ordering of IdentifierMatch
|
* @return the natural ordering of IdentifierMatch
|
||||||
|
|||||||
@@ -0,0 +1,238 @@
|
|||||||
|
/*
|
||||||
|
* 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 org.apache.commons.io.FileUtils;
|
||||||
|
import org.owasp.dependencycheck.Engine;
|
||||||
|
import org.owasp.dependencycheck.analyzer.exception.AnalysisException;
|
||||||
|
import org.owasp.dependencycheck.data.central.CentralSearch;
|
||||||
|
import org.owasp.dependencycheck.data.nexus.MavenArtifact;
|
||||||
|
import org.owasp.dependencycheck.dependency.Confidence;
|
||||||
|
import org.owasp.dependencycheck.dependency.Dependency;
|
||||||
|
import org.owasp.dependencycheck.dependency.Evidence;
|
||||||
|
import org.owasp.dependencycheck.xml.pom.PomUtils;
|
||||||
|
import org.slf4j.Logger;
|
||||||
|
import org.slf4j.LoggerFactory;
|
||||||
|
|
||||||
|
import java.io.File;
|
||||||
|
import java.io.FileFilter;
|
||||||
|
import java.io.FileNotFoundException;
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.net.URL;
|
||||||
|
import java.util.List;
|
||||||
|
import org.owasp.dependencycheck.utils.DownloadFailedException;
|
||||||
|
import org.owasp.dependencycheck.utils.Downloader;
|
||||||
|
import org.owasp.dependencycheck.utils.FileFilterBuilder;
|
||||||
|
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 = LoggerFactory.getLogger(CentralAnalyzer.class);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 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 String SUPPORTED_EXTENSIONS = "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.debug("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.warn("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.debug("Initializing Central analyzer");
|
||||||
|
LOGGER.debug("Central analyzer enabled: {}", isEnabled());
|
||||||
|
if (isEnabled()) {
|
||||||
|
final String searchUrl = Settings.getString(Settings.KEYS.ANALYZER_CENTRAL_URL);
|
||||||
|
LOGGER.debug("Central Analyzer URL: {}", 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;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The file filter used to determine which files this analyzer supports.
|
||||||
|
*/
|
||||||
|
private static final FileFilter FILTER = FileFilterBuilder.newInstance().addExtensions(SUPPORTED_EXTENSIONS).build();
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected FileFilter getFileFilter() {
|
||||||
|
return FILTER;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 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.debug("Central analyzer found artifact ({}) for dependency ({})", ma.toString(), dependency.getFileName());
|
||||||
|
dependency.addAsEvidence("central", ma, confidence);
|
||||||
|
boolean pomAnalyzed = false;
|
||||||
|
for (Evidence e : dependency.getVendorEvidence()) {
|
||||||
|
if ("pom".equals(e.getSource())) {
|
||||||
|
pomAnalyzed = true;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (!pomAnalyzed && ma.getPomUrl() != null) {
|
||||||
|
File pomFile = null;
|
||||||
|
try {
|
||||||
|
final File baseDir = Settings.getTempDirectory();
|
||||||
|
pomFile = File.createTempFile("pom", ".xml", baseDir);
|
||||||
|
if (!pomFile.delete()) {
|
||||||
|
LOGGER.warn("Unable to fetch pom.xml for {} from Central; "
|
||||||
|
+ "this could result in undetected CPE/CVEs.", dependency.getFileName());
|
||||||
|
LOGGER.debug("Unable to delete temp file");
|
||||||
|
}
|
||||||
|
LOGGER.debug("Downloading {}", ma.getPomUrl());
|
||||||
|
Downloader.fetchFile(new URL(ma.getPomUrl()), pomFile);
|
||||||
|
PomUtils.analyzePOM(dependency, pomFile);
|
||||||
|
|
||||||
|
} catch (DownloadFailedException ex) {
|
||||||
|
LOGGER.warn("Unable to download pom.xml for {} from Central; "
|
||||||
|
+ "this could result in undetected CPE/CVEs.", dependency.getFileName());
|
||||||
|
} finally {
|
||||||
|
if (pomFile != null && !FileUtils.deleteQuietly(pomFile)) {
|
||||||
|
pomFile.deleteOnExit();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
} catch (IllegalArgumentException iae) {
|
||||||
|
LOGGER.info("invalid sha1-hash on {}", dependency.getFileName());
|
||||||
|
} catch (FileNotFoundException fnfe) {
|
||||||
|
LOGGER.debug("Artifact not found in repository: '{}", dependency.getFileName());
|
||||||
|
} catch (IOException ioe) {
|
||||||
|
LOGGER.debug("Could not connect to Central search", ioe);
|
||||||
|
errorFlag = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -26,7 +26,7 @@ import org.owasp.dependencycheck.suppression.SuppressionRule;
|
|||||||
* The suppression analyzer processes an externally defined XML document that complies with the suppressions.xsd schema.
|
* The suppression analyzer processes an externally defined XML document that complies with the suppressions.xsd schema.
|
||||||
* Any identified CPE entries within the dependencies that match will be removed.
|
* Any identified CPE entries within the dependencies that match will be removed.
|
||||||
*
|
*
|
||||||
* @author Jeremy Long <jeremy.long@owasp.org>
|
* @author Jeremy Long
|
||||||
*/
|
*/
|
||||||
public class CpeSuppressionAnalyzer extends AbstractSuppressionAnalyzer {
|
public class CpeSuppressionAnalyzer extends AbstractSuppressionAnalyzer {
|
||||||
|
|
||||||
|
|||||||
@@ -22,8 +22,6 @@ import java.util.HashSet;
|
|||||||
import java.util.Iterator;
|
import java.util.Iterator;
|
||||||
import java.util.ListIterator;
|
import java.util.ListIterator;
|
||||||
import java.util.Set;
|
import java.util.Set;
|
||||||
import java.util.logging.Level;
|
|
||||||
import java.util.logging.Logger;
|
|
||||||
import java.util.regex.Matcher;
|
import java.util.regex.Matcher;
|
||||||
import java.util.regex.Pattern;
|
import java.util.regex.Pattern;
|
||||||
import org.owasp.dependencycheck.Engine;
|
import org.owasp.dependencycheck.Engine;
|
||||||
@@ -32,30 +30,31 @@ import org.owasp.dependencycheck.dependency.Dependency;
|
|||||||
import org.owasp.dependencycheck.dependency.Identifier;
|
import org.owasp.dependencycheck.dependency.Identifier;
|
||||||
import org.owasp.dependencycheck.utils.DependencyVersion;
|
import org.owasp.dependencycheck.utils.DependencyVersion;
|
||||||
import org.owasp.dependencycheck.utils.DependencyVersionUtil;
|
import org.owasp.dependencycheck.utils.DependencyVersionUtil;
|
||||||
import org.owasp.dependencycheck.utils.LogUtils;
|
import org.slf4j.Logger;
|
||||||
|
import org.slf4j.LoggerFactory;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* <p>
|
* <p>
|
||||||
* This analyzer ensures dependencies that should be grouped together, to remove excess noise from the report, are
|
* This analyzer ensures dependencies that should be grouped together, to remove excess noise from the report, are grouped. An
|
||||||
* grouped. An example would be Spring, Spring Beans, Spring MVC, etc. If they are all for the same version and have the
|
* example would be Spring, Spring Beans, Spring MVC, etc. If they are all for the same version and have the same relative path
|
||||||
* same relative path then these should be grouped into a single dependency under the core/main library.</p>
|
* then these should be grouped into a single dependency under the core/main library.</p>
|
||||||
* <p>
|
* <p>
|
||||||
* Note, this grouping only works on dependencies with identified CVE entries</p>
|
* Note, this grouping only works on dependencies with identified CVE entries</p>
|
||||||
*
|
*
|
||||||
* @author Jeremy Long <jeremy.long@owasp.org>
|
* @author Jeremy Long
|
||||||
*/
|
*/
|
||||||
public class DependencyBundlingAnalyzer extends AbstractAnalyzer implements Analyzer {
|
public class DependencyBundlingAnalyzer extends AbstractAnalyzer implements Analyzer {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The Logger.
|
* The Logger.
|
||||||
*/
|
*/
|
||||||
private static final Logger LOGGER = Logger.getLogger(DependencyBundlingAnalyzer.class.getName());
|
private static final Logger LOGGER = LoggerFactory.getLogger(DependencyBundlingAnalyzer.class);
|
||||||
|
|
||||||
//<editor-fold defaultstate="collapsed" desc="Constants and Member Variables">
|
//<editor-fold defaultstate="collapsed" desc="Constants and Member Variables">
|
||||||
/**
|
/**
|
||||||
* A pattern for obtaining the first part of a filename.
|
* 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.
|
* a flag indicating if this analyzer has run. This analyzer only runs once.
|
||||||
*/
|
*/
|
||||||
@@ -91,8 +90,8 @@ public class DependencyBundlingAnalyzer extends AbstractAnalyzer implements Anal
|
|||||||
//</editor-fold>
|
//</editor-fold>
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Analyzes a set of dependencies. If they have been found to have the same base path and the same set of
|
* Analyzes a set of dependencies. If they have been found to have the same base path and the same set of identifiers they are
|
||||||
* identifiers they are likely related. The related dependencies are bundled into a single reportable item.
|
* likely related. The related dependencies are bundled into a single reportable item.
|
||||||
*
|
*
|
||||||
* @param ignore this analyzer ignores the dependency being analyzed
|
* @param ignore this analyzer ignores the dependency being analyzed
|
||||||
* @param engine the engine that is scanning the dependencies
|
* @param engine the engine that is scanning the dependencies
|
||||||
@@ -107,30 +106,35 @@ public class DependencyBundlingAnalyzer extends AbstractAnalyzer implements Anal
|
|||||||
//for (Dependency nextDependency : engine.getDependencies()) {
|
//for (Dependency nextDependency : engine.getDependencies()) {
|
||||||
while (mainIterator.hasNext()) {
|
while (mainIterator.hasNext()) {
|
||||||
final Dependency dependency = mainIterator.next();
|
final Dependency dependency = mainIterator.next();
|
||||||
if (mainIterator.hasNext()) {
|
if (mainIterator.hasNext() && !dependenciesToRemove.contains(dependency)) {
|
||||||
final ListIterator<Dependency> subIterator = engine.getDependencies().listIterator(mainIterator.nextIndex());
|
final ListIterator<Dependency> subIterator = engine.getDependencies().listIterator(mainIterator.nextIndex());
|
||||||
while (subIterator.hasNext()) {
|
while (subIterator.hasNext()) {
|
||||||
final Dependency nextDependency = subIterator.next();
|
final Dependency nextDependency = subIterator.next();
|
||||||
if (hashesMatch(dependency, nextDependency)) {
|
if (hashesMatch(dependency, nextDependency) && !containedInWar(dependency.getFilePath())
|
||||||
if (isCore(dependency, nextDependency)) {
|
&& !containedInWar(nextDependency.getFilePath())) {
|
||||||
|
if (firstPathIsShortest(dependency.getFilePath(), nextDependency.getFilePath())) {
|
||||||
mergeDependencies(dependency, nextDependency, dependenciesToRemove);
|
mergeDependencies(dependency, nextDependency, dependenciesToRemove);
|
||||||
} else {
|
} else {
|
||||||
mergeDependencies(nextDependency, dependency, dependenciesToRemove);
|
mergeDependencies(nextDependency, dependency, dependenciesToRemove);
|
||||||
|
break; //since we merged into the next dependency - skip forward to the next in mainIterator
|
||||||
}
|
}
|
||||||
} else if (isShadedJar(dependency, nextDependency)) {
|
} else if (isShadedJar(dependency, nextDependency)) {
|
||||||
if (dependency.getFileName().toLowerCase().endsWith("pom.xml")) {
|
if (dependency.getFileName().toLowerCase().endsWith("pom.xml")) {
|
||||||
dependenciesToRemove.add(dependency);
|
mergeDependencies(nextDependency, dependency, dependenciesToRemove);
|
||||||
|
nextDependency.getRelatedDependencies().remove(dependency);
|
||||||
|
break;
|
||||||
} else {
|
} else {
|
||||||
dependenciesToRemove.add(nextDependency);
|
mergeDependencies(dependency, nextDependency, dependenciesToRemove);
|
||||||
|
dependency.getRelatedDependencies().remove(nextDependency);
|
||||||
}
|
}
|
||||||
} else if (cpeIdentifiersMatch(dependency, nextDependency)
|
} else if (cpeIdentifiersMatch(dependency, nextDependency)
|
||||||
&& hasSameBasePath(dependency, nextDependency)
|
&& hasSameBasePath(dependency, nextDependency)
|
||||||
&& fileNameMatch(dependency, nextDependency)) {
|
&& fileNameMatch(dependency, nextDependency)) {
|
||||||
|
|
||||||
if (isCore(dependency, nextDependency)) {
|
if (isCore(dependency, nextDependency)) {
|
||||||
mergeDependencies(dependency, nextDependency, dependenciesToRemove);
|
mergeDependencies(dependency, nextDependency, dependenciesToRemove);
|
||||||
} else {
|
} else {
|
||||||
mergeDependencies(nextDependency, dependency, dependenciesToRemove);
|
mergeDependencies(nextDependency, dependency, dependenciesToRemove);
|
||||||
|
break; //since we merged into the next dependency - skip forward to the next in mainIterator
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -138,9 +142,7 @@ public class DependencyBundlingAnalyzer extends AbstractAnalyzer implements Anal
|
|||||||
}
|
}
|
||||||
//removing dependencies here as ensuring correctness and avoiding ConcurrentUpdateExceptions
|
//removing dependencies here as ensuring correctness and avoiding ConcurrentUpdateExceptions
|
||||||
// was difficult because of the inner iterator.
|
// was difficult because of the inner iterator.
|
||||||
for (Dependency d : dependenciesToRemove) {
|
engine.getDependencies().removeAll(dependenciesToRemove);
|
||||||
engine.getDependencies().remove(d);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -148,10 +150,10 @@ public class DependencyBundlingAnalyzer extends AbstractAnalyzer implements Anal
|
|||||||
* Adds the relatedDependency to the dependency's related dependencies.
|
* Adds the relatedDependency to the dependency's related dependencies.
|
||||||
*
|
*
|
||||||
* @param dependency the main dependency
|
* @param dependency the main dependency
|
||||||
* @param relatedDependency a collection of dependencies to be removed from the main analysis loop, this is the
|
* @param relatedDependency a collection of dependencies to be removed from the main analysis loop, this is the source of
|
||||||
* source of dependencies to remove
|
* dependencies to remove
|
||||||
* @param dependenciesToRemove a collection of dependencies that will be removed from the main analysis loop, this
|
* @param dependenciesToRemove a collection of dependencies that will be removed from the main analysis loop, this function
|
||||||
* function adds to this collection
|
* adds to this collection
|
||||||
*/
|
*/
|
||||||
private void mergeDependencies(final Dependency dependency, final Dependency relatedDependency, final Set<Dependency> dependenciesToRemove) {
|
private void mergeDependencies(final Dependency dependency, final Dependency relatedDependency, final Set<Dependency> dependenciesToRemove) {
|
||||||
dependency.addRelatedDependency(relatedDependency);
|
dependency.addRelatedDependency(relatedDependency);
|
||||||
@@ -160,12 +162,14 @@ public class DependencyBundlingAnalyzer extends AbstractAnalyzer implements Anal
|
|||||||
dependency.addRelatedDependency(i.next());
|
dependency.addRelatedDependency(i.next());
|
||||||
i.remove();
|
i.remove();
|
||||||
}
|
}
|
||||||
|
if (dependency.getSha1sum().equals(relatedDependency.getSha1sum())) {
|
||||||
|
dependency.addAllProjectReferences(relatedDependency.getProjectReferences());
|
||||||
|
}
|
||||||
dependenciesToRemove.add(relatedDependency);
|
dependenciesToRemove.add(relatedDependency);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Attempts to trim a maven repo to a common base path. This is typically
|
* Attempts to trim a maven repo to a common base path. This is typically [drive]\[repo_location]\repository\[path1]\[path2].
|
||||||
* [drive]\[repo_location]\repository\[path1]\[path2].
|
|
||||||
*
|
*
|
||||||
* @param path the path to trim
|
* @param path the path to trim
|
||||||
* @return a string representing the base path.
|
* @return a string representing the base path.
|
||||||
@@ -201,25 +205,8 @@ public class DependencyBundlingAnalyzer extends AbstractAnalyzer implements Anal
|
|||||||
|| dependency2 == null || dependency2.getFileName() == null) {
|
|| dependency2 == null || dependency2.getFileName() == null) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
String fileName1 = dependency1.getFileName();
|
final String fileName1 = dependency1.getActualFile().getName();
|
||||||
String fileName2 = dependency2.getFileName();
|
final String fileName2 = dependency2.getActualFile().getName();
|
||||||
|
|
||||||
//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;
|
|
||||||
}
|
|
||||||
|
|
||||||
//version check
|
//version check
|
||||||
final DependencyVersion version1 = DependencyVersionUtil.parseVersion(fileName1);
|
final DependencyVersion version1 = DependencyVersionUtil.parseVersion(fileName1);
|
||||||
@@ -267,16 +254,15 @@ public class DependencyBundlingAnalyzer extends AbstractAnalyzer implements Anal
|
|||||||
}
|
}
|
||||||
if (cpeCount1 > 0 && cpeCount1 == cpeCount2) {
|
if (cpeCount1 > 0 && cpeCount1 == cpeCount2) {
|
||||||
for (Identifier i : dependency1.getIdentifiers()) {
|
for (Identifier i : dependency1.getIdentifiers()) {
|
||||||
matches |= dependency2.getIdentifiers().contains(i);
|
if ("cpe".equals(i.getType())) {
|
||||||
if (!matches) {
|
matches |= dependency2.getIdentifiers().contains(i);
|
||||||
break;
|
if (!matches) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (LogUtils.isVerboseLoggingEnabled()) {
|
LOGGER.debug("IdentifiersMatch={} ({}, {})", matches, dependency1.getFileName(), dependency2.getFileName());
|
||||||
final String msg = String.format("IdentifiersMatch=%s (%s, %s)", matches, dependency1.getFileName(), dependency2.getFileName());
|
|
||||||
LOGGER.log(Level.FINE, msg);
|
|
||||||
}
|
|
||||||
return matches;
|
return matches;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -318,8 +304,8 @@ public class DependencyBundlingAnalyzer extends AbstractAnalyzer implements Anal
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* This is likely a very broken attempt at determining if the 'left' dependency is the 'core' library in comparison
|
* This is likely a very broken attempt at determining if the 'left' dependency is the 'core' library in comparison to the
|
||||||
* to the 'right' library.
|
* 'right' library.
|
||||||
*
|
*
|
||||||
* @param left the dependency to test
|
* @param left the dependency to test
|
||||||
* @param right the dependency to test against
|
* @param right the dependency to test against
|
||||||
@@ -338,6 +324,10 @@ public class DependencyBundlingAnalyzer extends AbstractAnalyzer implements Anal
|
|||||||
|| !rightName.contains("core") && leftName.contains("core")
|
|| !rightName.contains("core") && leftName.contains("core")
|
||||||
|| !rightName.contains("kernel") && leftName.contains("kernel")) {
|
|| !rightName.contains("kernel") && leftName.contains("kernel")) {
|
||||||
returnVal = true;
|
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 {
|
} else {
|
||||||
/*
|
/*
|
||||||
* considered splitting the names up and comparing the components,
|
* considered splitting the names up and comparing the components,
|
||||||
@@ -350,10 +340,7 @@ public class DependencyBundlingAnalyzer extends AbstractAnalyzer implements Anal
|
|||||||
*/
|
*/
|
||||||
returnVal = leftName.length() <= rightName.length();
|
returnVal = leftName.length() <= rightName.length();
|
||||||
}
|
}
|
||||||
if (LogUtils.isVerboseLoggingEnabled()) {
|
LOGGER.debug("IsCore={} ({}, {})", returnVal, left.getFileName(), right.getFileName());
|
||||||
final String msg = String.format("IsCore=%s (%s, %s)", returnVal, left.getFileName(), right.getFileName());
|
|
||||||
LOGGER.log(Level.FINE, msg);
|
|
||||||
}
|
|
||||||
return returnVal;
|
return returnVal;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -372,13 +359,12 @@ public class DependencyBundlingAnalyzer extends AbstractAnalyzer implements Anal
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Determines if the jar is shaded and the created pom.xml identified the same CPE as the jar - if so, the pom.xml
|
* Determines if the jar is shaded and the created pom.xml identified the same CPE as the jar - if so, the pom.xml dependency
|
||||||
* dependency should be removed.
|
* should be removed.
|
||||||
*
|
*
|
||||||
* @param dependency a dependency to check
|
* @param dependency a dependency to check
|
||||||
* @param nextDependency another dependency to check
|
* @param nextDependency another dependency to check
|
||||||
* @return true if on of the dependencies is a pom.xml and the identifiers between the two collections match;
|
* @return true if on of the dependencies is a pom.xml and the identifiers between the two collections match; otherwise false
|
||||||
* otherwise false
|
|
||||||
*/
|
*/
|
||||||
private boolean isShadedJar(Dependency dependency, Dependency nextDependency) {
|
private boolean isShadedJar(Dependency dependency, Dependency nextDependency) {
|
||||||
final String mainName = dependency.getFileName().toLowerCase();
|
final String mainName = dependency.getFileName().toLowerCase();
|
||||||
@@ -390,4 +376,53 @@ public class DependencyBundlingAnalyzer extends AbstractAnalyzer implements Anal
|
|||||||
}
|
}
|
||||||
return false;
|
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;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Checks if the given file path is contained within a war or ear file.
|
||||||
|
*
|
||||||
|
* @param filePath the file path to check
|
||||||
|
* @return true if the path contains '.war\' or '.ear\'.
|
||||||
|
*/
|
||||||
|
private boolean containedInWar(String filePath) {
|
||||||
|
return filePath == null ? false : filePath.matches(".*\\.(ear|war)[\\\\/].*");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -17,6 +17,7 @@
|
|||||||
*/
|
*/
|
||||||
package org.owasp.dependencycheck.analyzer;
|
package org.owasp.dependencycheck.analyzer;
|
||||||
|
|
||||||
|
import java.io.FileFilter;
|
||||||
import java.io.UnsupportedEncodingException;
|
import java.io.UnsupportedEncodingException;
|
||||||
import java.net.URLEncoder;
|
import java.net.URLEncoder;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
@@ -25,8 +26,6 @@ import java.util.Iterator;
|
|||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.ListIterator;
|
import java.util.ListIterator;
|
||||||
import java.util.Set;
|
import java.util.Set;
|
||||||
import java.util.logging.Level;
|
|
||||||
import java.util.logging.Logger;
|
|
||||||
import java.util.regex.Matcher;
|
import java.util.regex.Matcher;
|
||||||
import java.util.regex.Pattern;
|
import java.util.regex.Pattern;
|
||||||
import org.owasp.dependencycheck.Engine;
|
import org.owasp.dependencycheck.Engine;
|
||||||
@@ -34,18 +33,27 @@ import org.owasp.dependencycheck.analyzer.exception.AnalysisException;
|
|||||||
import org.owasp.dependencycheck.dependency.Dependency;
|
import org.owasp.dependencycheck.dependency.Dependency;
|
||||||
import org.owasp.dependencycheck.dependency.Identifier;
|
import org.owasp.dependencycheck.dependency.Identifier;
|
||||||
import org.owasp.dependencycheck.dependency.VulnerableSoftware;
|
import org.owasp.dependencycheck.dependency.VulnerableSoftware;
|
||||||
|
import org.owasp.dependencycheck.utils.FileFilterBuilder;
|
||||||
|
import org.slf4j.Logger;
|
||||||
|
import org.slf4j.LoggerFactory;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* This analyzer attempts to remove some well known false positives - specifically regarding the java runtime.
|
* This analyzer attempts to remove some well known false positives - specifically regarding the java runtime.
|
||||||
*
|
*
|
||||||
* @author Jeremy Long <jeremy.long@owasp.org>
|
* @author Jeremy Long
|
||||||
*/
|
*/
|
||||||
public class FalsePositiveAnalyzer extends AbstractAnalyzer {
|
public class FalsePositiveAnalyzer extends AbstractAnalyzer {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The Logger.
|
* The Logger.
|
||||||
*/
|
*/
|
||||||
private static final Logger LOGGER = Logger.getLogger(FalsePositiveAnalyzer.class.getName());
|
private static final Logger LOGGER = LoggerFactory.getLogger(FalsePositiveAnalyzer.class);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The file filter used to find DLL and EXE.
|
||||||
|
*/
|
||||||
|
private static final FileFilter DLL_EXE_FILTER = FileFilterBuilder.newInstance().addExtensions("dll", "exe").build();
|
||||||
|
|
||||||
//<editor-fold defaultstate="collapsed" desc="All standard implementation details of Analyzer">
|
//<editor-fold defaultstate="collapsed" desc="All standard implementation details of Analyzer">
|
||||||
/**
|
/**
|
||||||
* The name of the analyzer.
|
* The name of the analyzer.
|
||||||
@@ -86,12 +94,46 @@ public class FalsePositiveAnalyzer extends AbstractAnalyzer {
|
|||||||
public void analyze(Dependency dependency, Engine engine) throws AnalysisException {
|
public void analyze(Dependency dependency, Engine engine) throws AnalysisException {
|
||||||
removeJreEntries(dependency);
|
removeJreEntries(dependency);
|
||||||
removeBadMatches(dependency);
|
removeBadMatches(dependency);
|
||||||
|
removeBadSpringMatches(dependency);
|
||||||
removeWrongVersionMatches(dependency);
|
removeWrongVersionMatches(dependency);
|
||||||
removeSpuriousCPE(dependency);
|
removeSpuriousCPE(dependency);
|
||||||
removeDuplicativeEntriesFromJar(dependency, engine);
|
removeDuplicativeEntriesFromJar(dependency, engine);
|
||||||
addFalseNegativeCPEs(dependency);
|
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>
|
* <p>
|
||||||
* Intended to remove spurious CPE entries. By spurious we mean duplicate, less specific CPE entries.</p>
|
* Intended to remove spurious CPE entries. By spurious we mean duplicate, less specific CPE entries.</p>
|
||||||
@@ -137,7 +179,7 @@ public class FalsePositiveAnalyzer extends AbstractAnalyzer {
|
|||||||
final String nextVersion = nextCpe.getVersion();
|
final String nextVersion = nextCpe.getVersion();
|
||||||
if (currentVersion == null && nextVersion == null) {
|
if (currentVersion == null && nextVersion == null) {
|
||||||
//how did we get here?
|
//how did we get here?
|
||||||
LOGGER.log(Level.FINE, "currentVersion and nextVersion are both null?");
|
LOGGER.debug("currentVersion and nextVersion are both null?");
|
||||||
} else if (currentVersion == null && nextVersion != null) {
|
} else if (currentVersion == null && nextVersion != null) {
|
||||||
dependency.getIdentifiers().remove(currentId);
|
dependency.getIdentifiers().remove(currentId);
|
||||||
} else if (nextVersion == null && currentVersion != null) {
|
} else if (nextVersion == null && currentVersion != null) {
|
||||||
@@ -214,15 +256,15 @@ public class FalsePositiveAnalyzer extends AbstractAnalyzer {
|
|||||||
try {
|
try {
|
||||||
cpe.parseName(value);
|
cpe.parseName(value);
|
||||||
} catch (UnsupportedEncodingException ex) {
|
} catch (UnsupportedEncodingException ex) {
|
||||||
LOGGER.log(Level.FINEST, null, ex);
|
LOGGER.trace("", ex);
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
return cpe;
|
return cpe;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Removes bad CPE matches for a dependency. Unfortunately, right now these are hard-coded patches for specific
|
* Removes bad CPE matches for a dependency. Unfortunately, right now these are hard-coded patches for specific problems
|
||||||
* problems identified when testing this on a LARGE volume of jar files.
|
* identified when testing this on a LARGE volume of jar files.
|
||||||
*
|
*
|
||||||
* @param dependency the dependency to analyze
|
* @param dependency the dependency to analyze
|
||||||
*/
|
*/
|
||||||
@@ -239,7 +281,7 @@ public class FalsePositiveAnalyzer extends AbstractAnalyzer {
|
|||||||
//Set<Evidence> artifactId = dependency.getVendorEvidence().getEvidence("pom", "artifactid");
|
//Set<Evidence> artifactId = dependency.getVendorEvidence().getEvidence("pom", "artifactid");
|
||||||
while (itr.hasNext()) {
|
while (itr.hasNext()) {
|
||||||
final Identifier i = itr.next();
|
final Identifier i = itr.next();
|
||||||
//TODO move this startsWith expression to a configuration file?
|
//TODO move this startsWith expression to the base suppression file
|
||||||
if ("cpe".equals(i.getType())) {
|
if ("cpe".equals(i.getType())) {
|
||||||
if ((i.getValue().matches(".*c\\+\\+.*")
|
if ((i.getValue().matches(".*c\\+\\+.*")
|
||||||
|| i.getValue().startsWith("cpe:/a:file:file")
|
|| i.getValue().startsWith("cpe:/a:file:file")
|
||||||
@@ -254,7 +296,14 @@ public class FalsePositiveAnalyzer extends AbstractAnalyzer {
|
|||||||
|| dependency.getFileName().toLowerCase().endsWith(".dll")
|
|| dependency.getFileName().toLowerCase().endsWith(".dll")
|
||||||
|| dependency.getFileName().toLowerCase().endsWith(".exe")
|
|| dependency.getFileName().toLowerCase().endsWith(".exe")
|
||||||
|| dependency.getFileName().toLowerCase().endsWith(".nuspec")
|
|| dependency.getFileName().toLowerCase().endsWith(".nuspec")
|
||||||
|| dependency.getFileName().toLowerCase().endsWith(".nupkg"))) {
|
|| dependency.getFileName().toLowerCase().endsWith(".zip")
|
||||||
|
|| dependency.getFileName().toLowerCase().endsWith(".sar")
|
||||||
|
|| dependency.getFileName().toLowerCase().endsWith(".apk")
|
||||||
|
|| dependency.getFileName().toLowerCase().endsWith(".tar")
|
||||||
|
|| dependency.getFileName().toLowerCase().endsWith(".gz")
|
||||||
|
|| dependency.getFileName().toLowerCase().endsWith(".tgz")
|
||||||
|
|| dependency.getFileName().toLowerCase().endsWith(".ear")
|
||||||
|
|| dependency.getFileName().toLowerCase().endsWith(".war"))) {
|
||||||
itr.remove();
|
itr.remove();
|
||||||
} else if ((i.getValue().startsWith("cpe:/a:jquery:jquery")
|
} else if ((i.getValue().startsWith("cpe:/a:jquery:jquery")
|
||||||
|| i.getValue().startsWith("cpe:/a:prototypejs:prototype")
|
|| i.getValue().startsWith("cpe:/a:prototypejs:prototype")
|
||||||
@@ -268,8 +317,11 @@ public class FalsePositiveAnalyzer extends AbstractAnalyzer {
|
|||||||
|| i.getValue().startsWith("cpe:/a:microsoft:word")
|
|| i.getValue().startsWith("cpe:/a:microsoft:word")
|
||||||
|| i.getValue().startsWith("cpe:/a:microsoft:visio")
|
|| i.getValue().startsWith("cpe:/a:microsoft:visio")
|
||||||
|| i.getValue().startsWith("cpe:/a:microsoft:powerpoint")
|
|| i.getValue().startsWith("cpe:/a:microsoft:powerpoint")
|
||||||
|| i.getValue().startsWith("cpe:/a:microsoft:office"))
|
|| i.getValue().startsWith("cpe:/a:microsoft:office")
|
||||||
|
|| i.getValue().startsWith("cpe:/a:core_ftp:core_ftp"))
|
||||||
&& (dependency.getFileName().toLowerCase().endsWith(".jar")
|
&& (dependency.getFileName().toLowerCase().endsWith(".jar")
|
||||||
|
|| dependency.getFileName().toLowerCase().endsWith(".ear")
|
||||||
|
|| dependency.getFileName().toLowerCase().endsWith(".war")
|
||||||
|| dependency.getFileName().toLowerCase().endsWith("pom.xml"))) {
|
|| dependency.getFileName().toLowerCase().endsWith("pom.xml"))) {
|
||||||
itr.remove();
|
itr.remove();
|
||||||
} else if (i.getValue().startsWith("cpe:/a:apache:maven")
|
} else if (i.getValue().startsWith("cpe:/a:apache:maven")
|
||||||
@@ -320,9 +372,8 @@ public class FalsePositiveAnalyzer extends AbstractAnalyzer {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* There are some known CPE entries, specifically regarding sun and oracle products due to the acquisition and
|
* There are some known CPE entries, specifically regarding sun and oracle products due to the acquisition and changes in
|
||||||
* changes in product names, that based on given evidence we can add the related CPE entries to ensure a complete
|
* product names, that based on given evidence we can add the related CPE entries to ensure a complete list of CVE entries.
|
||||||
* list of CVE entries.
|
|
||||||
*
|
*
|
||||||
* @param dependency the dependency being analyzed
|
* @param dependency the dependency being analyzed
|
||||||
*/
|
*/
|
||||||
@@ -354,23 +405,22 @@ public class FalsePositiveAnalyzer extends AbstractAnalyzer {
|
|||||||
newCpe4,
|
newCpe4,
|
||||||
String.format(CPEAnalyzer.NVD_SEARCH_URL, URLEncoder.encode(newCpe4, "UTF-8")));
|
String.format(CPEAnalyzer.NVD_SEARCH_URL, URLEncoder.encode(newCpe4, "UTF-8")));
|
||||||
} catch (UnsupportedEncodingException ex) {
|
} catch (UnsupportedEncodingException ex) {
|
||||||
LOGGER.log(Level.FINE, null, ex);
|
LOGGER.debug("", ex);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Removes duplicate entries identified that are contained within JAR files. These occasionally crop up due to POM
|
* Removes duplicate entries identified that are contained within JAR files. These occasionally crop up due to POM entries or
|
||||||
* entries or other types of files (such as DLLs and EXEs) being contained within the JAR.
|
* other types of files (such as DLLs and EXEs) being contained within the JAR.
|
||||||
*
|
*
|
||||||
* @param dependency the dependency that might be a duplicate
|
* @param dependency the dependency that might be a duplicate
|
||||||
* @param engine the engine used to scan all dependencies
|
* @param engine the engine used to scan all dependencies
|
||||||
*/
|
*/
|
||||||
private void removeDuplicativeEntriesFromJar(Dependency dependency, Engine engine) {
|
private void removeDuplicativeEntriesFromJar(Dependency dependency, Engine engine) {
|
||||||
if (dependency.getFileName().toLowerCase().endsWith("pom.xml")
|
if (dependency.getFileName().toLowerCase().endsWith("pom.xml")
|
||||||
|| "dll".equals(dependency.getFileExtension())
|
|| DLL_EXE_FILTER.accept(dependency.getActualFile())) {
|
||||||
|| "exe".equals(dependency.getFileExtension())) {
|
|
||||||
String parentPath = dependency.getFilePath().toLowerCase();
|
String parentPath = dependency.getFilePath().toLowerCase();
|
||||||
if (parentPath.contains(".jar")) {
|
if (parentPath.contains(".jar")) {
|
||||||
parentPath = parentPath.substring(0, parentPath.indexOf(".jar") + 4);
|
parentPath = parentPath.substring(0, parentPath.indexOf(".jar") + 4);
|
||||||
|
|||||||
@@ -29,7 +29,7 @@ import org.owasp.dependencycheck.utils.DependencyVersionUtil;
|
|||||||
*
|
*
|
||||||
* Takes a dependency and analyzes the filename and determines the hashes.
|
* Takes a dependency and analyzes the filename and determines the hashes.
|
||||||
*
|
*
|
||||||
* @author Jeremy Long <jeremy.long@owasp.org>
|
* @author Jeremy Long
|
||||||
*/
|
*/
|
||||||
public class FileNameAnalyzer extends AbstractAnalyzer implements Analyzer {
|
public class FileNameAnalyzer extends AbstractAnalyzer implements Analyzer {
|
||||||
|
|
||||||
@@ -73,7 +73,7 @@ public class FileNameAnalyzer extends AbstractAnalyzer implements Analyzer {
|
|||||||
public void analyze(Dependency dependency, Engine engine) throws AnalysisException {
|
public void analyze(Dependency dependency, Engine engine) throws AnalysisException {
|
||||||
|
|
||||||
//strip any path information that may get added by ArchiveAnalyzer, etc.
|
//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();
|
String fileName = f.getName();
|
||||||
|
|
||||||
//remove file extension
|
//remove file extension
|
||||||
|
|||||||
@@ -17,18 +17,17 @@
|
|||||||
*/
|
*/
|
||||||
package org.owasp.dependencycheck.analyzer;
|
package org.owasp.dependencycheck.analyzer;
|
||||||
|
|
||||||
|
import java.io.FileFilter;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* An Analyzer that scans specific file types.
|
* An Analyzer that scans specific file types.
|
||||||
*
|
*
|
||||||
* @author Jeremy Long <jeremy.long@owasp.org>
|
* @author Jeremy Long
|
||||||
*/
|
*/
|
||||||
public interface FileTypeAnalyzer extends Analyzer {
|
public interface FileTypeAnalyzer extends Analyzer, FileFilter {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns whether or not this analyzer can process the given extension.
|
* Resets the analyzers state.
|
||||||
*
|
|
||||||
* @param extension the file extension to test for support.
|
|
||||||
* @return whether or not the specified file extension is supported by this analyzer.
|
|
||||||
*/
|
*/
|
||||||
boolean supportsExtension(String extension);
|
void reset();
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -19,6 +19,7 @@ package org.owasp.dependencycheck.analyzer;
|
|||||||
|
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.Iterator;
|
import java.util.Iterator;
|
||||||
|
import java.util.List;
|
||||||
import java.util.Set;
|
import java.util.Set;
|
||||||
import org.owasp.dependencycheck.Engine;
|
import org.owasp.dependencycheck.Engine;
|
||||||
import org.owasp.dependencycheck.analyzer.exception.AnalysisException;
|
import org.owasp.dependencycheck.analyzer.exception.AnalysisException;
|
||||||
@@ -28,7 +29,7 @@ import org.owasp.dependencycheck.dependency.Evidence;
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
*
|
*
|
||||||
* @author Jeremy Long <jeremy.long@owasp.org>
|
* @author Jeremy Long
|
||||||
*/
|
*/
|
||||||
public class HintAnalyzer extends AbstractAnalyzer implements Analyzer {
|
public class HintAnalyzer extends AbstractAnalyzer implements Analyzer {
|
||||||
|
|
||||||
@@ -64,8 +65,8 @@ public class HintAnalyzer extends AbstractAnalyzer implements Analyzer {
|
|||||||
//</editor-fold>
|
//</editor-fold>
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The HintAnalyzer uses knowledge about a dependency to add additional information to help in identification of
|
* The HintAnalyzer uses knowledge about a dependency to add additional information to help in identification of identifiers
|
||||||
* identifiers or vulnerabilities.
|
* or vulnerabilities.
|
||||||
*
|
*
|
||||||
* @param dependency The dependency being analyzed
|
* @param dependency The dependency being analyzed
|
||||||
* @param engine The scanning engine
|
* @param engine The scanning engine
|
||||||
@@ -84,24 +85,52 @@ public class HintAnalyzer extends AbstractAnalyzer implements Analyzer {
|
|||||||
Confidence.HIGH);
|
Confidence.HIGH);
|
||||||
|
|
||||||
final Evidence springTest3 = new Evidence("Manifest",
|
final Evidence springTest3 = new Evidence("Manifest",
|
||||||
"Bundle-Vendor",
|
"Implementation-Title",
|
||||||
"SpringSource",
|
"spring-core",
|
||||||
Confidence.HIGH);
|
Confidence.HIGH);
|
||||||
|
|
||||||
Set<Evidence> evidence = dependency.getProductEvidence().getEvidence();
|
final Evidence springTest4 = new Evidence("jar",
|
||||||
if (evidence.contains(springTest1) || evidence.contains(springTest2)) {
|
"package name",
|
||||||
|
"springframework",
|
||||||
|
Confidence.LOW);
|
||||||
|
|
||||||
|
final Evidence springSecurityTest1 = new Evidence("Manifest",
|
||||||
|
"Bundle-Name",
|
||||||
|
"Spring Security Core",
|
||||||
|
Confidence.MEDIUM);
|
||||||
|
|
||||||
|
final Evidence springSecurityTest2 = new Evidence("pom",
|
||||||
|
"artifactid",
|
||||||
|
"spring-security-core",
|
||||||
|
Confidence.HIGH);
|
||||||
|
|
||||||
|
//springsource/vware problem
|
||||||
|
final Set<Evidence> product = dependency.getProductEvidence().getEvidence();
|
||||||
|
final Set<Evidence> vendor = dependency.getVendorEvidence().getEvidence();
|
||||||
|
|
||||||
|
if (product.contains(springTest1) || product.contains(springTest2) || product.contains(springTest3)
|
||||||
|
|| (dependency.getFileName().contains("spring") && product.contains(springTest4))) {
|
||||||
|
dependency.getProductEvidence().addEvidence("hint analyzer", "product", "springsource spring framework", Confidence.HIGH);
|
||||||
|
dependency.getVendorEvidence().addEvidence("hint analyzer", "vendor", "SpringSource", Confidence.HIGH);
|
||||||
|
dependency.getVendorEvidence().addEvidence("hint analyzer", "vendor", "vmware", Confidence.HIGH);
|
||||||
|
dependency.getVendorEvidence().addEvidence("hint analyzer", "vendor", "pivotal", Confidence.HIGH);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (vendor.contains(springTest4)) {
|
||||||
dependency.getProductEvidence().addEvidence("hint analyzer", "product", "springsource_spring_framework", Confidence.HIGH);
|
dependency.getProductEvidence().addEvidence("hint analyzer", "product", "springsource_spring_framework", Confidence.HIGH);
|
||||||
|
dependency.getVendorEvidence().addEvidence("hint analyzer", "vendor", "vmware", Confidence.HIGH);
|
||||||
|
dependency.getVendorEvidence().addEvidence("hint analyzer", "vendor", "pivotal", Confidence.HIGH);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (product.contains(springSecurityTest1) || product.contains(springSecurityTest2)) {
|
||||||
|
dependency.getProductEvidence().addEvidence("hint analyzer", "product", "springsource_spring_security", Confidence.HIGH);
|
||||||
dependency.getVendorEvidence().addEvidence("hint analyzer", "vendor", "SpringSource", Confidence.HIGH);
|
dependency.getVendorEvidence().addEvidence("hint analyzer", "vendor", "SpringSource", Confidence.HIGH);
|
||||||
dependency.getVendorEvidence().addEvidence("hint analyzer", "vendor", "vmware", Confidence.HIGH);
|
dependency.getVendorEvidence().addEvidence("hint analyzer", "vendor", "vmware", Confidence.HIGH);
|
||||||
}
|
}
|
||||||
|
|
||||||
evidence = dependency.getVendorEvidence().getEvidence();
|
//sun/oracle problem
|
||||||
if (evidence.contains(springTest3)) {
|
|
||||||
dependency.getProductEvidence().addEvidence("hint analyzer", "product", "springsource_spring_framework", Confidence.HIGH);
|
|
||||||
dependency.getVendorEvidence().addEvidence("hint analyzer", "vendor", "vmware", Confidence.HIGH);
|
|
||||||
}
|
|
||||||
final Iterator<Evidence> itr = dependency.getVendorEvidence().iterator();
|
final Iterator<Evidence> itr = dependency.getVendorEvidence().iterator();
|
||||||
final ArrayList<Evidence> newEntries = new ArrayList<Evidence>();
|
final List<Evidence> newEntries = new ArrayList<Evidence>();
|
||||||
while (itr.hasNext()) {
|
while (itr.hasNext()) {
|
||||||
final Evidence e = itr.next();
|
final Evidence e = itr.next();
|
||||||
if ("sun".equalsIgnoreCase(e.getValue(false))) {
|
if ("sun".equalsIgnoreCase(e.getValue(false))) {
|
||||||
|
|||||||
@@ -19,15 +19,13 @@ package org.owasp.dependencycheck.analyzer;
|
|||||||
|
|
||||||
import java.io.BufferedOutputStream;
|
import java.io.BufferedOutputStream;
|
||||||
import java.io.File;
|
import java.io.File;
|
||||||
import java.io.FileInputStream;
|
import java.io.FileFilter;
|
||||||
import java.io.FileNotFoundException;
|
|
||||||
import java.io.FileOutputStream;
|
import java.io.FileOutputStream;
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.io.InputStream;
|
import java.io.InputStream;
|
||||||
import java.io.InputStreamReader;
|
import java.io.InputStreamReader;
|
||||||
import java.io.OutputStream;
|
import java.io.OutputStream;
|
||||||
import java.io.Reader;
|
import java.io.Reader;
|
||||||
import java.io.UnsupportedEncodingException;
|
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.Collections;
|
import java.util.Collections;
|
||||||
import java.util.Enumeration;
|
import java.util.Enumeration;
|
||||||
@@ -42,40 +40,27 @@ import java.util.jar.Attributes;
|
|||||||
import java.util.jar.JarEntry;
|
import java.util.jar.JarEntry;
|
||||||
import java.util.jar.JarFile;
|
import java.util.jar.JarFile;
|
||||||
import java.util.jar.Manifest;
|
import java.util.jar.Manifest;
|
||||||
import java.util.logging.Level;
|
|
||||||
import java.util.logging.Logger;
|
|
||||||
import java.util.regex.Pattern;
|
import java.util.regex.Pattern;
|
||||||
import java.util.zip.ZipEntry;
|
import java.util.zip.ZipEntry;
|
||||||
import javax.xml.bind.JAXBContext;
|
|
||||||
import javax.xml.bind.JAXBElement;
|
|
||||||
import javax.xml.bind.JAXBException;
|
|
||||||
import javax.xml.bind.Unmarshaller;
|
|
||||||
import javax.xml.parsers.ParserConfigurationException;
|
|
||||||
import javax.xml.parsers.SAXParser;
|
|
||||||
import javax.xml.parsers.SAXParserFactory;
|
|
||||||
import javax.xml.transform.sax.SAXSource;
|
|
||||||
import org.jsoup.Jsoup;
|
import org.jsoup.Jsoup;
|
||||||
import org.owasp.dependencycheck.Engine;
|
import org.owasp.dependencycheck.Engine;
|
||||||
import org.owasp.dependencycheck.analyzer.exception.AnalysisException;
|
import org.owasp.dependencycheck.analyzer.exception.AnalysisException;
|
||||||
import org.owasp.dependencycheck.dependency.Confidence;
|
import org.owasp.dependencycheck.dependency.Confidence;
|
||||||
import org.owasp.dependencycheck.dependency.Dependency;
|
import org.owasp.dependencycheck.dependency.Dependency;
|
||||||
import org.owasp.dependencycheck.dependency.EvidenceCollection;
|
import org.owasp.dependencycheck.dependency.EvidenceCollection;
|
||||||
import org.owasp.dependencycheck.jaxb.pom.MavenNamespaceFilter;
|
import org.owasp.dependencycheck.utils.FileFilterBuilder;
|
||||||
import org.owasp.dependencycheck.jaxb.pom.generated.License;
|
import org.owasp.dependencycheck.xml.pom.License;
|
||||||
import org.owasp.dependencycheck.jaxb.pom.generated.Model;
|
import org.owasp.dependencycheck.xml.pom.PomUtils;
|
||||||
import org.owasp.dependencycheck.jaxb.pom.generated.Organization;
|
import org.owasp.dependencycheck.xml.pom.Model;
|
||||||
import org.owasp.dependencycheck.utils.FileUtils;
|
import org.owasp.dependencycheck.utils.FileUtils;
|
||||||
import org.owasp.dependencycheck.utils.NonClosingStream;
|
|
||||||
import org.owasp.dependencycheck.utils.Settings;
|
import org.owasp.dependencycheck.utils.Settings;
|
||||||
import org.xml.sax.InputSource;
|
import org.slf4j.Logger;
|
||||||
import org.xml.sax.SAXException;
|
import org.slf4j.LoggerFactory;
|
||||||
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.
|
* 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>
|
* @author Jeremy Long
|
||||||
*/
|
*/
|
||||||
public class JarAnalyzer extends AbstractFileTypeAnalyzer {
|
public class JarAnalyzer extends AbstractFileTypeAnalyzer {
|
||||||
|
|
||||||
@@ -83,7 +68,7 @@ public class JarAnalyzer extends AbstractFileTypeAnalyzer {
|
|||||||
/**
|
/**
|
||||||
* The logger.
|
* The logger.
|
||||||
*/
|
*/
|
||||||
private static final Logger LOGGER = Logger.getLogger(JarAnalyzer.class.getName());
|
private static final Logger LOGGER = LoggerFactory.getLogger(JarAnalyzer.class);
|
||||||
/**
|
/**
|
||||||
* The buffer size to use when extracting files from the archive.
|
* The buffer size to use when extracting files from the archive.
|
||||||
*/
|
*/
|
||||||
@@ -133,11 +118,18 @@ public class JarAnalyzer extends AbstractFileTypeAnalyzer {
|
|||||||
"tool",
|
"tool",
|
||||||
"bundle-manifestversion",
|
"bundle-manifestversion",
|
||||||
"bundlemanifestversion",
|
"bundlemanifestversion",
|
||||||
|
"bundle-vendor",
|
||||||
"include-resource",
|
"include-resource",
|
||||||
"embed-dependency",
|
"embed-dependency",
|
||||||
"ipojo-components",
|
"ipojo-components",
|
||||||
"ipojo-extension",
|
"ipojo-extension",
|
||||||
"eclipse-sourcereferences");
|
"eclipse-sourcereferences");
|
||||||
|
/**
|
||||||
|
* Deprecated Jar manifest attribute, that is, nonetheless, useful for analysis.
|
||||||
|
*/
|
||||||
|
@SuppressWarnings("deprecation")
|
||||||
|
private static final String IMPLEMENTATION_VENDOR_ID = Attributes.Name.IMPLEMENTATION_VENDOR_ID
|
||||||
|
.toString();
|
||||||
/**
|
/**
|
||||||
* item in some manifest, should be considered medium confidence.
|
* item in some manifest, should be considered medium confidence.
|
||||||
*/
|
*/
|
||||||
@@ -150,31 +142,16 @@ public class JarAnalyzer extends AbstractFileTypeAnalyzer {
|
|||||||
* item in some manifest, should be considered medium confidence.
|
* item in some manifest, should be considered medium confidence.
|
||||||
*/
|
*/
|
||||||
private static final String BUNDLE_NAME = "Bundle-Name"; //: Struts 2 Core
|
private static final String BUNDLE_NAME = "Bundle-Name"; //: Struts 2 Core
|
||||||
/**
|
|
||||||
* item in some manifest, should be considered medium confidence.
|
|
||||||
*/
|
|
||||||
private static final String BUNDLE_VENDOR = "Bundle-Vendor"; //: Apache Software Foundation
|
|
||||||
/**
|
/**
|
||||||
* A pattern to detect HTML within text.
|
* A pattern to detect HTML within text.
|
||||||
*/
|
*/
|
||||||
private static final Pattern HTML_DETECTION_PATTERN = Pattern.compile("\\<[a-z]+.*/?\\>", Pattern.CASE_INSENSITIVE);
|
private static final Pattern HTML_DETECTION_PATTERN = Pattern.compile("\\<[a-z]+.*/?\\>", Pattern.CASE_INSENSITIVE);
|
||||||
/**
|
|
||||||
* The unmarshaller used to parse the pom.xml from a JAR file.
|
|
||||||
*/
|
|
||||||
private Unmarshaller pomUnmarshaller;
|
|
||||||
//</editor-fold>
|
|
||||||
|
|
||||||
|
//</editor-fold>
|
||||||
/**
|
/**
|
||||||
* Constructs a new JarAnalyzer.
|
* Constructs a new JarAnalyzer.
|
||||||
*/
|
*/
|
||||||
public JarAnalyzer() {
|
public JarAnalyzer() {
|
||||||
try {
|
|
||||||
final JAXBContext jaxbContext = JAXBContext.newInstance("org.owasp.dependencycheck.jaxb.pom.generated");
|
|
||||||
pomUnmarshaller = jaxbContext.createUnmarshaller();
|
|
||||||
} catch (JAXBException ex) { //guess we will just have a null pointer exception later...
|
|
||||||
LOGGER.log(Level.SEVERE, "Unable to load parser. See the log for more details.");
|
|
||||||
LOGGER.log(Level.FINE, null, ex);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
//<editor-fold defaultstate="collapsed" desc="All standard implmentation details of Analyzer">
|
//<editor-fold defaultstate="collapsed" desc="All standard implmentation details of Analyzer">
|
||||||
@@ -189,16 +166,21 @@ public class JarAnalyzer extends AbstractFileTypeAnalyzer {
|
|||||||
/**
|
/**
|
||||||
* The set of file extensions supported by this analyzer.
|
* The set of file extensions supported by this analyzer.
|
||||||
*/
|
*/
|
||||||
private static final Set<String> EXTENSIONS = newHashSet("jar", "war");
|
private static final String[] EXTENSIONS = {"jar", "war"};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns a list of file EXTENSIONS supported by this analyzer.
|
* The file filter used to determine which files this analyzer supports.
|
||||||
|
*/
|
||||||
|
private static final FileFilter FILTER = FileFilterBuilder.newInstance().addExtensions(EXTENSIONS).build();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the FileFilter.
|
||||||
*
|
*
|
||||||
* @return a list of file EXTENSIONS supported by this analyzer.
|
* @return the FileFilter
|
||||||
*/
|
*/
|
||||||
@Override
|
@Override
|
||||||
public Set<String> getSupportedExtensions() {
|
protected FileFilter getFileFilter() {
|
||||||
return EXTENSIONS;
|
return FILTER;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -242,7 +224,7 @@ public class JarAnalyzer extends AbstractFileTypeAnalyzer {
|
|||||||
@Override
|
@Override
|
||||||
public void analyzeFileType(Dependency dependency, Engine engine) throws AnalysisException {
|
public void analyzeFileType(Dependency dependency, Engine engine) throws AnalysisException {
|
||||||
try {
|
try {
|
||||||
final ArrayList<ClassNameInformation> classNames = collectClassNames(dependency);
|
final List<ClassNameInformation> classNames = collectClassNames(dependency);
|
||||||
final String fileName = dependency.getFileName().toLowerCase();
|
final String fileName = dependency.getFileName().toLowerCase();
|
||||||
if (classNames.isEmpty()
|
if (classNames.isEmpty()
|
||||||
&& (fileName.endsWith("-sources.jar")
|
&& (fileName.endsWith("-sources.jar")
|
||||||
@@ -261,8 +243,8 @@ public class JarAnalyzer extends AbstractFileTypeAnalyzer {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Attempts to find a pom.xml within the JAR file. If found it extracts information and adds it to the evidence.
|
* Attempts to find a pom.xml within the JAR file. If found it extracts information and adds it to the evidence. This will
|
||||||
* This will attempt to interpolate the strings contained within the pom.properties if one exists.
|
* attempt to interpolate the strings contained within the pom.properties if one exists.
|
||||||
*
|
*
|
||||||
* @param dependency the dependency being analyzed
|
* @param dependency the dependency being analyzed
|
||||||
* @param classes a collection of class name information
|
* @param classes a collection of class name information
|
||||||
@@ -270,37 +252,44 @@ public class JarAnalyzer extends AbstractFileTypeAnalyzer {
|
|||||||
* @throws AnalysisException is thrown if there is an exception parsing the pom
|
* @throws AnalysisException is thrown if there is an exception parsing the pom
|
||||||
* @return whether or not evidence was added to the dependency
|
* @return whether or not evidence was added to the dependency
|
||||||
*/
|
*/
|
||||||
protected boolean analyzePOM(Dependency dependency, ArrayList<ClassNameInformation> classes, Engine engine) throws AnalysisException {
|
protected boolean analyzePOM(Dependency dependency, List<ClassNameInformation> classes, Engine engine) throws AnalysisException {
|
||||||
boolean foundSomething = false;
|
boolean foundSomething = false;
|
||||||
final JarFile jar;
|
final JarFile jar;
|
||||||
try {
|
try {
|
||||||
jar = new JarFile(dependency.getActualFilePath());
|
jar = new JarFile(dependency.getActualFilePath());
|
||||||
} catch (IOException ex) {
|
} catch (IOException ex) {
|
||||||
final String msg = String.format("Unable to read JarFile '%s'.", dependency.getActualFilePath());
|
LOGGER.warn("Unable to read JarFile '{}'.", dependency.getActualFilePath());
|
||||||
//final AnalysisException ax = new AnalysisException(msg, ex);
|
LOGGER.trace("", ex);
|
||||||
LOGGER.log(Level.WARNING, msg);
|
|
||||||
LOGGER.log(Level.FINE, "", ex);
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
List<String> pomEntries;
|
List<String> pomEntries;
|
||||||
try {
|
try {
|
||||||
pomEntries = retrievePomListing(jar);
|
pomEntries = retrievePomListing(jar);
|
||||||
} catch (IOException ex) {
|
} catch (IOException ex) {
|
||||||
final String msg = String.format("Unable to read Jar file entries in '%s'.", dependency.getActualFilePath());
|
LOGGER.warn("Unable to read Jar file entries in '{}'.", dependency.getActualFilePath());
|
||||||
//final AnalysisException ax = new AnalysisException(msg, ex);
|
LOGGER.trace("", ex);
|
||||||
LOGGER.log(Level.WARNING, msg);
|
|
||||||
LOGGER.log(Level.FINE, msg, ex);
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
File externalPom = null;
|
||||||
if (pomEntries.isEmpty()) {
|
if (pomEntries.isEmpty()) {
|
||||||
return false;
|
String pomPath = dependency.getActualFilePath();
|
||||||
|
pomPath = pomPath.substring(0, pomPath.lastIndexOf('.')) + ".pom";
|
||||||
|
externalPom = new File(pomPath);
|
||||||
|
if (externalPom.isFile()) {
|
||||||
|
pomEntries.add(pomPath);
|
||||||
|
} else {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
for (String path : pomEntries) {
|
for (String path : pomEntries) {
|
||||||
|
LOGGER.debug("Reading pom entry: {}", path);
|
||||||
Properties pomProperties = null;
|
Properties pomProperties = null;
|
||||||
try {
|
try {
|
||||||
pomProperties = retrievePomProperties(path, jar);
|
if (externalPom == null) {
|
||||||
|
pomProperties = retrievePomProperties(path, jar);
|
||||||
|
}
|
||||||
} catch (IOException ex) {
|
} catch (IOException ex) {
|
||||||
LOGGER.log(Level.FINEST, "ignore this, failed reading a non-existent pom.properties", ex);
|
LOGGER.trace("ignore this, failed reading a non-existent pom.properties", ex);
|
||||||
}
|
}
|
||||||
Model pom = null;
|
Model pom = null;
|
||||||
try {
|
try {
|
||||||
@@ -312,25 +301,30 @@ public class JarAnalyzer extends AbstractFileTypeAnalyzer {
|
|||||||
final String displayPath = String.format("%s%s%s",
|
final String displayPath = String.format("%s%s%s",
|
||||||
dependency.getFilePath(),
|
dependency.getFilePath(),
|
||||||
File.separator,
|
File.separator,
|
||||||
path); //.replaceAll("[\\/]", File.separator));
|
path);
|
||||||
final String displayName = String.format("%s%s%s",
|
final String displayName = String.format("%s%s%s",
|
||||||
dependency.getFileName(),
|
dependency.getFileName(),
|
||||||
File.separator,
|
File.separator,
|
||||||
path); //.replaceAll("[\\/]", File.separator));
|
path);
|
||||||
|
|
||||||
newDependency.setFileName(displayName);
|
newDependency.setFileName(displayName);
|
||||||
newDependency.setFilePath(displayPath);
|
newDependency.setFilePath(displayPath);
|
||||||
setPomEvidence(newDependency, pom, pomProperties, null);
|
pom.processProperties(pomProperties);
|
||||||
|
setPomEvidence(newDependency, pom, null);
|
||||||
engine.getDependencies().add(newDependency);
|
engine.getDependencies().add(newDependency);
|
||||||
Collections.sort(engine.getDependencies());
|
Collections.sort(engine.getDependencies());
|
||||||
} else {
|
} else {
|
||||||
pom = retrievePom(path, jar);
|
if (externalPom == null) {
|
||||||
foundSomething |= setPomEvidence(dependency, pom, pomProperties, classes);
|
pom = PomUtils.readPom(path, jar);
|
||||||
|
} else {
|
||||||
|
pom = PomUtils.readPom(externalPom);
|
||||||
|
}
|
||||||
|
pom.processProperties(pomProperties);
|
||||||
|
foundSomething |= setPomEvidence(dependency, pom, classes);
|
||||||
}
|
}
|
||||||
} catch (AnalysisException ex) {
|
} catch (AnalysisException ex) {
|
||||||
final String msg = String.format("An error occured while analyzing '%s'.", dependency.getActualFilePath());
|
LOGGER.warn("An error occured while analyzing '{}'.", dependency.getActualFilePath());
|
||||||
LOGGER.log(Level.WARNING, msg);
|
LOGGER.trace("", ex);
|
||||||
LOGGER.log(Level.FINE, "", ex);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return foundSomething;
|
return foundSomething;
|
||||||
@@ -344,16 +338,26 @@ public class JarAnalyzer extends AbstractFileTypeAnalyzer {
|
|||||||
* @return a Properties object or null if no pom.properties was found
|
* @return a Properties object or null if no pom.properties was found
|
||||||
* @throws IOException thrown if there is an exception reading the pom.properties
|
* @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 {
|
private Properties retrievePomProperties(String path, final JarFile jar) throws IOException {
|
||||||
Properties pomProperties = null;
|
Properties pomProperties = null;
|
||||||
final String propPath = path.substring(0, path.length() - 7) + "pom.properies";
|
final String propPath = path.substring(0, path.length() - 7) + "pom.properies";
|
||||||
final ZipEntry propEntry = jar.getEntry(propPath);
|
final ZipEntry propEntry = jar.getEntry(propPath);
|
||||||
if (propEntry != null) {
|
if (propEntry != null) {
|
||||||
final Reader reader = new InputStreamReader(jar.getInputStream(propEntry), "UTF-8");
|
Reader reader = null;
|
||||||
pomProperties = new Properties();
|
try {
|
||||||
pomProperties.load(reader);
|
reader = new InputStreamReader(jar.getInputStream(propEntry), "UTF-8");
|
||||||
|
pomProperties = new Properties();
|
||||||
|
pomProperties.load(reader);
|
||||||
|
LOGGER.debug("Read pom.properties: {}", propPath);
|
||||||
|
} finally {
|
||||||
|
if (reader != null) {
|
||||||
|
try {
|
||||||
|
reader.close();
|
||||||
|
} catch (IOException ex) {
|
||||||
|
LOGGER.trace("close error", ex);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
return pomProperties;
|
return pomProperties;
|
||||||
}
|
}
|
||||||
@@ -372,6 +376,7 @@ public class JarAnalyzer extends AbstractFileTypeAnalyzer {
|
|||||||
final JarEntry entry = entries.nextElement();
|
final JarEntry entry = entries.nextElement();
|
||||||
final String entryName = (new File(entry.getName())).getName().toLowerCase();
|
final String entryName = (new File(entry.getName())).getName().toLowerCase();
|
||||||
if (!entry.isDirectory() && "pom.xml".equals(entryName)) {
|
if (!entry.isDirectory() && "pom.xml".equals(entryName)) {
|
||||||
|
LOGGER.trace("POM Entry found: {}", entry.getName());
|
||||||
pomEntries.add(entry.getName());
|
pomEntries.add(entry.getName());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -386,7 +391,7 @@ public class JarAnalyzer extends AbstractFileTypeAnalyzer {
|
|||||||
* @param dependency the dependency being analyzed
|
* @param dependency the dependency being analyzed
|
||||||
* @return returns the POM object
|
* @return returns the POM object
|
||||||
* @throws AnalysisException is thrown if there is an exception extracting or parsing the POM
|
* @throws AnalysisException is thrown if there is an exception extracting or parsing the POM
|
||||||
* {@link org.owasp.dependencycheck.jaxb.pom.generated.Model} object
|
* {@link org.owasp.dependencycheck.xml.pom.Model} object
|
||||||
*/
|
*/
|
||||||
private Model extractPom(String path, JarFile jar, Dependency dependency) throws AnalysisException {
|
private Model extractPom(String path, JarFile jar, Dependency dependency) throws AnalysisException {
|
||||||
InputStream input = null;
|
InputStream input = null;
|
||||||
@@ -400,48 +405,21 @@ public class JarAnalyzer extends AbstractFileTypeAnalyzer {
|
|||||||
fos = new FileOutputStream(file);
|
fos = new FileOutputStream(file);
|
||||||
bos = new BufferedOutputStream(fos, BUFFER_SIZE);
|
bos = new BufferedOutputStream(fos, BUFFER_SIZE);
|
||||||
int count;
|
int count;
|
||||||
final byte data[] = new byte[BUFFER_SIZE];
|
final byte[] data = new byte[BUFFER_SIZE];
|
||||||
while ((count = input.read(data, 0, BUFFER_SIZE)) != -1) {
|
while ((count = input.read(data, 0, BUFFER_SIZE)) != -1) {
|
||||||
bos.write(data, 0, count);
|
bos.write(data, 0, count);
|
||||||
}
|
}
|
||||||
bos.flush();
|
bos.flush();
|
||||||
dependency.setActualFilePath(file.getAbsolutePath());
|
dependency.setActualFilePath(file.getAbsolutePath());
|
||||||
} catch (IOException ex) {
|
} catch (IOException ex) {
|
||||||
final String msg = String.format("An error occurred reading '%s' from '%s'.", path, dependency.getFilePath());
|
LOGGER.warn("An error occurred reading '{}' from '{}'.", path, dependency.getFilePath());
|
||||||
LOGGER.warning(msg);
|
LOGGER.error("", ex);
|
||||||
LOGGER.log(Level.SEVERE, "", ex);
|
|
||||||
} finally {
|
} finally {
|
||||||
closeStream(bos);
|
closeStream(bos);
|
||||||
closeStream(fos);
|
closeStream(fos);
|
||||||
closeStream(input);
|
closeStream(input);
|
||||||
}
|
}
|
||||||
Model model = null;
|
return PomUtils.readPom(file);
|
||||||
FileInputStream fis = null;
|
|
||||||
try {
|
|
||||||
fis = new FileInputStream(file);
|
|
||||||
final InputStreamReader reader = new InputStreamReader(fis, "UTF-8");
|
|
||||||
final InputSource xml = new InputSource(reader);
|
|
||||||
final SAXSource source = new SAXSource(xml);
|
|
||||||
model = readPom(source);
|
|
||||||
} catch (FileNotFoundException ex) {
|
|
||||||
final String msg = String.format("Unable to parse pom '%s' in jar '%s' (File Not Found)", path, jar.getName());
|
|
||||||
LOGGER.log(Level.WARNING, msg);
|
|
||||||
LOGGER.log(Level.FINE, "", ex);
|
|
||||||
throw new AnalysisException(ex);
|
|
||||||
} catch (UnsupportedEncodingException ex) {
|
|
||||||
final String msg = String.format("Unable to parse pom '%s' in jar '%s' (IO Exception)", path, jar.getName());
|
|
||||||
LOGGER.log(Level.WARNING, msg);
|
|
||||||
LOGGER.log(Level.FINE, "", ex);
|
|
||||||
throw new AnalysisException(ex);
|
|
||||||
} catch (AnalysisException ex) {
|
|
||||||
final String msg = String.format("Unable to parse pom '%s' in jar '%s'", path, jar.getName());
|
|
||||||
LOGGER.log(Level.WARNING, msg);
|
|
||||||
LOGGER.log(Level.FINE, "", ex);
|
|
||||||
throw ex;
|
|
||||||
} finally {
|
|
||||||
closeStream(fis);
|
|
||||||
}
|
|
||||||
return model;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -454,7 +432,7 @@ public class JarAnalyzer extends AbstractFileTypeAnalyzer {
|
|||||||
try {
|
try {
|
||||||
stream.close();
|
stream.close();
|
||||||
} catch (IOException ex) {
|
} catch (IOException ex) {
|
||||||
LOGGER.log(Level.FINEST, null, ex);
|
LOGGER.trace("", ex);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -469,115 +447,64 @@ public class JarAnalyzer extends AbstractFileTypeAnalyzer {
|
|||||||
try {
|
try {
|
||||||
stream.close();
|
stream.close();
|
||||||
} catch (IOException ex) {
|
} catch (IOException ex) {
|
||||||
LOGGER.log(Level.FINEST, null, ex);
|
LOGGER.trace("", ex);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Retrieves the specified POM from a jar file and converts it to a Model.
|
|
||||||
*
|
|
||||||
* @param path the path to the pom.xml file within the jar file
|
|
||||||
* @param jar the jar file to extract the pom from
|
|
||||||
* @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(String path, JarFile jar) throws AnalysisException {
|
|
||||||
final ZipEntry entry = jar.getEntry(path);
|
|
||||||
Model model = null;
|
|
||||||
if (entry != null) { //should never be null
|
|
||||||
try {
|
|
||||||
final NonClosingStream stream = new NonClosingStream(jar.getInputStream(entry));
|
|
||||||
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' in jar '%s'; invalid signature", path, jar.getName());
|
|
||||||
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' in jar '%s' (IO Exception)", path, jar.getName());
|
|
||||||
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' in jar '%s'", path, jar.getName());
|
|
||||||
LOGGER.log(Level.WARNING, msg);
|
|
||||||
LOGGER.log(Level.FINE, "", ex);
|
|
||||||
throw new AnalysisException(ex);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return model;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Retrieves the specified POM from a jar file and converts it to a Model.
|
|
||||||
*
|
|
||||||
* @param source the SAXSource input stream to read the POM from
|
|
||||||
* @return returns the POM object
|
|
||||||
* @throws AnalysisException is thrown if there is an exception extracting or parsing the POM
|
|
||||||
* {@link org.owasp.dependencycheck.jaxb.pom.generated.Model} object
|
|
||||||
*/
|
|
||||||
private Model readPom(SAXSource source) throws AnalysisException {
|
|
||||||
Model model = null;
|
|
||||||
try {
|
|
||||||
final XMLFilter filter = new MavenNamespaceFilter();
|
|
||||||
final SAXParserFactory spf = SAXParserFactory.newInstance();
|
|
||||||
final SAXParser sp = spf.newSAXParser();
|
|
||||||
final XMLReader xr = sp.getXMLReader();
|
|
||||||
filter.setParent(xr);
|
|
||||||
final JAXBElement<Model> el = pomUnmarshaller.unmarshal(source, Model.class);
|
|
||||||
model = el.getValue();
|
|
||||||
} catch (SecurityException ex) {
|
|
||||||
throw new AnalysisException(ex);
|
|
||||||
} catch (ParserConfigurationException ex) {
|
|
||||||
throw new AnalysisException(ex);
|
|
||||||
} catch (SAXException ex) {
|
|
||||||
throw new AnalysisException(ex);
|
|
||||||
} catch (JAXBException ex) {
|
|
||||||
throw new AnalysisException(ex);
|
|
||||||
} catch (Throwable ex) {
|
|
||||||
throw new AnalysisException(ex);
|
|
||||||
}
|
|
||||||
return model;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Sets evidence from the pom on the supplied dependency.
|
* Sets evidence from the pom on the supplied dependency.
|
||||||
*
|
*
|
||||||
* @param dependency the dependency to set data on
|
* @param dependency the dependency to set data on
|
||||||
* @param pom the information from the pom
|
* @param pom the information from the pom
|
||||||
* @param pomProperties the pom properties file (null if none exists)
|
* @param classes a collection of ClassNameInformation - containing data about the fully qualified class names within the JAR
|
||||||
* @param classes a collection of ClassNameInformation - containing data about the fully qualified class names
|
* file being analyzed
|
||||||
* within the JAR file being analyzed
|
|
||||||
* @return true if there was evidence within the pom that we could use; otherwise false
|
* @return true if there was evidence within the pom that we could use; otherwise false
|
||||||
*/
|
*/
|
||||||
private boolean setPomEvidence(Dependency dependency, Model pom, Properties pomProperties, ArrayList<ClassNameInformation> classes) {
|
public static boolean setPomEvidence(Dependency dependency, Model pom, List<ClassNameInformation> classes) {
|
||||||
boolean foundSomething = false;
|
boolean foundSomething = false;
|
||||||
boolean addAsIdentifier = true;
|
boolean addAsIdentifier = true;
|
||||||
if (pom == null) {
|
if (pom == null) {
|
||||||
return foundSomething;
|
return foundSomething;
|
||||||
}
|
}
|
||||||
String groupid = interpolateString(pom.getGroupId(), pomProperties);
|
String groupid = pom.getGroupId();
|
||||||
String parentGroupId = null;
|
String parentGroupId = pom.getParentGroupId();
|
||||||
|
String artifactid = pom.getArtifactId();
|
||||||
|
String parentArtifactId = pom.getParentArtifactId();
|
||||||
|
String version = pom.getVersion();
|
||||||
|
String parentVersion = pom.getParentVersion();
|
||||||
|
|
||||||
if (pom.getParent() != null) {
|
if ("org.sonatype.oss".equals(parentGroupId) && "oss-parent".equals(parentArtifactId)) {
|
||||||
parentGroupId = interpolateString(pom.getParent().getGroupId(), pomProperties);
|
parentGroupId = null;
|
||||||
if ((groupid == null || groupid.isEmpty()) && parentGroupId != null && !parentGroupId.isEmpty()) {
|
parentArtifactId = null;
|
||||||
groupid = parentGroupId;
|
parentVersion = null;
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if ((groupid == null || groupid.isEmpty()) && parentGroupId != null && !parentGroupId.isEmpty()) {
|
||||||
|
groupid = parentGroupId;
|
||||||
|
}
|
||||||
|
|
||||||
final String originalGroupID = groupid;
|
final String originalGroupID = groupid;
|
||||||
|
if (groupid.startsWith("org.") || groupid.startsWith("com.")) {
|
||||||
|
groupid = groupid.substring(4);
|
||||||
|
}
|
||||||
|
|
||||||
|
if ((artifactid == null || artifactid.isEmpty()) && parentArtifactId != null && !parentArtifactId.isEmpty()) {
|
||||||
|
artifactid = parentArtifactId;
|
||||||
|
}
|
||||||
|
|
||||||
|
final String originalArtifactID = artifactid;
|
||||||
|
if (artifactid.startsWith("org.") || artifactid.startsWith("com.")) {
|
||||||
|
artifactid = artifactid.substring(4);
|
||||||
|
}
|
||||||
|
|
||||||
|
if ((version == null || version.isEmpty()) && parentVersion != null && !parentVersion.isEmpty()) {
|
||||||
|
version = parentVersion;
|
||||||
|
}
|
||||||
|
|
||||||
if (groupid != null && !groupid.isEmpty()) {
|
if (groupid != null && !groupid.isEmpty()) {
|
||||||
if (groupid.startsWith("org.") || groupid.startsWith("com.")) {
|
|
||||||
groupid = groupid.substring(4);
|
|
||||||
}
|
|
||||||
foundSomething = true;
|
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);
|
dependency.getProductEvidence().addEvidence("pom", "groupid", groupid, Confidence.LOW);
|
||||||
addMatchingValues(classes, groupid, dependency.getVendorEvidence());
|
addMatchingValues(classes, groupid, dependency.getVendorEvidence());
|
||||||
addMatchingValues(classes, groupid, dependency.getProductEvidence());
|
addMatchingValues(classes, groupid, dependency.getProductEvidence());
|
||||||
@@ -591,22 +518,9 @@ public class JarAnalyzer extends AbstractFileTypeAnalyzer {
|
|||||||
addAsIdentifier = false;
|
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 != null && !artifactid.isEmpty()) {
|
||||||
if (artifactid.startsWith("org.") || artifactid.startsWith("com.")) {
|
|
||||||
artifactid = artifactid.substring(4);
|
|
||||||
}
|
|
||||||
foundSomething = true;
|
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);
|
dependency.getVendorEvidence().addEvidence("pom", "artifactid", artifactid, Confidence.LOW);
|
||||||
addMatchingValues(classes, artifactid, dependency.getVendorEvidence());
|
addMatchingValues(classes, artifactid, dependency.getVendorEvidence());
|
||||||
addMatchingValues(classes, artifactid, dependency.getProductEvidence());
|
addMatchingValues(classes, artifactid, dependency.getProductEvidence());
|
||||||
@@ -619,16 +533,6 @@ public class JarAnalyzer extends AbstractFileTypeAnalyzer {
|
|||||||
} else {
|
} else {
|
||||||
addAsIdentifier = false;
|
addAsIdentifier = false;
|
||||||
}
|
}
|
||||||
//version
|
|
||||||
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()) {
|
if (version != null && !version.isEmpty()) {
|
||||||
foundSomething = true;
|
foundSomething = true;
|
||||||
@@ -641,22 +545,21 @@ public class JarAnalyzer extends AbstractFileTypeAnalyzer {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (addAsIdentifier) {
|
if (addAsIdentifier) {
|
||||||
dependency.addIdentifier("maven", String.format("%s:%s:%s", originalGroupID, originalArtifactID, version), null, Confidence.LOW);
|
dependency.addIdentifier("maven", String.format("%s:%s:%s", originalGroupID, originalArtifactID, version), null, Confidence.HIGH);
|
||||||
}
|
}
|
||||||
|
|
||||||
// org name
|
// org name
|
||||||
final Organization org = pom.getOrganization();
|
final String org = pom.getOrganization();
|
||||||
if (org != null && org.getName() != null) {
|
if (org != null && !org.isEmpty()) {
|
||||||
foundSomething = true;
|
dependency.getVendorEvidence().addEvidence("pom", "organization name", org, Confidence.HIGH);
|
||||||
final String orgName = interpolateString(org.getName(), pomProperties);
|
dependency.getProductEvidence().addEvidence("pom", "organization name", org, Confidence.LOW);
|
||||||
if (orgName != null && !orgName.isEmpty()) {
|
addMatchingValues(classes, org, dependency.getVendorEvidence());
|
||||||
dependency.getVendorEvidence().addEvidence("pom", "organization name", orgName, Confidence.HIGH);
|
addMatchingValues(classes, org, dependency.getProductEvidence());
|
||||||
addMatchingValues(classes, orgName, dependency.getVendorEvidence());
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
//pom name
|
//pom name
|
||||||
final String pomName = interpolateString(pom.getName(), pomProperties);
|
final String pomName = pom.getName();
|
||||||
if (pomName != null && !pomName.isEmpty()) {
|
if (pomName
|
||||||
|
!= null && !pomName.isEmpty()) {
|
||||||
foundSomething = true;
|
foundSomething = true;
|
||||||
dependency.getProductEvidence().addEvidence("pom", "name", pomName, Confidence.HIGH);
|
dependency.getProductEvidence().addEvidence("pom", "name", pomName, Confidence.HIGH);
|
||||||
dependency.getVendorEvidence().addEvidence("pom", "name", pomName, Confidence.HIGH);
|
dependency.getVendorEvidence().addEvidence("pom", "name", pomName, Confidence.HIGH);
|
||||||
@@ -665,31 +568,30 @@ public class JarAnalyzer extends AbstractFileTypeAnalyzer {
|
|||||||
}
|
}
|
||||||
|
|
||||||
//Description
|
//Description
|
||||||
if (pom.getDescription() != null) {
|
final String description = pom.getDescription();
|
||||||
|
if (description != null && !description.isEmpty() && !description.startsWith("POM was created by")) {
|
||||||
foundSomething = true;
|
foundSomething = true;
|
||||||
final String description = interpolateString(pom.getDescription(), pomProperties);
|
final String trimmedDescription = addDescription(dependency, description, "pom", "description");
|
||||||
if (description != null && !description.isEmpty()) {
|
addMatchingValues(classes, trimmedDescription, dependency.getVendorEvidence());
|
||||||
final String trimmedDescription = addDescription(dependency, description, "pom", "description");
|
addMatchingValues(classes, trimmedDescription, dependency.getProductEvidence());
|
||||||
addMatchingValues(classes, trimmedDescription, dependency.getVendorEvidence());
|
|
||||||
addMatchingValues(classes, trimmedDescription, dependency.getProductEvidence());
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
extractLicense(pom, pomProperties, dependency);
|
|
||||||
|
extractLicense(pom, dependency);
|
||||||
return foundSomething;
|
return foundSomething;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Analyzes the path information of the classes contained within the JarAnalyzer to try and determine possible
|
* Analyzes the path information of the classes contained within the JarAnalyzer to try and determine possible vendor or
|
||||||
* vendor or product names. If any are found they are stored in the packageVendor and packageProduct hashSets.
|
* product names. If any are found they are stored in the packageVendor and packageProduct hashSets.
|
||||||
*
|
*
|
||||||
* @param classNames a list of class names
|
* @param classNames a list of class names
|
||||||
* @param dependency a dependency to analyze
|
* @param dependency a dependency to analyze
|
||||||
* @param addPackagesAsEvidence a flag indicating whether or not package names should be added as evidence.
|
* @param addPackagesAsEvidence a flag indicating whether or not package names should be added as evidence.
|
||||||
*/
|
*/
|
||||||
protected void analyzePackageNames(ArrayList<ClassNameInformation> classNames,
|
protected void analyzePackageNames(List<ClassNameInformation> classNames,
|
||||||
Dependency dependency, boolean addPackagesAsEvidence) {
|
Dependency dependency, boolean addPackagesAsEvidence) {
|
||||||
final HashMap<String, Integer> vendorIdentifiers = new HashMap<String, Integer>();
|
final Map<String, Integer> vendorIdentifiers = new HashMap<String, Integer>();
|
||||||
final HashMap<String, Integer> productIdentifiers = new HashMap<String, Integer>();
|
final Map<String, Integer> productIdentifiers = new HashMap<String, Integer>();
|
||||||
analyzeFullyQualifiedClassNames(classNames, vendorIdentifiers, productIdentifiers);
|
analyzeFullyQualifiedClassNames(classNames, vendorIdentifiers, productIdentifiers);
|
||||||
|
|
||||||
final int classCount = classNames.size();
|
final int classCount = classNames.size();
|
||||||
@@ -731,7 +633,7 @@ public class JarAnalyzer extends AbstractFileTypeAnalyzer {
|
|||||||
* @return whether evidence was identified parsing the manifest
|
* @return whether evidence was identified parsing the manifest
|
||||||
* @throws IOException if there is an issue reading the JAR file
|
* @throws IOException if there is an issue reading the JAR file
|
||||||
*/
|
*/
|
||||||
protected boolean parseManifest(Dependency dependency, ArrayList<ClassNameInformation> classInformation) throws IOException {
|
protected boolean parseManifest(Dependency dependency, List<ClassNameInformation> classInformation) throws IOException {
|
||||||
boolean foundSomething = false;
|
boolean foundSomething = false;
|
||||||
JarFile jar = null;
|
JarFile jar = null;
|
||||||
try {
|
try {
|
||||||
@@ -745,9 +647,8 @@ public class JarAnalyzer extends AbstractFileTypeAnalyzer {
|
|||||||
&& !dependency.getFileName().toLowerCase().endsWith("-javadoc.jar")
|
&& !dependency.getFileName().toLowerCase().endsWith("-javadoc.jar")
|
||||||
&& !dependency.getFileName().toLowerCase().endsWith("-src.jar")
|
&& !dependency.getFileName().toLowerCase().endsWith("-src.jar")
|
||||||
&& !dependency.getFileName().toLowerCase().endsWith("-doc.jar")) {
|
&& !dependency.getFileName().toLowerCase().endsWith("-doc.jar")) {
|
||||||
LOGGER.log(Level.FINE,
|
LOGGER.debug("Jar file '{}' does not contain a manifest.",
|
||||||
String.format("Jar file '%s' does not contain a manifest.",
|
dependency.getFileName());
|
||||||
dependency.getFileName()));
|
|
||||||
}
|
}
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
@@ -759,6 +660,9 @@ public class JarAnalyzer extends AbstractFileTypeAnalyzer {
|
|||||||
|
|
||||||
final String source = "Manifest";
|
final String source = "Manifest";
|
||||||
|
|
||||||
|
String specificationVersion = null;
|
||||||
|
boolean hasImplementationVersion = false;
|
||||||
|
|
||||||
for (Entry<Object, Object> entry : atts.entrySet()) {
|
for (Entry<Object, Object> entry : atts.entrySet()) {
|
||||||
String key = entry.getKey().toString();
|
String key = entry.getKey().toString();
|
||||||
String value = atts.getValue(key);
|
String value = atts.getValue(key);
|
||||||
@@ -772,13 +676,16 @@ public class JarAnalyzer extends AbstractFileTypeAnalyzer {
|
|||||||
productEvidence.addEvidence(source, key, value, Confidence.HIGH);
|
productEvidence.addEvidence(source, key, value, Confidence.HIGH);
|
||||||
addMatchingValues(classInformation, value, productEvidence);
|
addMatchingValues(classInformation, value, productEvidence);
|
||||||
} else if (key.equalsIgnoreCase(Attributes.Name.IMPLEMENTATION_VERSION.toString())) {
|
} else if (key.equalsIgnoreCase(Attributes.Name.IMPLEMENTATION_VERSION.toString())) {
|
||||||
|
hasImplementationVersion = true;
|
||||||
foundSomething = true;
|
foundSomething = true;
|
||||||
versionEvidence.addEvidence(source, key, value, Confidence.HIGH);
|
versionEvidence.addEvidence(source, key, value, Confidence.HIGH);
|
||||||
|
} else if ("specification-version".equalsIgnoreCase(key)) {
|
||||||
|
specificationVersion = key;
|
||||||
} else if (key.equalsIgnoreCase(Attributes.Name.IMPLEMENTATION_VENDOR.toString())) {
|
} else if (key.equalsIgnoreCase(Attributes.Name.IMPLEMENTATION_VENDOR.toString())) {
|
||||||
foundSomething = true;
|
foundSomething = true;
|
||||||
vendorEvidence.addEvidence(source, key, value, Confidence.HIGH);
|
vendorEvidence.addEvidence(source, key, value, Confidence.HIGH);
|
||||||
addMatchingValues(classInformation, value, vendorEvidence);
|
addMatchingValues(classInformation, value, vendorEvidence);
|
||||||
} else if (key.equalsIgnoreCase(Attributes.Name.IMPLEMENTATION_VENDOR_ID.toString())) {
|
} else if (key.equalsIgnoreCase(IMPLEMENTATION_VENDOR_ID)) {
|
||||||
foundSomething = true;
|
foundSomething = true;
|
||||||
vendorEvidence.addEvidence(source, key, value, Confidence.MEDIUM);
|
vendorEvidence.addEvidence(source, key, value, Confidence.MEDIUM);
|
||||||
addMatchingValues(classInformation, value, vendorEvidence);
|
addMatchingValues(classInformation, value, vendorEvidence);
|
||||||
@@ -791,10 +698,11 @@ public class JarAnalyzer extends AbstractFileTypeAnalyzer {
|
|||||||
foundSomething = true;
|
foundSomething = true;
|
||||||
productEvidence.addEvidence(source, key, value, Confidence.MEDIUM);
|
productEvidence.addEvidence(source, key, value, Confidence.MEDIUM);
|
||||||
addMatchingValues(classInformation, value, productEvidence);
|
addMatchingValues(classInformation, value, productEvidence);
|
||||||
} else if (key.equalsIgnoreCase(BUNDLE_VENDOR)) {
|
// //the following caused false positives.
|
||||||
foundSomething = true;
|
// } else if (key.equalsIgnoreCase(BUNDLE_VENDOR)) {
|
||||||
vendorEvidence.addEvidence(source, key, value, Confidence.HIGH);
|
// foundSomething = true;
|
||||||
addMatchingValues(classInformation, value, vendorEvidence);
|
// vendorEvidence.addEvidence(source, key, value, Confidence.HIGH);
|
||||||
|
// addMatchingValues(classInformation, value, vendorEvidence);
|
||||||
} else if (key.equalsIgnoreCase(BUNDLE_VERSION)) {
|
} else if (key.equalsIgnoreCase(BUNDLE_VERSION)) {
|
||||||
foundSomething = true;
|
foundSomething = true;
|
||||||
versionEvidence.addEvidence(source, key, value, Confidence.HIGH);
|
versionEvidence.addEvidence(source, key, value, Confidence.HIGH);
|
||||||
@@ -825,9 +733,9 @@ public class JarAnalyzer extends AbstractFileTypeAnalyzer {
|
|||||||
|
|
||||||
foundSomething = true;
|
foundSomething = true;
|
||||||
if (key.contains("version")) {
|
if (key.contains("version")) {
|
||||||
if (key.contains("specification")) {
|
if (!key.contains("specification")) {
|
||||||
versionEvidence.addEvidence(source, key, value, Confidence.LOW);
|
//versionEvidence.addEvidence(source, key, value, Confidence.LOW);
|
||||||
} else {
|
//} else {
|
||||||
versionEvidence.addEvidence(source, key, value, Confidence.MEDIUM);
|
versionEvidence.addEvidence(source, key, value, Confidence.MEDIUM);
|
||||||
}
|
}
|
||||||
} else if ("build-id".equals(key)) {
|
} else if ("build-id".equals(key)) {
|
||||||
@@ -879,6 +787,10 @@ public class JarAnalyzer extends AbstractFileTypeAnalyzer {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
if (specificationVersion != null && !hasImplementationVersion) {
|
||||||
|
foundSomething = true;
|
||||||
|
versionEvidence.addEvidence(source, "specificationn-version", specificationVersion, Confidence.HIGH);
|
||||||
|
}
|
||||||
} finally {
|
} finally {
|
||||||
if (jar != null) {
|
if (jar != null) {
|
||||||
jar.close();
|
jar.close();
|
||||||
@@ -888,18 +800,17 @@ public class JarAnalyzer extends AbstractFileTypeAnalyzer {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Adds a description to the given dependency. If the description contains one of the following strings beyond 100
|
* Adds a description to the given dependency. If the description contains one of the following strings beyond 100 characters,
|
||||||
* characters, then the description used will be trimmed to that position:
|
* then the description used will be trimmed to that position:
|
||||||
* <ul><li>"such as"</li><li>"like "</li><li>"will use "</li><li>"* uses "</li></ul>
|
* <ul><li>"such as"</li><li>"like "</li><li>"will use "</li><li>"* uses "</li></ul>
|
||||||
*
|
*
|
||||||
* @param dependency a dependency
|
* @param dependency a dependency
|
||||||
* @param description the description
|
* @param description the description
|
||||||
* @param source the source of the evidence
|
* @param source the source of the evidence
|
||||||
* @param key the "name" of the evidence
|
* @param key the "name" of the evidence
|
||||||
* @return if the description is trimmed, the trimmed version is returned; otherwise the original description is
|
* @return if the description is trimmed, the trimmed version is returned; otherwise the original description is returned
|
||||||
* returned
|
|
||||||
*/
|
*/
|
||||||
private String addDescription(Dependency dependency, String description, String source, String key) {
|
public static String addDescription(Dependency dependency, String description, String source, String key) {
|
||||||
if (dependency.getDescription() == null) {
|
if (dependency.getDescription() == null) {
|
||||||
dependency.setDescription(description);
|
dependency.setDescription(description);
|
||||||
}
|
}
|
||||||
@@ -993,72 +904,14 @@ public class JarAnalyzer extends AbstractFileTypeAnalyzer {
|
|||||||
@Override
|
@Override
|
||||||
public void close() {
|
public void close() {
|
||||||
if (tempFileLocation != null && tempFileLocation.exists()) {
|
if (tempFileLocation != null && tempFileLocation.exists()) {
|
||||||
LOGGER.log(Level.FINE, "Attempting to delete temporary files");
|
LOGGER.debug("Attempting to delete temporary files");
|
||||||
final boolean success = FileUtils.delete(tempFileLocation);
|
final boolean success = FileUtils.delete(tempFileLocation);
|
||||||
if (!success) {
|
if (!success) {
|
||||||
LOGGER.log(Level.WARNING,
|
LOGGER.warn("Failed to delete some temporary files, see the log for more details");
|
||||||
"Failed to delete some temporary files, see the log for more details");
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* <p>
|
|
||||||
* A utility function that will interpolate strings based on values given in the properties file. It will also
|
|
||||||
* interpolate the strings contained within the properties file so that properties can reference other
|
|
||||||
* properties.</p>
|
|
||||||
* <p>
|
|
||||||
* <b>Note:</b> if there is no property found the reference will be removed. In other words, if the interpolated
|
|
||||||
* string will be replaced with an empty string.
|
|
||||||
* </p>
|
|
||||||
* <p>
|
|
||||||
* Example:</p>
|
|
||||||
* <code>
|
|
||||||
* Properties p = new Properties();
|
|
||||||
* p.setProperty("key", "value");
|
|
||||||
* String s = interpolateString("'${key}' and '${nothing}'", p);
|
|
||||||
* System.out.println(s);
|
|
||||||
* </code>
|
|
||||||
* <p>
|
|
||||||
* Will result in:</p>
|
|
||||||
* <code>
|
|
||||||
* 'value' and ''
|
|
||||||
* </code>
|
|
||||||
*
|
|
||||||
* @param text the string that contains references to properties.
|
|
||||||
* @param properties a collection of properties that may be referenced within the text.
|
|
||||||
* @return the interpolated text.
|
|
||||||
*/
|
|
||||||
protected String interpolateString(String text, Properties properties) {
|
|
||||||
Properties props = properties;
|
|
||||||
if (text == null) {
|
|
||||||
return text;
|
|
||||||
}
|
|
||||||
if (props == null) {
|
|
||||||
props = new Properties();
|
|
||||||
}
|
|
||||||
|
|
||||||
final int pos = text.indexOf("${");
|
|
||||||
if (pos < 0) {
|
|
||||||
return text;
|
|
||||||
}
|
|
||||||
final int end = text.indexOf("}");
|
|
||||||
if (end < pos) {
|
|
||||||
return text;
|
|
||||||
}
|
|
||||||
|
|
||||||
final String propName = text.substring(pos + 2, end);
|
|
||||||
String propValue = interpolateString(props.getProperty(propName), props);
|
|
||||||
if (propValue == null) {
|
|
||||||
propValue = "";
|
|
||||||
}
|
|
||||||
final StringBuilder sb = new StringBuilder(propValue.length() + text.length());
|
|
||||||
sb.append(text.subSequence(0, pos));
|
|
||||||
sb.append(propValue);
|
|
||||||
sb.append(text.substring(end + 1));
|
|
||||||
return interpolateString(sb.toString(), props); //yes yes, this should be a loop...
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Determines if the key value pair from the manifest is for an "import" type entry for package names.
|
* Determines if the key value pair from the manifest is for an "import" type entry for package names.
|
||||||
*
|
*
|
||||||
@@ -1073,20 +926,20 @@ public class JarAnalyzer extends AbstractFileTypeAnalyzer {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Cycles through an enumeration of JarEntries, contained within the dependency, and returns a list of the class
|
* Cycles through an enumeration of JarEntries, contained within the dependency, and returns a list of the class names. This
|
||||||
* names. This does not include core Java package names (i.e. java.* or javax.*).
|
* does not include core Java package names (i.e. java.* or javax.*).
|
||||||
*
|
*
|
||||||
* @param dependency the dependency being analyzed
|
* @param dependency the dependency being analyzed
|
||||||
* @return an list of fully qualified class names
|
* @return an list of fully qualified class names
|
||||||
*/
|
*/
|
||||||
private ArrayList<ClassNameInformation> collectClassNames(Dependency dependency) {
|
private List<ClassNameInformation> collectClassNames(Dependency dependency) {
|
||||||
final ArrayList<ClassNameInformation> classNames = new ArrayList<ClassNameInformation>();
|
final List<ClassNameInformation> classNames = new ArrayList<ClassNameInformation>();
|
||||||
JarFile jar = null;
|
JarFile jar = null;
|
||||||
try {
|
try {
|
||||||
jar = new JarFile(dependency.getActualFilePath());
|
jar = new JarFile(dependency.getActualFilePath());
|
||||||
final Enumeration entries = jar.entries();
|
final Enumeration<JarEntry> entries = jar.entries();
|
||||||
while (entries.hasMoreElements()) {
|
while (entries.hasMoreElements()) {
|
||||||
final JarEntry entry = (JarEntry) entries.nextElement();
|
final JarEntry entry = entries.nextElement();
|
||||||
final String name = entry.getName().toLowerCase();
|
final String name = entry.getName().toLowerCase();
|
||||||
//no longer stripping "|com\\.sun" - there are some com.sun jar files with CVEs.
|
//no longer stripping "|com\\.sun" - there are some com.sun jar files with CVEs.
|
||||||
if (name.endsWith(".class") && !name.matches("^javax?\\..*$")) {
|
if (name.endsWith(".class") && !name.matches("^javax?\\..*$")) {
|
||||||
@@ -1095,15 +948,14 @@ public class JarAnalyzer extends AbstractFileTypeAnalyzer {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
} catch (IOException ex) {
|
} catch (IOException ex) {
|
||||||
final String msg = String.format("Unable to open jar file '%s'.", dependency.getFileName());
|
LOGGER.warn("Unable to open jar file '{}'.", dependency.getFileName());
|
||||||
LOGGER.log(Level.WARNING, msg);
|
LOGGER.debug("", ex);
|
||||||
LOGGER.log(Level.FINE, null, ex);
|
|
||||||
} finally {
|
} finally {
|
||||||
if (jar != null) {
|
if (jar != null) {
|
||||||
try {
|
try {
|
||||||
jar.close();
|
jar.close();
|
||||||
} catch (IOException ex) {
|
} catch (IOException ex) {
|
||||||
LOGGER.log(Level.FINEST, null, ex);
|
LOGGER.trace("", ex);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1111,17 +963,17 @@ public class JarAnalyzer extends AbstractFileTypeAnalyzer {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Cycles through the list of class names and places the package levels 0-3 into the provided maps for vendor and
|
* Cycles through the list of class names and places the package levels 0-3 into the provided maps for vendor and product.
|
||||||
* product. This is helpful when analyzing vendor/product as many times this is included in the package name.
|
* This is helpful when analyzing vendor/product as many times this is included in the package name.
|
||||||
*
|
*
|
||||||
* @param classNames a list of class names
|
* @param classNames a list of class names
|
||||||
* @param vendor HashMap of possible vendor names from package names (e.g. owasp)
|
* @param vendor HashMap of possible vendor names from package names (e.g. owasp)
|
||||||
* @param product HashMap of possible product names from package names (e.g. dependencycheck)
|
* @param product HashMap of possible product names from package names (e.g. dependencycheck)
|
||||||
*/
|
*/
|
||||||
private void analyzeFullyQualifiedClassNames(ArrayList<ClassNameInformation> classNames,
|
private void analyzeFullyQualifiedClassNames(List<ClassNameInformation> classNames,
|
||||||
HashMap<String, Integer> vendor, HashMap<String, Integer> product) {
|
Map<String, Integer> vendor, Map<String, Integer> product) {
|
||||||
for (ClassNameInformation entry : classNames) {
|
for (ClassNameInformation entry : classNames) {
|
||||||
final ArrayList<String> list = entry.getPackageStructure();
|
final List<String> list = entry.getPackageStructure();
|
||||||
addEntry(vendor, list.get(0));
|
addEntry(vendor, list.get(0));
|
||||||
|
|
||||||
if (list.size() == 2) {
|
if (list.size() == 2) {
|
||||||
@@ -1143,13 +995,13 @@ public class JarAnalyzer extends AbstractFileTypeAnalyzer {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Adds an entry to the specified collection and sets the Integer (e.g. the count) to 1. If the entry already exists
|
* Adds an entry to the specified collection and sets the Integer (e.g. the count) to 1. If the entry already exists in the
|
||||||
* in the collection then the Integer is incremented by 1.
|
* collection then the Integer is incremented by 1.
|
||||||
*
|
*
|
||||||
* @param collection a collection of strings and their occurrence count
|
* @param collection a collection of strings and their occurrence count
|
||||||
* @param key the key to add to the collection
|
* @param key the key to add to the collection
|
||||||
*/
|
*/
|
||||||
private void addEntry(HashMap<String, Integer> collection, String key) {
|
private void addEntry(Map<String, Integer> collection, String key) {
|
||||||
if (collection.containsKey(key)) {
|
if (collection.containsKey(key)) {
|
||||||
collection.put(key, collection.get(key) + 1);
|
collection.put(key, collection.get(key) + 1);
|
||||||
} else {
|
} else {
|
||||||
@@ -1158,15 +1010,15 @@ public class JarAnalyzer extends AbstractFileTypeAnalyzer {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Cycles through the collection of class name information to see if parts of the package names are contained in the
|
* Cycles through the collection of class name information to see if parts of the package names are contained in the provided
|
||||||
* provided value. If found, it will be added as the HIGHEST confidence evidence because we have more then one
|
* value. If found, it will be added as the HIGHEST confidence evidence because we have more then one source corroborating the
|
||||||
* source corroborating the value.
|
* value.
|
||||||
*
|
*
|
||||||
* @param classes a collection of class name information
|
* @param classes a collection of class name information
|
||||||
* @param value the value to check to see if it contains a package name
|
* @param value the value to check to see if it contains a package name
|
||||||
* @param evidence the evidence collection to add new entries too
|
* @param evidence the evidence collection to add new entries too
|
||||||
*/
|
*/
|
||||||
private void addMatchingValues(ArrayList<ClassNameInformation> classes, String value, EvidenceCollection evidence) {
|
private static void addMatchingValues(List<ClassNameInformation> classes, String value, EvidenceCollection evidence) {
|
||||||
if (value == null || value.isEmpty() || classes == null || classes.isEmpty()) {
|
if (value == null || value.isEmpty() || classes == null || classes.isEmpty()) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@@ -1198,23 +1050,22 @@ public class JarAnalyzer extends AbstractFileTypeAnalyzer {
|
|||||||
* Extracts the license information from the pom and adds it to the dependency.
|
* Extracts the license information from the pom and adds it to the dependency.
|
||||||
*
|
*
|
||||||
* @param pom the pom object
|
* @param pom the pom object
|
||||||
* @param pomProperties the properties, used for string interpolation
|
|
||||||
* @param dependency the dependency to add license information too
|
* @param dependency the dependency to add license information too
|
||||||
*/
|
*/
|
||||||
private void extractLicense(Model pom, Properties pomProperties, Dependency dependency) {
|
public static void extractLicense(Model pom, Dependency dependency) {
|
||||||
//license
|
//license
|
||||||
if (pom.getLicenses() != null) {
|
if (pom.getLicenses() != null) {
|
||||||
String license = null;
|
String license = null;
|
||||||
for (License lic : pom.getLicenses().getLicense()) {
|
for (License lic : pom.getLicenses()) {
|
||||||
String tmp = null;
|
String tmp = null;
|
||||||
if (lic.getName() != null) {
|
if (lic.getName() != null) {
|
||||||
tmp = interpolateString(lic.getName(), pomProperties);
|
tmp = lic.getName();
|
||||||
}
|
}
|
||||||
if (lic.getUrl() != null) {
|
if (lic.getUrl() != null) {
|
||||||
if (tmp == null) {
|
if (tmp == null) {
|
||||||
tmp = interpolateString(lic.getUrl(), pomProperties);
|
tmp = lic.getUrl();
|
||||||
} else {
|
} else {
|
||||||
tmp += ": " + interpolateString(lic.getUrl(), pomProperties);
|
tmp += ": " + lic.getUrl();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (tmp == null) {
|
if (tmp == null) {
|
||||||
@@ -1231,6 +1082,7 @@ public class JarAnalyzer extends AbstractFileTypeAnalyzer {
|
|||||||
}
|
}
|
||||||
if (license != null) {
|
if (license != null) {
|
||||||
dependency.setLicense(license);
|
dependency.setLicense(license);
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1242,9 +1094,9 @@ public class JarAnalyzer extends AbstractFileTypeAnalyzer {
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* <p>
|
* <p>
|
||||||
* Stores information about a given class name. This class will keep the fully qualified class name and a list
|
* Stores information about a given class name. This class will keep the fully qualified class name and a list of the
|
||||||
* of the important parts of the package structure. Up to the first four levels of the package structure are
|
* important parts of the package structure. Up to the first four levels of the package structure are stored, excluding a
|
||||||
* stored, excluding a leading "org" or "com". Example:</p>
|
* leading "org" or "com". Example:</p>
|
||||||
* <code>ClassNameInformation obj = new ClassNameInformation("org.owasp.dependencycheck.analyzer.JarAnalyzer");
|
* <code>ClassNameInformation obj = new ClassNameInformation("org.owasp.dependencycheck.analyzer.JarAnalyzer");
|
||||||
* System.out.println(obj.getName());
|
* System.out.println(obj.getName());
|
||||||
* for (String p : obj.getPackageStructure())
|
* for (String p : obj.getPackageStructure())
|
||||||
|
|||||||
@@ -1,141 +0,0 @@
|
|||||||
/*
|
|
||||||
* This file is part of dependency-check-core.
|
|
||||||
*
|
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
||||||
* you may not use this file except in compliance with the License.
|
|
||||||
* You may obtain a copy of the License at
|
|
||||||
*
|
|
||||||
* http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
*
|
|
||||||
* Unless required by applicable law or agreed to in writing, software
|
|
||||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
||||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
* See the License for the specific language governing permissions and
|
|
||||||
* limitations under the License.
|
|
||||||
*
|
|
||||||
* Copyright (c) 2014 Jeremy Long. All Rights Reserved.
|
|
||||||
*/
|
|
||||||
package org.owasp.dependencycheck.analyzer;
|
|
||||||
|
|
||||||
import java.io.BufferedReader;
|
|
||||||
import java.io.File;
|
|
||||||
import java.io.FileNotFoundException;
|
|
||||||
import java.io.FileReader;
|
|
||||||
import java.io.IOException;
|
|
||||||
import java.util.Set;
|
|
||||||
import java.util.logging.Level;
|
|
||||||
import java.util.logging.Logger;
|
|
||||||
import java.util.regex.Pattern;
|
|
||||||
import org.owasp.dependencycheck.Engine;
|
|
||||||
import org.owasp.dependencycheck.analyzer.exception.AnalysisException;
|
|
||||||
import org.owasp.dependencycheck.dependency.Dependency;
|
|
||||||
import org.owasp.dependencycheck.utils.Settings;
|
|
||||||
|
|
||||||
/**
|
|
||||||
*
|
|
||||||
* Used to analyze a JavaScript file to gather information to aid in identification of a CPE identifier.
|
|
||||||
*
|
|
||||||
* @author Jeremy Long <jeremy.long@owasp.org>
|
|
||||||
*/
|
|
||||||
public class JavaScriptAnalyzer extends AbstractFileTypeAnalyzer {
|
|
||||||
|
|
||||||
/**
|
|
||||||
* The logger.
|
|
||||||
*/
|
|
||||||
private static final Logger LOGGER = Logger.getLogger(JavaScriptAnalyzer.class.getName());
|
|
||||||
|
|
||||||
//<editor-fold defaultstate="collapsed" desc="All standard implementation details of Analyzer">
|
|
||||||
/**
|
|
||||||
* The name of the analyzer.
|
|
||||||
*/
|
|
||||||
private static final String ANALYZER_NAME = "JavaScript Analyzer";
|
|
||||||
/**
|
|
||||||
* The phase that this analyzer is intended to run in.
|
|
||||||
*/
|
|
||||||
private static final AnalysisPhase ANALYSIS_PHASE = AnalysisPhase.INFORMATION_COLLECTION;
|
|
||||||
/**
|
|
||||||
* The set of file extensions supported by this analyzer.
|
|
||||||
*/
|
|
||||||
private static final Set<String> EXTENSIONS = newHashSet("js");
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Returns a list of file EXTENSIONS supported by this analyzer.
|
|
||||||
*
|
|
||||||
* @return a list of file EXTENSIONS supported by this analyzer.
|
|
||||||
*/
|
|
||||||
@Override
|
|
||||||
public Set<String> getSupportedExtensions() {
|
|
||||||
return EXTENSIONS;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Returns the name of the analyzer.
|
|
||||||
*
|
|
||||||
* @return the name of the analyzer.
|
|
||||||
*/
|
|
||||||
@Override
|
|
||||||
public String getName() {
|
|
||||||
return ANALYZER_NAME;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Returns the phase that the analyzer is intended to run in.
|
|
||||||
*
|
|
||||||
* @return the phase that the analyzer is intended to run in.
|
|
||||||
*/
|
|
||||||
@Override
|
|
||||||
public AnalysisPhase getAnalysisPhase() {
|
|
||||||
return ANALYSIS_PHASE;
|
|
||||||
}
|
|
||||||
//</editor-fold>
|
|
||||||
/**
|
|
||||||
* Returns the key used in the properties file to reference the analyzer's enabled property.
|
|
||||||
*
|
|
||||||
* @return the analyzer's enabled property setting key
|
|
||||||
*/
|
|
||||||
@Override
|
|
||||||
protected String getAnalyzerEnabledSettingKey() {
|
|
||||||
return Settings.KEYS.ANALYZER_JAVASCRIPT_ENABLED;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Loads a specified JavaScript file and collects information from the copyright information contained within.
|
|
||||||
*
|
|
||||||
* @param dependency the dependency to analyze.
|
|
||||||
* @param engine the engine that is scanning the dependencies
|
|
||||||
* @throws AnalysisException is thrown if there is an error reading the JavaScript file.
|
|
||||||
*/
|
|
||||||
@Override
|
|
||||||
public void analyzeFileType(Dependency dependency, Engine engine) throws AnalysisException {
|
|
||||||
BufferedReader fin = null;
|
|
||||||
try {
|
|
||||||
// /\*([^\*][^/]|[\r\n\f])+?\*/
|
|
||||||
final Pattern extractComments = Pattern.compile("(/\\*([^*]|[\\r\\n]|(\\*+([^*/]|[\\r\\n])))*\\*+/)|(//.*)", Pattern.MULTILINE);
|
|
||||||
File file = dependency.getActualFile();
|
|
||||||
fin = new BufferedReader(new FileReader(file));
|
|
||||||
StringBuilder sb = new StringBuilder(2000);
|
|
||||||
String text;
|
|
||||||
while ((text = fin.readLine()) != null) {
|
|
||||||
sb.append(text);
|
|
||||||
}
|
|
||||||
} catch (FileNotFoundException ex) {
|
|
||||||
final String msg = String.format("Dependency file not found: '%s'", dependency.getActualFilePath());
|
|
||||||
throw new AnalysisException(msg, ex);
|
|
||||||
} catch (IOException ex) {
|
|
||||||
LOGGER.log(Level.SEVERE, null, ex);
|
|
||||||
} finally {
|
|
||||||
if (fin != null) {
|
|
||||||
try {
|
|
||||||
fin.close();
|
|
||||||
} catch (IOException ex) {
|
|
||||||
LOGGER.log(Level.FINEST, null, ex);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
protected void initializeFileTypeAnalyzer() throws Exception {
|
|
||||||
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -17,20 +17,28 @@
|
|||||||
*/
|
*/
|
||||||
package org.owasp.dependencycheck.analyzer;
|
package org.owasp.dependencycheck.analyzer;
|
||||||
|
|
||||||
import java.io.FileNotFoundException;
|
import org.apache.commons.io.FileUtils;
|
||||||
import java.io.IOException;
|
|
||||||
import java.net.MalformedURLException;
|
|
||||||
import java.net.URL;
|
|
||||||
import java.util.Set;
|
|
||||||
import java.util.logging.Level;
|
|
||||||
import java.util.logging.Logger;
|
|
||||||
import org.owasp.dependencycheck.Engine;
|
import org.owasp.dependencycheck.Engine;
|
||||||
import org.owasp.dependencycheck.analyzer.exception.AnalysisException;
|
import org.owasp.dependencycheck.analyzer.exception.AnalysisException;
|
||||||
import org.owasp.dependencycheck.data.nexus.MavenArtifact;
|
import org.owasp.dependencycheck.data.nexus.MavenArtifact;
|
||||||
import org.owasp.dependencycheck.data.nexus.NexusSearch;
|
import org.owasp.dependencycheck.data.nexus.NexusSearch;
|
||||||
import org.owasp.dependencycheck.dependency.Confidence;
|
import org.owasp.dependencycheck.dependency.Confidence;
|
||||||
import org.owasp.dependencycheck.dependency.Dependency;
|
import org.owasp.dependencycheck.dependency.Dependency;
|
||||||
import org.owasp.dependencycheck.dependency.Identifier;
|
import org.owasp.dependencycheck.dependency.Evidence;
|
||||||
|
import org.owasp.dependencycheck.xml.pom.PomUtils;
|
||||||
|
import org.slf4j.Logger;
|
||||||
|
import org.slf4j.LoggerFactory;
|
||||||
|
|
||||||
|
import java.io.File;
|
||||||
|
import java.io.FileFilter;
|
||||||
|
import java.io.FileNotFoundException;
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.net.MalformedURLException;
|
||||||
|
import java.net.URL;
|
||||||
|
import org.owasp.dependencycheck.utils.DownloadFailedException;
|
||||||
|
import org.owasp.dependencycheck.utils.Downloader;
|
||||||
|
import org.owasp.dependencycheck.utils.FileFilterBuilder;
|
||||||
|
import org.owasp.dependencycheck.utils.InvalidSettingException;
|
||||||
import org.owasp.dependencycheck.utils.Settings;
|
import org.owasp.dependencycheck.utils.Settings;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -39,20 +47,25 @@ import org.owasp.dependencycheck.utils.Settings;
|
|||||||
* There are two settings which govern this behavior:
|
* There are two settings which govern this behavior:
|
||||||
*
|
*
|
||||||
* <ul>
|
* <ul>
|
||||||
* <li>{@link org.owasp.dependencycheck.utils.Settings.KEYS#ANALYZER_NEXUS_ENABLED} determines whether this analyzer is
|
* <li>{@link org.owasp.dependencycheck.utils.Settings.KEYS#ANALYZER_NEXUS_ENABLED} determines whether this analyzer is even
|
||||||
* even enabled. This can be overridden by setting the system property.</li>
|
* enabled. This can be overridden by setting the system property.</li>
|
||||||
* <li>{@link org.owasp.dependencycheck.utils.Settings.KEYS#ANALYZER_NEXUS_URL} the URL to a Nexus service to search by
|
* <li>{@link org.owasp.dependencycheck.utils.Settings.KEYS#ANALYZER_NEXUS_URL} the URL to a Nexus service to search by SHA-1.
|
||||||
* SHA-1. There is an expected <code>%s</code> in this where the SHA-1 will get entered.</li>
|
* There is an expected <code>%s</code> in this where the SHA-1 will get entered.</li>
|
||||||
* </ul>
|
* </ul>
|
||||||
*
|
*
|
||||||
* @author colezlaw
|
* @author colezlaw
|
||||||
*/
|
*/
|
||||||
public class NexusAnalyzer extends AbstractFileTypeAnalyzer {
|
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.
|
* The logger.
|
||||||
*/
|
*/
|
||||||
private static final Logger LOGGER = Logger.getLogger(NexusAnalyzer.class.getName());
|
private static final Logger LOGGER = LoggerFactory.getLogger(NexusAnalyzer.class);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The name of the analyzer.
|
* The name of the analyzer.
|
||||||
@@ -67,13 +80,54 @@ public class NexusAnalyzer extends AbstractFileTypeAnalyzer {
|
|||||||
/**
|
/**
|
||||||
* The types of files on which this will work.
|
* The types of files on which this will work.
|
||||||
*/
|
*/
|
||||||
private static final Set<String> SUPPORTED_EXTENSIONS = newHashSet("jar");
|
private static final String SUPPORTED_EXTENSIONS = "jar";
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The Nexus Search to be set up for this analyzer.
|
* The Nexus Search to be set up for this analyzer.
|
||||||
*/
|
*/
|
||||||
private NexusSearch searcher;
|
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.debug("Nexus analyzer disabled, using Central instead");
|
||||||
|
}
|
||||||
|
} catch (InvalidSettingException ise) {
|
||||||
|
LOGGER.warn("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.
|
* Initializes the analyzer once before any analysis is performed.
|
||||||
*
|
*
|
||||||
@@ -81,21 +135,21 @@ public class NexusAnalyzer extends AbstractFileTypeAnalyzer {
|
|||||||
*/
|
*/
|
||||||
@Override
|
@Override
|
||||||
public void initializeFileTypeAnalyzer() throws Exception {
|
public void initializeFileTypeAnalyzer() throws Exception {
|
||||||
LOGGER.fine("Initializing Nexus Analyzer");
|
LOGGER.debug("Initializing Nexus Analyzer");
|
||||||
LOGGER.fine(String.format("Nexus Analyzer enabled: %s", isEnabled()));
|
LOGGER.debug("Nexus Analyzer enabled: {}", isEnabled());
|
||||||
if (isEnabled()) {
|
if (isEnabled()) {
|
||||||
final String searchUrl = Settings.getString(Settings.KEYS.ANALYZER_NEXUS_URL);
|
final String searchUrl = Settings.getString(Settings.KEYS.ANALYZER_NEXUS_URL);
|
||||||
LOGGER.fine(String.format("Nexus Analyzer URL: %s", searchUrl));
|
LOGGER.debug("Nexus Analyzer URL: {}", searchUrl);
|
||||||
try {
|
try {
|
||||||
searcher = new NexusSearch(new URL(searchUrl));
|
searcher = new NexusSearch(new URL(searchUrl));
|
||||||
if (!searcher.preflightRequest()) {
|
if (!searcher.preflightRequest()) {
|
||||||
LOGGER.warning("There was an issue getting Nexus status. Disabling analyzer.");
|
LOGGER.warn("There was an issue getting Nexus status. Disabling analyzer.");
|
||||||
setEnabled(false);
|
setEnabled(false);
|
||||||
}
|
}
|
||||||
} catch (MalformedURLException mue) {
|
} catch (MalformedURLException mue) {
|
||||||
// I know that initialize can throw an exception, but we'll
|
// I know that initialize can throw an exception, but we'll
|
||||||
// just disable the analyzer if the URL isn't valid
|
// just disable the analyzer if the URL isn't valid
|
||||||
LOGGER.warning(String.format("Property %s not a valid URL. Nexus Analyzer disabled", searchUrl));
|
LOGGER.warn("Property {} not a valid URL. Nexus Analyzer disabled", searchUrl);
|
||||||
setEnabled(false);
|
setEnabled(false);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -132,13 +186,18 @@ public class NexusAnalyzer extends AbstractFileTypeAnalyzer {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns the extensions for which this Analyzer runs.
|
* The file filter used to determine which files this analyzer supports.
|
||||||
|
*/
|
||||||
|
private static final FileFilter FILTER = FileFilterBuilder.newInstance().addExtensions(SUPPORTED_EXTENSIONS).build();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the FileFilter
|
||||||
*
|
*
|
||||||
* @return the extensions for which this Analyzer runs
|
* @return the FileFilter
|
||||||
*/
|
*/
|
||||||
@Override
|
@Override
|
||||||
public Set<String> getSupportedExtensions() {
|
protected FileFilter getFileFilter() {
|
||||||
return SUPPORTED_EXTENSIONS;
|
return FILTER;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -150,29 +209,40 @@ public class NexusAnalyzer extends AbstractFileTypeAnalyzer {
|
|||||||
*/
|
*/
|
||||||
@Override
|
@Override
|
||||||
public void analyzeFileType(Dependency dependency, Engine engine) throws AnalysisException {
|
public void analyzeFileType(Dependency dependency, Engine engine) throws AnalysisException {
|
||||||
|
if (!isEnabled()) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
try {
|
try {
|
||||||
final MavenArtifact ma = searcher.searchSha1(dependency.getSha1sum());
|
final MavenArtifact ma = searcher.searchSha1(dependency.getSha1sum());
|
||||||
if (ma.getGroupId() != null && !"".equals(ma.getGroupId())) {
|
dependency.addAsEvidence("nexus", ma, Confidence.HIGH);
|
||||||
dependency.getVendorEvidence().addEvidence("nexus", "groupid", ma.getGroupId(), Confidence.HIGH);
|
boolean pomAnalyzed = false;
|
||||||
}
|
LOGGER.debug("POM URL {}", ma.getPomUrl());
|
||||||
if (ma.getArtifactId() != null && !"".equals(ma.getArtifactId())) {
|
for (Evidence e : dependency.getVendorEvidence()) {
|
||||||
dependency.getProductEvidence().addEvidence("nexus", "artifactid", ma.getArtifactId(), Confidence.HIGH);
|
if ("pom".equals(e.getSource())) {
|
||||||
}
|
pomAnalyzed = true;
|
||||||
if (ma.getVersion() != null && !"".equals(ma.getVersion())) {
|
break;
|
||||||
dependency.getVersionEvidence().addEvidence("nexus", "version", ma.getVersion(), Confidence.HIGH);
|
|
||||||
}
|
|
||||||
if (ma.getArtifactUrl() != null && !"".equals(ma.getArtifactUrl())) {
|
|
||||||
boolean found = false;
|
|
||||||
for (Identifier i : dependency.getIdentifiers()) {
|
|
||||||
if ("maven".equals(i.getType()) && i.getValue().equals(ma.toString())) {
|
|
||||||
found = true;
|
|
||||||
i.setConfidence(Confidence.HIGHEST);
|
|
||||||
i.setUrl(ma.getArtifactUrl());
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
if (!found) {
|
}
|
||||||
dependency.addIdentifier("maven", ma.toString(), ma.getArtifactUrl(), Confidence.HIGHEST);
|
if (!pomAnalyzed && ma.getPomUrl() != null) {
|
||||||
|
File pomFile = null;
|
||||||
|
try {
|
||||||
|
final File baseDir = Settings.getTempDirectory();
|
||||||
|
pomFile = File.createTempFile("pom", ".xml", baseDir);
|
||||||
|
if (!pomFile.delete()) {
|
||||||
|
LOGGER.warn("Unable to fetch pom.xml for {} from Nexus repository; "
|
||||||
|
+ "this could result in undetected CPE/CVEs.", dependency.getFileName());
|
||||||
|
LOGGER.debug("Unable to delete temp file");
|
||||||
|
}
|
||||||
|
LOGGER.debug("Downloading {}", ma.getPomUrl());
|
||||||
|
Downloader.fetchFile(new URL(ma.getPomUrl()), pomFile);
|
||||||
|
PomUtils.analyzePOM(dependency, pomFile);
|
||||||
|
} catch (DownloadFailedException ex) {
|
||||||
|
LOGGER.warn("Unable to download pom.xml for {} from Nexus repository; "
|
||||||
|
+ "this could result in undetected CPE/CVEs.", dependency.getFileName());
|
||||||
|
} finally {
|
||||||
|
if (pomFile != null && !FileUtils.deleteQuietly(pomFile)) {
|
||||||
|
pomFile.deleteOnExit();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} catch (IllegalArgumentException iae) {
|
} catch (IllegalArgumentException iae) {
|
||||||
@@ -180,11 +250,11 @@ public class NexusAnalyzer extends AbstractFileTypeAnalyzer {
|
|||||||
LOGGER.info(String.format("invalid sha-1 hash on %s", dependency.getFileName()));
|
LOGGER.info(String.format("invalid sha-1 hash on %s", dependency.getFileName()));
|
||||||
} catch (FileNotFoundException fnfe) {
|
} catch (FileNotFoundException fnfe) {
|
||||||
//dependency.addAnalysisException(new AnalysisException("Artifact not found on repository"));
|
//dependency.addAnalysisException(new AnalysisException("Artifact not found on repository"));
|
||||||
LOGGER.fine(String.format("Artifact not found in repository '%s'", dependency.getFileName()));
|
LOGGER.debug("Artifact not found in repository '{}'", dependency.getFileName());
|
||||||
LOGGER.log(Level.FINE, fnfe.getMessage(), fnfe);
|
LOGGER.debug(fnfe.getMessage(), fnfe);
|
||||||
} catch (IOException ioe) {
|
} catch (IOException ioe) {
|
||||||
//dependency.addAnalysisException(new AnalysisException("Could not connect to repository", ioe));
|
//dependency.addAnalysisException(new AnalysisException("Could not connect to repository", ioe));
|
||||||
LOGGER.log(Level.FINE, "Could not connect to nexus repository", ioe);
|
LOGGER.debug("Could not connect to nexus repository", ioe);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -17,12 +17,6 @@
|
|||||||
*/
|
*/
|
||||||
package org.owasp.dependencycheck.analyzer;
|
package org.owasp.dependencycheck.analyzer;
|
||||||
|
|
||||||
import java.io.FileInputStream;
|
|
||||||
import java.io.FileNotFoundException;
|
|
||||||
import java.io.IOException;
|
|
||||||
import java.util.Set;
|
|
||||||
import java.util.logging.Level;
|
|
||||||
import java.util.logging.Logger;
|
|
||||||
import org.owasp.dependencycheck.Engine;
|
import org.owasp.dependencycheck.Engine;
|
||||||
import org.owasp.dependencycheck.analyzer.exception.AnalysisException;
|
import org.owasp.dependencycheck.analyzer.exception.AnalysisException;
|
||||||
import org.owasp.dependencycheck.data.nuget.NugetPackage;
|
import org.owasp.dependencycheck.data.nuget.NugetPackage;
|
||||||
@@ -31,7 +25,15 @@ import org.owasp.dependencycheck.data.nuget.NuspecParser;
|
|||||||
import org.owasp.dependencycheck.data.nuget.XPathNuspecParser;
|
import org.owasp.dependencycheck.data.nuget.XPathNuspecParser;
|
||||||
import org.owasp.dependencycheck.dependency.Confidence;
|
import org.owasp.dependencycheck.dependency.Confidence;
|
||||||
import org.owasp.dependencycheck.dependency.Dependency;
|
import org.owasp.dependencycheck.dependency.Dependency;
|
||||||
|
import org.owasp.dependencycheck.utils.FileFilterBuilder;
|
||||||
import org.owasp.dependencycheck.utils.Settings;
|
import org.owasp.dependencycheck.utils.Settings;
|
||||||
|
import org.slf4j.Logger;
|
||||||
|
import org.slf4j.LoggerFactory;
|
||||||
|
|
||||||
|
import java.io.FileFilter;
|
||||||
|
import java.io.FileInputStream;
|
||||||
|
import java.io.FileNotFoundException;
|
||||||
|
import java.io.IOException;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Analyzer which will parse a Nuspec file to gather module information.
|
* Analyzer which will parse a Nuspec file to gather module information.
|
||||||
@@ -43,7 +45,7 @@ public class NuspecAnalyzer extends AbstractFileTypeAnalyzer {
|
|||||||
/**
|
/**
|
||||||
* The logger.
|
* The logger.
|
||||||
*/
|
*/
|
||||||
private static final Logger LOGGER = Logger.getLogger(NuspecAnalyzer.class.getName());
|
private static final Logger LOGGER = LoggerFactory.getLogger(NuspecAnalyzer.class);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The name of the analyzer.
|
* The name of the analyzer.
|
||||||
@@ -58,7 +60,7 @@ public class NuspecAnalyzer extends AbstractFileTypeAnalyzer {
|
|||||||
/**
|
/**
|
||||||
* The types of files on which this will work.
|
* The types of files on which this will work.
|
||||||
*/
|
*/
|
||||||
private static final Set<String> SUPPORTED_EXTENSIONS = newHashSet("nuspec");
|
private static final String SUPPORTED_EXTENSIONS = "nuspec";
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Initializes the analyzer once before any analysis is performed.
|
* Initializes the analyzer once before any analysis is performed.
|
||||||
@@ -100,13 +102,19 @@ public class NuspecAnalyzer extends AbstractFileTypeAnalyzer {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns the extensions for which this Analyzer runs.
|
* The file filter used to determine which files this analyzer supports.
|
||||||
|
*/
|
||||||
|
private static final FileFilter FILTER = FileFilterBuilder.newInstance().addExtensions(
|
||||||
|
SUPPORTED_EXTENSIONS).build();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the FileFilter
|
||||||
*
|
*
|
||||||
* @return the extensions for which this Analyzer runs
|
* @return the FileFilter
|
||||||
*/
|
*/
|
||||||
@Override
|
@Override
|
||||||
public Set<String> getSupportedExtensions() {
|
protected FileFilter getFileFilter() {
|
||||||
return SUPPORTED_EXTENSIONS;
|
return FILTER;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -118,7 +126,7 @@ public class NuspecAnalyzer extends AbstractFileTypeAnalyzer {
|
|||||||
*/
|
*/
|
||||||
@Override
|
@Override
|
||||||
public void analyzeFileType(Dependency dependency, Engine engine) throws AnalysisException {
|
public void analyzeFileType(Dependency dependency, Engine engine) throws AnalysisException {
|
||||||
LOGGER.log(Level.FINE, "Checking Nuspec file {0}", dependency.toString());
|
LOGGER.debug("Checking Nuspec file {}", dependency.toString());
|
||||||
try {
|
try {
|
||||||
final NuspecParser parser = new XPathNuspecParser();
|
final NuspecParser parser = new XPathNuspecParser();
|
||||||
NugetPackage np = null;
|
NugetPackage np = null;
|
||||||
@@ -135,7 +143,7 @@ public class NuspecAnalyzer extends AbstractFileTypeAnalyzer {
|
|||||||
try {
|
try {
|
||||||
fis.close();
|
fis.close();
|
||||||
} catch (IOException e) {
|
} catch (IOException e) {
|
||||||
LOGGER.fine("Error closing input stream");
|
LOGGER.debug("Error closing input stream");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -32,7 +32,7 @@ import org.owasp.dependencycheck.dependency.Vulnerability;
|
|||||||
* NvdCveAnalyzer is a utility class that takes a project dependency and attempts to discern if there is an associated
|
* NvdCveAnalyzer is a utility class that takes a project dependency and attempts to discern if there is an associated
|
||||||
* CVEs. It uses the the identifiers found by other analyzers to lookup the CVE data.
|
* CVEs. It uses the the identifiers found by other analyzers to lookup the CVE data.
|
||||||
*
|
*
|
||||||
* @author Jeremy Long <jeremy.long@owasp.org>
|
* @author Jeremy Long
|
||||||
*/
|
*/
|
||||||
public class NvdCveAnalyzer implements Analyzer {
|
public class NvdCveAnalyzer implements Analyzer {
|
||||||
|
|
||||||
|
|||||||
@@ -0,0 +1,175 @@
|
|||||||
|
/*
|
||||||
|
* This file is part of dependency-check-core.
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*
|
||||||
|
* Copyright (c) 2015 Institute for Defense Analyses. All Rights Reserved.
|
||||||
|
*/
|
||||||
|
package org.owasp.dependencycheck.analyzer;
|
||||||
|
|
||||||
|
import org.apache.commons.io.FileUtils;
|
||||||
|
import org.owasp.dependencycheck.Engine;
|
||||||
|
import org.owasp.dependencycheck.analyzer.exception.AnalysisException;
|
||||||
|
import org.owasp.dependencycheck.dependency.Confidence;
|
||||||
|
import org.owasp.dependencycheck.dependency.Dependency;
|
||||||
|
import org.owasp.dependencycheck.utils.FileFilterBuilder;
|
||||||
|
import org.owasp.dependencycheck.utils.Settings;
|
||||||
|
|
||||||
|
import java.io.File;
|
||||||
|
import java.io.FileFilter;
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.util.regex.Matcher;
|
||||||
|
import java.util.regex.Pattern;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Used to analyze OpenSSL source code present in the file system.
|
||||||
|
*
|
||||||
|
* @author Dale Visser <dvisser@ida.org>
|
||||||
|
*/
|
||||||
|
public class OpenSSLAnalyzer extends AbstractFileTypeAnalyzer {
|
||||||
|
|
||||||
|
private static final int HEXADECIMAL = 16;
|
||||||
|
/**
|
||||||
|
* Filename to analyze. All other .h files get removed from consideration.
|
||||||
|
*/
|
||||||
|
private static final String OPENSSLV_H = "opensslv.h";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Filter that detects files named "__init__.py".
|
||||||
|
*/
|
||||||
|
private static final FileFilter OPENSSLV_FILTER = FileFilterBuilder.newInstance().addFilenames(OPENSSLV_H).build();
|
||||||
|
private static final Pattern VERSION_PATTERN = Pattern.compile(
|
||||||
|
"define\\s+OPENSSL_VERSION_NUMBER\\s+0x([0-9a-zA-Z]{8})L", Pattern.DOTALL
|
||||||
|
| Pattern.CASE_INSENSITIVE);
|
||||||
|
private static final int MAJOR_OFFSET = 28;
|
||||||
|
private static final long MINOR_MASK = 0x0ff00000L;
|
||||||
|
private static final int MINOR_OFFSET = 20;
|
||||||
|
private static final long FIX_MASK = 0x000ff000L;
|
||||||
|
private static final int FIX_OFFSET = 12;
|
||||||
|
private static final long PATCH_MASK = 0x00000ff0L;
|
||||||
|
private static final int PATCH_OFFSET = 4;
|
||||||
|
private static final int NUM_LETTERS = 26;
|
||||||
|
private static final int STATUS_MASK = 0x0000000f;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the open SSL version as a string.
|
||||||
|
*
|
||||||
|
* @param openSSLVersionConstant The open SSL version
|
||||||
|
* @return the version of openssl
|
||||||
|
*/
|
||||||
|
static String getOpenSSLVersion(long openSSLVersionConstant) {
|
||||||
|
final long major = openSSLVersionConstant >>> MAJOR_OFFSET;
|
||||||
|
final long minor = (openSSLVersionConstant & MINOR_MASK) >>> MINOR_OFFSET;
|
||||||
|
final long fix = (openSSLVersionConstant & FIX_MASK) >>> FIX_OFFSET;
|
||||||
|
final long patchLevel = (openSSLVersionConstant & PATCH_MASK) >>> PATCH_OFFSET;
|
||||||
|
final String patch = 0 == patchLevel || patchLevel > NUM_LETTERS ? "" : String.valueOf((char) (patchLevel + 'a' - 1));
|
||||||
|
final int statusCode = (int) (openSSLVersionConstant & STATUS_MASK);
|
||||||
|
final String status = 0xf == statusCode ? "" : (0 == statusCode ? "-dev" : "-beta" + statusCode);
|
||||||
|
return String.format("%d.%d.%d%s%s", major, minor, fix, patch, status);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the name of the Python Package Analyzer.
|
||||||
|
*
|
||||||
|
* @return the name of the analyzer
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
public String getName() {
|
||||||
|
return "OpenSSL Source Analyzer";
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Tell that we are used for information collection.
|
||||||
|
*
|
||||||
|
* @return INFORMATION_COLLECTION
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
public AnalysisPhase getAnalysisPhase() {
|
||||||
|
return AnalysisPhase.INFORMATION_COLLECTION;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the set of supported file extensions.
|
||||||
|
*
|
||||||
|
* @return the set of supported file extensions
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
protected FileFilter getFileFilter() {
|
||||||
|
return OPENSSLV_FILTER;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* No-op initializer implementation.
|
||||||
|
*
|
||||||
|
* @throws Exception never thrown
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
protected void initializeFileTypeAnalyzer() throws Exception {
|
||||||
|
// Nothing to do here.
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Analyzes python packages and adds evidence to the dependency.
|
||||||
|
*
|
||||||
|
* @param dependency the dependency being analyzed
|
||||||
|
* @param engine the engine being used to perform the scan
|
||||||
|
* @throws AnalysisException thrown if there is an unrecoverable error analyzing the dependency
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
protected void analyzeFileType(Dependency dependency, Engine engine)
|
||||||
|
throws AnalysisException {
|
||||||
|
final File file = dependency.getActualFile();
|
||||||
|
final String parentName = file.getParentFile().getName();
|
||||||
|
boolean found = false;
|
||||||
|
final String contents = getFileContents(file);
|
||||||
|
if (!contents.isEmpty()) {
|
||||||
|
final Matcher matcher = VERSION_PATTERN.matcher(contents);
|
||||||
|
if (matcher.find()) {
|
||||||
|
dependency.getVersionEvidence().addEvidence(OPENSSLV_H, "Version Constant",
|
||||||
|
getOpenSSLVersion(Long.parseLong(matcher.group(1), HEXADECIMAL)), Confidence.HIGH);
|
||||||
|
found = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (found) {
|
||||||
|
dependency.setDisplayFileName(parentName + File.separatorChar + OPENSSLV_H);
|
||||||
|
dependency.getVendorEvidence().addEvidence(OPENSSLV_H, "Vendor", "OpenSSL", Confidence.HIGHEST);
|
||||||
|
dependency.getProductEvidence().addEvidence(OPENSSLV_H, "Product", "OpenSSL", Confidence.HIGHEST);
|
||||||
|
} else {
|
||||||
|
engine.getDependencies().remove(dependency);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Retrieves the contents of a given file.
|
||||||
|
*
|
||||||
|
* @param actualFile the file to read
|
||||||
|
* @return the contents of the file
|
||||||
|
* @throws AnalysisException thrown if there is an IO Exception
|
||||||
|
*/
|
||||||
|
private String getFileContents(final File actualFile)
|
||||||
|
throws AnalysisException {
|
||||||
|
String contents;
|
||||||
|
try {
|
||||||
|
contents = FileUtils.readFileToString(actualFile).trim();
|
||||||
|
} catch (IOException e) {
|
||||||
|
throw new AnalysisException(
|
||||||
|
"Problem occurred while reading dependency file.", e);
|
||||||
|
}
|
||||||
|
return contents;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected String getAnalyzerEnabledSettingKey() {
|
||||||
|
return Settings.KEYS.ANALYZER_OPENSSL_ENABLED;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,376 @@
|
|||||||
|
/*
|
||||||
|
* This file is part of dependency-check-core.
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*
|
||||||
|
* Copyright (c) 2015 Institute for Defense Analyses. All Rights Reserved.
|
||||||
|
*/
|
||||||
|
package org.owasp.dependencycheck.analyzer;
|
||||||
|
|
||||||
|
import java.io.BufferedInputStream;
|
||||||
|
import java.io.File;
|
||||||
|
import java.io.FileFilter;
|
||||||
|
import java.io.FileInputStream;
|
||||||
|
import java.io.FileNotFoundException;
|
||||||
|
import java.io.FilenameFilter;
|
||||||
|
import org.apache.commons.io.filefilter.NameFileFilter;
|
||||||
|
import org.apache.commons.io.filefilter.SuffixFileFilter;
|
||||||
|
import org.apache.commons.io.input.AutoCloseInputStream;
|
||||||
|
import org.apache.commons.lang.StringUtils;
|
||||||
|
import org.owasp.dependencycheck.Engine;
|
||||||
|
import org.owasp.dependencycheck.analyzer.exception.AnalysisException;
|
||||||
|
import org.owasp.dependencycheck.dependency.Confidence;
|
||||||
|
import org.owasp.dependencycheck.dependency.Dependency;
|
||||||
|
import org.owasp.dependencycheck.dependency.EvidenceCollection;
|
||||||
|
import org.slf4j.Logger;
|
||||||
|
import org.slf4j.LoggerFactory;
|
||||||
|
|
||||||
|
import javax.mail.MessagingException;
|
||||||
|
import javax.mail.internet.InternetHeaders;
|
||||||
|
import org.owasp.dependencycheck.utils.ExtractionException;
|
||||||
|
import org.owasp.dependencycheck.utils.ExtractionUtil;
|
||||||
|
import org.owasp.dependencycheck.utils.FileFilterBuilder;
|
||||||
|
import org.owasp.dependencycheck.utils.FileUtils;
|
||||||
|
import org.owasp.dependencycheck.utils.Settings;
|
||||||
|
import org.owasp.dependencycheck.utils.UrlStringUtils;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Used to analyze a Wheel or egg distribution files, or their contents in unzipped form, and collect information that can be used
|
||||||
|
* to determine the associated CPE.
|
||||||
|
*
|
||||||
|
* @author Dale Visser <dvisser@ida.org>
|
||||||
|
*/
|
||||||
|
public class PythonDistributionAnalyzer extends AbstractFileTypeAnalyzer {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Name of egg metatdata files to analyze.
|
||||||
|
*/
|
||||||
|
private static final String PKG_INFO = "PKG-INFO";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Name of wheel metadata files to analyze.
|
||||||
|
*/
|
||||||
|
private static final String METADATA = "METADATA";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The logger.
|
||||||
|
*/
|
||||||
|
private static final Logger LOGGER = LoggerFactory
|
||||||
|
.getLogger(PythonDistributionAnalyzer.class);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The count of directories created during analysis. This is used for creating temporary directories.
|
||||||
|
*/
|
||||||
|
private static int dirCount = 0;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The name of the analyzer.
|
||||||
|
*/
|
||||||
|
private static final String ANALYZER_NAME = "Python Distribution Analyzer";
|
||||||
|
/**
|
||||||
|
* The phase that this analyzer is intended to run in.
|
||||||
|
*/
|
||||||
|
private static final AnalysisPhase ANALYSIS_PHASE = AnalysisPhase.INFORMATION_COLLECTION;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The set of file extensions supported by this analyzer.
|
||||||
|
*/
|
||||||
|
private static final String[] EXTENSIONS = {"whl", "egg", "zip"};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Used to match on egg archive candidate extensions.
|
||||||
|
*/
|
||||||
|
private static final FileFilter EGG_OR_ZIP = FileFilterBuilder.newInstance().addExtensions("egg", "zip").build();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Used to detect files with a .whl extension.
|
||||||
|
*/
|
||||||
|
private static final FileFilter WHL_FILTER = FileFilterBuilder.newInstance().addExtensions("whl").build();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The parent directory for the individual directories per archive.
|
||||||
|
*/
|
||||||
|
private File tempFileLocation;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Filter that detects *.dist-info files (but doesn't verify they are directories.
|
||||||
|
*/
|
||||||
|
private static final FilenameFilter DIST_INFO_FILTER = new SuffixFileFilter(
|
||||||
|
".dist-info");
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Filter that detects files named "METADATA".
|
||||||
|
*/
|
||||||
|
private static final FilenameFilter EGG_INFO_FILTER = new NameFileFilter(
|
||||||
|
"EGG-INFO");
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Filter that detects files named "METADATA".
|
||||||
|
*/
|
||||||
|
private static final NameFileFilter METADATA_FILTER = new NameFileFilter(
|
||||||
|
METADATA);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Filter that detects files named "PKG-INFO".
|
||||||
|
*/
|
||||||
|
private static final NameFileFilter PKG_INFO_FILTER = new NameFileFilter(
|
||||||
|
PKG_INFO);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The file filter used to determine which files this analyzer supports.
|
||||||
|
*/
|
||||||
|
private static final FileFilter FILTER = FileFilterBuilder.newInstance().addFileFilters(
|
||||||
|
METADATA_FILTER, PKG_INFO_FILTER).addExtensions(EXTENSIONS).build();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the FileFilter
|
||||||
|
*
|
||||||
|
* @return the FileFilter
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
protected FileFilter getFileFilter() {
|
||||||
|
return FILTER;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the name of the analyzer.
|
||||||
|
*
|
||||||
|
* @return the name of the analyzer.
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
public String getName() {
|
||||||
|
return ANALYZER_NAME;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the phase that the analyzer is intended to run in.
|
||||||
|
*
|
||||||
|
* @return the phase that the analyzer is intended to run in.
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
public AnalysisPhase getAnalysisPhase() {
|
||||||
|
return ANALYSIS_PHASE;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the key used in the properties file to reference the analyzer's enabled property.
|
||||||
|
*
|
||||||
|
* @return the analyzer's enabled property setting key
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
protected String getAnalyzerEnabledSettingKey() {
|
||||||
|
return Settings.KEYS.ANALYZER_PYTHON_DISTRIBUTION_ENABLED;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void analyzeFileType(Dependency dependency, Engine engine)
|
||||||
|
throws AnalysisException {
|
||||||
|
final File actualFile = dependency.getActualFile();
|
||||||
|
if (WHL_FILTER.accept(actualFile)) {
|
||||||
|
collectMetadataFromArchiveFormat(dependency, DIST_INFO_FILTER,
|
||||||
|
METADATA_FILTER);
|
||||||
|
} else if (EGG_OR_ZIP.accept(actualFile)) {
|
||||||
|
collectMetadataFromArchiveFormat(dependency, EGG_INFO_FILTER,
|
||||||
|
PKG_INFO_FILTER);
|
||||||
|
} else {
|
||||||
|
final String name = actualFile.getName();
|
||||||
|
final boolean metadata = METADATA.equals(name);
|
||||||
|
if (metadata || PKG_INFO.equals(name)) {
|
||||||
|
final File parent = actualFile.getParentFile();
|
||||||
|
final String parentName = parent.getName();
|
||||||
|
dependency.setDisplayFileName(parentName + "/" + name);
|
||||||
|
if (parent.isDirectory()
|
||||||
|
&& (metadata && parentName.endsWith(".dist-info")
|
||||||
|
|| parentName.endsWith(".egg-info") || "EGG-INFO"
|
||||||
|
.equals(parentName))) {
|
||||||
|
collectWheelMetadata(dependency, actualFile);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Collects the meta data from an archive.
|
||||||
|
*
|
||||||
|
* @param dependency the archive being scanned
|
||||||
|
* @param folderFilter the filter to apply to the folder
|
||||||
|
* @param metadataFilter the filter to apply to the meta data
|
||||||
|
* @throws AnalysisException thrown when there is a problem analyzing the dependency
|
||||||
|
*/
|
||||||
|
private void collectMetadataFromArchiveFormat(Dependency dependency,
|
||||||
|
FilenameFilter folderFilter, FilenameFilter metadataFilter)
|
||||||
|
throws AnalysisException {
|
||||||
|
final File temp = getNextTempDirectory();
|
||||||
|
LOGGER.debug("{} exists? {}", temp, temp.exists());
|
||||||
|
try {
|
||||||
|
ExtractionUtil.extractFilesUsingFilter(
|
||||||
|
new File(dependency.getActualFilePath()), temp,
|
||||||
|
metadataFilter);
|
||||||
|
} catch (ExtractionException ex) {
|
||||||
|
throw new AnalysisException(ex);
|
||||||
|
}
|
||||||
|
|
||||||
|
collectWheelMetadata(
|
||||||
|
dependency,
|
||||||
|
getMatchingFile(getMatchingFile(temp, folderFilter),
|
||||||
|
metadataFilter));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Makes sure a usable temporary directory is available.
|
||||||
|
*
|
||||||
|
* @throws Exception an AnalyzeException is thrown when the temp directory cannot be created
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
protected void initializeFileTypeAnalyzer() throws Exception {
|
||||||
|
final File baseDir = Settings.getTempDirectory();
|
||||||
|
tempFileLocation = File.createTempFile("check", "tmp", baseDir);
|
||||||
|
if (!tempFileLocation.delete()) {
|
||||||
|
final String msg = String.format(
|
||||||
|
"Unable to delete temporary file '%s'.",
|
||||||
|
tempFileLocation.getAbsolutePath());
|
||||||
|
throw new AnalysisException(msg);
|
||||||
|
}
|
||||||
|
if (!tempFileLocation.mkdirs()) {
|
||||||
|
final String msg = String.format(
|
||||||
|
"Unable to create directory '%s'.",
|
||||||
|
tempFileLocation.getAbsolutePath());
|
||||||
|
throw new AnalysisException(msg);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Deletes any files extracted from the Wheel during analysis.
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
public void close() {
|
||||||
|
if (tempFileLocation != null && tempFileLocation.exists()) {
|
||||||
|
LOGGER.debug("Attempting to delete temporary files");
|
||||||
|
final boolean success = FileUtils.delete(tempFileLocation);
|
||||||
|
if (!success) {
|
||||||
|
LOGGER.warn(
|
||||||
|
"Failed to delete some temporary files, see the log for more details");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gathers evidence from the METADATA file.
|
||||||
|
*
|
||||||
|
* @param dependency the dependency being analyzed
|
||||||
|
* @param file a reference to the manifest/properties file
|
||||||
|
* @throws AnalysisException thrown when there is an error
|
||||||
|
*/
|
||||||
|
private static void collectWheelMetadata(Dependency dependency, File file)
|
||||||
|
throws AnalysisException {
|
||||||
|
final InternetHeaders headers = getManifestProperties(file);
|
||||||
|
addPropertyToEvidence(headers, dependency.getVersionEvidence(),
|
||||||
|
"Version", Confidence.HIGHEST);
|
||||||
|
addPropertyToEvidence(headers, dependency.getProductEvidence(), "Name",
|
||||||
|
Confidence.HIGHEST);
|
||||||
|
final String url = headers.getHeader("Home-page", null);
|
||||||
|
final EvidenceCollection vendorEvidence = dependency
|
||||||
|
.getVendorEvidence();
|
||||||
|
if (StringUtils.isNotBlank(url)) {
|
||||||
|
if (UrlStringUtils.isUrl(url)) {
|
||||||
|
vendorEvidence.addEvidence(METADATA, "vendor", url,
|
||||||
|
Confidence.MEDIUM);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
addPropertyToEvidence(headers, vendorEvidence, "Author", Confidence.LOW);
|
||||||
|
final String summary = headers.getHeader("Summary", null);
|
||||||
|
if (StringUtils.isNotBlank(summary)) {
|
||||||
|
JarAnalyzer
|
||||||
|
.addDescription(dependency, summary, METADATA, "summary");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Adds a value to the evidence collection.
|
||||||
|
*
|
||||||
|
* @param headers the properties collection
|
||||||
|
* @param evidence the evidence collection to add the value
|
||||||
|
* @param property the property name
|
||||||
|
* @param confidence the confidence of the evidence
|
||||||
|
*/
|
||||||
|
private static void addPropertyToEvidence(InternetHeaders headers,
|
||||||
|
EvidenceCollection evidence, String property, Confidence confidence) {
|
||||||
|
final String value = headers.getHeader(property, null);
|
||||||
|
LOGGER.debug("Property: {}, Value: {}", property, value);
|
||||||
|
if (StringUtils.isNotBlank(value)) {
|
||||||
|
evidence.addEvidence(METADATA, property, value, confidence);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns a list of files that match the given filter, this does not recursively scan the directory.
|
||||||
|
*
|
||||||
|
* @param folder the folder to filter
|
||||||
|
* @param filter the filter to apply to the files in the directory
|
||||||
|
* @return the list of Files in the directory that match the provided filter
|
||||||
|
*/
|
||||||
|
private static File getMatchingFile(File folder, FilenameFilter filter) {
|
||||||
|
File result = null;
|
||||||
|
final File[] matches = folder.listFiles(filter);
|
||||||
|
if (null != matches && 1 == matches.length) {
|
||||||
|
result = matches[0];
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Reads the manifest entries from the provided file.
|
||||||
|
*
|
||||||
|
* @param manifest the manifest
|
||||||
|
* @return the manifest entries
|
||||||
|
*/
|
||||||
|
private static InternetHeaders getManifestProperties(File manifest) {
|
||||||
|
final InternetHeaders result = new InternetHeaders();
|
||||||
|
if (null == manifest) {
|
||||||
|
LOGGER.debug("Manifest file not found.");
|
||||||
|
} else {
|
||||||
|
try {
|
||||||
|
result.load(new AutoCloseInputStream(new BufferedInputStream(
|
||||||
|
new FileInputStream(manifest))));
|
||||||
|
} catch (MessagingException e) {
|
||||||
|
LOGGER.warn(e.getMessage(), e);
|
||||||
|
} catch (FileNotFoundException e) {
|
||||||
|
LOGGER.warn(e.getMessage(), e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Retrieves the next temporary destingation directory for extracting an archive.
|
||||||
|
*
|
||||||
|
* @return a directory
|
||||||
|
* @throws AnalysisException thrown if unable to create temporary directory
|
||||||
|
*/
|
||||||
|
private File getNextTempDirectory() throws AnalysisException {
|
||||||
|
File directory;
|
||||||
|
|
||||||
|
// getting an exception for some directories not being able to be
|
||||||
|
// created; might be because the directory already exists?
|
||||||
|
do {
|
||||||
|
dirCount += 1;
|
||||||
|
directory = new File(tempFileLocation, String.valueOf(dirCount));
|
||||||
|
} while (directory.exists());
|
||||||
|
if (!directory.mkdirs()) {
|
||||||
|
throw new AnalysisException(String.format(
|
||||||
|
"Unable to create temp directory '%s'.",
|
||||||
|
directory.getAbsolutePath()));
|
||||||
|
}
|
||||||
|
return directory;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,327 @@
|
|||||||
|
/*
|
||||||
|
* This file is part of dependency-check-core.
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*
|
||||||
|
* Copyright (c) 2015 Institute for Defense Analyses. All Rights Reserved.
|
||||||
|
*/
|
||||||
|
package org.owasp.dependencycheck.analyzer;
|
||||||
|
|
||||||
|
import org.apache.commons.io.FileUtils;
|
||||||
|
import org.apache.commons.io.filefilter.NameFileFilter;
|
||||||
|
import org.apache.commons.io.filefilter.SuffixFileFilter;
|
||||||
|
import org.owasp.dependencycheck.Engine;
|
||||||
|
import org.owasp.dependencycheck.analyzer.exception.AnalysisException;
|
||||||
|
import org.owasp.dependencycheck.dependency.Confidence;
|
||||||
|
import org.owasp.dependencycheck.dependency.Dependency;
|
||||||
|
import org.owasp.dependencycheck.dependency.EvidenceCollection;
|
||||||
|
import org.owasp.dependencycheck.utils.FileFilterBuilder;
|
||||||
|
import org.owasp.dependencycheck.utils.Settings;
|
||||||
|
import org.owasp.dependencycheck.utils.UrlStringUtils;
|
||||||
|
import org.slf4j.Logger;
|
||||||
|
import org.slf4j.LoggerFactory;
|
||||||
|
|
||||||
|
import java.io.File;
|
||||||
|
import java.io.FileFilter;
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.net.MalformedURLException;
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.regex.Matcher;
|
||||||
|
import java.util.regex.Pattern;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Used to analyze a Python package, and collect information that can be used to determine the associated CPE.
|
||||||
|
*
|
||||||
|
* @author Dale Visser <dvisser@ida.org>
|
||||||
|
*/
|
||||||
|
public class PythonPackageAnalyzer extends AbstractFileTypeAnalyzer {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Used when compiling file scanning regex patterns.
|
||||||
|
*/
|
||||||
|
private static final int REGEX_OPTIONS = Pattern.DOTALL
|
||||||
|
| Pattern.CASE_INSENSITIVE;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The logger.
|
||||||
|
*/
|
||||||
|
private static final Logger LOGGER = LoggerFactory
|
||||||
|
.getLogger(PythonPackageAnalyzer.class);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Filename extensions for files to be analyzed.
|
||||||
|
*/
|
||||||
|
private static final String EXTENSIONS = "py";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Pattern for matching the module docstring in a source file.
|
||||||
|
*/
|
||||||
|
private static final Pattern MODULE_DOCSTRING = Pattern.compile(
|
||||||
|
"^(['\\\"]{3})(.*?)\\1", REGEX_OPTIONS);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Matches assignments to version variables in Python source code.
|
||||||
|
*/
|
||||||
|
private static final Pattern VERSION_PATTERN = Pattern.compile(
|
||||||
|
"\\b(__)?version(__)? *= *(['\"]+)(\\d+\\.\\d+.*?)\\3",
|
||||||
|
REGEX_OPTIONS);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Matches assignments to title variables in Python source code.
|
||||||
|
*/
|
||||||
|
private static final Pattern TITLE_PATTERN = compileAssignPattern("title");
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Matches assignments to summary variables in Python source code.
|
||||||
|
*/
|
||||||
|
private static final Pattern SUMMARY_PATTERN = compileAssignPattern("summary");
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Matches assignments to URL/URL variables in Python source code.
|
||||||
|
*/
|
||||||
|
private static final Pattern URI_PATTERN = compileAssignPattern("ur[il]");
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Matches assignments to home page variables in Python source code.
|
||||||
|
*/
|
||||||
|
private static final Pattern HOMEPAGE_PATTERN = compileAssignPattern("home_?page");
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Matches assignments to author variables in Python source code.
|
||||||
|
*/
|
||||||
|
private static final Pattern AUTHOR_PATTERN = compileAssignPattern("author");
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Filter that detects files named "__init__.py".
|
||||||
|
*/
|
||||||
|
private static final FileFilter INIT_PY_FILTER = new NameFileFilter("__init__.py");
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The file filter for python files.
|
||||||
|
*/
|
||||||
|
private static final FileFilter PY_FILTER = new SuffixFileFilter(".py");
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the name of the Python Package Analyzer.
|
||||||
|
*
|
||||||
|
* @return the name of the analyzer
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
public String getName() {
|
||||||
|
return "Python Package Analyzer";
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Tell that we are used for information collection.
|
||||||
|
*
|
||||||
|
* @return INFORMATION_COLLECTION
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
public AnalysisPhase getAnalysisPhase() {
|
||||||
|
return AnalysisPhase.INFORMATION_COLLECTION;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The file filter used to determine which files this analyzer supports.
|
||||||
|
*/
|
||||||
|
private static final FileFilter FILTER = FileFilterBuilder.newInstance().addExtensions(EXTENSIONS).build();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the FileFilter
|
||||||
|
*
|
||||||
|
* @return the FileFilter
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
protected FileFilter getFileFilter() {
|
||||||
|
return FILTER;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* No-op initializer implementation.
|
||||||
|
*
|
||||||
|
* @throws Exception never thrown
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
protected void initializeFileTypeAnalyzer() throws Exception {
|
||||||
|
// Nothing to do here.
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Utility function to create a regex pattern matcher.
|
||||||
|
*
|
||||||
|
* @param name the value to use when constructing the assignment pattern
|
||||||
|
* @return the compiled Pattern
|
||||||
|
*/
|
||||||
|
private static Pattern compileAssignPattern(String name) {
|
||||||
|
return Pattern.compile(
|
||||||
|
String.format("\\b(__)?%s(__)?\\b *= *(['\"]+)(.*?)\\3", name),
|
||||||
|
REGEX_OPTIONS);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Analyzes python packages and adds evidence to the dependency.
|
||||||
|
*
|
||||||
|
* @param dependency the dependency being analyzed
|
||||||
|
* @param engine the engine being used to perform the scan
|
||||||
|
* @throws AnalysisException thrown if there is an unrecoverable error analyzing the dependency
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
protected void analyzeFileType(Dependency dependency, Engine engine)
|
||||||
|
throws AnalysisException {
|
||||||
|
final File file = dependency.getActualFile();
|
||||||
|
final File parent = file.getParentFile();
|
||||||
|
final String parentName = parent.getName();
|
||||||
|
boolean found = false;
|
||||||
|
if (INIT_PY_FILTER.accept(file)) {
|
||||||
|
for (final File sourcefile : parent.listFiles(PY_FILTER)) {
|
||||||
|
found |= analyzeFileContents(dependency, sourcefile);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (found) {
|
||||||
|
dependency.setDisplayFileName(parentName + "/__init__.py");
|
||||||
|
dependency.getProductEvidence().addEvidence(file.getName(),
|
||||||
|
"PackageName", parentName, Confidence.MEDIUM);
|
||||||
|
} else {
|
||||||
|
// copy, alter and set in case some other thread is iterating over
|
||||||
|
final List<Dependency> deps = new ArrayList<Dependency>(
|
||||||
|
engine.getDependencies());
|
||||||
|
deps.remove(dependency);
|
||||||
|
engine.setDependencies(deps);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This should gather information from leading docstrings, file comments, and assignments to __version__, __title__,
|
||||||
|
* __summary__, __uri__, __url__, __home*page__, __author__, and their all caps equivalents.
|
||||||
|
*
|
||||||
|
* @param dependency the dependency being analyzed
|
||||||
|
* @param file the file name to analyze
|
||||||
|
* @return whether evidence was found
|
||||||
|
* @throws AnalysisException thrown if there is an unrecoverable error
|
||||||
|
*/
|
||||||
|
private boolean analyzeFileContents(Dependency dependency, File file)
|
||||||
|
throws AnalysisException {
|
||||||
|
String contents;
|
||||||
|
try {
|
||||||
|
contents = FileUtils.readFileToString(file).trim();
|
||||||
|
} catch (IOException e) {
|
||||||
|
throw new AnalysisException(
|
||||||
|
"Problem occurred while reading dependency file.", e);
|
||||||
|
}
|
||||||
|
boolean found = false;
|
||||||
|
if (!contents.isEmpty()) {
|
||||||
|
final String source = file.getName();
|
||||||
|
found = gatherEvidence(VERSION_PATTERN, contents, source,
|
||||||
|
dependency.getVersionEvidence(), "SourceVersion",
|
||||||
|
Confidence.MEDIUM);
|
||||||
|
found |= addSummaryInfo(dependency, SUMMARY_PATTERN, 4, contents,
|
||||||
|
source, "summary");
|
||||||
|
if (INIT_PY_FILTER.accept(file)) {
|
||||||
|
found |= addSummaryInfo(dependency, MODULE_DOCSTRING, 2,
|
||||||
|
contents, source, "docstring");
|
||||||
|
}
|
||||||
|
found |= gatherEvidence(TITLE_PATTERN, contents, source,
|
||||||
|
dependency.getProductEvidence(), "SourceTitle",
|
||||||
|
Confidence.LOW);
|
||||||
|
final EvidenceCollection vendorEvidence = dependency
|
||||||
|
.getVendorEvidence();
|
||||||
|
found |= gatherEvidence(AUTHOR_PATTERN, contents, source,
|
||||||
|
vendorEvidence, "SourceAuthor", Confidence.MEDIUM);
|
||||||
|
try {
|
||||||
|
found |= gatherHomePageEvidence(URI_PATTERN, vendorEvidence,
|
||||||
|
source, "URL", contents);
|
||||||
|
found |= gatherHomePageEvidence(HOMEPAGE_PATTERN,
|
||||||
|
vendorEvidence, source, "HomePage", contents);
|
||||||
|
} catch (MalformedURLException e) {
|
||||||
|
LOGGER.warn(e.getMessage());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return found;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Adds summary information to the dependency
|
||||||
|
*
|
||||||
|
* @param dependency the dependency being analyzed
|
||||||
|
* @param pattern the pattern used to perform analysis
|
||||||
|
* @param group the group from the pattern that indicates the data to use
|
||||||
|
* @param contents the data being analyzed
|
||||||
|
* @param source the source name to use when recording the evidence
|
||||||
|
* @param key the key name to use when recording the evidence
|
||||||
|
* @return true if evidence was collected; otherwise false
|
||||||
|
*/
|
||||||
|
private boolean addSummaryInfo(Dependency dependency, Pattern pattern,
|
||||||
|
int group, String contents, String source, String key) {
|
||||||
|
final Matcher matcher = pattern.matcher(contents);
|
||||||
|
final boolean found = matcher.find();
|
||||||
|
if (found) {
|
||||||
|
JarAnalyzer.addDescription(dependency, matcher.group(group),
|
||||||
|
source, key);
|
||||||
|
}
|
||||||
|
return found;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Collects evidence from the home page URL.
|
||||||
|
*
|
||||||
|
* @param pattern the pattern to match
|
||||||
|
* @param evidence the evidence collection to add the evidence to
|
||||||
|
* @param source the source of the evidence
|
||||||
|
* @param name the name of the evidence
|
||||||
|
* @param contents the home page URL
|
||||||
|
* @return true if evidence was collected; otherwise false
|
||||||
|
* @throws MalformedURLException thrown if the URL is malformed
|
||||||
|
*/
|
||||||
|
private boolean gatherHomePageEvidence(Pattern pattern,
|
||||||
|
EvidenceCollection evidence, String source, String name,
|
||||||
|
String contents) throws MalformedURLException {
|
||||||
|
final Matcher matcher = pattern.matcher(contents);
|
||||||
|
boolean found = false;
|
||||||
|
if (matcher.find()) {
|
||||||
|
final String url = matcher.group(4);
|
||||||
|
if (UrlStringUtils.isUrl(url)) {
|
||||||
|
found = true;
|
||||||
|
evidence.addEvidence(source, name, url, Confidence.MEDIUM);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return found;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gather evidence from a Python source file usin the given string assignment regex pattern.
|
||||||
|
*
|
||||||
|
* @param pattern to scan contents with
|
||||||
|
* @param contents of Python source file
|
||||||
|
* @param source for storing evidence
|
||||||
|
* @param evidence to store evidence in
|
||||||
|
* @param name of evidence
|
||||||
|
* @param confidence in evidence
|
||||||
|
* @return whether evidence was found
|
||||||
|
*/
|
||||||
|
private boolean gatherEvidence(Pattern pattern, String contents,
|
||||||
|
String source, EvidenceCollection evidence, String name,
|
||||||
|
Confidence confidence) {
|
||||||
|
final Matcher matcher = pattern.matcher(contents);
|
||||||
|
final boolean found = matcher.find();
|
||||||
|
if (found) {
|
||||||
|
evidence.addEvidence(source, name, matcher.group(4), confidence);
|
||||||
|
}
|
||||||
|
return found;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected String getAnalyzerEnabledSettingKey() {
|
||||||
|
return Settings.KEYS.ANALYZER_PYTHON_PACKAGE_ENABLED;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -26,7 +26,7 @@ import org.owasp.dependencycheck.suppression.SuppressionRule;
|
|||||||
* The suppression analyzer processes an externally defined XML document that complies with the suppressions.xsd schema.
|
* The suppression analyzer processes an externally defined XML document that complies with the suppressions.xsd schema.
|
||||||
* Any identified Vulnerability entries within the dependencies that match will be removed.
|
* Any identified Vulnerability entries within the dependencies that match will be removed.
|
||||||
*
|
*
|
||||||
* @author Jeremy Long <jeremy.long@owasp.org>
|
* @author Jeremy Long
|
||||||
*/
|
*/
|
||||||
public class VulnerabilitySuppressionAnalyzer extends AbstractSuppressionAnalyzer {
|
public class VulnerabilitySuppressionAnalyzer extends AbstractSuppressionAnalyzer {
|
||||||
|
|
||||||
|
|||||||
@@ -20,7 +20,7 @@ package org.owasp.dependencycheck.analyzer.exception;
|
|||||||
/**
|
/**
|
||||||
* An exception thrown when the analysis of a dependency fails.
|
* An exception thrown when the analysis of a dependency fails.
|
||||||
*
|
*
|
||||||
* @author Jeremy Long <jeremy.long@owasp.org>
|
* @author Jeremy Long
|
||||||
*/
|
*/
|
||||||
public class AnalysisException extends Exception {
|
public class AnalysisException extends Exception {
|
||||||
|
|
||||||
|
|||||||
@@ -20,7 +20,7 @@ package org.owasp.dependencycheck.analyzer.exception;
|
|||||||
/**
|
/**
|
||||||
* An exception thrown when files in an archive cannot be extracted.
|
* An exception thrown when files in an archive cannot be extracted.
|
||||||
*
|
*
|
||||||
* @author Jeremy Long <jeremy.long@owasp.org>
|
* @author Jeremy Long
|
||||||
*/
|
*/
|
||||||
public class ArchiveExtractionException extends Exception {
|
public class ArchiveExtractionException extends Exception {
|
||||||
|
|
||||||
|
|||||||
@@ -1,12 +1,4 @@
|
|||||||
/**
|
/**
|
||||||
* <html>
|
* A collection of exception classes used within the analyzers.
|
||||||
* <head>
|
|
||||||
* <title>org.owasp.dependencycheck.analyzer.exception</title>
|
|
||||||
* </head>
|
|
||||||
* <body>
|
|
||||||
* <p>
|
|
||||||
* A collection of exception classes used within the analyzers.</p>
|
|
||||||
* </body>
|
|
||||||
* </html>
|
|
||||||
*/
|
*/
|
||||||
package org.owasp.dependencycheck.analyzer.exception;
|
package org.owasp.dependencycheck.analyzer.exception;
|
||||||
|
|||||||
@@ -1,13 +1,4 @@
|
|||||||
/**
|
/**
|
||||||
* <html>
|
* Analyzers are used to inspect the identified dependencies, collect Evidence, and process the dependencies.
|
||||||
* <head>
|
*/
|
||||||
* <title>org.owasp.dependencycheck.analyzer</title>
|
|
||||||
* </head>
|
|
||||||
* <body>
|
|
||||||
* Analyzers are used to inspect the identified dependencies, collect Evidence,
|
|
||||||
* and process the dependencies.
|
|
||||||
* </body>
|
|
||||||
* </html>
|
|
||||||
*/
|
|
||||||
|
|
||||||
package org.owasp.dependencycheck.analyzer;
|
package org.owasp.dependencycheck.analyzer;
|
||||||
|
|||||||
@@ -0,0 +1,171 @@
|
|||||||
|
/*
|
||||||
|
* 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 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.slf4j.Logger;
|
||||||
|
import org.slf4j.LoggerFactory;
|
||||||
|
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 = LoggerFactory.getLogger(CentralSearch.class);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 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.debug("Using proxy");
|
||||||
|
} else {
|
||||||
|
useProxy = false;
|
||||||
|
LOGGER.debug("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.debug("Searching Central url {}", 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.trace("GroupId: {}", g);
|
||||||
|
final String a = xpath.evaluate("./str[@name='a']", docs.item(i));
|
||||||
|
LOGGER.trace("ArtifactId: {}", a);
|
||||||
|
final String v = xpath.evaluate("./str[@name='v']", docs.item(i));
|
||||||
|
NodeList atts = (NodeList) xpath.evaluate("./arr[@name='ec']/str", docs.item(i), XPathConstants.NODESET);
|
||||||
|
boolean pomAvailable = false;
|
||||||
|
boolean jarAvailable = false;
|
||||||
|
for (int x = 0; x < atts.getLength(); x++) {
|
||||||
|
final String tmp = xpath.evaluate(".", atts.item(x));
|
||||||
|
if (".pom".equals(tmp)) {
|
||||||
|
pomAvailable = true;
|
||||||
|
} else if (".jar".equals(tmp)) {
|
||||||
|
jarAvailable = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
atts = (NodeList) xpath.evaluate("./arr[@name='tags']/str", docs.item(i), XPathConstants.NODESET);
|
||||||
|
boolean useHTTPS = false;
|
||||||
|
for (int x = 0; x < atts.getLength(); x++) {
|
||||||
|
final String tmp = xpath.evaluate(".", atts.item(x));
|
||||||
|
if ("https".equals(tmp)) {
|
||||||
|
useHTTPS = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
LOGGER.trace("Version: {}", v);
|
||||||
|
result.add(new MavenArtifact(g, a, v, jarAvailable, pomAvailable, useHTTPS));
|
||||||
|
}
|
||||||
|
|
||||||
|
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 {
|
||||||
|
LOGGER.debug("Could not connect to Central received response code: {} {}",
|
||||||
|
conn.getResponseCode(), conn.getResponseMessage());
|
||||||
|
throw new IOException("Could not connect to Central");
|
||||||
|
}
|
||||||
|
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,7 @@
|
|||||||
|
/**
|
||||||
|
*
|
||||||
|
* Contains classes related to searching Maven Central.<br/><br/>
|
||||||
|
*
|
||||||
|
* These are used to abstract Maven Central searching away from OWASP Dependency Check so they can be reused elsewhere.
|
||||||
|
*/
|
||||||
|
package org.owasp.dependencycheck.data.central;
|
||||||
@@ -21,8 +21,6 @@ import java.io.IOException;
|
|||||||
import java.util.HashMap;
|
import java.util.HashMap;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
import java.util.Set;
|
import java.util.Set;
|
||||||
import java.util.logging.Level;
|
|
||||||
import java.util.logging.Logger;
|
|
||||||
import org.apache.lucene.analysis.Analyzer;
|
import org.apache.lucene.analysis.Analyzer;
|
||||||
import org.apache.lucene.analysis.core.KeywordAnalyzer;
|
import org.apache.lucene.analysis.core.KeywordAnalyzer;
|
||||||
import org.apache.lucene.analysis.miscellaneous.PerFieldAnalyzerWrapper;
|
import org.apache.lucene.analysis.miscellaneous.PerFieldAnalyzerWrapper;
|
||||||
@@ -46,22 +44,25 @@ import org.owasp.dependencycheck.data.lucene.SearchFieldAnalyzer;
|
|||||||
import org.owasp.dependencycheck.data.nvdcve.CveDB;
|
import org.owasp.dependencycheck.data.nvdcve.CveDB;
|
||||||
import org.owasp.dependencycheck.data.nvdcve.DatabaseException;
|
import org.owasp.dependencycheck.data.nvdcve.DatabaseException;
|
||||||
import org.owasp.dependencycheck.utils.Pair;
|
import org.owasp.dependencycheck.utils.Pair;
|
||||||
|
import org.slf4j.Logger;
|
||||||
|
import org.slf4j.LoggerFactory;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* An in memory lucene index that contains the vendor/product combinations from the CPE (application) identifiers within
|
* An in memory lucene index that contains the vendor/product combinations from the CPE (application) identifiers within the NVD
|
||||||
* the NVD CVE data.
|
* CVE data.
|
||||||
*
|
*
|
||||||
* @author Jeremy Long <jeremy.long@owasp.org>
|
* @author Jeremy Long
|
||||||
*/
|
*/
|
||||||
public final class CpeMemoryIndex {
|
public final class CpeMemoryIndex {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The logger.
|
* The logger.
|
||||||
*/
|
*/
|
||||||
private static final Logger LOGGER = Logger.getLogger(CpeMemoryIndex.class.getName());
|
private static final Logger LOGGER = LoggerFactory.getLogger(CpeMemoryIndex.class);
|
||||||
/**
|
/**
|
||||||
* singleton instance.
|
* singleton instance.
|
||||||
*/
|
*/
|
||||||
private static CpeMemoryIndex instance = new CpeMemoryIndex();
|
private static final CpeMemoryIndex INSTANCE = new CpeMemoryIndex();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* private constructor for singleton.
|
* private constructor for singleton.
|
||||||
@@ -75,7 +76,7 @@ public final class CpeMemoryIndex {
|
|||||||
* @return the instance of the CpeMemoryIndex
|
* @return the instance of the CpeMemoryIndex
|
||||||
*/
|
*/
|
||||||
public static CpeMemoryIndex getInstance() {
|
public static CpeMemoryIndex getInstance() {
|
||||||
return instance;
|
return INSTANCE;
|
||||||
}
|
}
|
||||||
/**
|
/**
|
||||||
* The in memory Lucene index.
|
* The in memory Lucene index.
|
||||||
@@ -113,18 +114,20 @@ public final class CpeMemoryIndex {
|
|||||||
* @throws IndexException thrown if there is an error creating the index
|
* @throws IndexException thrown if there is an error creating the index
|
||||||
*/
|
*/
|
||||||
public void open(CveDB cve) throws IndexException {
|
public void open(CveDB cve) throws IndexException {
|
||||||
if (!openState) {
|
synchronized (INSTANCE) {
|
||||||
index = new RAMDirectory();
|
if (!openState) {
|
||||||
buildIndex(cve);
|
index = new RAMDirectory();
|
||||||
try {
|
buildIndex(cve);
|
||||||
indexReader = DirectoryReader.open(index);
|
try {
|
||||||
} catch (IOException ex) {
|
indexReader = DirectoryReader.open(index);
|
||||||
throw new IndexException(ex);
|
} catch (IOException ex) {
|
||||||
|
throw new IndexException(ex);
|
||||||
|
}
|
||||||
|
indexSearcher = new IndexSearcher(indexReader);
|
||||||
|
searchingAnalyzer = createSearchingAnalyzer();
|
||||||
|
queryParser = new QueryParser(LuceneUtils.CURRENT_VERSION, Fields.DOCUMENT_KEY, searchingAnalyzer);
|
||||||
|
openState = true;
|
||||||
}
|
}
|
||||||
indexSearcher = new IndexSearcher(indexReader);
|
|
||||||
searchingAnalyzer = createSearchingAnalyzer();
|
|
||||||
queryParser = new QueryParser(LuceneUtils.CURRENT_VERSION, Fields.DOCUMENT_KEY, searchingAnalyzer);
|
|
||||||
openState = true;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
/**
|
/**
|
||||||
@@ -160,7 +163,7 @@ public final class CpeMemoryIndex {
|
|||||||
*/
|
*/
|
||||||
@SuppressWarnings("unchecked")
|
@SuppressWarnings("unchecked")
|
||||||
private Analyzer createSearchingAnalyzer() {
|
private Analyzer createSearchingAnalyzer() {
|
||||||
final Map fieldAnalyzers = new HashMap();
|
final Map<String, Analyzer> fieldAnalyzers = new HashMap<String, Analyzer>();
|
||||||
fieldAnalyzers.put(Fields.DOCUMENT_KEY, new KeywordAnalyzer());
|
fieldAnalyzers.put(Fields.DOCUMENT_KEY, new KeywordAnalyzer());
|
||||||
productSearchFieldAnalyzer = new SearchFieldAnalyzer(LuceneUtils.CURRENT_VERSION);
|
productSearchFieldAnalyzer = new SearchFieldAnalyzer(LuceneUtils.CURRENT_VERSION);
|
||||||
vendorSearchFieldAnalyzer = new SearchFieldAnalyzer(LuceneUtils.CURRENT_VERSION);
|
vendorSearchFieldAnalyzer = new SearchFieldAnalyzer(LuceneUtils.CURRENT_VERSION);
|
||||||
@@ -200,7 +203,7 @@ public final class CpeMemoryIndex {
|
|||||||
try {
|
try {
|
||||||
indexReader.close();
|
indexReader.close();
|
||||||
} catch (IOException ex) {
|
} catch (IOException ex) {
|
||||||
LOGGER.log(Level.FINEST, null, ex);
|
LOGGER.trace("", ex);
|
||||||
}
|
}
|
||||||
indexReader = null;
|
indexReader = null;
|
||||||
}
|
}
|
||||||
@@ -232,7 +235,7 @@ public final class CpeMemoryIndex {
|
|||||||
saveEntry(pair.getLeft(), pair.getRight(), indexWriter);
|
saveEntry(pair.getLeft(), pair.getRight(), indexWriter);
|
||||||
}
|
}
|
||||||
} catch (DatabaseException ex) {
|
} catch (DatabaseException ex) {
|
||||||
LOGGER.log(Level.FINE, null, ex);
|
LOGGER.debug("", ex);
|
||||||
throw new IndexException("Error reading CPE data", ex);
|
throw new IndexException("Error reading CPE data", ex);
|
||||||
}
|
}
|
||||||
} catch (CorruptIndexException ex) {
|
} catch (CorruptIndexException ex) {
|
||||||
|
|||||||
@@ -20,9 +20,9 @@ package org.owasp.dependencycheck.data.cpe;
|
|||||||
/**
|
/**
|
||||||
* Fields is a collection of field names used within the Lucene index for CPE entries.
|
* Fields is a collection of field names used within the Lucene index for CPE entries.
|
||||||
*
|
*
|
||||||
* @author Jeremy Long <jeremy.long@owasp.org>
|
* @author Jeremy Long
|
||||||
*/
|
*/
|
||||||
public abstract class Fields {
|
public final class Fields {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The key for the name document id.
|
* The key for the name document id.
|
||||||
@@ -36,7 +36,10 @@ public abstract class Fields {
|
|||||||
* The key for the product field.
|
* The key for the product field.
|
||||||
*/
|
*/
|
||||||
public static final String PRODUCT = "product";
|
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() {
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -24,7 +24,7 @@ import java.net.URLDecoder;
|
|||||||
/**
|
/**
|
||||||
* A CPE entry containing the name, vendor, product, and version.
|
* A CPE entry containing the name, vendor, product, and version.
|
||||||
*
|
*
|
||||||
* @author Jeremy Long <jeremy.long@owasp.org>
|
* @author Jeremy Long
|
||||||
*/
|
*/
|
||||||
public class IndexEntry implements Serializable {
|
public class IndexEntry implements Serializable {
|
||||||
|
|
||||||
|
|||||||
@@ -20,7 +20,7 @@ package org.owasp.dependencycheck.data.cpe;
|
|||||||
/**
|
/**
|
||||||
* An exception thrown when the there is an issue using the in-memory CPE Index.
|
* An exception thrown when the there is an issue using the in-memory CPE Index.
|
||||||
*
|
*
|
||||||
* @author Jeremy Long <jeremy.long@owasp.org>
|
* @author Jeremy Long
|
||||||
*/
|
*/
|
||||||
public class IndexException extends Exception {
|
public class IndexException extends Exception {
|
||||||
|
|
||||||
|
|||||||
@@ -1,12 +1,4 @@
|
|||||||
/**
|
/**
|
||||||
* <html>
|
|
||||||
* <head>
|
|
||||||
* <title>org.owasp.dependencycheck.data.cpe</title>
|
|
||||||
* </head>
|
|
||||||
* <body>
|
|
||||||
* Contains classes for working with the CPE Lucene Index.
|
* Contains classes for working with the CPE Lucene Index.
|
||||||
* </body>
|
*/
|
||||||
* </html>
|
|
||||||
*/
|
|
||||||
|
|
||||||
package org.owasp.dependencycheck.data.cpe;
|
package org.owasp.dependencycheck.data.cpe;
|
||||||
|
|||||||
@@ -17,22 +17,25 @@
|
|||||||
*/
|
*/
|
||||||
package org.owasp.dependencycheck.data.cwe;
|
package org.owasp.dependencycheck.data.cwe;
|
||||||
|
|
||||||
|
import org.slf4j.Logger;
|
||||||
|
import org.slf4j.LoggerFactory;
|
||||||
|
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.io.InputStream;
|
import java.io.InputStream;
|
||||||
import java.io.ObjectInputStream;
|
import java.io.ObjectInputStream;
|
||||||
import java.util.HashMap;
|
import java.util.HashMap;
|
||||||
import java.util.logging.Level;
|
|
||||||
import java.util.logging.Logger;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
*
|
*
|
||||||
* @author Jeremy Long <jeremy.long@owasp.org>
|
* @author Jeremy Long
|
||||||
*/
|
*/
|
||||||
public final class CweDB {
|
public final class CweDB {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The Logger.
|
* The Logger.
|
||||||
*/
|
*/
|
||||||
private static final Logger LOGGER = Logger.getLogger(CweDB.class.getName());
|
private static final Logger LOGGER = LoggerFactory.getLogger(CweDB.class);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Empty private constructor as this is a utility class.
|
* Empty private constructor as this is a utility class.
|
||||||
*/
|
*/
|
||||||
@@ -55,19 +58,21 @@ public final class CweDB {
|
|||||||
final String filePath = "data/cwe.hashmap.serialized";
|
final String filePath = "data/cwe.hashmap.serialized";
|
||||||
final InputStream input = CweDB.class.getClassLoader().getResourceAsStream(filePath);
|
final InputStream input = CweDB.class.getClassLoader().getResourceAsStream(filePath);
|
||||||
oin = new ObjectInputStream(input);
|
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) {
|
} catch (ClassNotFoundException ex) {
|
||||||
LOGGER.log(Level.WARNING, "Unable to load CWE data. This should not be an issue.");
|
LOGGER.warn("Unable to load CWE data. This should not be an issue.");
|
||||||
LOGGER.log(Level.FINE, null, ex);
|
LOGGER.debug("", ex);
|
||||||
} catch (IOException ex) {
|
} catch (IOException ex) {
|
||||||
LOGGER.log(Level.WARNING, "Unable to load CWE data due to an IO Error. This should not be an issue.");
|
LOGGER.warn("Unable to load CWE data due to an IO Error. This should not be an issue.");
|
||||||
LOGGER.log(Level.FINE, null, ex);
|
LOGGER.debug("", ex);
|
||||||
} finally {
|
} finally {
|
||||||
if (oin != null) {
|
if (oin != null) {
|
||||||
try {
|
try {
|
||||||
oin.close();
|
oin.close();
|
||||||
} catch (IOException ex) {
|
} catch (IOException ex) {
|
||||||
LOGGER.log(Level.FINEST, null, ex);
|
LOGGER.trace("", ex);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -25,7 +25,7 @@ import org.xml.sax.helpers.DefaultHandler;
|
|||||||
/**
|
/**
|
||||||
* A SAX Handler that will parse the CWE XML.
|
* A SAX Handler that will parse the CWE XML.
|
||||||
*
|
*
|
||||||
* @author Jeremy Long <jeremy.long@owasp.org>
|
* @author Jeremy Long
|
||||||
*/
|
*/
|
||||||
public class CweHandler extends DefaultHandler {
|
public class CweHandler extends DefaultHandler {
|
||||||
|
|
||||||
|
|||||||
@@ -1,12 +1,4 @@
|
|||||||
/**
|
/**
|
||||||
* <html>
|
|
||||||
* <head>
|
|
||||||
* <title>org.owasp.dependencycheck.data.cwe</title>
|
|
||||||
* </head>
|
|
||||||
* <body>
|
|
||||||
* Contains classes for working with the CWE Database.
|
* Contains classes for working with the CWE Database.
|
||||||
* </body>
|
*/
|
||||||
* </html>
|
|
||||||
*/
|
|
||||||
|
|
||||||
package org.owasp.dependencycheck.data.cwe;
|
package org.owasp.dependencycheck.data.cwe;
|
||||||
|
|||||||
@@ -25,7 +25,7 @@ import org.apache.lucene.analysis.tokenattributes.CharTermAttribute;
|
|||||||
/**
|
/**
|
||||||
* An abstract tokenizing filter that can be used as the base for a tokenizing filter.
|
* An abstract tokenizing filter that can be used as the base for a tokenizing filter.
|
||||||
*
|
*
|
||||||
* @author Jeremy Long <jeremy.long@owasp.org>
|
* @author Jeremy Long
|
||||||
*/
|
*/
|
||||||
public abstract class AbstractTokenizingFilter extends TokenFilter {
|
public abstract class AbstractTokenizingFilter extends TokenFilter {
|
||||||
|
|
||||||
@@ -72,7 +72,7 @@ public abstract class AbstractTokenizingFilter extends TokenFilter {
|
|||||||
* @return whether or not a new term was added
|
* @return whether or not a new term was added
|
||||||
*/
|
*/
|
||||||
protected boolean addTerm() {
|
protected boolean addTerm() {
|
||||||
final boolean termAdded = tokens.size() > 0;
|
final boolean termAdded = !tokens.isEmpty();
|
||||||
if (termAdded) {
|
if (termAdded) {
|
||||||
final String term = tokens.pop();
|
final String term = tokens.pop();
|
||||||
clearAttributes();
|
clearAttributes();
|
||||||
|
|||||||
@@ -24,7 +24,7 @@ import org.apache.lucene.util.Version;
|
|||||||
/**
|
/**
|
||||||
* Tokenizes the input breaking it into tokens when non-alpha/numeric characters are found.
|
* Tokenizes the input breaking it into tokens when non-alpha/numeric characters are found.
|
||||||
*
|
*
|
||||||
* @author Jeremy Long <jeremy.long@owasp.org>
|
* @author Jeremy Long
|
||||||
*/
|
*/
|
||||||
public class AlphaNumericTokenizer extends CharTokenizer {
|
public class AlphaNumericTokenizer extends CharTokenizer {
|
||||||
|
|
||||||
|
|||||||
@@ -21,7 +21,7 @@ import org.apache.lucene.search.similarities.DefaultSimilarity;
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
*
|
*
|
||||||
* @author Jeremy Long <jeremy.long@owasp.org>
|
* @author Jeremy Long
|
||||||
*/
|
*/
|
||||||
public class DependencySimilarity extends DefaultSimilarity {
|
public class DependencySimilarity extends DefaultSimilarity {
|
||||||
|
|
||||||
|
|||||||
@@ -29,10 +29,10 @@ import org.apache.lucene.util.Version;
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* <p>
|
* <p>
|
||||||
* A Lucene Analyzer that utilizes the WhitespaceTokenizer, WordDelimiterFilter, LowerCaseFilter, and StopFilter. The
|
* A Lucene Analyzer that utilizes the WhitespaceTokenizer, WordDelimiterFilter, LowerCaseFilter, and StopFilter. The intended
|
||||||
* intended purpose of this Analyzer is to index the CPE fields vendor and product.</p>
|
* purpose of this Analyzer is to index the CPE fields vendor and product.</p>
|
||||||
*
|
*
|
||||||
* @author Jeremy Long <jeremy.long@owasp.org>
|
* @author Jeremy Long
|
||||||
*/
|
*/
|
||||||
public class FieldAnalyzer extends Analyzer {
|
public class FieldAnalyzer extends Analyzer {
|
||||||
|
|
||||||
|
|||||||
@@ -17,21 +17,22 @@
|
|||||||
*/
|
*/
|
||||||
package org.owasp.dependencycheck.data.lucene;
|
package org.owasp.dependencycheck.data.lucene;
|
||||||
|
|
||||||
|
import edu.umd.cs.findbugs.annotations.SuppressFBWarnings;
|
||||||
import org.apache.lucene.util.Version;
|
import org.apache.lucene.util.Version;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* <p>
|
* <p>
|
||||||
* Lucene utils is a set of utilize written to make constructing Lucene queries simpler.</p>
|
* Lucene utils is a set of utilize written to make constructing Lucene queries simpler.</p>
|
||||||
*
|
*
|
||||||
* @author Jeremy Long <jeremy.long@owasp.org>
|
* @author Jeremy Long
|
||||||
*/
|
*/
|
||||||
public final class LuceneUtils {
|
public final class LuceneUtils {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The current version of Lucene being used. Declaring this one place so an upgrade doesn't require hunting through
|
* The current version of Lucene being used. Declaring this one place so an upgrade doesn't require hunting through the code
|
||||||
* the code base.
|
* base.
|
||||||
*/
|
*/
|
||||||
public static final Version CURRENT_VERSION = Version.LUCENE_45;
|
public static final Version CURRENT_VERSION = Version.LUCENE_47;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Private constructor as this is a utility class.
|
* Private constructor as this is a utility class.
|
||||||
@@ -46,7 +47,7 @@ public final class LuceneUtils {
|
|||||||
* @param text the data to be escaped
|
* @param text the data to be escaped
|
||||||
*/
|
*/
|
||||||
@SuppressWarnings("fallthrough")
|
@SuppressWarnings("fallthrough")
|
||||||
@edu.umd.cs.findbugs.annotations.SuppressWarnings(
|
@SuppressFBWarnings(
|
||||||
value = "SF_SWITCH_NO_DEFAULT",
|
value = "SF_SWITCH_NO_DEFAULT",
|
||||||
justification = "The switch below does have a default.")
|
justification = "The switch below does have a default.")
|
||||||
public static void appendEscapedLuceneQuery(StringBuilder buf,
|
public static void appendEscapedLuceneQuery(StringBuilder buf,
|
||||||
|
|||||||
@@ -30,7 +30,7 @@ import org.apache.lucene.util.Version;
|
|||||||
/**
|
/**
|
||||||
* A Lucene field analyzer used to analyzer queries against the CPE data.
|
* A Lucene field analyzer used to analyzer queries against the CPE data.
|
||||||
*
|
*
|
||||||
* @author Jeremy Long <jeremy.long@owasp.org>
|
* @author Jeremy Long
|
||||||
*/
|
*/
|
||||||
public class SearchFieldAnalyzer extends Analyzer {
|
public class SearchFieldAnalyzer extends Analyzer {
|
||||||
|
|
||||||
@@ -39,8 +39,7 @@ public class SearchFieldAnalyzer extends Analyzer {
|
|||||||
*/
|
*/
|
||||||
private final Version version;
|
private final Version version;
|
||||||
/**
|
/**
|
||||||
* A local reference to the TokenPairConcatenatingFilter so that we can clear any left over state if this analyzer
|
* A local reference to the TokenPairConcatenatingFilter so that we can clear any left over state if this analyzer is re-used.
|
||||||
* is re-used.
|
|
||||||
*/
|
*/
|
||||||
private TokenPairConcatenatingFilter concatenatingFilter;
|
private TokenPairConcatenatingFilter concatenatingFilter;
|
||||||
|
|
||||||
@@ -85,8 +84,7 @@ public class SearchFieldAnalyzer extends Analyzer {
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* <p>
|
* <p>
|
||||||
* Resets the analyzer and clears any internal state data that may have been left-over from previous uses of the
|
* Resets the analyzer and clears any internal state data that may have been left-over from previous uses of the analyzer.</p>
|
||||||
* analyzer.</p>
|
|
||||||
* <p>
|
* <p>
|
||||||
* <b>If this analyzer is re-used this method must be called between uses.</b></p>
|
* <b>If this analyzer is re-used this method must be called between uses.</b></p>
|
||||||
*/
|
*/
|
||||||
|
|||||||
@@ -1,72 +0,0 @@
|
|||||||
/*
|
|
||||||
* This file is part of dependency-check-core.
|
|
||||||
*
|
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
||||||
* you may not use this file except in compliance with the License.
|
|
||||||
* You may obtain a copy of the License at
|
|
||||||
*
|
|
||||||
* http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
*
|
|
||||||
* Unless required by applicable law or agreed to in writing, software
|
|
||||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
||||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
* See the License for the specific language governing permissions and
|
|
||||||
* limitations under the License.
|
|
||||||
*
|
|
||||||
* Copyright (c) 2012 Jeremy Long. All Rights Reserved.
|
|
||||||
*/
|
|
||||||
package org.owasp.dependencycheck.data.lucene;
|
|
||||||
|
|
||||||
import java.io.Reader;
|
|
||||||
import org.apache.lucene.analysis.Analyzer;
|
|
||||||
import org.apache.lucene.analysis.TokenStream;
|
|
||||||
import org.apache.lucene.analysis.Tokenizer;
|
|
||||||
import org.apache.lucene.analysis.core.LowerCaseFilter;
|
|
||||||
import org.apache.lucene.analysis.core.WhitespaceTokenizer;
|
|
||||||
import org.apache.lucene.util.Version;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* SearchVersionAnalyzer is a Lucene Analyzer used to analyze version information.
|
|
||||||
*
|
|
||||||
* @author Jeremy Long <jeremy.long@owasp.org>
|
|
||||||
* @deprecated version information is no longer stored in lucene
|
|
||||||
*/
|
|
||||||
@Deprecated
|
|
||||||
public class SearchVersionAnalyzer extends Analyzer {
|
|
||||||
//TODO consider implementing payloads/custom attributes...
|
|
||||||
// use custom attributes for major, minor, x, x, x, rcx
|
|
||||||
// these can then be used to weight the score for searches on the version.
|
|
||||||
// see http://lucene.apache.org/core/3_6_1/api/core/org/apache/lucene/analysis/package-summary.html#package_description
|
|
||||||
// look at this article to implement
|
|
||||||
// http://www.codewrecks.com/blog/index.php/2012/08/25/index-your-blog-using-tags-and-lucene-net/
|
|
||||||
|
|
||||||
/**
|
|
||||||
* The Lucene Version used.
|
|
||||||
*/
|
|
||||||
private final Version version;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Creates a new SearchVersionAnalyzer.
|
|
||||||
*
|
|
||||||
* @param version the Lucene version
|
|
||||||
*/
|
|
||||||
public SearchVersionAnalyzer(Version version) {
|
|
||||||
this.version = version;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Creates the TokenStreamComponents
|
|
||||||
*
|
|
||||||
* @param fieldName the field name being analyzed
|
|
||||||
* @param reader the reader containing the input
|
|
||||||
* @return the TokenStreamComponents
|
|
||||||
*/
|
|
||||||
@Override
|
|
||||||
protected TokenStreamComponents createComponents(String fieldName, Reader reader) {
|
|
||||||
final Tokenizer source = new WhitespaceTokenizer(version, reader);
|
|
||||||
TokenStream stream = source;
|
|
||||||
stream = new LowerCaseFilter(version, stream);
|
|
||||||
stream = new VersionTokenizingFilter(stream);
|
|
||||||
return new TokenStreamComponents(source, stream);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -29,7 +29,7 @@ import org.apache.lucene.analysis.tokenattributes.CharTermAttribute;
|
|||||||
* <p>
|
* <p>
|
||||||
* <b>Example:</b> "Spring Framework Core" -> "Spring SpringFramework Framework FrameworkCore Core".</p>
|
* <b>Example:</b> "Spring Framework Core" -> "Spring SpringFramework Framework FrameworkCore Core".</p>
|
||||||
*
|
*
|
||||||
* @author Jeremy Long <jeremy.long@owasp.org>
|
* @author Jeremy Long
|
||||||
*/
|
*/
|
||||||
public final class TokenPairConcatenatingFilter extends TokenFilter {
|
public final class TokenPairConcatenatingFilter extends TokenFilter {
|
||||||
|
|
||||||
@@ -92,7 +92,7 @@ public final class TokenPairConcatenatingFilter extends TokenFilter {
|
|||||||
|
|
||||||
//if we have a previousTerm - write it out as its own token concatenated
|
//if we have a previousTerm - write it out as its own token concatenated
|
||||||
// with the current word (if one is available).
|
// with the current word (if one is available).
|
||||||
if (previousWord != null && words.size() > 0) {
|
if (previousWord != null && !words.isEmpty()) {
|
||||||
final String word = words.getFirst();
|
final String word = words.getFirst();
|
||||||
clearAttributes();
|
clearAttributes();
|
||||||
termAtt.append(previousWord).append(word);
|
termAtt.append(previousWord).append(word);
|
||||||
@@ -100,7 +100,7 @@ public final class TokenPairConcatenatingFilter extends TokenFilter {
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
//if we have words, write it out as a single token
|
//if we have words, write it out as a single token
|
||||||
if (words.size() > 0) {
|
if (!words.isEmpty()) {
|
||||||
final String word = words.removeFirst();
|
final String word = words.removeFirst();
|
||||||
clearAttributes();
|
clearAttributes();
|
||||||
termAtt.append(word);
|
termAtt.append(word);
|
||||||
|
|||||||
@@ -21,11 +21,11 @@ import java.io.IOException;
|
|||||||
import java.net.MalformedURLException;
|
import java.net.MalformedURLException;
|
||||||
import java.util.LinkedList;
|
import java.util.LinkedList;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.logging.Level;
|
|
||||||
import java.util.logging.Logger;
|
|
||||||
import org.apache.lucene.analysis.TokenStream;
|
import org.apache.lucene.analysis.TokenStream;
|
||||||
import org.apache.lucene.analysis.tokenattributes.CharTermAttribute;
|
import org.apache.lucene.analysis.tokenattributes.CharTermAttribute;
|
||||||
import org.owasp.dependencycheck.utils.UrlStringUtils;
|
import org.owasp.dependencycheck.utils.UrlStringUtils;
|
||||||
|
import org.slf4j.Logger;
|
||||||
|
import org.slf4j.LoggerFactory;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* <p>
|
* <p>
|
||||||
@@ -33,13 +33,13 @@ import org.owasp.dependencycheck.utils.UrlStringUtils;
|
|||||||
* <p>
|
* <p>
|
||||||
* <b>Example:</b> "3.0.0.RELEASE" -> "3 3.0 3.0.0 RELEASE 3.0.0.RELEASE".</p>
|
* <b>Example:</b> "3.0.0.RELEASE" -> "3 3.0 3.0.0 RELEASE 3.0.0.RELEASE".</p>
|
||||||
*
|
*
|
||||||
* @author Jeremy Long <jeremy.long@owasp.org>
|
* @author Jeremy Long
|
||||||
*/
|
*/
|
||||||
public final class UrlTokenizingFilter extends AbstractTokenizingFilter {
|
public final class UrlTokenizingFilter extends AbstractTokenizingFilter {
|
||||||
/**
|
/**
|
||||||
* The logger.
|
* The logger.
|
||||||
*/
|
*/
|
||||||
private static final Logger LOGGER = Logger.getLogger(UrlTokenizingFilter.class.getName());
|
private static final Logger LOGGER = LoggerFactory.getLogger(UrlTokenizingFilter.class);
|
||||||
/**
|
/**
|
||||||
* Constructs a new VersionTokenizingFilter.
|
* Constructs a new VersionTokenizingFilter.
|
||||||
*
|
*
|
||||||
@@ -60,7 +60,7 @@ public final class UrlTokenizingFilter extends AbstractTokenizingFilter {
|
|||||||
public boolean incrementToken() throws IOException {
|
public boolean incrementToken() throws IOException {
|
||||||
final LinkedList<String> tokens = getTokens();
|
final LinkedList<String> tokens = getTokens();
|
||||||
final CharTermAttribute termAtt = getTermAtt();
|
final CharTermAttribute termAtt = getTermAtt();
|
||||||
if (tokens.size() == 0 && input.incrementToken()) {
|
if (tokens.isEmpty() && input.incrementToken()) {
|
||||||
final String text = new String(termAtt.buffer(), 0, termAtt.length());
|
final String text = new String(termAtt.buffer(), 0, termAtt.length());
|
||||||
if (UrlStringUtils.containsUrl(text)) {
|
if (UrlStringUtils.containsUrl(text)) {
|
||||||
final String[] parts = text.split("\\s");
|
final String[] parts = text.split("\\s");
|
||||||
@@ -70,7 +70,7 @@ public final class UrlTokenizingFilter extends AbstractTokenizingFilter {
|
|||||||
final List<String> data = UrlStringUtils.extractImportantUrlData(part);
|
final List<String> data = UrlStringUtils.extractImportantUrlData(part);
|
||||||
tokens.addAll(data);
|
tokens.addAll(data);
|
||||||
} catch (MalformedURLException ex) {
|
} catch (MalformedURLException ex) {
|
||||||
LOGGER.log(Level.FINE, "error parsing " + part, ex);
|
LOGGER.debug("error parsing {}", part, ex);
|
||||||
tokens.add(part);
|
tokens.add(part);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
|
|||||||
@@ -1,71 +0,0 @@
|
|||||||
/*
|
|
||||||
* This file is part of dependency-check-core.
|
|
||||||
*
|
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
||||||
* you may not use this file except in compliance with the License.
|
|
||||||
* You may obtain a copy of the License at
|
|
||||||
*
|
|
||||||
* http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
*
|
|
||||||
* Unless required by applicable law or agreed to in writing, software
|
|
||||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
||||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
* See the License for the specific language governing permissions and
|
|
||||||
* limitations under the License.
|
|
||||||
*
|
|
||||||
* Copyright (c) 2012 Jeremy Long. All Rights Reserved.
|
|
||||||
*/
|
|
||||||
package org.owasp.dependencycheck.data.lucene;
|
|
||||||
|
|
||||||
import java.io.Reader;
|
|
||||||
import org.apache.lucene.analysis.Analyzer;
|
|
||||||
import org.apache.lucene.analysis.TokenStream;
|
|
||||||
import org.apache.lucene.analysis.Tokenizer;
|
|
||||||
import org.apache.lucene.analysis.core.LowerCaseFilter;
|
|
||||||
import org.apache.lucene.analysis.core.WhitespaceTokenizer;
|
|
||||||
import org.apache.lucene.util.Version;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* VersionAnalyzer is a Lucene Analyzer used to analyze version information.
|
|
||||||
*
|
|
||||||
* @author Jeremy Long <jeremy.long@owasp.org>
|
|
||||||
* @deprecated version information is no longer stored in lucene
|
|
||||||
*/
|
|
||||||
@Deprecated
|
|
||||||
public class VersionAnalyzer extends Analyzer {
|
|
||||||
//TODO consider implementing payloads/custom attributes...
|
|
||||||
// use custom attributes for major, minor, x, x, x, rcx
|
|
||||||
// these can then be used to weight the score for searches on the version.
|
|
||||||
// see http://lucene.apache.org/core/3_6_1/api/core/org/apache/lucene/analysis/package-summary.html#package_description
|
|
||||||
// look at this article to implement
|
|
||||||
// http://www.codewrecks.com/blog/index.php/2012/08/25/index-your-blog-using-tags-and-lucene-net/
|
|
||||||
|
|
||||||
/**
|
|
||||||
* The Lucene Version used.
|
|
||||||
*/
|
|
||||||
private final Version version;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Creates a new VersionAnalyzer.
|
|
||||||
*
|
|
||||||
* @param version the Lucene version
|
|
||||||
*/
|
|
||||||
public VersionAnalyzer(Version version) {
|
|
||||||
this.version = version;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Creates the TokenStreamComponents
|
|
||||||
*
|
|
||||||
* @param fieldName the field name being analyzed
|
|
||||||
* @param reader the reader containing the input
|
|
||||||
* @return the TokenStreamComponents
|
|
||||||
*/
|
|
||||||
@Override
|
|
||||||
protected TokenStreamComponents createComponents(String fieldName, Reader reader) {
|
|
||||||
final Tokenizer source = new WhitespaceTokenizer(version, reader);
|
|
||||||
TokenStream stream = source;
|
|
||||||
stream = new LowerCaseFilter(version, stream);
|
|
||||||
return new TokenStreamComponents(source, stream);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,98 +0,0 @@
|
|||||||
/*
|
|
||||||
* This file is part of dependency-check-core.
|
|
||||||
*
|
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
||||||
* you may not use this file except in compliance with the License.
|
|
||||||
* You may obtain a copy of the License at
|
|
||||||
*
|
|
||||||
* http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
*
|
|
||||||
* Unless required by applicable law or agreed to in writing, software
|
|
||||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
||||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
* See the License for the specific language governing permissions and
|
|
||||||
* limitations under the License.
|
|
||||||
*
|
|
||||||
* Copyright (c) 2012 Jeremy Long. All Rights Reserved.
|
|
||||||
*/
|
|
||||||
package org.owasp.dependencycheck.data.lucene;
|
|
||||||
|
|
||||||
import java.io.IOException;
|
|
||||||
import java.util.LinkedList;
|
|
||||||
import org.apache.lucene.analysis.TokenStream;
|
|
||||||
import org.apache.lucene.analysis.tokenattributes.CharTermAttribute;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* <p>
|
|
||||||
* Takes a TokenStream and splits or adds tokens to correctly index version numbers.</p>
|
|
||||||
* <p>
|
|
||||||
* <b>Example:</b> "3.0.0.RELEASE" -> "3 3.0 3.0.0 RELEASE 3.0.0.RELEASE".</p>
|
|
||||||
*
|
|
||||||
* @author Jeremy Long <jeremy.long@owasp.org>
|
|
||||||
* @deprecated version information is no longer stored in lucene
|
|
||||||
*/
|
|
||||||
@Deprecated
|
|
||||||
public final class VersionTokenizingFilter extends AbstractTokenizingFilter {
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Constructs a new VersionTokenizingFilter.
|
|
||||||
*
|
|
||||||
* @param stream the TokenStream that this filter will process
|
|
||||||
*/
|
|
||||||
public VersionTokenizingFilter(TokenStream stream) {
|
|
||||||
super(stream);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Increments the underlying TokenStream and sets CharTermAttributes to construct an expanded set of tokens by
|
|
||||||
* concatenating tokens with the previous token.
|
|
||||||
*
|
|
||||||
* @return whether or not we have hit the end of the TokenStream
|
|
||||||
* @throws IOException is thrown when an IOException occurs
|
|
||||||
*/
|
|
||||||
@Override
|
|
||||||
public boolean incrementToken() throws IOException {
|
|
||||||
final LinkedList<String> tokens = getTokens();
|
|
||||||
final CharTermAttribute termAtt = getTermAtt();
|
|
||||||
if (tokens.size() == 0 && input.incrementToken()) {
|
|
||||||
final String version = new String(termAtt.buffer(), 0, termAtt.length());
|
|
||||||
final String[] toAnalyze = version.split("[_-]");
|
|
||||||
//ensure we analyze the whole string as one too
|
|
||||||
analyzeVersion(version);
|
|
||||||
for (String str : toAnalyze) {
|
|
||||||
analyzeVersion(str);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return addTerm();
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* <p>
|
|
||||||
* Analyzes the version and adds several copies of the version as different tokens. For example, the version 1.2.7
|
|
||||||
* would create the tokens 1 1.2 1.2.7. This is useful in discovering the correct version - sometimes a maintenance
|
|
||||||
* or build number will throw off the version identification.</p>
|
|
||||||
*
|
|
||||||
* <p>
|
|
||||||
* expected format:&nbps;major.minor[.maintenance[.build]]</p>
|
|
||||||
*
|
|
||||||
* @param version the version to analyze
|
|
||||||
*/
|
|
||||||
private void analyzeVersion(String version) {
|
|
||||||
//todo should we also be splitting on dash or underscore? we would need
|
|
||||||
// to incorporate the dash or underscore back in...
|
|
||||||
final LinkedList<String> tokens = getTokens();
|
|
||||||
final String[] versionParts = version.split("\\.");
|
|
||||||
String dottedVersion = null;
|
|
||||||
for (String current : versionParts) {
|
|
||||||
if (!current.matches("^/d+$")) {
|
|
||||||
tokens.add(current);
|
|
||||||
}
|
|
||||||
if (dottedVersion == null) {
|
|
||||||
dottedVersion = current;
|
|
||||||
} else {
|
|
||||||
dottedVersion = dottedVersion + "." + current;
|
|
||||||
}
|
|
||||||
tokens.add(dottedVersion);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,12 +1,4 @@
|
|||||||
/**
|
/**
|
||||||
* <html>
|
|
||||||
* <head>
|
|
||||||
* <title>org.owasp.dependencycheck.data.lucene</title>
|
|
||||||
* </head>
|
|
||||||
* <body>
|
|
||||||
* Contains classes used to work with the Lucene Indexes.
|
* Contains classes used to work with the Lucene Indexes.
|
||||||
* </body>
|
*/
|
||||||
* </html>
|
|
||||||
*/
|
|
||||||
|
|
||||||
package org.owasp.dependencycheck.data.lucene;
|
package org.owasp.dependencycheck.data.lucene;
|
||||||
|
|||||||
@@ -24,6 +24,11 @@ package org.owasp.dependencycheck.data.nexus;
|
|||||||
*/
|
*/
|
||||||
public class MavenArtifact {
|
public class MavenArtifact {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The base URL for download artifacts from Central.
|
||||||
|
*/
|
||||||
|
private static final String CENTRAL_CONTENT_URL = "//search.maven.org/remotecontent?filepath=";
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The groupId
|
* The groupId
|
||||||
*/
|
*/
|
||||||
@@ -43,6 +48,10 @@ public class MavenArtifact {
|
|||||||
* The artifact url. This may change depending on which Nexus server the search took place.
|
* The artifact url. This may change depending on which Nexus server the search took place.
|
||||||
*/
|
*/
|
||||||
private String artifactUrl;
|
private String artifactUrl;
|
||||||
|
/**
|
||||||
|
* The url to download the POM from.
|
||||||
|
*/
|
||||||
|
private String pomUrl;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Creates an empty MavenArtifact.
|
* Creates an empty MavenArtifact.
|
||||||
@@ -58,9 +67,41 @@ public class MavenArtifact {
|
|||||||
* @param version the version
|
* @param version the version
|
||||||
*/
|
*/
|
||||||
public MavenArtifact(String groupId, String artifactId, String version) {
|
public MavenArtifact(String groupId, String artifactId, String version) {
|
||||||
setGroupId(groupId);
|
this.groupId = groupId;
|
||||||
setArtifactId(artifactId);
|
this.artifactId = artifactId;
|
||||||
setVersion(version);
|
this.version = version;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates a MavenArtifact with the given attributes.
|
||||||
|
*
|
||||||
|
* @param groupId the groupId
|
||||||
|
* @param artifactId the artifactId
|
||||||
|
* @param version the version
|
||||||
|
* @param jarAvailable if the jar file is available from central
|
||||||
|
* @param pomAvailable if the pom file is available from central
|
||||||
|
* @param secureDownload if the jar and pom files should be downloaded using HTTPS.
|
||||||
|
*/
|
||||||
|
public MavenArtifact(String groupId, String artifactId, String version, boolean jarAvailable, boolean pomAvailable, boolean secureDownload) {
|
||||||
|
this.groupId = groupId;
|
||||||
|
this.artifactId = artifactId;
|
||||||
|
this.version = version;
|
||||||
|
String base;
|
||||||
|
if (secureDownload) {
|
||||||
|
base = "https:" + CENTRAL_CONTENT_URL;
|
||||||
|
} else {
|
||||||
|
base = "http:" + CENTRAL_CONTENT_URL;
|
||||||
|
}
|
||||||
|
if (jarAvailable) {
|
||||||
|
//org/springframework/spring-core/3.2.0.RELEASE/spring-core-3.2.0.RELEASE.pom
|
||||||
|
this.artifactUrl = base + groupId.replace('.', '/') + "/" + artifactId + "/"
|
||||||
|
+ version + "/" + artifactId + "-" + version + ".jar";
|
||||||
|
}
|
||||||
|
if (pomAvailable) {
|
||||||
|
//org/springframework/spring-core/3.2.0.RELEASE/spring-core-3.2.0.RELEASE.pom
|
||||||
|
this.pomUrl = base + groupId.replace('.', '/') + "/" + artifactId + "/"
|
||||||
|
+ version + "/" + artifactId + "-" + version + ".pom";
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -72,10 +113,10 @@ public class MavenArtifact {
|
|||||||
* @param url the artifactLink url
|
* @param url the artifactLink url
|
||||||
*/
|
*/
|
||||||
public MavenArtifact(String groupId, String artifactId, String version, String url) {
|
public MavenArtifact(String groupId, String artifactId, String version, String url) {
|
||||||
setGroupId(groupId);
|
this.groupId = groupId;
|
||||||
setArtifactId(artifactId);
|
this.artifactId = artifactId;
|
||||||
setVersion(version);
|
this.version = version;
|
||||||
setArtifactUrl(url);
|
this.artifactUrl = url;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -159,6 +200,25 @@ public class MavenArtifact {
|
|||||||
public String getArtifactUrl() {
|
public String getArtifactUrl() {
|
||||||
return artifactUrl;
|
return artifactUrl;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the value of pomUrl.
|
||||||
|
*
|
||||||
|
* @return the value of pomUrl
|
||||||
|
*/
|
||||||
|
public String getPomUrl() {
|
||||||
|
return pomUrl;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Set the value of pomUrl.
|
||||||
|
*
|
||||||
|
* @param pomUrl new value of pomUrl
|
||||||
|
*/
|
||||||
|
public void setPomUrl(String pomUrl) {
|
||||||
|
this.pomUrl = pomUrl;
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// vim: cc=120:sw=4:ts=4:sts=4
|
// vim: cc=120:sw=4:ts=4:sts=4
|
||||||
|
|||||||
@@ -21,8 +21,6 @@ import java.io.FileNotFoundException;
|
|||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.net.HttpURLConnection;
|
import java.net.HttpURLConnection;
|
||||||
import java.net.URL;
|
import java.net.URL;
|
||||||
import java.util.logging.Level;
|
|
||||||
import java.util.logging.Logger;
|
|
||||||
import javax.xml.parsers.DocumentBuilder;
|
import javax.xml.parsers.DocumentBuilder;
|
||||||
import javax.xml.parsers.DocumentBuilderFactory;
|
import javax.xml.parsers.DocumentBuilderFactory;
|
||||||
import javax.xml.xpath.XPath;
|
import javax.xml.xpath.XPath;
|
||||||
@@ -30,6 +28,8 @@ import javax.xml.xpath.XPathFactory;
|
|||||||
import org.owasp.dependencycheck.utils.InvalidSettingException;
|
import org.owasp.dependencycheck.utils.InvalidSettingException;
|
||||||
import org.owasp.dependencycheck.utils.Settings;
|
import org.owasp.dependencycheck.utils.Settings;
|
||||||
import org.owasp.dependencycheck.utils.URLConnectionFactory;
|
import org.owasp.dependencycheck.utils.URLConnectionFactory;
|
||||||
|
import org.slf4j.Logger;
|
||||||
|
import org.slf4j.LoggerFactory;
|
||||||
import org.w3c.dom.Document;
|
import org.w3c.dom.Document;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -40,26 +40,24 @@ import org.w3c.dom.Document;
|
|||||||
public class NexusSearch {
|
public class NexusSearch {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The root URL for the Nexus repository service
|
* The root URL for the Nexus repository service.
|
||||||
*/
|
*/
|
||||||
private final URL rootURL;
|
private final URL rootURL;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Whether to use the Proxy when making requests
|
* Whether to use the Proxy when making requests.
|
||||||
*/
|
*/
|
||||||
private boolean useProxy;
|
private boolean useProxy;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Used for logging.
|
* Used for logging.
|
||||||
*/
|
*/
|
||||||
private static final Logger LOGGER = Logger.getLogger(NexusSearch.class
|
private static final Logger LOGGER = LoggerFactory.getLogger(NexusSearch.class);
|
||||||
.getName());
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Creates a NexusSearch for the given repository URL.
|
* Creates a NexusSearch for the given repository URL.
|
||||||
*
|
*
|
||||||
* @param rootURL the root URL of the repository on which searches should execute. full URL's are calculated
|
* @param rootURL the root URL of the repository on which searches should execute. full URL's are calculated relative to this
|
||||||
* relative to this URL, so it should end with a /
|
* URL, so it should end with a /
|
||||||
*/
|
*/
|
||||||
public NexusSearch(URL rootURL) {
|
public NexusSearch(URL rootURL) {
|
||||||
this.rootURL = rootURL;
|
this.rootURL = rootURL;
|
||||||
@@ -67,10 +65,10 @@ public class NexusSearch {
|
|||||||
if (null != Settings.getString(Settings.KEYS.PROXY_SERVER)
|
if (null != Settings.getString(Settings.KEYS.PROXY_SERVER)
|
||||||
&& Settings.getBoolean(Settings.KEYS.ANALYZER_NEXUS_PROXY)) {
|
&& Settings.getBoolean(Settings.KEYS.ANALYZER_NEXUS_PROXY)) {
|
||||||
useProxy = true;
|
useProxy = true;
|
||||||
LOGGER.fine("Using proxy");
|
LOGGER.debug("Using proxy");
|
||||||
} else {
|
} else {
|
||||||
useProxy = false;
|
useProxy = false;
|
||||||
LOGGER.fine("Not using proxy");
|
LOGGER.debug("Not using proxy");
|
||||||
}
|
}
|
||||||
} catch (InvalidSettingException ise) {
|
} catch (InvalidSettingException ise) {
|
||||||
useProxy = false;
|
useProxy = false;
|
||||||
@@ -78,13 +76,12 @@ public class NexusSearch {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Searches the configured Nexus repository for the given sha1 hash. If the artifact is found, a
|
* Searches the configured Nexus repository for the given sha1 hash. If the artifact is found, a <code>MavenArtifact</code> is
|
||||||
* <code>MavenArtifact</code> is populated with the coordinate information.
|
* populated with the coordinate information.
|
||||||
*
|
*
|
||||||
* @param sha1 The SHA-1 hash string for which to search
|
* @param sha1 The SHA-1 hash string for which to search
|
||||||
* @return the populated Maven coordinates
|
* @return the populated Maven coordinates
|
||||||
* @throws IOException if it's unable to connect to the specified repository or if the specified artifact is not
|
* @throws IOException if it's unable to connect to the specified repository or if the specified artifact is not found.
|
||||||
* found.
|
|
||||||
*/
|
*/
|
||||||
public MavenArtifact searchSha1(String sha1) throws IOException {
|
public MavenArtifact searchSha1(String sha1) throws IOException {
|
||||||
if (null == sha1 || !sha1.matches("^[0-9A-Fa-f]{40}$")) {
|
if (null == sha1 || !sha1.matches("^[0-9A-Fa-f]{40}$")) {
|
||||||
@@ -94,15 +91,14 @@ public class NexusSearch {
|
|||||||
final URL url = new URL(rootURL, String.format("identify/sha1/%s",
|
final URL url = new URL(rootURL, String.format("identify/sha1/%s",
|
||||||
sha1.toLowerCase()));
|
sha1.toLowerCase()));
|
||||||
|
|
||||||
LOGGER.fine(String.format("Searching Nexus url %s", url.toString()));
|
LOGGER.debug("Searching Nexus url {}", url);
|
||||||
|
|
||||||
// Determine if we need to use a proxy. The rules:
|
// 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
|
// 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,
|
// 2) Otherwise, don't use the proxy (either the proxy isn't configured,
|
||||||
// or proxy is specifically
|
// or proxy is specifically set to false
|
||||||
// set to false
|
HttpURLConnection conn;
|
||||||
final HttpURLConnection conn = URLConnectionFactory.createHttpURLConnection(url, useProxy);
|
conn = URLConnectionFactory.createHttpURLConnection(url, useProxy);
|
||||||
|
|
||||||
conn.setDoOutput(true);
|
conn.setDoOutput(true);
|
||||||
|
|
||||||
// JSON would be more elegant, but there's not currently a dependency
|
// JSON would be more elegant, but there's not currently a dependency
|
||||||
@@ -131,7 +127,18 @@ public class NexusSearch {
|
|||||||
.evaluate(
|
.evaluate(
|
||||||
"/org.sonatype.nexus.rest.model.NexusArtifact/artifactLink",
|
"/org.sonatype.nexus.rest.model.NexusArtifact/artifactLink",
|
||||||
doc);
|
doc);
|
||||||
return new MavenArtifact(groupId, artifactId, version, link);
|
final String pomLink = xpath
|
||||||
|
.evaluate(
|
||||||
|
"/org.sonatype.nexus.rest.model.NexusArtifact/pomLink",
|
||||||
|
doc);
|
||||||
|
final MavenArtifact ma = new MavenArtifact(groupId, artifactId, version);
|
||||||
|
if (link != null && !"".equals(link)) {
|
||||||
|
ma.setArtifactUrl(link);
|
||||||
|
}
|
||||||
|
if (pomLink != null && !"".equals(pomLink)) {
|
||||||
|
ma.setPomUrl(pomLink);
|
||||||
|
}
|
||||||
|
return ma;
|
||||||
} catch (Throwable e) {
|
} catch (Throwable e) {
|
||||||
// Anything else is jacked-up XML stuff that we really can't recover
|
// Anything else is jacked-up XML stuff that we really can't recover
|
||||||
// from well
|
// from well
|
||||||
@@ -140,10 +147,9 @@ public class NexusSearch {
|
|||||||
} else if (conn.getResponseCode() == 404) {
|
} else if (conn.getResponseCode() == 404) {
|
||||||
throw new FileNotFoundException("Artifact not found in Nexus");
|
throw new FileNotFoundException("Artifact not found in Nexus");
|
||||||
} else {
|
} else {
|
||||||
final String msg = String.format("Could not connect to Nexus received response code: %d %s",
|
LOGGER.debug("Could not connect to Nexus received response code: {} {}",
|
||||||
conn.getResponseCode(), conn.getResponseMessage());
|
conn.getResponseCode(), conn.getResponseMessage());
|
||||||
LOGGER.fine(msg);
|
throw new IOException("Could not connect to Nexus");
|
||||||
throw new IOException(msg);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -153,18 +159,20 @@ public class NexusSearch {
|
|||||||
* @return whether the repository is listening and returns the /status URL correctly
|
* @return whether the repository is listening and returns the /status URL correctly
|
||||||
*/
|
*/
|
||||||
public boolean preflightRequest() {
|
public boolean preflightRequest() {
|
||||||
|
HttpURLConnection conn;
|
||||||
try {
|
try {
|
||||||
final HttpURLConnection conn = URLConnectionFactory.createHttpURLConnection(new URL(rootURL, "status"), useProxy);
|
final URL url = new URL(rootURL, "status");
|
||||||
|
conn = URLConnectionFactory.createHttpURLConnection(url, useProxy);
|
||||||
conn.addRequestProperty("Accept", "application/xml");
|
conn.addRequestProperty("Accept", "application/xml");
|
||||||
conn.connect();
|
conn.connect();
|
||||||
if (conn.getResponseCode() != 200) {
|
if (conn.getResponseCode() != 200) {
|
||||||
LOGGER.log(Level.WARNING, "Expected 200 result from Nexus, got {0}", conn.getResponseCode());
|
LOGGER.warn("Expected 200 result from Nexus, got {}", conn.getResponseCode());
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
final DocumentBuilder builder = DocumentBuilderFactory.newInstance().newDocumentBuilder();
|
final DocumentBuilder builder = DocumentBuilderFactory.newInstance().newDocumentBuilder();
|
||||||
final Document doc = builder.parse(conn.getInputStream());
|
final Document doc = builder.parse(conn.getInputStream());
|
||||||
if (!"status".equals(doc.getDocumentElement().getNodeName())) {
|
if (!"status".equals(doc.getDocumentElement().getNodeName())) {
|
||||||
LOGGER.log(Level.WARNING, "Expected root node name of status, got {0}", doc.getDocumentElement().getNodeName());
|
LOGGER.warn("Expected root node name of status, got {}", doc.getDocumentElement().getNodeName());
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
} catch (Throwable e) {
|
} catch (Throwable e) {
|
||||||
|
|||||||
@@ -1,14 +1,6 @@
|
|||||||
/**
|
/**
|
||||||
* <html>
|
* Contains classes related to searching a Nexus repository.<br/><br/>
|
||||||
* <head>
|
*
|
||||||
* <title>org.owasp.dependencycheck.data.nexus</title>
|
* These are used to abstract Nexus searching away from OWASP Dependency Check so they can be reused elsewhere.
|
||||||
* </head>
|
|
||||||
* <body>
|
|
||||||
* <p>
|
|
||||||
* Contains classes related to searching a Nexus repository.</p>
|
|
||||||
* <p>
|
|
||||||
* These are used to abstract Nexus searching away from OWASP Dependency Check so they can be reused elsewhere.</p>
|
|
||||||
* </body>
|
|
||||||
* </html>
|
|
||||||
*/
|
*/
|
||||||
package org.owasp.dependencycheck.data.nexus;
|
package org.owasp.dependencycheck.data.nexus;
|
||||||
|
|||||||
@@ -1,15 +1,5 @@
|
|||||||
/**
|
/**
|
||||||
* <html>
|
* Contains classes related to parsing Nuget related files<br/><br/>
|
||||||
* <head>
|
* These are used to abstract away Nuget-related handling from Dependency Check so they can be used elsewhere.
|
||||||
* <title>org.owasp.dependencycheck.data.nuget</title>
|
|
||||||
* </head>
|
|
||||||
* <body>
|
|
||||||
* <p>
|
|
||||||
* Contains classes related to parsing Nuget related files</p>
|
|
||||||
* <p>
|
|
||||||
* These are used to abstract away Nuget-related handling from Dependency Check
|
|
||||||
* so they can be used elsewhere.</p>
|
|
||||||
* </body>
|
|
||||||
* </html>
|
|
||||||
*/
|
*/
|
||||||
package org.owasp.dependencycheck.data.nuget;
|
package org.owasp.dependencycheck.data.nuget;
|
||||||
|
|||||||
@@ -29,31 +29,35 @@ import java.sql.DriverManager;
|
|||||||
import java.sql.ResultSet;
|
import java.sql.ResultSet;
|
||||||
import java.sql.SQLException;
|
import java.sql.SQLException;
|
||||||
import java.sql.Statement;
|
import java.sql.Statement;
|
||||||
import java.util.logging.Level;
|
|
||||||
import java.util.logging.Logger;
|
|
||||||
import org.owasp.dependencycheck.utils.DBUtils;
|
import org.owasp.dependencycheck.utils.DBUtils;
|
||||||
import org.owasp.dependencycheck.utils.Settings;
|
import org.owasp.dependencycheck.utils.Settings;
|
||||||
|
import org.slf4j.Logger;
|
||||||
|
import org.slf4j.LoggerFactory;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Loads the configured database driver and returns the database connection. If the embedded H2 database is used
|
* Loads the configured database driver and returns the database connection. If the embedded H2 database is used obtaining a
|
||||||
* obtaining a connection will ensure the database file exists and that the appropriate table structure has been
|
* connection will ensure the database file exists and that the appropriate table structure has been created.
|
||||||
* created.
|
|
||||||
*
|
*
|
||||||
* @author Jeremy Long <jeremy.long@owasp.org>
|
* @author Jeremy Long
|
||||||
*/
|
*/
|
||||||
public final class ConnectionFactory {
|
public final class ConnectionFactory {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The Logger.
|
* The Logger.
|
||||||
*/
|
*/
|
||||||
private static final Logger LOGGER = Logger.getLogger(ConnectionFactory.class.getName());
|
private static final Logger LOGGER = LoggerFactory.getLogger(ConnectionFactory.class);
|
||||||
/**
|
/**
|
||||||
* The version of the current DB Schema.
|
* 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.
|
* Resource location for SQL file used to create the database schema.
|
||||||
*/
|
*/
|
||||||
public static final String DB_STRUCTURE_RESOURCE = "data/initialize.sql";
|
public static final String DB_STRUCTURE_RESOURCE = "data/initialize.sql";
|
||||||
|
/**
|
||||||
|
* Resource location for SQL file used to create the database schema.
|
||||||
|
*/
|
||||||
|
public static final String DB_STRUCTURE_UPDATE_RESOURCE = "data/upgrade_%s.sql";
|
||||||
/**
|
/**
|
||||||
* The database driver used to connect to the database.
|
* The database driver used to connect to the database.
|
||||||
*/
|
*/
|
||||||
@@ -78,8 +82,8 @@ public final class ConnectionFactory {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Initializes the connection factory. Ensuring that the appropriate drivers are loaded and that a connection can be
|
* Initializes the connection factory. Ensuring that the appropriate drivers are loaded and that a connection can be made
|
||||||
* made successfully.
|
* successfully.
|
||||||
*
|
*
|
||||||
* @throws DatabaseException thrown if we are unable to connect to the database
|
* @throws DatabaseException thrown if we are unable to connect to the database
|
||||||
*/
|
*/
|
||||||
@@ -93,17 +97,17 @@ public final class ConnectionFactory {
|
|||||||
//load the driver if necessary
|
//load the driver if necessary
|
||||||
final String driverName = Settings.getString(Settings.KEYS.DB_DRIVER_NAME, "");
|
final String driverName = Settings.getString(Settings.KEYS.DB_DRIVER_NAME, "");
|
||||||
if (!driverName.isEmpty()) { //likely need to load the correct driver
|
if (!driverName.isEmpty()) { //likely need to load the correct driver
|
||||||
LOGGER.log(Level.FINE, "Loading driver: {0}", driverName);
|
LOGGER.debug("Loading driver: {}", driverName);
|
||||||
final String driverPath = Settings.getString(Settings.KEYS.DB_DRIVER_PATH, "");
|
final String driverPath = Settings.getString(Settings.KEYS.DB_DRIVER_PATH, "");
|
||||||
try {
|
try {
|
||||||
if (!driverPath.isEmpty()) {
|
if (!driverPath.isEmpty()) {
|
||||||
LOGGER.log(Level.FINE, "Loading driver from: {0}", driverPath);
|
LOGGER.debug("Loading driver from: {}", driverPath);
|
||||||
driver = DriverLoader.load(driverName, driverPath);
|
driver = DriverLoader.load(driverName, driverPath);
|
||||||
} else {
|
} else {
|
||||||
driver = DriverLoader.load(driverName);
|
driver = DriverLoader.load(driverName);
|
||||||
}
|
}
|
||||||
} catch (DriverLoadException ex) {
|
} catch (DriverLoadException ex) {
|
||||||
LOGGER.log(Level.FINE, "Unable to load database driver", ex);
|
LOGGER.debug("Unable to load database driver", ex);
|
||||||
throw new DatabaseException("Unable to load database driver");
|
throw new DatabaseException("Unable to load database driver");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -111,25 +115,27 @@ public final class ConnectionFactory {
|
|||||||
//yes, yes - hard-coded password - only if there isn't one in the properties file.
|
//yes, yes - hard-coded password - only if there isn't one in the properties file.
|
||||||
password = Settings.getString(Settings.KEYS.DB_PASSWORD, "DC-Pass1337!");
|
password = Settings.getString(Settings.KEYS.DB_PASSWORD, "DC-Pass1337!");
|
||||||
try {
|
try {
|
||||||
connectionString = getConnectionString();
|
connectionString = Settings.getConnectionString(
|
||||||
|
Settings.KEYS.DB_CONNECTION_STRING,
|
||||||
|
Settings.KEYS.DB_FILE_NAME);
|
||||||
} catch (IOException ex) {
|
} catch (IOException ex) {
|
||||||
LOGGER.log(Level.FINE,
|
LOGGER.debug(
|
||||||
"Unable to retrieve the database connection string", ex);
|
"Unable to retrieve the database connection string", ex);
|
||||||
throw new DatabaseException("Unable to retrieve the database connection string");
|
throw new DatabaseException("Unable to retrieve the database connection string");
|
||||||
}
|
}
|
||||||
boolean shouldCreateSchema = false;
|
boolean shouldCreateSchema = false;
|
||||||
try {
|
try {
|
||||||
if (connectionString.startsWith("jdbc:h2:file:")) { //H2
|
if (connectionString.startsWith("jdbc:h2:file:")) { //H2
|
||||||
shouldCreateSchema = !dbSchemaExists();
|
shouldCreateSchema = !h2DataFileExists();
|
||||||
LOGGER.log(Level.FINE, "Need to create DB Structure: {0}", shouldCreateSchema);
|
LOGGER.debug("Need to create DB Structure: {}", shouldCreateSchema);
|
||||||
}
|
}
|
||||||
} catch (IOException ioex) {
|
} catch (IOException ioex) {
|
||||||
LOGGER.log(Level.FINE, "Unable to verify database exists", ioex);
|
LOGGER.debug("Unable to verify database exists", ioex);
|
||||||
throw new DatabaseException("Unable to verify database exists");
|
throw new DatabaseException("Unable to verify database exists");
|
||||||
}
|
}
|
||||||
LOGGER.log(Level.FINE, "Loading database connection");
|
LOGGER.debug("Loading database connection");
|
||||||
LOGGER.log(Level.FINE, "Connection String: {0}", connectionString);
|
LOGGER.debug("Connection String: {}", connectionString);
|
||||||
LOGGER.log(Level.FINE, "Database User: {0}", userName);
|
LOGGER.debug("Database User: {}", userName);
|
||||||
|
|
||||||
try {
|
try {
|
||||||
conn = DriverManager.getConnection(connectionString, userName, password);
|
conn = DriverManager.getConnection(connectionString, userName, password);
|
||||||
@@ -139,14 +145,14 @@ public final class ConnectionFactory {
|
|||||||
try {
|
try {
|
||||||
conn = DriverManager.getConnection(connectionString, userName, password);
|
conn = DriverManager.getConnection(connectionString, userName, password);
|
||||||
Settings.setString(Settings.KEYS.DB_CONNECTION_STRING, connectionString);
|
Settings.setString(Settings.KEYS.DB_CONNECTION_STRING, connectionString);
|
||||||
LOGGER.log(Level.FINE,
|
LOGGER.debug(
|
||||||
"Unable to start the database in server mode; reverting to single user mode");
|
"Unable to start the database in server mode; reverting to single user mode");
|
||||||
} catch (SQLException sqlex) {
|
} catch (SQLException sqlex) {
|
||||||
LOGGER.log(Level.FINE, "Unable to connect to the database", ex);
|
LOGGER.debug("Unable to connect to the database", ex);
|
||||||
throw new DatabaseException("Unable to connect to the database");
|
throw new DatabaseException("Unable to connect to the database");
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
LOGGER.log(Level.FINE, "Unable to connect to the database", ex);
|
LOGGER.debug("Unable to connect to the database", ex);
|
||||||
throw new DatabaseException("Unable to connect to the database");
|
throw new DatabaseException("Unable to connect to the database");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -155,23 +161,22 @@ public final class ConnectionFactory {
|
|||||||
try {
|
try {
|
||||||
createTables(conn);
|
createTables(conn);
|
||||||
} catch (DatabaseException dex) {
|
} catch (DatabaseException dex) {
|
||||||
LOGGER.log(Level.FINE, null, dex);
|
LOGGER.debug("", dex);
|
||||||
throw new DatabaseException("Unable to create the database structure");
|
throw new DatabaseException("Unable to create the database structure");
|
||||||
}
|
}
|
||||||
} else {
|
}
|
||||||
try {
|
try {
|
||||||
ensureSchemaVersion(conn);
|
ensureSchemaVersion(conn);
|
||||||
} catch (DatabaseException dex) {
|
} catch (DatabaseException dex) {
|
||||||
LOGGER.log(Level.FINE, null, dex);
|
LOGGER.debug("", dex);
|
||||||
throw new DatabaseException("Database schema does not match this version of dependency-check");
|
throw new DatabaseException("Database schema does not match this version of dependency-check", dex);
|
||||||
}
|
|
||||||
}
|
}
|
||||||
} finally {
|
} finally {
|
||||||
if (conn != null) {
|
if (conn != null) {
|
||||||
try {
|
try {
|
||||||
conn.close();
|
conn.close();
|
||||||
} catch (SQLException ex) {
|
} catch (SQLException ex) {
|
||||||
LOGGER.log(Level.FINE, "An error occurred closing the connection", ex);
|
LOGGER.debug("An error occurred closing the connection", ex);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -179,17 +184,17 @@ public final class ConnectionFactory {
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Cleans up resources and unloads any registered database drivers. This needs to be called to ensure the driver is
|
* Cleans up resources and unloads any registered database drivers. This needs to be called to ensure the driver is
|
||||||
* unregistered prior to the finalize method being called as during shutdown the class loader used to load the
|
* unregistered prior to the finalize method being called as during shutdown the class loader used to load the driver may be
|
||||||
* driver may be unloaded prior to the driver being de-registered.
|
* unloaded prior to the driver being de-registered.
|
||||||
*/
|
*/
|
||||||
public static synchronized void cleanup() {
|
public static synchronized void cleanup() {
|
||||||
if (driver != null) {
|
if (driver != null) {
|
||||||
try {
|
try {
|
||||||
DriverManager.deregisterDriver(driver);
|
DriverManager.deregisterDriver(driver);
|
||||||
} catch (SQLException ex) {
|
} catch (SQLException ex) {
|
||||||
LOGGER.log(Level.FINE, "An error occurred unloading the database driver", ex);
|
LOGGER.debug("An error occurred unloading the database driver", ex);
|
||||||
} catch (Throwable unexpected) {
|
} catch (Throwable unexpected) {
|
||||||
LOGGER.log(Level.FINE,
|
LOGGER.debug(
|
||||||
"An unexpected throwable occurred unloading the database driver", unexpected);
|
"An unexpected throwable occurred unloading the database driver", unexpected);
|
||||||
}
|
}
|
||||||
driver = null;
|
driver = null;
|
||||||
@@ -211,57 +216,22 @@ public final class ConnectionFactory {
|
|||||||
try {
|
try {
|
||||||
conn = DriverManager.getConnection(connectionString, userName, password);
|
conn = DriverManager.getConnection(connectionString, userName, password);
|
||||||
} catch (SQLException ex) {
|
} catch (SQLException ex) {
|
||||||
LOGGER.log(Level.FINE, null, ex);
|
LOGGER.debug("", ex);
|
||||||
throw new DatabaseException("Unable to connect to the database");
|
throw new DatabaseException("Unable to connect to the database");
|
||||||
}
|
}
|
||||||
return conn;
|
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.
|
* 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
|
* @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
|
* @throws IOException thrown if the data directory does not exist and cannot be created
|
||||||
*/
|
*/
|
||||||
private static boolean dbSchemaExists() throws IOException {
|
private static boolean h2DataFileExists() throws IOException {
|
||||||
final File dir = getDataDirectory();
|
final File dir = Settings.getDataDirectory();
|
||||||
final String name = String.format("cve.%s.h2.db", DB_SCHEMA_VERSION);
|
final String fileName = Settings.getString(Settings.KEYS.DB_FILE_NAME);
|
||||||
final File file = new File(dir, name);
|
final File file = new File(dir, fileName);
|
||||||
return file.exists();
|
return file.exists();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -272,7 +242,7 @@ public final class ConnectionFactory {
|
|||||||
* @throws DatabaseException thrown if there is a Database Exception
|
* @throws DatabaseException thrown if there is a Database Exception
|
||||||
*/
|
*/
|
||||||
private static void createTables(Connection conn) throws DatabaseException {
|
private static void createTables(Connection conn) throws DatabaseException {
|
||||||
LOGGER.log(Level.FINE, "Creating database structure");
|
LOGGER.debug("Creating database structure");
|
||||||
InputStream is;
|
InputStream is;
|
||||||
InputStreamReader reader;
|
InputStreamReader reader;
|
||||||
BufferedReader in = null;
|
BufferedReader in = null;
|
||||||
@@ -290,7 +260,7 @@ public final class ConnectionFactory {
|
|||||||
statement = conn.createStatement();
|
statement = conn.createStatement();
|
||||||
statement.execute(sb.toString());
|
statement.execute(sb.toString());
|
||||||
} catch (SQLException ex) {
|
} catch (SQLException ex) {
|
||||||
LOGGER.log(Level.FINE, null, ex);
|
LOGGER.debug("", ex);
|
||||||
throw new DatabaseException("Unable to create database statement", ex);
|
throw new DatabaseException("Unable to create database statement", ex);
|
||||||
} finally {
|
} finally {
|
||||||
DBUtils.closeStatement(statement);
|
DBUtils.closeStatement(statement);
|
||||||
@@ -302,7 +272,59 @@ public final class ConnectionFactory {
|
|||||||
try {
|
try {
|
||||||
in.close();
|
in.close();
|
||||||
} catch (IOException ex) {
|
} catch (IOException ex) {
|
||||||
LOGGER.log(Level.FINEST, null, ex);
|
LOGGER.trace("", ex);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Updates the database schema by loading the upgrade script for the version specified. The intended use is that if the
|
||||||
|
* current schema version is 2.9 then we would call updateSchema(conn, "2.9"). This would load the upgrade_2.9.sql file and
|
||||||
|
* execute it against the database. The upgrade script must update the 'version' in the properties table.
|
||||||
|
*
|
||||||
|
* @param conn the database connection object
|
||||||
|
* @param schema the current schema version that is being upgraded
|
||||||
|
* @throws DatabaseException thrown if there is an exception upgrading the database schema
|
||||||
|
*/
|
||||||
|
private static void updateSchema(Connection conn, String schema) throws DatabaseException {
|
||||||
|
LOGGER.debug("Updating database structure");
|
||||||
|
InputStream is;
|
||||||
|
InputStreamReader reader;
|
||||||
|
BufferedReader in = null;
|
||||||
|
String updateFile = null;
|
||||||
|
try {
|
||||||
|
updateFile = String.format(DB_STRUCTURE_UPDATE_RESOURCE, schema);
|
||||||
|
is = ConnectionFactory.class.getClassLoader().getResourceAsStream(updateFile);
|
||||||
|
if (is == null) {
|
||||||
|
throw new DatabaseException(String.format("Unable to load update file '%s'", updateFile));
|
||||||
|
}
|
||||||
|
reader = new InputStreamReader(is, "UTF-8");
|
||||||
|
in = new BufferedReader(reader);
|
||||||
|
final StringBuilder sb = new StringBuilder(2110);
|
||||||
|
String tmp;
|
||||||
|
while ((tmp = in.readLine()) != null) {
|
||||||
|
sb.append(tmp);
|
||||||
|
}
|
||||||
|
Statement statement = null;
|
||||||
|
try {
|
||||||
|
statement = conn.createStatement();
|
||||||
|
statement.execute(sb.toString());
|
||||||
|
} catch (SQLException ex) {
|
||||||
|
LOGGER.debug("", ex);
|
||||||
|
throw new DatabaseException("Unable to update database schema", ex);
|
||||||
|
} finally {
|
||||||
|
DBUtils.closeStatement(statement);
|
||||||
|
}
|
||||||
|
} catch (IOException ex) {
|
||||||
|
final String msg = String.format("Upgrade SQL file does not exist: %s", updateFile);
|
||||||
|
throw new DatabaseException(msg, ex);
|
||||||
|
} finally {
|
||||||
|
if (in != null) {
|
||||||
|
try {
|
||||||
|
in.close();
|
||||||
|
} catch (IOException ex) {
|
||||||
|
LOGGER.trace("", ex);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -318,18 +340,20 @@ public final class ConnectionFactory {
|
|||||||
ResultSet rs = null;
|
ResultSet rs = null;
|
||||||
CallableStatement cs = null;
|
CallableStatement cs = null;
|
||||||
try {
|
try {
|
||||||
|
//TODO convert this to use DatabaseProperties
|
||||||
cs = conn.prepareCall("SELECT value FROM properties WHERE id = 'version'");
|
cs = conn.prepareCall("SELECT value FROM properties WHERE id = 'version'");
|
||||||
rs = cs.executeQuery();
|
rs = cs.executeQuery();
|
||||||
if (rs.next()) {
|
if (rs.next()) {
|
||||||
final boolean isWrongSchema = !DB_SCHEMA_VERSION.equals(rs.getString(1));
|
if (!DB_SCHEMA_VERSION.equals(rs.getString(1))) {
|
||||||
if (isWrongSchema) {
|
LOGGER.debug("Current Schema: " + DB_SCHEMA_VERSION);
|
||||||
throw new DatabaseException("Incorrect database schema; unable to continue");
|
LOGGER.debug("DB Schema: " + rs.getString(1));
|
||||||
|
updateSchema(conn, rs.getString(1));
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
throw new DatabaseException("Database schema is missing");
|
throw new DatabaseException("Database schema is missing");
|
||||||
}
|
}
|
||||||
} catch (SQLException ex) {
|
} catch (SQLException ex) {
|
||||||
LOGGER.log(Level.FINE, null, ex);
|
LOGGER.debug("", ex);
|
||||||
throw new DatabaseException("Unable to check the database schema version");
|
throw new DatabaseException("Unable to check the database schema version");
|
||||||
} finally {
|
} finally {
|
||||||
DBUtils.closeResultSet(rs);
|
DBUtils.closeResultSet(rs);
|
||||||
|
|||||||
@@ -21,7 +21,7 @@ package org.owasp.dependencycheck.data.nvdcve;
|
|||||||
* An exception used to indicate the db4o database is corrupt. This could be due to invalid data or a complete failure
|
* An exception used to indicate the db4o database is corrupt. This could be due to invalid data or a complete failure
|
||||||
* of the db.
|
* of the db.
|
||||||
*
|
*
|
||||||
* @author Jeremy Long <jeremy.long@owasp.org>
|
* @author Jeremy Long
|
||||||
*/
|
*/
|
||||||
class CorruptDatabaseException extends DatabaseException {
|
class CorruptDatabaseException extends DatabaseException {
|
||||||
|
|
||||||
|
|||||||
@@ -17,20 +17,23 @@
|
|||||||
*/
|
*/
|
||||||
package org.owasp.dependencycheck.data.nvdcve;
|
package org.owasp.dependencycheck.data.nvdcve;
|
||||||
|
|
||||||
|
import java.io.IOException;
|
||||||
import java.io.UnsupportedEncodingException;
|
import java.io.UnsupportedEncodingException;
|
||||||
|
import java.sql.CallableStatement;
|
||||||
import java.sql.Connection;
|
import java.sql.Connection;
|
||||||
import java.sql.PreparedStatement;
|
import java.sql.PreparedStatement;
|
||||||
import java.sql.ResultSet;
|
import java.sql.ResultSet;
|
||||||
import java.sql.SQLException;
|
import java.sql.SQLException;
|
||||||
import java.sql.Statement;
|
import java.sql.Statement;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
|
import java.util.HashMap;
|
||||||
import java.util.HashSet;
|
import java.util.HashSet;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
import java.util.Map;
|
||||||
import java.util.Map.Entry;
|
import java.util.Map.Entry;
|
||||||
import java.util.Properties;
|
import java.util.Properties;
|
||||||
|
import java.util.ResourceBundle;
|
||||||
import java.util.Set;
|
import java.util.Set;
|
||||||
import java.util.logging.Level;
|
|
||||||
import java.util.logging.Logger;
|
|
||||||
import org.owasp.dependencycheck.data.cwe.CweDB;
|
import org.owasp.dependencycheck.data.cwe.CweDB;
|
||||||
import org.owasp.dependencycheck.dependency.Reference;
|
import org.owasp.dependencycheck.dependency.Reference;
|
||||||
import org.owasp.dependencycheck.dependency.Vulnerability;
|
import org.owasp.dependencycheck.dependency.Vulnerability;
|
||||||
@@ -39,31 +42,39 @@ import org.owasp.dependencycheck.utils.DBUtils;
|
|||||||
import org.owasp.dependencycheck.utils.DependencyVersion;
|
import org.owasp.dependencycheck.utils.DependencyVersion;
|
||||||
import org.owasp.dependencycheck.utils.DependencyVersionUtil;
|
import org.owasp.dependencycheck.utils.DependencyVersionUtil;
|
||||||
import org.owasp.dependencycheck.utils.Pair;
|
import org.owasp.dependencycheck.utils.Pair;
|
||||||
|
import org.owasp.dependencycheck.utils.Settings;
|
||||||
|
import org.slf4j.Logger;
|
||||||
|
import org.slf4j.LoggerFactory;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The database holding information about the NVD CVE data.
|
* The database holding information about the NVD CVE data.
|
||||||
*
|
*
|
||||||
* @author Jeremy Long <jeremy.long@owasp.org>
|
* @author Jeremy Long
|
||||||
*/
|
*/
|
||||||
public class CveDB {
|
public class CveDB {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The logger.
|
* The logger.
|
||||||
*/
|
*/
|
||||||
private static final Logger LOGGER = Logger.getLogger(CveDB.class.getName());
|
private static final Logger LOGGER = LoggerFactory.getLogger(CveDB.class);
|
||||||
/**
|
/**
|
||||||
* Database connection
|
* Database connection
|
||||||
*/
|
*/
|
||||||
private Connection conn;
|
private Connection conn;
|
||||||
|
/**
|
||||||
|
* The bundle of statements used when accessing the database.
|
||||||
|
*/
|
||||||
|
private ResourceBundle statementBundle = null;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Creates a new CveDB object and opens the database connection. Note, the connection must be closed by the caller
|
* Creates a new CveDB object and opens the database connection. Note, the connection must be closed by the caller by calling
|
||||||
* by calling the close method.
|
* the close method.
|
||||||
*
|
*
|
||||||
* @throws DatabaseException thrown if there is an exception opening the database.
|
* @throws DatabaseException thrown if there is an exception opening the database.
|
||||||
*/
|
*/
|
||||||
public CveDB() throws DatabaseException {
|
public CveDB() throws DatabaseException {
|
||||||
super();
|
super();
|
||||||
|
statementBundle = ResourceBundle.getBundle("data/dbStatements");
|
||||||
try {
|
try {
|
||||||
open();
|
open();
|
||||||
databaseProperties = new DatabaseProperties(this);
|
databaseProperties = new DatabaseProperties(this);
|
||||||
@@ -87,7 +98,9 @@ public class CveDB {
|
|||||||
* @throws DatabaseException thrown if there is an error opening the database connection
|
* @throws DatabaseException thrown if there is an error opening the database connection
|
||||||
*/
|
*/
|
||||||
public final void open() throws DatabaseException {
|
public final void open() throws DatabaseException {
|
||||||
conn = ConnectionFactory.getConnection();
|
if (!isOpen()) {
|
||||||
|
conn = ConnectionFactory.getConnection();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -98,13 +111,11 @@ public class CveDB {
|
|||||||
try {
|
try {
|
||||||
conn.close();
|
conn.close();
|
||||||
} catch (SQLException ex) {
|
} catch (SQLException ex) {
|
||||||
final String msg = "There was an error attempting to close the CveDB, see the log for more details.";
|
LOGGER.error("There was an error attempting to close the CveDB, see the log for more details.");
|
||||||
LOGGER.log(Level.SEVERE, msg);
|
LOGGER.debug("", ex);
|
||||||
LOGGER.log(Level.FINE, null, ex);
|
|
||||||
} catch (Throwable ex) {
|
} catch (Throwable ex) {
|
||||||
final String msg = "There was an exception attempting to close the CveDB, see the log for more details.";
|
LOGGER.error("There was an exception attempting to close the CveDB, see the log for more details.");
|
||||||
LOGGER.log(Level.SEVERE, msg);
|
LOGGER.debug("", ex);
|
||||||
LOGGER.log(Level.FINE, null, ex);
|
|
||||||
}
|
}
|
||||||
conn = null;
|
conn = null;
|
||||||
}
|
}
|
||||||
@@ -139,7 +150,7 @@ public class CveDB {
|
|||||||
@Override
|
@Override
|
||||||
@SuppressWarnings("FinalizeDeclaration")
|
@SuppressWarnings("FinalizeDeclaration")
|
||||||
protected void finalize() throws Throwable {
|
protected void finalize() throws Throwable {
|
||||||
LOGGER.log(Level.FINE, "Entering finalize");
|
LOGGER.debug("Entering finalize");
|
||||||
close();
|
close();
|
||||||
super.finalize();
|
super.finalize();
|
||||||
}
|
}
|
||||||
@@ -156,118 +167,10 @@ public class CveDB {
|
|||||||
public DatabaseProperties getDatabaseProperties() {
|
public DatabaseProperties getDatabaseProperties() {
|
||||||
return databaseProperties;
|
return databaseProperties;
|
||||||
}
|
}
|
||||||
//<editor-fold defaultstate="collapsed" desc="Constants to create, maintain, and retrieve data from the CVE Database">
|
|
||||||
/**
|
|
||||||
* SQL Statement to delete references by vulnerability ID.
|
|
||||||
*/
|
|
||||||
private static final String DELETE_REFERENCE = "DELETE FROM reference WHERE cveid = ?";
|
|
||||||
/**
|
|
||||||
* SQL Statement to delete software by vulnerability ID.
|
|
||||||
*/
|
|
||||||
private static final String DELETE_SOFTWARE = "DELETE FROM software WHERE cveid = ?";
|
|
||||||
/**
|
|
||||||
* SQL Statement to delete a vulnerability by CVE.
|
|
||||||
*/
|
|
||||||
private static final String DELETE_VULNERABILITY = "DELETE FROM vulnerability WHERE id = ?";
|
|
||||||
/**
|
|
||||||
* SQL Statement to cleanup orphan entries. Yes, the db schema could be a little tighter, but what we have works
|
|
||||||
* well to keep the data file size down a bit.
|
|
||||||
*/
|
|
||||||
private static final String CLEANUP_ORPHANS = "DELETE FROM CpeEntry WHERE id not in (SELECT CPEEntryId FROM Software); ";
|
|
||||||
/**
|
|
||||||
* SQL Statement to insert a new reference.
|
|
||||||
*/
|
|
||||||
private static final String INSERT_REFERENCE = "INSERT INTO reference (cveid, name, url, source) VALUES (?, ?, ?, ?)";
|
|
||||||
/**
|
|
||||||
* SQL Statement to insert a new software.
|
|
||||||
*/
|
|
||||||
private static final String INSERT_SOFTWARE = "INSERT INTO software (cveid, cpeEntryId, previousVersion) VALUES (?, ?, ?)";
|
|
||||||
/**
|
|
||||||
* SQL Statement to insert a new cpe.
|
|
||||||
*/
|
|
||||||
private static final String INSERT_CPE = "INSERT INTO cpeEntry (cpe, vendor, product) VALUES (?, ?, ?)";
|
|
||||||
/**
|
|
||||||
* SQL Statement to get a CPEProductID.
|
|
||||||
*/
|
|
||||||
private static final String SELECT_CPE_ID = "SELECT id FROM cpeEntry WHERE cpe = ?";
|
|
||||||
/**
|
|
||||||
* SQL Statement to insert a new vulnerability.
|
|
||||||
*/
|
|
||||||
private static final String INSERT_VULNERABILITY = "INSERT INTO vulnerability (cve, description, cwe, cvssScore, cvssAccessVector, "
|
|
||||||
+ "cvssAccessComplexity, cvssAuthentication, cvssConfidentialityImpact, cvssIntegrityImpact, cvssAvailabilityImpact) "
|
|
||||||
+ "VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?)";
|
|
||||||
/**
|
|
||||||
* SQL Statement to update a vulnerability.
|
|
||||||
*/
|
|
||||||
private static final String UPDATE_VULNERABILITY = "UPDATE vulnerability SET description=?, cwe=?, cvssScore=?, cvssAccessVector=?, "
|
|
||||||
+ "cvssAccessComplexity=?, cvssAuthentication=?, cvssConfidentialityImpact=?, cvssIntegrityImpact=?, cvssAvailabilityImpact=? "
|
|
||||||
+ "WHERE id=?";
|
|
||||||
/**
|
|
||||||
* SQL Statement to find CVE entries based on CPE data.
|
|
||||||
*/
|
|
||||||
private static final String SELECT_CVE_FROM_SOFTWARE = "SELECT cve, cpe, previousVersion "
|
|
||||||
+ "FROM software INNER JOIN vulnerability ON vulnerability.id = software.cveId "
|
|
||||||
+ "INNER JOIN cpeEntry ON cpeEntry.id = software.cpeEntryId "
|
|
||||||
+ "WHERE vendor = ? AND product = ?";
|
|
||||||
//unfortunately, the version info is too complicated to do in a select. Need to filter this afterwards
|
|
||||||
// + " AND (version = '-' OR previousVersion IS NOT NULL OR version=?)";
|
|
||||||
//
|
|
||||||
/**
|
|
||||||
* SQL Statement to find the CPE entry based on the vendor and product.
|
|
||||||
*/
|
|
||||||
private static final String SELECT_CPE_ENTRIES = "SELECT cpe FROM cpeEntry WHERE vendor = ? AND product = ?";
|
|
||||||
/**
|
|
||||||
* SQL Statement to select references by CVEID.
|
|
||||||
*/
|
|
||||||
private static final String SELECT_REFERENCE = "SELECT source, name, url FROM reference WHERE cveid = ?";
|
|
||||||
/**
|
|
||||||
* SQL Statement to select vendor and product for lucene index.
|
|
||||||
*/
|
|
||||||
private static final String SELECT_VENDOR_PRODUCT_LIST = "SELECT vendor, product FROM cpeEntry GROUP BY vendor, product";
|
|
||||||
/**
|
|
||||||
* SQL Statement to select software by CVEID.
|
|
||||||
*/
|
|
||||||
private static final String SELECT_SOFTWARE = "SELECT cpe, previousVersion "
|
|
||||||
+ "FROM software INNER JOIN cpeEntry ON software.cpeEntryId = cpeEntry.id WHERE cveid = ?";
|
|
||||||
// public static final String SELECT_SOFTWARE = "SELECT part, vendor, product, version, revision, previousVersion "
|
|
||||||
// + "FROM software INNER JOIN cpeProduct ON cpeProduct.id = software.cpeProductId LEFT JOIN cpeVersion ON "
|
|
||||||
// + "software.cpeVersionId = cpeVersion.id LEFT JOIN Version ON cpeVersion.versionId = version.id WHERE cveid = ?";
|
|
||||||
/**
|
|
||||||
* SQL Statement to select a vulnerability by CVEID.
|
|
||||||
*/
|
|
||||||
private static final String SELECT_VULNERABILITY = "SELECT id, description, cwe, cvssScore, cvssAccessVector, cvssAccessComplexity, "
|
|
||||||
+ "cvssAuthentication, cvssConfidentialityImpact, cvssIntegrityImpact, cvssAvailabilityImpact FROM vulnerability WHERE cve = ?";
|
|
||||||
/**
|
|
||||||
* SQL Statement to select a vulnerability's primary key.
|
|
||||||
*/
|
|
||||||
private static final String SELECT_VULNERABILITY_ID = "SELECT id FROM vulnerability WHERE cve = ?";
|
|
||||||
/**
|
|
||||||
* SQL Statement to retrieve the properties from the database.
|
|
||||||
*/
|
|
||||||
private static final String SELECT_PROPERTIES = "SELECT id, value FROM properties";
|
|
||||||
/**
|
|
||||||
* 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.
|
|
||||||
*/
|
|
||||||
private static final String INSERT_PROPERTY = "INSERT INTO properties (id, value) VALUES (?, ?)";
|
|
||||||
/**
|
|
||||||
* SQL Statement to update a property.
|
|
||||||
*/
|
|
||||||
private static final String UPDATE_PROPERTY = "UPDATE properties SET value = ? WHERE id = ?";
|
|
||||||
/**
|
|
||||||
* SQL Statement to delete a property.
|
|
||||||
*/
|
|
||||||
@SuppressWarnings("unused")
|
|
||||||
private static final String DELETE_PROPERTY = "DELETE FROM properties WHERE id = ?";
|
|
||||||
|
|
||||||
//</editor-fold>
|
|
||||||
/**
|
/**
|
||||||
* Searches the CPE entries in the database and retrieves all entries for a given vendor and product combination.
|
* Searches the CPE entries in the database and retrieves all entries for a given vendor and product combination. The returned
|
||||||
* The returned list will include all versions of the product that are registered in the NVD CVE data.
|
* list will include all versions of the product that are registered in the NVD CVE data.
|
||||||
*
|
*
|
||||||
* @param vendor the identified vendor name of the dependency being analyzed
|
* @param vendor the identified vendor name of the dependency being analyzed
|
||||||
* @param product the identified name of the product of the dependency being analyzed
|
* @param product the identified name of the product of the dependency being analyzed
|
||||||
@@ -278,7 +181,7 @@ public class CveDB {
|
|||||||
ResultSet rs = null;
|
ResultSet rs = null;
|
||||||
PreparedStatement ps = null;
|
PreparedStatement ps = null;
|
||||||
try {
|
try {
|
||||||
ps = getConnection().prepareStatement(SELECT_CPE_ENTRIES);
|
ps = getConnection().prepareStatement(statementBundle.getString("SELECT_CPE_ENTRIES"));
|
||||||
ps.setString(1, vendor);
|
ps.setString(1, vendor);
|
||||||
ps.setString(2, product);
|
ps.setString(2, product);
|
||||||
rs = ps.executeQuery();
|
rs = ps.executeQuery();
|
||||||
@@ -289,9 +192,8 @@ public class CveDB {
|
|||||||
cpe.add(vs);
|
cpe.add(vs);
|
||||||
}
|
}
|
||||||
} catch (SQLException ex) {
|
} catch (SQLException ex) {
|
||||||
final String msg = "An unexpected SQL Exception occurred; please see the verbose log for more details.";
|
LOGGER.error("An unexpected SQL Exception occurred; please see the verbose log for more details.");
|
||||||
LOGGER.log(Level.SEVERE, msg);
|
LOGGER.debug("", ex);
|
||||||
LOGGER.log(Level.FINE, null, ex);
|
|
||||||
} finally {
|
} finally {
|
||||||
DBUtils.closeResultSet(rs);
|
DBUtils.closeResultSet(rs);
|
||||||
DBUtils.closeStatement(ps);
|
DBUtils.closeStatement(ps);
|
||||||
@@ -306,14 +208,14 @@ public class CveDB {
|
|||||||
* @throws DatabaseException thrown when there is an error retrieving the data from the DB
|
* @throws DatabaseException thrown when there is an error retrieving the data from the DB
|
||||||
*/
|
*/
|
||||||
public Set<Pair<String, String>> getVendorProductList() throws DatabaseException {
|
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;
|
ResultSet rs = null;
|
||||||
PreparedStatement ps = null;
|
PreparedStatement ps = null;
|
||||||
try {
|
try {
|
||||||
ps = getConnection().prepareStatement(SELECT_VENDOR_PRODUCT_LIST);
|
ps = getConnection().prepareStatement(statementBundle.getString("SELECT_VENDOR_PRODUCT_LIST"));
|
||||||
rs = ps.executeQuery();
|
rs = ps.executeQuery();
|
||||||
while (rs.next()) {
|
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) {
|
} catch (SQLException ex) {
|
||||||
final String msg = "An unexpected SQL Exception occurred; please see the verbose log for more details.";
|
final String msg = "An unexpected SQL Exception occurred; please see the verbose log for more details.";
|
||||||
@@ -335,15 +237,14 @@ public class CveDB {
|
|||||||
PreparedStatement ps = null;
|
PreparedStatement ps = null;
|
||||||
ResultSet rs = null;
|
ResultSet rs = null;
|
||||||
try {
|
try {
|
||||||
ps = getConnection().prepareStatement(SELECT_PROPERTIES);
|
ps = getConnection().prepareStatement(statementBundle.getString("SELECT_PROPERTIES"));
|
||||||
rs = ps.executeQuery();
|
rs = ps.executeQuery();
|
||||||
while (rs.next()) {
|
while (rs.next()) {
|
||||||
prop.setProperty(rs.getString(1), rs.getString(2));
|
prop.setProperty(rs.getString(1), rs.getString(2));
|
||||||
}
|
}
|
||||||
} catch (SQLException ex) {
|
} catch (SQLException ex) {
|
||||||
final String msg = "An unexpected SQL Exception occurred; please see the verbose log for more details.";
|
LOGGER.error("An unexpected SQL Exception occurred; please see the verbose log for more details.");
|
||||||
LOGGER.log(Level.SEVERE, msg);
|
LOGGER.debug("", ex);
|
||||||
LOGGER.log(Level.FINE, null, ex);
|
|
||||||
} finally {
|
} finally {
|
||||||
DBUtils.closeStatement(ps);
|
DBUtils.closeStatement(ps);
|
||||||
DBUtils.closeResultSet(rs);
|
DBUtils.closeResultSet(rs);
|
||||||
@@ -361,11 +262,11 @@ public class CveDB {
|
|||||||
PreparedStatement insertProperty = null;
|
PreparedStatement insertProperty = null;
|
||||||
try {
|
try {
|
||||||
try {
|
try {
|
||||||
updateProperty = getConnection().prepareStatement(UPDATE_PROPERTY);
|
updateProperty = getConnection().prepareStatement(statementBundle.getString("UPDATE_PROPERTY"));
|
||||||
insertProperty = getConnection().prepareStatement(INSERT_PROPERTY);
|
insertProperty = getConnection().prepareStatement(statementBundle.getString("INSERT_PROPERTY"));
|
||||||
} catch (SQLException ex) {
|
} catch (SQLException ex) {
|
||||||
LOGGER.log(Level.WARNING, "Unable to save properties to the database");
|
LOGGER.warn("Unable to save properties to the database");
|
||||||
LOGGER.log(Level.FINE, "Unable to save properties to the database", ex);
|
LOGGER.debug("Unable to save properties to the database", ex);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
for (Entry<Object, Object> entry : props.entrySet()) {
|
for (Entry<Object, Object> entry : props.entrySet()) {
|
||||||
@@ -379,9 +280,8 @@ public class CveDB {
|
|||||||
insertProperty.setString(2, value);
|
insertProperty.setString(2, value);
|
||||||
}
|
}
|
||||||
} catch (SQLException ex) {
|
} catch (SQLException ex) {
|
||||||
final String msg = String.format("Unable to save property '%s' with a value of '%s' to the database", key, value);
|
LOGGER.warn("Unable to save property '{}' with a value of '{}' to the database", key, value);
|
||||||
LOGGER.log(Level.WARNING, msg);
|
LOGGER.debug("", ex);
|
||||||
LOGGER.log(Level.FINE, null, ex);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} finally {
|
} finally {
|
||||||
@@ -401,10 +301,10 @@ public class CveDB {
|
|||||||
PreparedStatement insertProperty = null;
|
PreparedStatement insertProperty = null;
|
||||||
try {
|
try {
|
||||||
try {
|
try {
|
||||||
updateProperty = getConnection().prepareStatement(UPDATE_PROPERTY);
|
updateProperty = getConnection().prepareStatement(statementBundle.getString("UPDATE_PROPERTY"));
|
||||||
} catch (SQLException ex) {
|
} catch (SQLException ex) {
|
||||||
LOGGER.log(Level.WARNING, "Unable to save properties to the database");
|
LOGGER.warn("Unable to save properties to the database");
|
||||||
LOGGER.log(Level.FINE, "Unable to save properties to the database", ex);
|
LOGGER.debug("Unable to save properties to the database", ex);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
try {
|
try {
|
||||||
@@ -412,10 +312,10 @@ public class CveDB {
|
|||||||
updateProperty.setString(2, key);
|
updateProperty.setString(2, key);
|
||||||
if (updateProperty.executeUpdate() == 0) {
|
if (updateProperty.executeUpdate() == 0) {
|
||||||
try {
|
try {
|
||||||
insertProperty = getConnection().prepareStatement(INSERT_PROPERTY);
|
insertProperty = getConnection().prepareStatement(statementBundle.getString("INSERT_PROPERTY"));
|
||||||
} catch (SQLException ex) {
|
} catch (SQLException ex) {
|
||||||
LOGGER.log(Level.WARNING, "Unable to save properties to the database");
|
LOGGER.warn("Unable to save properties to the database");
|
||||||
LOGGER.log(Level.FINE, "Unable to save properties to the database", ex);
|
LOGGER.debug("Unable to save properties to the database", ex);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
insertProperty.setString(1, key);
|
insertProperty.setString(1, key);
|
||||||
@@ -423,9 +323,8 @@ public class CveDB {
|
|||||||
insertProperty.execute();
|
insertProperty.execute();
|
||||||
}
|
}
|
||||||
} catch (SQLException ex) {
|
} catch (SQLException ex) {
|
||||||
final String msg = String.format("Unable to save property '%s' with a value of '%s' to the database", key, value);
|
LOGGER.warn("Unable to save property '{}' with a value of '{}' to the database", key, value);
|
||||||
LOGGER.log(Level.WARNING, msg);
|
LOGGER.debug("", ex);
|
||||||
LOGGER.log(Level.FINE, null, ex);
|
|
||||||
}
|
}
|
||||||
} finally {
|
} finally {
|
||||||
DBUtils.closeStatement(updateProperty);
|
DBUtils.closeStatement(updateProperty);
|
||||||
@@ -446,36 +345,47 @@ public class CveDB {
|
|||||||
try {
|
try {
|
||||||
cpe.parseName(cpeStr);
|
cpe.parseName(cpeStr);
|
||||||
} catch (UnsupportedEncodingException ex) {
|
} catch (UnsupportedEncodingException ex) {
|
||||||
LOGGER.log(Level.FINEST, null, ex);
|
LOGGER.trace("", ex);
|
||||||
}
|
}
|
||||||
final DependencyVersion detectedVersion = parseDependencyVersion(cpe);
|
final DependencyVersion detectedVersion = parseDependencyVersion(cpe);
|
||||||
final List<Vulnerability> vulnerabilities = new ArrayList<Vulnerability>();
|
final List<Vulnerability> vulnerabilities = new ArrayList<Vulnerability>();
|
||||||
|
|
||||||
PreparedStatement ps;
|
PreparedStatement ps;
|
||||||
final HashSet<String> cveEntries = new HashSet<String>();
|
|
||||||
try {
|
try {
|
||||||
ps = getConnection().prepareStatement(SELECT_CVE_FROM_SOFTWARE);
|
ps = getConnection().prepareStatement(statementBundle.getString("SELECT_CVE_FROM_SOFTWARE"));
|
||||||
ps.setString(1, cpe.getVendor());
|
ps.setString(1, cpe.getVendor());
|
||||||
ps.setString(2, cpe.getProduct());
|
ps.setString(2, cpe.getProduct());
|
||||||
rs = ps.executeQuery();
|
rs = ps.executeQuery();
|
||||||
|
String currentCVE = "";
|
||||||
|
|
||||||
|
final Map<String, Boolean> vulnSoftware = new HashMap<String, Boolean>();
|
||||||
while (rs.next()) {
|
while (rs.next()) {
|
||||||
final String cveId = rs.getString(1);
|
final String cveId = rs.getString(1);
|
||||||
|
if (!currentCVE.equals(cveId)) { //check for match and add
|
||||||
|
final Entry<String, Boolean> matchedCPE = getMatchingSoftware(vulnSoftware, cpe.getVendor(), cpe.getProduct(), detectedVersion);
|
||||||
|
if (matchedCPE != null) {
|
||||||
|
final Vulnerability v = getVulnerability(currentCVE);
|
||||||
|
v.setMatchedCPE(matchedCPE.getKey(), matchedCPE.getValue() ? "Y" : null);
|
||||||
|
vulnerabilities.add(v);
|
||||||
|
}
|
||||||
|
vulnSoftware.clear();
|
||||||
|
currentCVE = cveId;
|
||||||
|
}
|
||||||
|
|
||||||
final String cpeId = rs.getString(2);
|
final String cpeId = rs.getString(2);
|
||||||
final String previous = rs.getString(3);
|
final String previous = rs.getString(3);
|
||||||
if (!cveEntries.contains(cveId) && isAffected(cpe.getVendor(), cpe.getProduct(), detectedVersion, cpeId, previous)) {
|
final Boolean p = previous != null && !previous.isEmpty();
|
||||||
cveEntries.add(cveId);
|
vulnSoftware.put(cpeId, p);
|
||||||
final Vulnerability v = getVulnerability(cveId);
|
}
|
||||||
v.setMatchedCPE(cpeId, previous);
|
//remember to process the last set of CVE/CPE entries
|
||||||
vulnerabilities.add(v);
|
final Entry<String, Boolean> matchedCPE = getMatchingSoftware(vulnSoftware, cpe.getVendor(), cpe.getProduct(), detectedVersion);
|
||||||
}
|
if (matchedCPE != null) {
|
||||||
|
final Vulnerability v = getVulnerability(currentCVE);
|
||||||
|
v.setMatchedCPE(matchedCPE.getKey(), matchedCPE.getValue() ? "Y" : null);
|
||||||
|
vulnerabilities.add(v);
|
||||||
}
|
}
|
||||||
DBUtils.closeResultSet(rs);
|
DBUtils.closeResultSet(rs);
|
||||||
DBUtils.closeStatement(ps);
|
DBUtils.closeStatement(ps);
|
||||||
// for (String cve : cveEntries) {
|
|
||||||
// final Vulnerability v = getVulnerability(cve);
|
|
||||||
// vulnerabilities.add(v);
|
|
||||||
// }
|
|
||||||
|
|
||||||
} catch (SQLException ex) {
|
} catch (SQLException ex) {
|
||||||
throw new DatabaseException("Exception retrieving vulnerability for " + cpeStr, ex);
|
throw new DatabaseException("Exception retrieving vulnerability for " + cpeStr, ex);
|
||||||
} finally {
|
} finally {
|
||||||
@@ -500,7 +410,7 @@ public class CveDB {
|
|||||||
ResultSet rsS = null;
|
ResultSet rsS = null;
|
||||||
Vulnerability vuln = null;
|
Vulnerability vuln = null;
|
||||||
try {
|
try {
|
||||||
psV = getConnection().prepareStatement(SELECT_VULNERABILITY);
|
psV = getConnection().prepareStatement(statementBundle.getString("SELECT_VULNERABILITY"));
|
||||||
psV.setString(1, cve);
|
psV.setString(1, cve);
|
||||||
rsV = psV.executeQuery();
|
rsV = psV.executeQuery();
|
||||||
if (rsV.next()) {
|
if (rsV.next()) {
|
||||||
@@ -524,13 +434,13 @@ public class CveDB {
|
|||||||
vuln.setCvssIntegrityImpact(rsV.getString(9));
|
vuln.setCvssIntegrityImpact(rsV.getString(9));
|
||||||
vuln.setCvssAvailabilityImpact(rsV.getString(10));
|
vuln.setCvssAvailabilityImpact(rsV.getString(10));
|
||||||
|
|
||||||
psR = getConnection().prepareStatement(SELECT_REFERENCE);
|
psR = getConnection().prepareStatement(statementBundle.getString("SELECT_REFERENCES"));
|
||||||
psR.setInt(1, cveId);
|
psR.setInt(1, cveId);
|
||||||
rsR = psR.executeQuery();
|
rsR = psR.executeQuery();
|
||||||
while (rsR.next()) {
|
while (rsR.next()) {
|
||||||
vuln.addReference(rsR.getString(1), rsR.getString(2), rsR.getString(3));
|
vuln.addReference(rsR.getString(1), rsR.getString(2), rsR.getString(3));
|
||||||
}
|
}
|
||||||
psS = getConnection().prepareStatement(SELECT_SOFTWARE);
|
psS = getConnection().prepareStatement(statementBundle.getString("SELECT_SOFTWARE"));
|
||||||
psS.setInt(1, cveId);
|
psS.setInt(1, cveId);
|
||||||
rsS = psS.executeQuery();
|
rsS = psS.executeQuery();
|
||||||
while (rsS.next()) {
|
while (rsS.next()) {
|
||||||
@@ -575,16 +485,21 @@ public class CveDB {
|
|||||||
PreparedStatement insertSoftware = null;
|
PreparedStatement insertSoftware = null;
|
||||||
|
|
||||||
try {
|
try {
|
||||||
selectVulnerabilityId = getConnection().prepareStatement(SELECT_VULNERABILITY_ID);
|
selectVulnerabilityId = getConnection().prepareStatement(statementBundle.getString("SELECT_VULNERABILITY_ID"));
|
||||||
deleteVulnerability = getConnection().prepareStatement(DELETE_VULNERABILITY);
|
deleteVulnerability = getConnection().prepareStatement(statementBundle.getString("DELETE_VULNERABILITY"));
|
||||||
deleteReferences = getConnection().prepareStatement(DELETE_REFERENCE);
|
deleteReferences = getConnection().prepareStatement(statementBundle.getString("DELETE_REFERENCE"));
|
||||||
deleteSoftware = getConnection().prepareStatement(DELETE_SOFTWARE);
|
deleteSoftware = getConnection().prepareStatement(statementBundle.getString("DELETE_SOFTWARE"));
|
||||||
updateVulnerability = getConnection().prepareStatement(UPDATE_VULNERABILITY);
|
updateVulnerability = getConnection().prepareStatement(statementBundle.getString("UPDATE_VULNERABILITY"));
|
||||||
insertVulnerability = getConnection().prepareStatement(INSERT_VULNERABILITY, Statement.RETURN_GENERATED_KEYS);
|
String ids[] = {"id"};
|
||||||
insertReference = getConnection().prepareStatement(INSERT_REFERENCE);
|
insertVulnerability = getConnection().prepareStatement(statementBundle.getString("INSERT_VULNERABILITY"),
|
||||||
selectCpeId = getConnection().prepareStatement(SELECT_CPE_ID);
|
//Statement.RETURN_GENERATED_KEYS);
|
||||||
insertCpe = getConnection().prepareStatement(INSERT_CPE, Statement.RETURN_GENERATED_KEYS);
|
ids);
|
||||||
insertSoftware = getConnection().prepareStatement(INSERT_SOFTWARE);
|
insertReference = getConnection().prepareStatement(statementBundle.getString("INSERT_REFERENCE"));
|
||||||
|
selectCpeId = getConnection().prepareStatement(statementBundle.getString("SELECT_CPE_ID"));
|
||||||
|
insertCpe = getConnection().prepareStatement(statementBundle.getString("INSERT_CPE"),
|
||||||
|
//Statement.RETURN_GENERATED_KEYS);
|
||||||
|
ids);
|
||||||
|
insertSoftware = getConnection().prepareStatement(statementBundle.getString("INSERT_SOFTWARE"));
|
||||||
int vulnerabilityId = 0;
|
int vulnerabilityId = 0;
|
||||||
selectVulnerabilityId.setString(1, vuln.getName());
|
selectVulnerabilityId.setString(1, vuln.getName());
|
||||||
ResultSet rs = selectVulnerabilityId.executeQuery();
|
ResultSet rs = selectVulnerabilityId.executeQuery();
|
||||||
@@ -684,7 +599,7 @@ public class CveDB {
|
|||||||
|
|
||||||
} catch (SQLException ex) {
|
} catch (SQLException ex) {
|
||||||
final String msg = String.format("Error updating '%s'", vuln.getName());
|
final String msg = String.format("Error updating '%s'", vuln.getName());
|
||||||
LOGGER.log(Level.FINE, null, ex);
|
LOGGER.debug("", ex);
|
||||||
throw new DatabaseException(msg, ex);
|
throw new DatabaseException(msg, ex);
|
||||||
} finally {
|
} finally {
|
||||||
DBUtils.closeStatement(selectVulnerabilityId);
|
DBUtils.closeStatement(selectVulnerabilityId);
|
||||||
@@ -701,66 +616,135 @@ public class CveDB {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* It is possible that orphaned rows may be generated during database updates. This should be called after all
|
* Checks to see if data exists so that analysis can be performed.
|
||||||
* updates have been completed to ensure orphan entries are removed.
|
*
|
||||||
|
* @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);
|
||||||
|
}
|
||||||
|
LOGGER.error("Unable to access the local database.\n\nEnsure that '{}' is a writable directory. "
|
||||||
|
+ "If the problem persist try deleting the files in '{}' and running {} 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.debug("", ex);
|
||||||
|
} finally {
|
||||||
|
DBUtils.closeResultSet(rs);
|
||||||
|
DBUtils.closeStatement(cs);
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* It is possible that orphaned rows may be generated during database updates. This should be called after all updates have
|
||||||
|
* been completed to ensure orphan entries are removed.
|
||||||
*/
|
*/
|
||||||
public void cleanupDatabase() {
|
public void cleanupDatabase() {
|
||||||
PreparedStatement ps = null;
|
PreparedStatement ps = null;
|
||||||
try {
|
try {
|
||||||
ps = getConnection().prepareStatement(CLEANUP_ORPHANS);
|
ps = getConnection().prepareStatement(statementBundle.getString("CLEANUP_ORPHANS"));
|
||||||
if (ps != null) {
|
if (ps != null) {
|
||||||
ps.executeUpdate();
|
ps.executeUpdate();
|
||||||
}
|
}
|
||||||
} catch (SQLException ex) {
|
} catch (SQLException ex) {
|
||||||
final String msg = "An unexpected SQL Exception occurred; please see the verbose log for more details.";
|
LOGGER.error("An unexpected SQL Exception occurred; please see the verbose log for more details.");
|
||||||
LOGGER.log(Level.SEVERE, msg);
|
LOGGER.debug("", ex);
|
||||||
LOGGER.log(Level.FINE, null, ex);
|
|
||||||
} finally {
|
} finally {
|
||||||
DBUtils.closeStatement(ps);
|
DBUtils.closeStatement(ps);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Determines if the given identifiedVersion is affected by the given cpeId and previous version flag. A non-null,
|
* Determines if the given identifiedVersion is affected by the given cpeId and previous version flag. A non-null, non-empty
|
||||||
* non-empty string passed to the previous version argument indicates that all previous versions are affected.
|
* string passed to the previous version argument indicates that all previous versions are affected.
|
||||||
*
|
*
|
||||||
* @param vendor the vendor of the dependency being analyzed
|
* @param vendor the vendor of the dependency being analyzed
|
||||||
* @param product the product name of the dependency being analyzed
|
* @param product the product name of the dependency being analyzed
|
||||||
|
* @param vulnerableSoftware a map of the vulnerable software with a boolean indicating if all previous versions are affected
|
||||||
* @param identifiedVersion the identified version of the dependency being analyzed
|
* @param identifiedVersion the identified version of the dependency being analyzed
|
||||||
* @param cpeId the cpe identifier of software that has a known vulnerability
|
|
||||||
* @param previous a flag indicating if previous versions of the product are vulnerable
|
|
||||||
* @return true if the identified version is affected, otherwise false
|
* @return true if the identified version is affected, otherwise false
|
||||||
*/
|
*/
|
||||||
private boolean isAffected(String vendor, String product, DependencyVersion identifiedVersion, String cpeId, String previous) {
|
Entry<String, Boolean> getMatchingSoftware(Map<String, Boolean> vulnerableSoftware, String vendor, String product,
|
||||||
boolean affected = false;
|
DependencyVersion identifiedVersion) {
|
||||||
final boolean isStruts = "apache".equals(vendor) && "struts".equals(product);
|
|
||||||
final DependencyVersion v = parseDependencyVersion(cpeId);
|
final boolean isVersionTwoADifferentProduct = "apache".equals(vendor) && "struts".equals(product);
|
||||||
final boolean prevAffected = previous != null && !previous.isEmpty();
|
|
||||||
if (v == null || "-".equals(v.toString())) { //all versions
|
final Set<String> majorVersionsAffectingAllPrevious = new HashSet<String>();
|
||||||
affected = true;
|
final boolean matchesAnyPrevious = identifiedVersion == null || "-".equals(identifiedVersion.toString());
|
||||||
} else if (identifiedVersion == null || "-".equals(identifiedVersion.toString())) {
|
String majorVersionMatch = null;
|
||||||
if (prevAffected) {
|
for (Entry<String, Boolean> entry : vulnerableSoftware.entrySet()) {
|
||||||
affected = true;
|
final DependencyVersion v = parseDependencyVersion(entry.getKey());
|
||||||
|
if (v == null || "-".equals(v.toString())) { //all versions
|
||||||
|
return entry;
|
||||||
}
|
}
|
||||||
} else if (identifiedVersion.equals(v) || (prevAffected && identifiedVersion.compareTo(v) < 0)) {
|
if (entry.getValue()) {
|
||||||
if (isStruts) { //struts 2 vulns don't affect struts 1
|
if (matchesAnyPrevious) {
|
||||||
if (identifiedVersion.getVersionParts().get(0).equals(v.getVersionParts().get(0))) {
|
return entry;
|
||||||
affected = true;
|
|
||||||
}
|
}
|
||||||
} else {
|
if (identifiedVersion != null && identifiedVersion.getVersionParts().get(0).equals(v.getVersionParts().get(0))) {
|
||||||
affected = true;
|
majorVersionMatch = v.getVersionParts().get(0);
|
||||||
|
}
|
||||||
|
majorVersionsAffectingAllPrevious.add(v.getVersionParts().get(0));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
/*
|
if (matchesAnyPrevious) {
|
||||||
* TODO consider utilizing the matchThreeVersion method to get additional results. However, this
|
return null;
|
||||||
* might also introduce false positives.
|
}
|
||||||
*/
|
|
||||||
return affected;
|
final boolean canSkipVersions = majorVersionMatch != null && majorVersionsAffectingAllPrevious.size() > 1;
|
||||||
|
//yes, we are iterating over this twice. The first time we are skipping versions those that affect all versions
|
||||||
|
//then later we process those that affect all versions. This could be done with sorting...
|
||||||
|
for (Entry<String, Boolean> entry : vulnerableSoftware.entrySet()) {
|
||||||
|
if (!entry.getValue()) {
|
||||||
|
final DependencyVersion v = parseDependencyVersion(entry.getKey());
|
||||||
|
//this can't dereference a null 'majorVersionMatch' as canSkipVersions accounts for this.
|
||||||
|
if (canSkipVersions && !majorVersionMatch.equals(v.getVersionParts().get(0))) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
//this can't dereference a null 'identifiedVersion' because if it was null we would have exited
|
||||||
|
//in the above loop or just after loop (if matchesAnyPrevious return null).
|
||||||
|
if (identifiedVersion.equals(v)) {
|
||||||
|
return entry;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
for (Entry<String, Boolean> entry : vulnerableSoftware.entrySet()) {
|
||||||
|
if (entry.getValue()) {
|
||||||
|
final DependencyVersion v = parseDependencyVersion(entry.getKey());
|
||||||
|
//this can't dereference a null 'majorVersionMatch' as canSkipVersions accounts for this.
|
||||||
|
if (canSkipVersions && !majorVersionMatch.equals(v.getVersionParts().get(0))) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
//this can't dereference a null 'identifiedVersion' because if it was null we would have exited
|
||||||
|
//in the above loop or just after loop (if matchesAnyPrevious return null).
|
||||||
|
if (entry.getValue() && identifiedVersion.compareTo(v) <= 0) {
|
||||||
|
if (!(isVersionTwoADifferentProduct && !identifiedVersion.getVersionParts().get(0).equals(v.getVersionParts().get(0)))) {
|
||||||
|
return entry;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Parses the version (including revision) from a CPE identifier. If no version is identified then a '-' is
|
* Parses the version (including revision) from a CPE identifier. If no version is identified then a '-' is returned.
|
||||||
* returned.
|
|
||||||
*
|
*
|
||||||
* @param cpeStr a cpe identifier
|
* @param cpeStr a cpe identifier
|
||||||
* @return a dependency version
|
* @return a dependency version
|
||||||
@@ -771,7 +755,7 @@ public class CveDB {
|
|||||||
cpe.parseName(cpeStr);
|
cpe.parseName(cpeStr);
|
||||||
} catch (UnsupportedEncodingException ex) {
|
} catch (UnsupportedEncodingException ex) {
|
||||||
//never going to happen.
|
//never going to happen.
|
||||||
LOGGER.log(Level.FINEST, null, ex);
|
LOGGER.trace("", ex);
|
||||||
}
|
}
|
||||||
return parseDependencyVersion(cpe);
|
return parseDependencyVersion(cpe);
|
||||||
}
|
}
|
||||||
@@ -784,10 +768,10 @@ public class CveDB {
|
|||||||
*/
|
*/
|
||||||
private DependencyVersion parseDependencyVersion(VulnerableSoftware cpe) {
|
private DependencyVersion parseDependencyVersion(VulnerableSoftware cpe) {
|
||||||
DependencyVersion cpeVersion;
|
DependencyVersion cpeVersion;
|
||||||
if (cpe.getVersion() != null && cpe.getVersion().length() > 0) {
|
if (cpe.getVersion() != null && !cpe.getVersion().isEmpty()) {
|
||||||
String versionText;
|
String versionText;
|
||||||
if (cpe.getRevision() != null && cpe.getRevision().length() > 0) {
|
if (cpe.getUpdate() != null && !cpe.getUpdate().isEmpty()) {
|
||||||
versionText = String.format("%s.%s", cpe.getVersion(), cpe.getRevision());
|
versionText = String.format("%s.%s", cpe.getVersion(), cpe.getUpdate());
|
||||||
} else {
|
} else {
|
||||||
versionText = cpe.getVersion();
|
versionText = cpe.getVersion();
|
||||||
}
|
}
|
||||||
@@ -797,4 +781,41 @@ public class CveDB {
|
|||||||
}
|
}
|
||||||
return cpeVersion;
|
return cpeVersion;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Deletes unused dictionary entries from the database.
|
||||||
|
*/
|
||||||
|
public void deleteUnusedCpe() {
|
||||||
|
CallableStatement cs = null;
|
||||||
|
try {
|
||||||
|
cs = getConnection().prepareCall(statementBundle.getString("DELETE_UNUSED_DICT_CPE"));
|
||||||
|
cs.executeUpdate();
|
||||||
|
} catch (SQLException ex) {
|
||||||
|
LOGGER.error("Unable to delete CPE dictionary entries", ex);
|
||||||
|
} finally {
|
||||||
|
DBUtils.closeStatement(cs);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Merges CPE entries into the database.
|
||||||
|
*
|
||||||
|
* @param cpe the CPE identifier
|
||||||
|
* @param vendor the CPE vendor
|
||||||
|
* @param product the CPE product
|
||||||
|
*/
|
||||||
|
public void addCpe(String cpe, String vendor, String product) {
|
||||||
|
PreparedStatement ps = null;
|
||||||
|
try {
|
||||||
|
ps = getConnection().prepareCall(statementBundle.getString("ADD_DICT_CPE"));
|
||||||
|
ps.setString(1, cpe);
|
||||||
|
ps.setString(2, vendor);
|
||||||
|
ps.setString(3, product);
|
||||||
|
ps.executeUpdate();
|
||||||
|
} catch (SQLException ex) {
|
||||||
|
LOGGER.error("Unable to add CPE dictionary entry", ex);
|
||||||
|
} finally {
|
||||||
|
DBUtils.closeStatement(ps);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -20,7 +20,7 @@ package org.owasp.dependencycheck.data.nvdcve;
|
|||||||
/**
|
/**
|
||||||
* An exception thrown if an operation against the database fails.
|
* An exception thrown if an operation against the database fails.
|
||||||
*
|
*
|
||||||
* @author Jeremy Long <jeremy.long@owasp.org>
|
* @author Jeremy Long
|
||||||
*/
|
*/
|
||||||
public class DatabaseException extends Exception {
|
public class DatabaseException extends Exception {
|
||||||
|
|
||||||
|
|||||||
@@ -24,37 +24,45 @@ import java.util.Map;
|
|||||||
import java.util.Map.Entry;
|
import java.util.Map.Entry;
|
||||||
import java.util.Properties;
|
import java.util.Properties;
|
||||||
import java.util.TreeMap;
|
import java.util.TreeMap;
|
||||||
import java.util.logging.Level;
|
import org.owasp.dependencycheck.data.update.nvd.NvdCveInfo;
|
||||||
import java.util.logging.Logger;
|
|
||||||
import org.owasp.dependencycheck.data.update.NvdCveInfo;
|
|
||||||
import org.owasp.dependencycheck.data.update.exception.UpdateException;
|
import org.owasp.dependencycheck.data.update.exception.UpdateException;
|
||||||
|
import org.slf4j.Logger;
|
||||||
|
import org.slf4j.LoggerFactory;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* This is a wrapper around a set of properties that are stored in the database.
|
* This is a wrapper around a set of properties that are stored in the database.
|
||||||
*
|
*
|
||||||
* @author Jeremy Long <jeremy.long@owasp.org>
|
* @author Jeremy Long
|
||||||
*/
|
*/
|
||||||
public class DatabaseProperties {
|
public class DatabaseProperties {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The Logger.
|
* The Logger.
|
||||||
*/
|
*/
|
||||||
private static final Logger LOGGER = Logger.getLogger(DatabaseProperties.class.getName());
|
private static final Logger LOGGER = LoggerFactory.getLogger(DatabaseProperties.class);
|
||||||
/**
|
/**
|
||||||
* Modified key word, used as a key to store information about the modified file (i.e. the containing the last 8
|
* Modified key word, used as a key to store information about the modified file (i.e. the containing the last 8 days of
|
||||||
* days of updates)..
|
* updates)..
|
||||||
*/
|
*/
|
||||||
public static final String MODIFIED = "Modified";
|
public static final String MODIFIED = "Modified";
|
||||||
/**
|
/**
|
||||||
* The properties file key for the last updated field - used to store the last updated time of the Modified NVD CVE
|
* The properties file key for the last updated field - used to store the last updated time of the Modified NVD CVE xml file.
|
||||||
* xml file.
|
|
||||||
*/
|
*/
|
||||||
public static final String LAST_UPDATED = "NVD CVE Modified";
|
public static final String LAST_UPDATED = "NVD CVE Modified";
|
||||||
/**
|
/**
|
||||||
* Stores the last updated time for each of the NVD CVE files. These timestamps should be updated if we process the
|
* Stores the last updated time for each of the NVD CVE files. These timestamps should be updated if we process the modified
|
||||||
* modified file within 7 days of the last update.
|
* file within 7 days of the last update.
|
||||||
*/
|
*/
|
||||||
public static final String LAST_UPDATED_BASE = "NVD CVE ";
|
public static final String LAST_UPDATED_BASE = "NVD CVE ";
|
||||||
|
/**
|
||||||
|
* The key for the last time the CPE data was updated.
|
||||||
|
*/
|
||||||
|
public static final String LAST_CPE_UPDATE = "LAST_CPE_UPDATE";
|
||||||
|
/**
|
||||||
|
* The key for the database schema version.
|
||||||
|
*/
|
||||||
|
public static final String VERSION = "version";
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A collection of properties about the data.
|
* A collection of properties about the data.
|
||||||
*/
|
*/
|
||||||
@@ -91,7 +99,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
|
* @param updatedValue the updated NVD CVE entry
|
||||||
* @throws UpdateException is thrown if there is an update exception
|
* @throws UpdateException is thrown if there is an update exception
|
||||||
@@ -100,13 +108,23 @@ public class DatabaseProperties {
|
|||||||
if (updatedValue == null) {
|
if (updatedValue == null) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
properties.put(LAST_UPDATED_BASE + updatedValue.getId(), String.valueOf(updatedValue.getTimestamp()));
|
save(LAST_UPDATED_BASE + updatedValue.getId(), String.valueOf(updatedValue.getTimestamp()));
|
||||||
cveDB.saveProperty(LAST_UPDATED_BASE + updatedValue.getId(), String.valueOf(updatedValue.getTimestamp()));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns the property value for the given key. If the key is not contained in the underlying properties null is
|
* Saves the key value pair to the properties store.
|
||||||
* returned.
|
*
|
||||||
|
* @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);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the property value for the given key. If the key is not contained in the underlying properties null is returned.
|
||||||
*
|
*
|
||||||
* @param key the property key
|
* @param key the property key
|
||||||
* @return the value of the property
|
* @return the value of the property
|
||||||
@@ -116,8 +134,8 @@ public class DatabaseProperties {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns the property value for the given key. If the key is not contained in the underlying properties the
|
* Returns the property value for the given key. If the key is not contained in the underlying properties the default value is
|
||||||
* default value is returned.
|
* returned.
|
||||||
*
|
*
|
||||||
* @param key the property key
|
* @param key the property key
|
||||||
* @param defaultValue the default value
|
* @param defaultValue the default value
|
||||||
@@ -137,13 +155,13 @@ public class DatabaseProperties {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns a map of the meta data from the database properties. This primarily contains timestamps of when the NVD
|
* Returns a map of the meta data from the database properties. This primarily contains timestamps of when the NVD CVE
|
||||||
* CVE information was last updated.
|
* information was last updated.
|
||||||
*
|
*
|
||||||
* @return a map of the database meta data
|
* @return a map of the database meta data
|
||||||
*/
|
*/
|
||||||
public Map getMetaData() {
|
public Map<String, String> getMetaData() {
|
||||||
final TreeMap map = new TreeMap();
|
final Map<String, String> map = new TreeMap<String, String>();
|
||||||
for (Entry<Object, Object> entry : properties.entrySet()) {
|
for (Entry<Object, Object> entry : properties.entrySet()) {
|
||||||
final String key = (String) entry.getKey();
|
final String key = (String) entry.getKey();
|
||||||
if (!"version".equals(key)) {
|
if (!"version".equals(key)) {
|
||||||
@@ -155,11 +173,11 @@ public class DatabaseProperties {
|
|||||||
final String formatted = format.format(date);
|
final String formatted = format.format(date);
|
||||||
map.put(key, formatted);
|
map.put(key, formatted);
|
||||||
} catch (Throwable ex) { //deliberately being broad in this catch clause
|
} catch (Throwable ex) { //deliberately being broad in this catch clause
|
||||||
LOGGER.log(Level.FINE, "Unable to parse timestamp from DB", ex);
|
LOGGER.debug("Unable to parse timestamp from DB", ex);
|
||||||
map.put(key, entry.getValue());
|
map.put(key, (String) entry.getValue());
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
map.put(key, entry.getValue());
|
map.put(key, (String) entry.getValue());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -20,7 +20,7 @@ package org.owasp.dependencycheck.data.nvdcve;
|
|||||||
/**
|
/**
|
||||||
* An exception thrown the database driver is unable to be loaded.
|
* An exception thrown the database driver is unable to be loaded.
|
||||||
*
|
*
|
||||||
* @author Jeremy Long <jeremy.long@owasp.org>
|
* @author Jeremy Long
|
||||||
*/
|
*/
|
||||||
public class DriverLoadException extends Exception {
|
public class DriverLoadException extends Exception {
|
||||||
|
|
||||||
|
|||||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user