mirror of
https://github.com/ysoftdevs/DependencyCheck.git
synced 2026-01-14 15:53:36 +01:00
Compare commits
1171 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
550d6ca083 | ||
|
|
b425411357 | ||
|
|
a1f0cf749d | ||
|
|
22e0d1c74e | ||
|
|
cdc07047aa | ||
|
|
c832c2da28 | ||
|
|
8daa713639 | ||
|
|
e0a2966706 | ||
|
|
354bfa14f9 | ||
|
|
46b91702ba | ||
|
|
de9516e368 | ||
|
|
3924e07e5c | ||
|
|
76bcbb5a7e | ||
|
|
8022381d1c | ||
|
|
feb1233081 | ||
|
|
36eefd0836 | ||
|
|
0e31e59759 | ||
|
|
4a4c1e75da | ||
|
|
b0bfd2292a | ||
|
|
7214b24357 | ||
|
|
24637f496f | ||
|
|
d8ecde5265 | ||
|
|
28840c6209 | ||
|
|
1696213406 | ||
|
|
6f315ac765 | ||
|
|
a485307d92 | ||
|
|
3d3b861ba0 | ||
|
|
4b33ed25d5 | ||
|
|
e264880c7b | ||
|
|
ef8212701f | ||
|
|
492157a502 | ||
|
|
2605bc182e | ||
|
|
fe8dfdd804 | ||
|
|
bd917bc990 | ||
|
|
c5c32f683f | ||
|
|
5506e58c98 | ||
|
|
5af2d49b18 | ||
|
|
0fd35a4925 | ||
|
|
7ed20b1244 | ||
|
|
efa6a78255 | ||
|
|
8b58df3b34 | ||
|
|
0d2a090e1f | ||
|
|
7860d635a9 | ||
|
|
ba91c9fa9b | ||
|
|
b3630e0d5e | ||
|
|
f752285912 | ||
|
|
5a150d9b0e | ||
|
|
f0aa185832 | ||
|
|
9592f058d4 | ||
|
|
f630794e22 | ||
|
|
93636e89c5 | ||
|
|
585002c25c | ||
|
|
412ccc1be1 | ||
|
|
8b1306a36c | ||
|
|
81026e8dca | ||
|
|
dd440c8f9f | ||
|
|
76f3e4b27e | ||
|
|
5f5d3fdb66 | ||
|
|
853c92b87d | ||
|
|
00080f2abc | ||
|
|
55414208a3 | ||
|
|
5091499563 | ||
|
|
944b54d920 | ||
|
|
d023b2b2ff | ||
|
|
b45f9f514b | ||
|
|
239a9383e0 | ||
|
|
2190c0229c | ||
|
|
01ef14dc92 | ||
|
|
7b0784843c | ||
|
|
6fc805369e | ||
|
|
9e29939cd3 | ||
|
|
d750abca22 | ||
|
|
31df2fa131 | ||
|
|
6355a29a7a | ||
|
|
86a2b38340 | ||
|
|
9cb2b58557 | ||
|
|
2b0e2e8d0d | ||
|
|
cf46767196 | ||
|
|
ffc1034b5a | ||
|
|
46bb19de9b | ||
|
|
70bc7a6d01 | ||
|
|
3164505273 | ||
|
|
3d84fcd037 | ||
|
|
578fa32243 | ||
|
|
fc00b7d1cc | ||
|
|
d7351bd3e5 | ||
|
|
e7224c8f05 | ||
|
|
b97622f45b | ||
|
|
0e15f3b703 | ||
|
|
6604c0da89 | ||
|
|
e0b8be20b3 | ||
|
|
46965d8c96 | ||
|
|
66e92f00ee | ||
|
|
4a137b4e8e | ||
|
|
9d5ff28098 | ||
|
|
313b114da5 | ||
|
|
1b6bfc6338 | ||
|
|
49fd89f34a | ||
|
|
a2e862886e | ||
|
|
62f6c7c5a9 | ||
|
|
2294ed1ce1 | ||
|
|
c8a1c6a318 | ||
|
|
600ed66d5b | ||
|
|
512b17555c | ||
|
|
dc7849c9e8 | ||
|
|
6a99a51b91 | ||
|
|
8c7fa022a0 | ||
|
|
cca694a580 | ||
|
|
3a7f95b9b1 | ||
|
|
3a84dc3962 | ||
|
|
5961a96a4c | ||
|
|
a22382505f | ||
|
|
5faef75415 | ||
|
|
fed60907dc | ||
|
|
ce7e360b70 | ||
|
|
0b3def38b8 | ||
|
|
25a15dea8c | ||
|
|
e204971a6c | ||
|
|
d5b3a118bc | ||
|
|
3396cb2887 | ||
|
|
3c5beea218 | ||
|
|
e544384dd5 | ||
|
|
0e90f460f4 | ||
|
|
921efc4d2b | ||
|
|
1b3b4a5906 | ||
|
|
5c8b374352 | ||
|
|
e05cef6886 | ||
|
|
cb39ecacf9 | ||
|
|
e6816f94eb | ||
|
|
8b5dbeab44 | ||
|
|
29c21c3611 | ||
|
|
e05bed8d65 | ||
|
|
1b2210aba0 | ||
|
|
7fb1b1d57b | ||
|
|
a3adf71a1d | ||
|
|
51d81fab5d | ||
|
|
2ed5dc153a | ||
|
|
5f8f156bee | ||
|
|
eb03c90d7a | ||
|
|
fc05471086 | ||
|
|
b9db2dd89f | ||
|
|
de7fe21a4f | ||
|
|
56f9a7c4f9 | ||
|
|
df569a5ae2 | ||
|
|
acb9d04c51 | ||
|
|
09c4708a22 | ||
|
|
b346dfe0a3 | ||
|
|
5f259cb88c | ||
|
|
fb2aff3310 | ||
|
|
3c4c65c28c | ||
|
|
15885e3e8c | ||
|
|
5508c60e85 | ||
|
|
ffc341e4b9 | ||
|
|
41a68f7b25 | ||
|
|
041d3c5312 | ||
|
|
8e8b462bc8 | ||
|
|
efbc76e06f | ||
|
|
67a44d2adc | ||
|
|
92a35b929a | ||
|
|
e5744dd63f | ||
|
|
f2f3d050bd | ||
|
|
0cbecbe3a0 | ||
|
|
51a8b5a058 | ||
|
|
aaf716e54b | ||
|
|
209fcc7946 | ||
|
|
a5cb131806 | ||
|
|
8fbeb5f5d5 | ||
|
|
a92bdfe30d | ||
|
|
7f130ff036 | ||
|
|
b704f72854 | ||
|
|
e21f8a97ac | ||
|
|
a8ff403809 | ||
|
|
22097c0a25 | ||
|
|
92e7d9cf80 | ||
|
|
54d921f275 | ||
|
|
08d7b3dbce | ||
|
|
6949b3c229 | ||
|
|
b0ca38bd29 | ||
|
|
cf173ee9e7 | ||
|
|
aa9908b34a | ||
|
|
640674ef72 | ||
|
|
0c69ab80bb | ||
|
|
662557c2f3 | ||
|
|
346b2c31d2 | ||
|
|
62dbf99557 | ||
|
|
99b140adaa | ||
|
|
387d577d4f | ||
|
|
ab7eee7db9 | ||
|
|
487a45f01b | ||
|
|
60665c6bd8 | ||
|
|
8fc9a3d6d1 | ||
|
|
05a05f7e88 | ||
|
|
0c5bdfd7b7 | ||
|
|
626e93c7e3 | ||
|
|
b588c4c900 | ||
|
|
c52a0d88df | ||
|
|
84838d19d9 | ||
|
|
faf335a181 | ||
|
|
5c25351884 | ||
|
|
520f3cb09a | ||
|
|
e234246618 | ||
|
|
5d1d378f61 | ||
|
|
cef3bb7424 | ||
|
|
ccb03f2763 | ||
|
|
1f6168366b | ||
|
|
cd5bf85245 | ||
|
|
f2778e5d28 | ||
|
|
c2e6065ed7 | ||
|
|
fccba5f7fd | ||
|
|
3f230c5a05 | ||
|
|
dc849c3891 | ||
|
|
2770b58a20 | ||
|
|
37519acfb8 | ||
|
|
ad8c7b3cd2 | ||
|
|
04db8d3208 | ||
|
|
666e3b1e30 | ||
|
|
dc68781c06 | ||
|
|
a7f50d147e | ||
|
|
7e639db5de | ||
|
|
19a97a1706 | ||
|
|
cd66a9ef61 | ||
|
|
f121430a5d | ||
|
|
2f518dacfc | ||
|
|
fded8b6cd3 | ||
|
|
3b6c64dc9d | ||
|
|
d742985640 | ||
|
|
a13dd58989 | ||
|
|
622b3210ae | ||
|
|
90c97ed6aa | ||
|
|
53a4dfbf88 | ||
|
|
f488c57363 | ||
|
|
0ce830ca9d | ||
|
|
30ae418c2c | ||
|
|
3b976d211f | ||
|
|
cca49b5dc2 | ||
|
|
8c2b2070c6 | ||
|
|
24b8ff26db | ||
|
|
f0d93538ae | ||
|
|
02eab65c4e | ||
|
|
d941aa7df3 | ||
|
|
b5026a45f6 | ||
|
|
79fde3ebc9 | ||
|
|
031d648585 | ||
|
|
762b2fe7d6 | ||
|
|
5db377923e | ||
|
|
c3177df739 | ||
|
|
0dc36765f1 | ||
|
|
38e61ebd8d | ||
|
|
529b9739b5 | ||
|
|
a014ca7d8a | ||
|
|
83701f7d0d | ||
|
|
b2500939f3 | ||
|
|
1852b9dbb2 | ||
|
|
069474fc71 | ||
|
|
e7f518264a | ||
|
|
b0b096c3f5 | ||
|
|
bfa9d04d42 | ||
|
|
7dbe58469a | ||
|
|
41b36dabc2 | ||
|
|
4a685557d9 | ||
|
|
e7ef4b6906 | ||
|
|
67502fb9d3 | ||
|
|
960283bdcf | ||
|
|
39f30eab7a | ||
|
|
24b4741aaf | ||
|
|
64f373fb43 | ||
|
|
bc1830d8eb | ||
|
|
f2a2a91682 | ||
|
|
274ac339ad | ||
|
|
1d916286ee | ||
|
|
832d54300a | ||
|
|
ba6d3bbe15 | ||
|
|
c1d0789ac7 | ||
|
|
0573d0083e | ||
|
|
e57d62b682 | ||
|
|
bb6f27b322 | ||
|
|
86f424ad37 | ||
|
|
ad81bbc761 | ||
|
|
07e868e6f6 | ||
|
|
b45700df03 | ||
|
|
93ce2a8e3a | ||
|
|
fbc4d46962 | ||
|
|
d73d138b3f | ||
|
|
14ea21d53d | ||
|
|
2b3791b83e | ||
|
|
e04809f96b | ||
|
|
9203acff9c | ||
|
|
afc1a9f077 | ||
|
|
fc57851113 | ||
|
|
1f1d3f843f | ||
|
|
b389260dec | ||
|
|
1f37a5ff8f | ||
|
|
815d60eca2 | ||
|
|
877a584a26 | ||
|
|
0c60c9ff75 | ||
|
|
6a7a868b71 | ||
|
|
b5a070b228 | ||
|
|
39f13c6e5b | ||
|
|
8c98da09f0 | ||
|
|
ed70a7200c | ||
|
|
ea4410cd16 | ||
|
|
9d9b1cbcd5 | ||
|
|
f17d8f38fb | ||
|
|
0efc9d1cd2 | ||
|
|
4f5d5f1afd | ||
|
|
c4d8d7abf4 | ||
|
|
3fad29a709 | ||
|
|
665f204c1f | ||
|
|
362b651823 | ||
|
|
49b56588b8 | ||
|
|
c7a763ffdc | ||
|
|
5435ddad9f | ||
|
|
0ecd466c4c | ||
|
|
6117e25b97 | ||
|
|
ee10f09bc6 | ||
|
|
58512e302f | ||
|
|
ce564c209b | ||
|
|
7296d49693 | ||
|
|
290fdc4c0f | ||
|
|
1fa5ae695d | ||
|
|
b2ba6d38b8 | ||
|
|
620f1b94bc | ||
|
|
c8fb5d1a9a | ||
|
|
1f763aeb72 | ||
|
|
fcfb019555 | ||
|
|
d4c1acb126 | ||
|
|
862bf43685 | ||
|
|
f83139a9ee | ||
|
|
3d938b3edf | ||
|
|
6c6ae66e36 | ||
|
|
813e423bec | ||
|
|
a9a235fc87 | ||
|
|
6e1c6b4bed | ||
|
|
2214059a63 | ||
|
|
424cfcfa0c | ||
|
|
ce871dfa3e | ||
|
|
48a6eb1f86 | ||
|
|
fb85fb5b76 | ||
|
|
c39c3cfdae | ||
|
|
e2fa7c666a | ||
|
|
f49cc6fb1f | ||
|
|
69bef59473 | ||
|
|
9e931b9eb0 | ||
|
|
b26d9ea1e0 | ||
|
|
ca5607d79e | ||
|
|
903eaed250 | ||
|
|
0859eab2dc | ||
|
|
f0f84722ba | ||
|
|
17b8ba7069 | ||
|
|
eb91152cfa | ||
|
|
08c1b6879e | ||
|
|
0077a8f67c | ||
|
|
a89cc67bd2 | ||
|
|
388415ecc2 | ||
|
|
44c5ba208d | ||
|
|
d3a51857cb | ||
|
|
11a3db5d64 | ||
|
|
f3be8ae608 | ||
|
|
0577c9121c | ||
|
|
058f51e8c1 | ||
|
|
698444caec | ||
|
|
d575df4b19 | ||
|
|
bee98513a2 | ||
|
|
3746df49ee | ||
|
|
d98f67eab9 | ||
|
|
fde415e251 | ||
|
|
5702f39181 | ||
|
|
45658afd89 | ||
|
|
ece4a51b94 | ||
|
|
837d4918f2 | ||
|
|
57ae0f1676 | ||
|
|
48e644e007 | ||
|
|
49a04fa913 | ||
|
|
df943bcf75 | ||
|
|
fdbec176fa | ||
|
|
4b2b4e5482 | ||
|
|
96768d8529 | ||
|
|
2689a08026 | ||
|
|
54be70672e | ||
|
|
480fa50af5 | ||
|
|
b51731d15f | ||
|
|
c09650a136 | ||
|
|
769fcb20d8 | ||
|
|
537c4b3a50 | ||
|
|
a75c17ac5e | ||
|
|
85604e8afa | ||
|
|
9a45c9aa7c | ||
|
|
01450bacc2 | ||
|
|
af0255ee09 | ||
|
|
df25bbb6d2 | ||
|
|
444685bc05 | ||
|
|
115f63c330 | ||
|
|
f9dbc4f7bf | ||
|
|
83263f8dee | ||
|
|
a452ade957 | ||
|
|
1f48af024e | ||
|
|
0a643d7195 | ||
|
|
c3835b9da7 | ||
|
|
bb1a96cf7a | ||
|
|
56360301d7 | ||
|
|
435cccdeae | ||
|
|
b11b472933 | ||
|
|
514f8398e2 | ||
|
|
90935fef25 | ||
|
|
9b5ce1c3a6 | ||
|
|
8ad1639b02 | ||
|
|
6d70332cd6 | ||
|
|
717f6240e3 | ||
|
|
ab782054a1 | ||
|
|
b481f01217 | ||
|
|
d0f884f5b2 | ||
|
|
51e66354b0 | ||
|
|
1efe90f445 | ||
|
|
7b47b7549d | ||
|
|
7ccb77fb57 | ||
|
|
a32fa69823 | ||
|
|
ece4cb03ad | ||
|
|
5c53b6528f | ||
|
|
9b92007eff | ||
|
|
e433809f4d | ||
|
|
d74218004a | ||
|
|
c35276e3df | ||
|
|
064236ed5b | ||
|
|
2a50dcba9d | ||
|
|
f7974b324b | ||
|
|
3bb716b060 | ||
|
|
39e465261f | ||
|
|
784b78b17c | ||
|
|
22c68ed8ef | ||
|
|
c4c670a3b1 | ||
|
|
17a05cc1d4 | ||
|
|
d452c5fabb | ||
|
|
2cf974ef02 | ||
|
|
1f0e789575 | ||
|
|
92e1fd3f28 | ||
|
|
49736a87aa | ||
|
|
d009e39842 | ||
|
|
c2b8901537 | ||
|
|
dd910cb5ec | ||
|
|
4632753f02 | ||
|
|
3fdcd12b4f | ||
|
|
94d1d611c7 | ||
|
|
27b54a0bfa | ||
|
|
1b1ecd0748 | ||
|
|
1e29d2e751 | ||
|
|
a0437bf933 | ||
|
|
73e0292a4b | ||
|
|
c393e74160 | ||
|
|
80c4666198 | ||
|
|
ea7bd1f700 | ||
|
|
b3a55cc85d | ||
|
|
036200350d | ||
|
|
e630c484ff | ||
|
|
713e9658c5 | ||
|
|
782039810e | ||
|
|
b473d8ab9c | ||
|
|
2eb6918fb3 | ||
|
|
29626666a7 | ||
|
|
dc41c9a671 | ||
|
|
83af70bb59 | ||
|
|
b293873640 | ||
|
|
8bb92815cb | ||
|
|
7a8f7199c8 | ||
|
|
6f4ce34840 | ||
|
|
8853552161 | ||
|
|
95d3d17d83 | ||
|
|
3594280b04 | ||
|
|
1e447c6e3e | ||
|
|
c41a288280 | ||
|
|
a0492fe944 | ||
|
|
1fffebd497 | ||
|
|
62c05049a7 | ||
|
|
0fdf377d45 | ||
|
|
6ca8e2644a | ||
|
|
4a3061db6d | ||
|
|
61ac81518a | ||
|
|
acd4b4371d | ||
|
|
1d20291d44 | ||
|
|
c60245ea2b | ||
|
|
9e25480baa | ||
|
|
facd803943 | ||
|
|
05c8a6282d | ||
|
|
3f9ae34203 | ||
|
|
afb85309a2 | ||
|
|
2c5e64d0d5 | ||
|
|
ddb8c432be | ||
|
|
054be314f6 | ||
|
|
e484c5754e | ||
|
|
b36c4f65e5 | ||
|
|
4bdfbcc916 | ||
|
|
519198bb61 | ||
|
|
9a7c342f91 | ||
|
|
761a5ed3dd | ||
|
|
481e753ad4 | ||
|
|
271016f0fa | ||
|
|
4493f895c6 | ||
|
|
5c32ecd8e1 | ||
|
|
0b5244d321 | ||
|
|
b6f9715174 | ||
|
|
2db1f8d2b6 | ||
|
|
4c5957ae40 | ||
|
|
38cd19de15 | ||
|
|
f66ffbdd63 | ||
|
|
8d3f08e529 | ||
|
|
4209c1c406 | ||
|
|
1cd12d0a0c | ||
|
|
7eb18e1931 | ||
|
|
d308e50e1e | ||
|
|
88569cb369 | ||
|
|
235869fc79 | ||
|
|
89166e81fb | ||
|
|
2d109b81cf | ||
|
|
5c02b4dccb | ||
|
|
e7f154b58d | ||
|
|
c0752575c6 | ||
|
|
7eb2c89f39 | ||
|
|
bf4eb07342 | ||
|
|
c856d01b52 | ||
|
|
7a535b2576 | ||
|
|
4b17fd88a3 | ||
|
|
8d1f3f723f | ||
|
|
a543fbbec9 | ||
|
|
37f50db00e | ||
|
|
ccb87f43b7 | ||
|
|
d569f39f53 | ||
|
|
fb3951772f | ||
|
|
2c00bf4040 | ||
|
|
4f8772bd77 | ||
|
|
b4c3046ab5 | ||
|
|
2441b92bc6 | ||
|
|
c39eec32f2 | ||
|
|
7837718d04 | ||
|
|
7069671471 | ||
|
|
d1dbde2890 | ||
|
|
0472471ac9 | ||
|
|
62a0b8da90 | ||
|
|
810530fabd | ||
|
|
707de56612 | ||
|
|
921b0eb229 | ||
|
|
9afb92f0ed | ||
|
|
1ded88e089 | ||
|
|
1f074ff400 | ||
|
|
4764f61b48 | ||
|
|
56424924bb | ||
|
|
4c3831ec74 | ||
|
|
ba564a6aed | ||
|
|
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 |
5
.gitignore
vendored
5
.gitignore
vendored
@@ -1,4 +1,6 @@
|
||||
*/target/**
|
||||
# IntelliJ test run side-effects
|
||||
dependency-check-core/data/
|
||||
# Intellij project files
|
||||
*.iml
|
||||
*.ipr
|
||||
@@ -10,6 +12,7 @@
|
||||
.settings
|
||||
maven-eclipse.xml
|
||||
.externalToolBuilders
|
||||
.pmd
|
||||
# Netbeans configuration
|
||||
nb-configuration.xml
|
||||
/target/
|
||||
@@ -22,4 +25,4 @@ _site/**
|
||||
#unknown as to why these are showing up... but need to be ignored.
|
||||
.LCKpom.xml~
|
||||
#coverity
|
||||
/cov-int/
|
||||
/cov-int/
|
||||
|
||||
31
README.md
31
README.md
@@ -1,3 +1,4 @@
|
||||
[](https://dependency-check.ci.cloudbees.com/job/dependency-check/)
|
||||
Dependency-Check
|
||||
================
|
||||
|
||||
@@ -9,12 +10,14 @@ Current Releases
|
||||
-------------
|
||||
### Jenkins Plugin
|
||||
|
||||
For instructions on the use of the Jenkins plugin please see the [Jenkins dependency-check page](http://wiki.jenkins-ci.org/x/CwDgAQ).
|
||||
For instructions on the use of the Jenkins plugin please see the [OWASP Dependency-Check Plugin page](https://wiki.jenkins-ci.org/display/JENKINS/OWASP+Dependency-Check+Plugin).
|
||||
|
||||
### Command Line
|
||||
|
||||
More detailed instructions can be found on the [dependency-check github pages](http://jeremylong.github.io/DependencyCheck/dependency-check-cli/installation.html).
|
||||
The latest CLI can be downloaded from bintray's [dependency-check page](https://bintray.com/jeremy-long/owasp/dependency-check).
|
||||
More detailed instructions can be found on the
|
||||
[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
|
||||
```
|
||||
@@ -26,10 +29,16 @@ On Windows
|
||||
> bin/dependency-check.bat -h
|
||||
> 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
|
||||
|
||||
More detailed instructions can be found on the [dependency-check-maven github pages](http://jeremylong.github.io/DependencyCheck/dependency-check-maven/usage.html).
|
||||
More detailed instructions can be found on the [dependency-check-maven github pages](http://jeremylong.github.io/DependencyCheck/dependency-check-maven).
|
||||
The plugin can be configured using the following:
|
||||
|
||||
```xml
|
||||
@@ -58,15 +67,19 @@ The plugin can be configured using the following:
|
||||
|
||||
### Ant Task
|
||||
|
||||
For instructions on the use of the Ant Task, please see the [dependency-check-ant github page](http://jeremylong.github.io/DependencyCheck/dependency-check-ant/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).
|
||||
|
||||
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
|
||||
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
|
||||
download of data from the NVD is having an issue. This issue is still being researched and a solution should be published soon.
|
||||
The repository has some large files due to test resources. The team has tried to cleanup the history as much as possible.
|
||||
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
|
||||
```
|
||||
@@ -95,9 +108,9 @@ Archive: [google group](https://groups.google.com/forum/#!forum/dependency-check
|
||||
Copyright & License
|
||||
-
|
||||
|
||||
Dependency-Check is Copyright (c) 2012-2014 Jeremy Long. All Rights Reserved.
|
||||
Dependency-Check is Copyright (c) 2012-2016 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://raw.githubusercontent.com/jeremylong/DependencyCheck/master/LICENSE.txt) file for the full license.
|
||||
|
||||
Dependency-Check makes use of several other open source libraries. Please see the [NOTICE.txt] [notices] file for more information.
|
||||
|
||||
|
||||
@@ -1,9 +1,6 @@
|
||||
-----------------------------
|
||||
---begin dependency-check----
|
||||
-----------------------------
|
||||
dependency-check
|
||||
OWASP dependency-check
|
||||
|
||||
Copyright (c) 2012-2013 Jeremy Long. All Rights Reserved.
|
||||
Copyright (c) 2012-2015 Jeremy Long. All Rights Reserved.
|
||||
|
||||
The licenses for the software listed below can be found in the META-INF/licenses/[dependency name].
|
||||
|
||||
@@ -19,11 +16,3 @@ An original copy of the license agreement can be found at: http://www.h2database
|
||||
This product includes data from the Common Weakness Enumeration (CWE): http://cwe.mitre.org/
|
||||
|
||||
This product downloads and utilizes data from the National Vulnerability Database hosted by NIST: http://nvd.nist.gov/download.cfm
|
||||
|
||||
-----------------------------
|
||||
---end dependency-check------
|
||||
-----------------------------
|
||||
|
||||
Notices below are from dependent libraries and have been included via maven-shade-plugin.
|
||||
|
||||
-----------------------------
|
||||
@@ -1,25 +1,134 @@
|
||||
Dependency-Check Ant Task
|
||||
Dependency-Check-Gradle
|
||||
=========
|
||||
|
||||
Dependency-Check Ant Task can be used to check the project dependencies for published security vulnerabilities. The checks
|
||||
performed are a "best effort" and as such, there could be false positives as well as false negatives. However,
|
||||
vulnerabilities in 3rd party components is a well-known problem and is currently documented in the 2013 OWASP
|
||||
Top 10 as [A9 - Using Components with Known Vulnerabilities](https://www.owasp.org/index.php/Top_10_2013-A9-Using_Components_with_Known_Vulnerabilities).
|
||||
**Working in progress**
|
||||
|
||||
Documentation and links to production binary releases can be found on the [github pages](http://jeremylong.github.io/DependencyCheck/dependency-check-ant/installation.html).
|
||||
This is a DependencyCheck gradle plugin designed for project which use Gradle as build script.
|
||||
|
||||
Mailing List
|
||||
------------
|
||||
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.
|
||||
|
||||
Subscribe: [dependency-check+subscribe@googlegroups.com](mailto:dependency-check+subscribe@googlegroups.com)
|
||||
=========
|
||||
|
||||
Post: [dependency-check@googlegroups.com](mailto:dependency-check@googlegroups.com)
|
||||
## What's New
|
||||
Current latest version is `0.0.8`
|
||||
|
||||
Copyright & License
|
||||
-------------------
|
||||
## Usage
|
||||
|
||||
Dependency-Check is Copyright (c) 2012-2014 Jeremy Long. All Rights Reserved.
|
||||
### Step 1, Apply dependency check gradle plugin
|
||||
|
||||
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.
|
||||
Install from Maven central repo
|
||||
|
||||
Dependency-Check-Ant makes use of other open source libraries. Please see the [NOTICE.txt](https://github.com/jeremylong/DependencyCheck/dependency-check-ant/blob/master/NOTICES.txt) file for more information.
|
||||
```groovy
|
||||
buildscript {
|
||||
repositories {
|
||||
mavenCentral()
|
||||
}
|
||||
dependencies {
|
||||
classpath 'org.owasp:dependency-check-gradle:1.3.2'
|
||||
}
|
||||
}
|
||||
|
||||
apply plugin: 'dependency-check-gradle'
|
||||
```
|
||||
|
||||
### Step 2, Run gradle task
|
||||
|
||||
Once gradle plugin applied, run following gradle task to check dependencies:
|
||||
|
||||
```
|
||||
gradle dependencyCheck --info
|
||||
```
|
||||
|
||||
The reports will be generated automatically under `./reports` folder.
|
||||
|
||||
If your project includes multiple sub-projects, the report will be generated for each sub-project in different sub-directory.
|
||||
|
||||
## FAQ
|
||||
|
||||
> **Questions List:**
|
||||
> - What if I'm behind a proxy?
|
||||
> - What if my project includes multiple sub-project? How can I use this plugin for each of them including the root project?
|
||||
> - How to customize the report directory?
|
||||
|
||||
### What if I'm behind a proxy?
|
||||
|
||||
Maybe you have to use proxy to access internet, in this case, you could configure proxy settings for this plugin:
|
||||
|
||||
```groovy
|
||||
dependencyCheck {
|
||||
proxy {
|
||||
server = "127.0.0.1" // required, the server name or IP address of the proxy
|
||||
port = 3128 // required, the port number of the proxy
|
||||
|
||||
// optional, the proxy server might require username
|
||||
// username = "username"
|
||||
|
||||
// optional, the proxy server might require password
|
||||
// password = "password"
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
In addition, if the proxy only allow HTTP `GET` or `POST` methods, you will find that the update process will always fail,
|
||||
the root cause is that every time you run `dependencyCheck` task, it will try to query the latest timestamp to determine whether need to perform an update action,
|
||||
and for performance reason the HTTP method it uses by default is `HEAD`, which probably is disabled or not supported by the proxy. To avoid this problem, you can simply change the HTTP method by below configuration:
|
||||
|
||||
```groovy
|
||||
dependencyCheck {
|
||||
quickQueryTimestamp = false // when set to false, it means use HTTP GET method to query timestamp. (default value is true)
|
||||
}
|
||||
```
|
||||
|
||||
### What if my project includes multiple sub-project? How can I use this plugin for each of them including the root project?
|
||||
|
||||
Try put 'apply plugin: "dependency-check"' inside the 'allprojects' or 'subprojects' if you'd like to check all sub-projects only, see below:
|
||||
|
||||
(1) For all projects including root project:
|
||||
|
||||
```groovy
|
||||
buildscript {
|
||||
repositories {
|
||||
mavenCentral()
|
||||
}
|
||||
dependencies {
|
||||
classpath "gradle.plugin.com.tools.security:dependency-check:0.0.8"
|
||||
}
|
||||
}
|
||||
|
||||
allprojects {
|
||||
apply plugin: "dependency-check"
|
||||
}
|
||||
```
|
||||
|
||||
(2) For all sub-projects:
|
||||
|
||||
```groovy
|
||||
buildscript {
|
||||
repositories {
|
||||
mavenCentral()
|
||||
}
|
||||
dependencies {
|
||||
classpath "gradle.plugin.com.tools.security:dependency-check:0.0.8"
|
||||
}
|
||||
}
|
||||
|
||||
subprojects {
|
||||
apply plugin: "dependency-check"
|
||||
}
|
||||
```
|
||||
|
||||
In this way, the dependency check will be executed for all projects (including root project) or just sub projects.
|
||||
|
||||
### How to customize the report directory?
|
||||
|
||||
By default, all reports will be placed under `./reports` folder, to change the default directory, just modify it in the configuration section like this:
|
||||
|
||||
```groovy
|
||||
subprojects {
|
||||
apply plugin: "dependency-check"
|
||||
|
||||
dependencyCheck {
|
||||
outputDirectory = "./customized-path/security-report"
|
||||
}
|
||||
}
|
||||
```
|
||||
@@ -20,7 +20,7 @@ Copyright (c) 2013 - Jeremy Long. All Rights Reserved.
|
||||
<parent>
|
||||
<groupId>org.owasp</groupId>
|
||||
<artifactId>dependency-check-parent</artifactId>
|
||||
<version>1.2.9</version>
|
||||
<version>1.3.5</version>
|
||||
</parent>
|
||||
|
||||
<artifactId>dependency-check-ant</artifactId>
|
||||
@@ -190,38 +190,36 @@ Copyright (c) 2013 - Jeremy Long. All Rights Reserved.
|
||||
</execution>
|
||||
</executions>
|
||||
</plugin>
|
||||
<plugin>
|
||||
<groupId>org.apache.maven.plugins</groupId>
|
||||
<artifactId>maven-compiler-plugin</artifactId>
|
||||
</plugin>
|
||||
<plugin>
|
||||
<groupId>org.apache.maven.plugins</groupId>
|
||||
<artifactId>maven-jar-plugin</artifactId>
|
||||
<configuration>
|
||||
<archive>
|
||||
<manifest>
|
||||
<addClasspath>true</addClasspath>
|
||||
<classpathPrefix>lib/</classpathPrefix>
|
||||
</manifest>
|
||||
</archive>
|
||||
</configuration>
|
||||
</plugin>
|
||||
<plugin>
|
||||
<groupId>org.apache.maven.plugins</groupId>
|
||||
<artifactId>maven-shade-plugin</artifactId>
|
||||
<version>2.3</version>
|
||||
<artifactId>maven-assembly-plugin</artifactId>
|
||||
<configuration>
|
||||
<transformers>
|
||||
<transformer implementation="org.apache.maven.plugins.shade.resource.ServicesResourceTransformer" />
|
||||
<transformer implementation="org.apache.maven.plugins.shade.resource.AppendingTransformer">
|
||||
<resource>META-INF/NOTICE.txt</resource>
|
||||
</transformer>
|
||||
<transformer implementation="org.apache.maven.plugins.shade.resource.DontIncludeResourceTransformer">
|
||||
<resource>META-INF/NOTICE</resource>
|
||||
</transformer>
|
||||
<transformer implementation="org.apache.maven.plugins.shade.resource.DontIncludeResourceTransformer">
|
||||
<resource>META-INF/LICENSE</resource>
|
||||
</transformer>
|
||||
</transformers>
|
||||
<attach>false</attach> <!-- don't install/deploy this archive -->
|
||||
</configuration>
|
||||
<executions>
|
||||
<execution>
|
||||
<id>create-distribution</id>
|
||||
<phase>package</phase>
|
||||
<goals>
|
||||
<goal>shade</goal>
|
||||
<goal>single</goal>
|
||||
</goals>
|
||||
<configuration>
|
||||
<descriptors>
|
||||
<descriptor>src/main/assembly/release.xml</descriptor>
|
||||
</descriptors>
|
||||
</configuration>
|
||||
</execution>
|
||||
</executions>
|
||||
</plugin>
|
||||
@@ -229,9 +227,6 @@ Copyright (c) 2013 - Jeremy Long. All Rights Reserved.
|
||||
<groupId>org.codehaus.mojo</groupId>
|
||||
<artifactId>cobertura-maven-plugin</artifactId>
|
||||
<configuration>
|
||||
<!--instrumentation>
|
||||
<ignoreTrivial>true</ignoreTrivial>
|
||||
</instrumentation-->
|
||||
<check>
|
||||
<branchRate>85</branchRate>
|
||||
<lineRate>85</lineRate>
|
||||
@@ -273,100 +268,10 @@ Copyright (c) 2013 - Jeremy Long. All Rights Reserved.
|
||||
</build>
|
||||
<reporting>
|
||||
<plugins>
|
||||
<plugin>
|
||||
<groupId>org.apache.maven.plugins</groupId>
|
||||
<artifactId>maven-project-info-reports-plugin</artifactId>
|
||||
<version>2.7</version>
|
||||
<reportSets>
|
||||
<reportSet>
|
||||
<reports>
|
||||
<report>index</report>
|
||||
<report>summary</report>
|
||||
<report>license</report>
|
||||
<report>help</report>
|
||||
</reports>
|
||||
</reportSet>
|
||||
</reportSets>
|
||||
</plugin>
|
||||
<plugin>
|
||||
<groupId>org.apache.maven.plugins</groupId>
|
||||
<artifactId>maven-javadoc-plugin</artifactId>
|
||||
<version>2.9.1</version>
|
||||
<configuration>
|
||||
<bottom>Copyright© 2012-15 Jeremy Long. All Rights Reserved.</bottom>
|
||||
</configuration>
|
||||
<reportSets>
|
||||
<reportSet>
|
||||
<id>default</id>
|
||||
<reports>
|
||||
<report>javadoc</report>
|
||||
</reports>
|
||||
</reportSet>
|
||||
</reportSets>
|
||||
</plugin>
|
||||
<plugin>
|
||||
<groupId>org.codehaus.mojo</groupId>
|
||||
<artifactId>versions-maven-plugin</artifactId>
|
||||
<version>2.1</version>
|
||||
<reportSets>
|
||||
<reportSet>
|
||||
<reports>
|
||||
<report>dependency-updates-report</report>
|
||||
<report>plugin-updates-report</report>
|
||||
</reports>
|
||||
</reportSet>
|
||||
</reportSets>
|
||||
</plugin>
|
||||
<plugin>
|
||||
<groupId>org.apache.maven.plugins</groupId>
|
||||
<artifactId>maven-jxr-plugin</artifactId>
|
||||
<version>2.4</version>
|
||||
</plugin>
|
||||
<plugin>
|
||||
<groupId>org.codehaus.mojo</groupId>
|
||||
<artifactId>cobertura-maven-plugin</artifactId>
|
||||
<version>2.6</version>
|
||||
</plugin>
|
||||
<plugin>
|
||||
<groupId>org.apache.maven.plugins</groupId>
|
||||
<artifactId>maven-surefire-report-plugin</artifactId>
|
||||
<version>2.16</version>
|
||||
<reportSets>
|
||||
<reportSet>
|
||||
<reports>
|
||||
<report>report-only</report>
|
||||
</reports>
|
||||
</reportSet>
|
||||
</reportSets>
|
||||
</plugin>
|
||||
<plugin>
|
||||
<groupId>org.codehaus.mojo</groupId>
|
||||
<artifactId>taglist-maven-plugin</artifactId>
|
||||
<version>2.4</version>
|
||||
<configuration>
|
||||
<tagListOptions>
|
||||
<tagClasses>
|
||||
<tagClass>
|
||||
<displayName>Todo Work</displayName>
|
||||
<tags>
|
||||
<tag>
|
||||
<matchString>todo</matchString>
|
||||
<matchType>ignoreCase</matchType>
|
||||
</tag>
|
||||
<tag>
|
||||
<matchString>FIXME</matchString>
|
||||
<matchType>exact</matchType>
|
||||
</tag>
|
||||
</tags>
|
||||
</tagClass>
|
||||
</tagClasses>
|
||||
</tagListOptions>
|
||||
</configuration>
|
||||
</plugin>
|
||||
<plugin>
|
||||
<groupId>org.apache.maven.plugins</groupId>
|
||||
<artifactId>maven-checkstyle-plugin</artifactId>
|
||||
<version>2.11</version>
|
||||
<version>${reporting.checkstyle-plugin.version}</version>
|
||||
<configuration>
|
||||
<enableRulesSummary>false</enableRulesSummary>
|
||||
<enableFilesSummary>false</enableFilesSummary>
|
||||
@@ -379,7 +284,7 @@ Copyright (c) 2013 - Jeremy Long. All Rights Reserved.
|
||||
<plugin>
|
||||
<groupId>org.apache.maven.plugins</groupId>
|
||||
<artifactId>maven-pmd-plugin</artifactId>
|
||||
<version>3.0.1</version>
|
||||
<version>${reporting.pmd-plugin.version}</version>
|
||||
<configuration>
|
||||
<targetJdk>1.6</targetJdk>
|
||||
<linkXref>true</linkXref>
|
||||
@@ -395,11 +300,6 @@ Copyright (c) 2013 - Jeremy Long. All Rights Reserved.
|
||||
</rulesets>
|
||||
</configuration>
|
||||
</plugin>
|
||||
<plugin>
|
||||
<groupId>org.codehaus.mojo</groupId>
|
||||
<artifactId>findbugs-maven-plugin</artifactId>
|
||||
<version>2.5.3</version>
|
||||
</plugin>
|
||||
</plugins>
|
||||
</reporting>
|
||||
<dependencies>
|
||||
@@ -423,12 +323,11 @@ Copyright (c) 2013 - Jeremy Long. All Rights Reserved.
|
||||
<dependency>
|
||||
<groupId>org.apache.ant</groupId>
|
||||
<artifactId>ant</artifactId>
|
||||
<version>1.9.4</version>
|
||||
<scope>provided</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.apache.ant</groupId>
|
||||
<artifactId>ant-testutil</artifactId>
|
||||
<version>1.9.4</version>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
|
||||
@@ -12,18 +12,25 @@
|
||||
<format>zip</format>
|
||||
</formats>
|
||||
<includeBaseDirectory>false</includeBaseDirectory>
|
||||
<fileSets>
|
||||
<!--fileSets>
|
||||
<fileSet>
|
||||
<outputDirectory>/</outputDirectory>
|
||||
<outputDirectory>dependency-check</outputDirectory>
|
||||
<directory>${project.build.directory}</directory>
|
||||
<includes>
|
||||
<include>dependency-check*.jar</include>
|
||||
</includes>
|
||||
</fileSet>
|
||||
</fileSets>
|
||||
</fileSets-->
|
||||
<files>
|
||||
<file>
|
||||
<source>${project.build.directory}/${project.artifactId}-${project.version}.jar</source>
|
||||
<outputDirectory>dependency-check-ant</outputDirectory>
|
||||
<destName>dependency-check-ant.jar</destName>
|
||||
</file>
|
||||
</files>
|
||||
<dependencySets>
|
||||
<dependencySet>
|
||||
<outputDirectory>/lib</outputDirectory>
|
||||
<outputDirectory>dependency-check-ant/lib</outputDirectory>
|
||||
<scope>runtime</scope>
|
||||
</dependencySet>
|
||||
</dependencySets>
|
||||
|
||||
@@ -0,0 +1,273 @@
|
||||
/*
|
||||
* 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) {
|
||||
if (task != null) {
|
||||
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;
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,127 @@
|
||||
/*
|
||||
* 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 Jeremy Long. All Rights Reserved.
|
||||
*/
|
||||
package org.owasp.dependencycheck.taskdefs;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import org.apache.tools.ant.BuildException;
|
||||
import org.apache.tools.ant.Project;
|
||||
import org.apache.tools.ant.Task;
|
||||
import org.owasp.dependencycheck.utils.Settings;
|
||||
import org.slf4j.impl.StaticLoggerBinder;
|
||||
|
||||
/**
|
||||
* An Ant task definition to execute dependency-check during an Ant build.
|
||||
*
|
||||
* @author Jeremy Long
|
||||
*/
|
||||
public class Purge extends Task {
|
||||
|
||||
/**
|
||||
* The properties file location.
|
||||
*/
|
||||
private static final String PROPERTIES_FILE = "task.properties";
|
||||
|
||||
/**
|
||||
* Construct a new DependencyCheckTask.
|
||||
*/
|
||||
public Purge() {
|
||||
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 location of the data directory that contains
|
||||
*/
|
||||
private String dataDirectory = null;
|
||||
|
||||
/**
|
||||
* Get the value of dataDirectory.
|
||||
*
|
||||
* @return the value of dataDirectory
|
||||
*/
|
||||
public String getDataDirectory() {
|
||||
return dataDirectory;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the value of dataDirectory.
|
||||
*
|
||||
* @param dataDirectory new value of dataDirectory
|
||||
*/
|
||||
public void setDataDirectory(String dataDirectory) {
|
||||
this.dataDirectory = dataDirectory;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void execute() throws BuildException {
|
||||
populateSettings();
|
||||
File db;
|
||||
try {
|
||||
db = new File(Settings.getDataDirectory(), "dc.h2.db");
|
||||
if (db.exists()) {
|
||||
if (db.delete()) {
|
||||
log("Database file purged; local copy of the NVD has been removed", Project.MSG_INFO);
|
||||
} else {
|
||||
log(String.format("Unable to delete '%s'; please delete the file manually", db.getAbsolutePath()), Project.MSG_ERR);
|
||||
}
|
||||
} else {
|
||||
log(String.format("Unable to purge database; the database file does not exists: %s", db.getAbsolutePath()), Project.MSG_ERR);
|
||||
}
|
||||
} catch (IOException ex) {
|
||||
log("Unable to delete the database", Project.MSG_ERR);
|
||||
} finally {
|
||||
Settings.cleanup(true);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Takes the properties supplied and updates the dependency-check settings. Additionally, this sets the system properties
|
||||
* required to change the proxy server, port, and connection timeout.
|
||||
*/
|
||||
protected void populateSettings() {
|
||||
Settings.initialize();
|
||||
InputStream taskProperties = null;
|
||||
try {
|
||||
taskProperties = this.getClass().getClassLoader().getResourceAsStream(PROPERTIES_FILE);
|
||||
Settings.mergeProperties(taskProperties);
|
||||
} catch (IOException ex) {
|
||||
log("Unable to load the dependency-check ant task.properties file.", ex, Project.MSG_WARN);
|
||||
} finally {
|
||||
if (taskProperties != null) {
|
||||
try {
|
||||
taskProperties.close();
|
||||
} catch (IOException ex) {
|
||||
log("", ex, Project.MSG_DEBUG);
|
||||
}
|
||||
}
|
||||
}
|
||||
if (dataDirectory != null) {
|
||||
Settings.setString(Settings.KEYS.DATA_DIRECTORY, dataDirectory);
|
||||
} else {
|
||||
final File jarPath = new File(Purge.class.getProtectionDomain().getCodeSource().getLocation().getPath());
|
||||
final File base = jarPath.getParentFile();
|
||||
final String sub = Settings.getString(Settings.KEYS.DATA_DIRECTORY);
|
||||
final File dataDir = new File(base, sub);
|
||||
Settings.setString(Settings.KEYS.DATA_DIRECTORY, dataDir.getAbsolutePath());
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,437 @@
|
||||
/*
|
||||
* 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 Jeremy Long. All Rights Reserved.
|
||||
*/
|
||||
package org.owasp.dependencycheck.taskdefs;
|
||||
|
||||
import org.apache.tools.ant.BuildException;
|
||||
import org.owasp.dependencycheck.Engine;
|
||||
import org.owasp.dependencycheck.data.nvdcve.DatabaseException;
|
||||
import org.owasp.dependencycheck.utils.Settings;
|
||||
import org.slf4j.impl.StaticLoggerBinder;
|
||||
|
||||
/**
|
||||
* An Ant task definition to execute dependency-check update. This will download the latest data from the National Vulnerability
|
||||
* Database (NVD) and store a copy in the local database.
|
||||
*
|
||||
* @author Jeremy Long
|
||||
*/
|
||||
public class Update extends Purge {
|
||||
|
||||
/**
|
||||
* Construct a new UpdateTask.
|
||||
*/
|
||||
public Update() {
|
||||
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 Proxy Server.
|
||||
*/
|
||||
private String proxyServer;
|
||||
|
||||
/**
|
||||
* Get the value of proxyServer.
|
||||
*
|
||||
* @return the value of proxyServer
|
||||
*/
|
||||
public String getProxyServer() {
|
||||
return proxyServer;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the value of proxyServer.
|
||||
*
|
||||
* @param server new value of proxyServer
|
||||
*/
|
||||
public void setProxyServer(String server) {
|
||||
this.proxyServer = server;
|
||||
}
|
||||
|
||||
/**
|
||||
* The Proxy Port.
|
||||
*/
|
||||
private String proxyPort;
|
||||
|
||||
/**
|
||||
* Get the value of proxyPort.
|
||||
*
|
||||
* @return the value of proxyPort
|
||||
*/
|
||||
public String getProxyPort() {
|
||||
return proxyPort;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the value of proxyPort.
|
||||
*
|
||||
* @param proxyPort new value of proxyPort
|
||||
*/
|
||||
public void setProxyPort(String proxyPort) {
|
||||
this.proxyPort = proxyPort;
|
||||
}
|
||||
/**
|
||||
* The Proxy username.
|
||||
*/
|
||||
private String proxyUsername;
|
||||
|
||||
/**
|
||||
* Get the value of proxyUsername.
|
||||
*
|
||||
* @return the value of proxyUsername
|
||||
*/
|
||||
public String getProxyUsername() {
|
||||
return proxyUsername;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the value of proxyUsername.
|
||||
*
|
||||
* @param proxyUsername new value of proxyUsername
|
||||
*/
|
||||
public void setProxyUsername(String proxyUsername) {
|
||||
this.proxyUsername = proxyUsername;
|
||||
}
|
||||
/**
|
||||
* The Proxy password.
|
||||
*/
|
||||
private String proxyPassword;
|
||||
|
||||
/**
|
||||
* Get the value of proxyPassword.
|
||||
*
|
||||
* @return the value of proxyPassword
|
||||
*/
|
||||
public String getProxyPassword() {
|
||||
return proxyPassword;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the value of proxyPassword.
|
||||
*
|
||||
* @param proxyPassword new value of proxyPassword
|
||||
*/
|
||||
public void setProxyPassword(String proxyPassword) {
|
||||
this.proxyPassword = proxyPassword;
|
||||
}
|
||||
/**
|
||||
* The Connection Timeout.
|
||||
*/
|
||||
private String connectionTimeout;
|
||||
|
||||
/**
|
||||
* Get the value of connectionTimeout.
|
||||
*
|
||||
* @return the value of connectionTimeout
|
||||
*/
|
||||
public String getConnectionTimeout() {
|
||||
return connectionTimeout;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the value of connectionTimeout.
|
||||
*
|
||||
* @param connectionTimeout new value of connectionTimeout
|
||||
*/
|
||||
public void setConnectionTimeout(String connectionTimeout) {
|
||||
this.connectionTimeout = connectionTimeout;
|
||||
}
|
||||
/**
|
||||
* The database driver name; such as org.h2.Driver.
|
||||
*/
|
||||
private String databaseDriverName;
|
||||
|
||||
/**
|
||||
* Get the value of databaseDriverName.
|
||||
*
|
||||
* @return the value of databaseDriverName
|
||||
*/
|
||||
public String getDatabaseDriverName() {
|
||||
return databaseDriverName;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the value of databaseDriverName.
|
||||
*
|
||||
* @param databaseDriverName new value of databaseDriverName
|
||||
*/
|
||||
public void setDatabaseDriverName(String databaseDriverName) {
|
||||
this.databaseDriverName = databaseDriverName;
|
||||
}
|
||||
|
||||
/**
|
||||
* The path to the database driver JAR file if it is not on the class path.
|
||||
*/
|
||||
private String databaseDriverPath;
|
||||
|
||||
/**
|
||||
* Get the value of databaseDriverPath.
|
||||
*
|
||||
* @return the value of databaseDriverPath
|
||||
*/
|
||||
public String getDatabaseDriverPath() {
|
||||
return databaseDriverPath;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the value of databaseDriverPath.
|
||||
*
|
||||
* @param databaseDriverPath new value of databaseDriverPath
|
||||
*/
|
||||
public void setDatabaseDriverPath(String databaseDriverPath) {
|
||||
this.databaseDriverPath = databaseDriverPath;
|
||||
}
|
||||
/**
|
||||
* The database connection string.
|
||||
*/
|
||||
private String connectionString;
|
||||
|
||||
/**
|
||||
* Get the value of connectionString.
|
||||
*
|
||||
* @return the value of connectionString
|
||||
*/
|
||||
public String getConnectionString() {
|
||||
return connectionString;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the value of connectionString.
|
||||
*
|
||||
* @param connectionString new value of connectionString
|
||||
*/
|
||||
public void setConnectionString(String connectionString) {
|
||||
this.connectionString = connectionString;
|
||||
}
|
||||
/**
|
||||
* The user name for connecting to the database.
|
||||
*/
|
||||
private String databaseUser;
|
||||
|
||||
/**
|
||||
* Get the value of databaseUser.
|
||||
*
|
||||
* @return the value of databaseUser
|
||||
*/
|
||||
public String getDatabaseUser() {
|
||||
return databaseUser;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the value of databaseUser.
|
||||
*
|
||||
* @param databaseUser new value of databaseUser
|
||||
*/
|
||||
public void setDatabaseUser(String databaseUser) {
|
||||
this.databaseUser = databaseUser;
|
||||
}
|
||||
|
||||
/**
|
||||
* The password to use when connecting to the database.
|
||||
*/
|
||||
private String databasePassword;
|
||||
|
||||
/**
|
||||
* Get the value of databasePassword.
|
||||
*
|
||||
* @return the value of databasePassword
|
||||
*/
|
||||
public String getDatabasePassword() {
|
||||
return databasePassword;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the value of databasePassword.
|
||||
*
|
||||
* @param databasePassword new value of databasePassword
|
||||
*/
|
||||
public void setDatabasePassword(String databasePassword) {
|
||||
this.databasePassword = databasePassword;
|
||||
}
|
||||
|
||||
/**
|
||||
* The url for the modified NVD CVE (1.2 schema).
|
||||
*/
|
||||
private String cveUrl12Modified;
|
||||
|
||||
/**
|
||||
* Get the value of cveUrl12Modified.
|
||||
*
|
||||
* @return the value of cveUrl12Modified
|
||||
*/
|
||||
public String getCveUrl12Modified() {
|
||||
return cveUrl12Modified;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the value of cveUrl12Modified.
|
||||
*
|
||||
* @param cveUrl12Modified new value of cveUrl12Modified
|
||||
*/
|
||||
public void setCveUrl12Modified(String cveUrl12Modified) {
|
||||
this.cveUrl12Modified = cveUrl12Modified;
|
||||
}
|
||||
|
||||
/**
|
||||
* The url for the modified NVD CVE (2.0 schema).
|
||||
*/
|
||||
private String cveUrl20Modified;
|
||||
|
||||
/**
|
||||
* Get the value of cveUrl20Modified.
|
||||
*
|
||||
* @return the value of cveUrl20Modified
|
||||
*/
|
||||
public String getCveUrl20Modified() {
|
||||
return cveUrl20Modified;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the value of cveUrl20Modified.
|
||||
*
|
||||
* @param cveUrl20Modified new value of cveUrl20Modified
|
||||
*/
|
||||
public void setCveUrl20Modified(String cveUrl20Modified) {
|
||||
this.cveUrl20Modified = cveUrl20Modified;
|
||||
}
|
||||
|
||||
/**
|
||||
* Base Data Mirror URL for CVE 1.2.
|
||||
*/
|
||||
private String cveUrl12Base;
|
||||
|
||||
/**
|
||||
* Get the value of cveUrl12Base.
|
||||
*
|
||||
* @return the value of cveUrl12Base
|
||||
*/
|
||||
public String getCveUrl12Base() {
|
||||
return cveUrl12Base;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the value of cveUrl12Base.
|
||||
*
|
||||
* @param cveUrl12Base new value of cveUrl12Base
|
||||
*/
|
||||
public void setCveUrl12Base(String cveUrl12Base) {
|
||||
this.cveUrl12Base = cveUrl12Base;
|
||||
}
|
||||
|
||||
/**
|
||||
* Data Mirror URL for CVE 2.0.
|
||||
*/
|
||||
private String cveUrl20Base;
|
||||
|
||||
/**
|
||||
* Get the value of cveUrl20Base.
|
||||
*
|
||||
* @return the value of cveUrl20Base
|
||||
*/
|
||||
public String getCveUrl20Base() {
|
||||
return cveUrl20Base;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the value of cveUrl20Base.
|
||||
*
|
||||
* @param cveUrl20Base new value of cveUrl20Base
|
||||
*/
|
||||
public void setCveUrl20Base(String cveUrl20Base) {
|
||||
this.cveUrl20Base = cveUrl20Base;
|
||||
}
|
||||
|
||||
/**
|
||||
* The number of hours to wait before re-checking for updates.
|
||||
*/
|
||||
private Integer cveValidForHours;
|
||||
|
||||
/**
|
||||
* Get the value of cveValidForHours.
|
||||
*
|
||||
* @return the value of cveValidForHours
|
||||
*/
|
||||
public Integer getCveValidForHours() {
|
||||
return cveValidForHours;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the value of cveValidForHours.
|
||||
*
|
||||
* @param cveValidForHours new value of cveValidForHours
|
||||
*/
|
||||
public void setCveValidForHours(Integer cveValidForHours) {
|
||||
this.cveValidForHours = cveValidForHours;
|
||||
}
|
||||
|
||||
/**
|
||||
* Executes the update by initializing the settings, downloads the NVD XML data, and then processes the data storing it in the
|
||||
* local database.
|
||||
*
|
||||
* @throws BuildException thrown if a connection to the local database cannot be made.
|
||||
*/
|
||||
@Override
|
||||
public void execute() throws BuildException {
|
||||
populateSettings();
|
||||
Engine engine = null;
|
||||
try {
|
||||
engine = new Engine(Update.class.getClassLoader());
|
||||
engine.doUpdates();
|
||||
} catch (DatabaseException ex) {
|
||||
throw new BuildException("Unable to connect to the dependency-check database; unable to update the NVD data", ex);
|
||||
} finally {
|
||||
Settings.cleanup(true);
|
||||
if (engine != null) {
|
||||
engine.cleanup();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Takes the properties supplied and updates the dependency-check settings. Additionally, this sets the system properties
|
||||
* required to change the proxy server, port, and connection timeout.
|
||||
*
|
||||
* @throws BuildException thrown when an invalid setting is configured.
|
||||
*/
|
||||
@Override
|
||||
protected void populateSettings() throws BuildException {
|
||||
super.populateSettings();
|
||||
Settings.setStringIfNotEmpty(Settings.KEYS.PROXY_SERVER, proxyServer);
|
||||
Settings.setStringIfNotEmpty(Settings.KEYS.PROXY_PORT, proxyPort);
|
||||
Settings.setStringIfNotEmpty(Settings.KEYS.PROXY_USERNAME, proxyUsername);
|
||||
Settings.setStringIfNotEmpty(Settings.KEYS.PROXY_PASSWORD, proxyPassword);
|
||||
Settings.setStringIfNotEmpty(Settings.KEYS.CONNECTION_TIMEOUT, connectionTimeout);
|
||||
Settings.setStringIfNotEmpty(Settings.KEYS.DB_DRIVER_NAME, databaseDriverName);
|
||||
Settings.setStringIfNotEmpty(Settings.KEYS.DB_DRIVER_PATH, databaseDriverPath);
|
||||
Settings.setStringIfNotEmpty(Settings.KEYS.DB_CONNECTION_STRING, connectionString);
|
||||
Settings.setStringIfNotEmpty(Settings.KEYS.DB_USER, databaseUser);
|
||||
Settings.setStringIfNotEmpty(Settings.KEYS.DB_PASSWORD, databasePassword);
|
||||
Settings.setStringIfNotEmpty(Settings.KEYS.CVE_MODIFIED_12_URL, cveUrl12Modified);
|
||||
Settings.setStringIfNotEmpty(Settings.KEYS.CVE_MODIFIED_20_URL, cveUrl20Modified);
|
||||
Settings.setStringIfNotEmpty(Settings.KEYS.CVE_SCHEMA_1_2, cveUrl12Base);
|
||||
Settings.setStringIfNotEmpty(Settings.KEYS.CVE_SCHEMA_2_0, cveUrl20Base);
|
||||
if (cveValidForHours != null) {
|
||||
if (cveValidForHours >= 0) {
|
||||
Settings.setInt(Settings.KEYS.CVE_CHECK_VALID_FOR_HOURS, cveValidForHours);
|
||||
} else {
|
||||
throw new BuildException("Invalid setting: `cpeValidForHours` must be 0 or greater");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,11 +1,4 @@
|
||||
/**
|
||||
* <html>
|
||||
* <head>
|
||||
* <title>org.owasp.dependencycheck.taskdefs</title>
|
||||
* </head>
|
||||
* <body>
|
||||
* This package includes the Ant task definitions.
|
||||
* </body>
|
||||
* </html>
|
||||
* This package includes the a slf4j logging implementation that wraps the Ant logger.
|
||||
*/
|
||||
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 org.slf4j.LoggerFactory class with an actual instance of org.slf4j.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;
|
||||
@@ -0,0 +1,3 @@
|
||||
dependency-check=org.owasp.dependencycheck.taskdefs.Check
|
||||
dependency-check-purge=org.owasp.dependencycheck.taskdefs.Purge
|
||||
dependency-check-update=org.owasp.dependencycheck.taskdefs.Update
|
||||
@@ -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
|
||||
@@ -1,2 +1,2 @@
|
||||
# the path to the data directory
|
||||
data.directory=dependency-check-data
|
||||
data.directory=data/3.0
|
||||
|
||||
@@ -1,3 +0,0 @@
|
||||
# define custom tasks here
|
||||
|
||||
dependencycheck=org.owasp.dependencycheck.taskdefs.DependencyCheckTask
|
||||
19
dependency-check-ant/src/site/markdown/config-purge.md
Normal file
19
dependency-check-ant/src/site/markdown/config-purge.md
Normal file
@@ -0,0 +1,19 @@
|
||||
Configuration
|
||||
====================
|
||||
The dependency-check-purge task deletes the local copy of the NVD. This task
|
||||
should rarely be used, if ever. This is included as a convenience method in
|
||||
the rare circumstance that the local H2 database because corrupt.
|
||||
|
||||
```xml
|
||||
<target name="dependency-check-purge" description="Dependency-Check purge">
|
||||
<dependency-check-purge />
|
||||
</target>
|
||||
```
|
||||
|
||||
Configuration: dependency-check-purge Task
|
||||
--------------------
|
||||
The following properties can be set on the dependency-check-purge task.
|
||||
|
||||
Property | Description | Default Value
|
||||
----------------------|----------------------------------------------------------------|------------------
|
||||
dataDirectory | Data directory that is used to store the local copy of the NVD | data
|
||||
44
dependency-check-ant/src/site/markdown/config-update.md
Normal file
44
dependency-check-ant/src/site/markdown/config-update.md
Normal file
@@ -0,0 +1,44 @@
|
||||
Configuration
|
||||
====================
|
||||
The dependency-check-update task downloads and updates the local copy of the NVD.
|
||||
There are several reasons that one may want to use this task; primarily, creating
|
||||
an update that will be run only once a day or once every few days (but not greater
|
||||
then 7 days) and then use the `autoUpdate="false"` setting on individual
|
||||
dependency-check scans. See [Internet Access Required](https://jeremylong.github.io/DependencyCheck/data/index.html)
|
||||
for more information on why this task would be used.
|
||||
|
||||
```xml
|
||||
<target name="dependency-check-update" description="Dependency-Check Update">
|
||||
<dependency-check-update />
|
||||
</target>
|
||||
```
|
||||
|
||||
Configuration: dependency-check-update Task
|
||||
--------------------
|
||||
The following properties can be set on the dependency-check task.
|
||||
|
||||
Property | Description | Default Value
|
||||
----------------------|------------------------------------|------------------
|
||||
proxyServer | The Proxy Server. |
|
||||
proxyPort | The Proxy Port. |
|
||||
proxyUsername | Defines the proxy user name. |
|
||||
proxyPassword | Defines the proxy password. |
|
||||
connectionTimeout | The URL Connection Timeout. |
|
||||
|
||||
Advanced Configuration
|
||||
====================
|
||||
The following properties can be configured in the plugin. However, they are less frequently changed. One exception
|
||||
may be the cvedUrl properties, which can be used to host a mirror of the NVD within an enterprise environment.
|
||||
|
||||
Property | Description | Default Value
|
||||
---------------------|-------------------------------------------------------------------------------------------------------|------------------
|
||||
cveUrl12Modified | URL for the modified CVE 1.2. | https://nvd.nist.gov/download/nvdcve-Modified.xml.gz
|
||||
cveUrl20Modified | URL for the modified CVE 2.0. | https://nvd.nist.gov/feeds/xml/cve/nvdcve-2.0-Modified.xml.gz
|
||||
cveUrl12Base | Base URL for each year's CVE 1.2, the %d will be replaced with the year. | https://nvd.nist.gov/download/nvdcve-%d.xml.gz
|
||||
cveUrl20Base | Base URL for each year's CVE 2.0, the %d will be replaced with the year. | https://nvd.nist.gov/feeds/xml/cve/nvdcve-2.0-%d.xml.gz
|
||||
dataDirectory | Data directory that is used to store the local copy of the NVD. This should generally not be changed. | data
|
||||
databaseDriverName | The name of the database driver. Example: org.h2.Driver. |
|
||||
databaseDriverPath | The path to the database driver JAR file; only used if the driver is not in the class path. |
|
||||
connectionString | The connection string used to connect to the database. |
|
||||
databaseUser | The username used when connecting to the database. |
|
||||
databasePassword | The password used when connecting to the database. |
|
||||
@@ -1,5 +1,11 @@
|
||||
Configuration
|
||||
====================
|
||||
Once dependency-check-ant has been [installed](index.html) the defined tasks can be used.
|
||||
|
||||
* dependency-check - the primary task used to check the project dependencies. Configuration options are below.
|
||||
* dependency-check-purge - deletes the local copy of the NVD; this should rarely be used (if ever). See the [purge configuration](config-purge.html) for more information.
|
||||
* dependency-check-update - downloads and updates the local copy of the NVD. See the [update configuration](config-update.html) for more information.
|
||||
|
||||
To configure the dependency-check task you can add it to a target and include a
|
||||
file based [resource collection](http://ant.apache.org/manual/Types/resources.html#collection)
|
||||
such as a [FileSet](http://ant.apache.org/manual/Types/fileset.html), [DirSet](http://ant.apache.org/manual/Types/dirset.html),
|
||||
@@ -8,7 +14,7 @@ the project's dependencies.
|
||||
|
||||
```xml
|
||||
<target name="dependency-check" description="Dependency-Check Analysis">
|
||||
<dependency-check applicationname="Hello World"
|
||||
<dependency-check projectname="Hello World"
|
||||
reportoutputdirectory="${basedir}"
|
||||
reportformat="ALL">
|
||||
|
||||
@@ -19,24 +25,24 @@ the project's dependencies.
|
||||
</target>
|
||||
```
|
||||
|
||||
Configuration
|
||||
====================
|
||||
The following properties can be set on the dependency-check-maven plugin.
|
||||
Configuration: dependency-check Task
|
||||
--------------------
|
||||
The following properties can be set on the dependency-check-update task.
|
||||
|
||||
Property | Description | Default Value
|
||||
---------------------|------------------------------------|------------------
|
||||
autoUpdate | Sets whether auto-updating of the NVD CVE/CPE data is enabled. It is not recommended that this be turned to false. | true
|
||||
externalReport | When using as a Site plugin this parameter sets whether or not the external report format should be used. | false
|
||||
outputDirectory | The location to write the report(s). Note, this is not used if generating the report as part of a `mvn site` build | 'target'
|
||||
failBuildOnCVSS | Specifies if the build should be failed if a CVSS score above a specified level is identified. The default is 11 which means since the CVSS scores are 0-10, by default the build will never fail. | 11
|
||||
format | The report format to be generated (HTML, XML, VULN, ALL). This configuration option has no affect if using this within the Site plugin unless the externalReport is set to true. | HTML
|
||||
logFile | The file path to write verbose logging information. |
|
||||
suppressionFile | The file path to the XML suppression file \- used to suppress [false positives](../suppression.html) |
|
||||
proxyServer | The Proxy Server. |
|
||||
proxyPort | The Proxy Port. |
|
||||
proxyUsername | Defines the proxy user name. |
|
||||
proxyPassword | Defines the proxy password. |
|
||||
connectionTimeout | The URL Connection Timeout. |
|
||||
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
|
||||
cveValidForHours | Sets the number of hours to wait before checking for new updates from the NVD | 4
|
||||
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
|
||||
projectName | The name of the project being scanned. | Dependency-Check
|
||||
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
|
||||
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'
|
||||
suppressionFile | The file path to the XML suppression file \- used to suppress [false positives](../general/suppression.html) |
|
||||
proxyServer | The Proxy Server. |
|
||||
proxyPort | The Proxy Port. |
|
||||
proxyUsername | Defines the proxy user name. |
|
||||
proxyPassword | Defines the proxy password. |
|
||||
connectionTimeout | The URL Connection Timeout. |
|
||||
|
||||
Analyzer Configuration
|
||||
====================
|
||||
@@ -46,31 +52,39 @@ Note, that specific analyzers will automatically disable themselves if no file
|
||||
types that they support are detected - so specifically disabling them may not
|
||||
be needed.
|
||||
|
||||
Property | Description | Default Value
|
||||
------------------------|---------------------------------------------------------------------------|------------------
|
||||
archiveAnalyzerEnabled | Sets whether the Archive Analyzer will be used. | true
|
||||
zipExtensions | A comma-separated list of additional file extensions to be treated like a ZIP file, the contents will be extracted and analyzed. |
|
||||
jarAnalyzer | Sets whether the Jar Analyzer will be used. | true
|
||||
centralAnalyzerEnabled | Sets whether the Central Analyzer will be used. **Disabling this analyzer is not recommended as it could lead to false negatives (e.g. libraries that have vulnerabilities may not be reported correctly).** If this analyzer is being disabled there is a good chance you also want to disable the Nexus Analyzer (see below). | true
|
||||
nexusAnalyzerEnabled | Sets whether Nexus Analyzer will be used. This analyzer is superceded by the Central Analyzer; however, you can configure this to run against a Nexus Pro installation. | true
|
||||
nexusUrl | Defines the Nexus Pro URL. If not set the Nexus Analyzer will be disabled. |
|
||||
nexusUsesProxy | Whether or not the defined proxy should be used when connecting to Nexus. | true
|
||||
nuspecAnalyzerEnabled | Sets whether or not the .NET Nuget Nuspec Analyzer will be used. | true
|
||||
assemblyAnalyzerEnabled | Sets whether or not the .NET Assembly Analyzer should be used. | true
|
||||
pathToMono | The path to Mono for .NET assembly analysis on non-windows systems. |
|
||||
Property | Description | Default Value
|
||||
------------------------------|---------------------------------------------------------------------------|------------------
|
||||
archiveAnalyzerEnabled | Sets whether the Archive Analyzer will be used. | true
|
||||
zipExtensions | A comma-separated list of additional file extensions to be treated like a ZIP file, the contents will be extracted and analyzed. |
|
||||
jarAnalyzer | Sets whether the Jar Analyzer will be used. | true
|
||||
centralAnalyzerEnabled | Sets whether the Central Analyzer will be used. **Disabling this analyzer is not recommended as it could lead to false negatives (e.g. libraries that have vulnerabilities may not be reported correctly).** If this analyzer is being disabled there is a good chance you also want to disable the Nexus Analyzer (see below). | true
|
||||
nexusAnalyzerEnabled | Sets whether Nexus Analyzer will be used. This analyzer is superceded by the Central Analyzer; however, you can configure this to run against a Nexus Pro installation. | true
|
||||
nexusUrl | Defines the Nexus 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
|
||||
pyDistributionAnalyzerEnabled | Sets whether the Python Distribution Analyzer will be used. | true
|
||||
pyPackageAnalyzerEnabled | Sets whether the Python Package Analyzer will be used. | true
|
||||
rubygemsAnalyzerEnabled | Sets whether the Ruby Gemspec Analyzer will be used. | true
|
||||
opensslAnalyzerEnabled | Sets whether or not the openssl Analyzer should be used. | true
|
||||
cmakeAnalyzerEnabled | Sets whether or not the CMake Analyzer should be used. | true
|
||||
autoconfAnalyzerEnabled | Sets whether or not the autoconf Analyzer should be used. | true
|
||||
composerAnalyzerEnabled | Sets whether or not the PHP Composer Lock File Analyzer should be used. | true
|
||||
nodeAnalyzerEnabled | Sets whether or not the Node.js Analyzer should 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
|
||||
pathToMono | The path to Mono for .NET assembly analysis on non-windows systems. |
|
||||
|
||||
Advanced Configuration
|
||||
====================
|
||||
The following properties can be configured in the plugin. However, they are less frequently changed. One exception
|
||||
may be the cvedUrl properties, which can be used to host a mirror of the NVD within an enterprise environment.
|
||||
|
||||
Property | Description | Default Value
|
||||
---------------------|-------------------------------------------------------------------------|------------------
|
||||
cveUrl12Modified | URL for the modified CVE 1.2 | http://nvd.nist.gov/download/nvdcve-modified.xml
|
||||
cveUrl20Modified | URL for the modified CVE 2.0 | http://static.nvd.nist.gov/feeds/xml/cve/nvdcve-2.0-modified.xml
|
||||
cveUrl12Base | Base URL for each year's CVE 1.2, the %d will be replaced with the year | http://nvd.nist.gov/download/nvdcve-%d.xml
|
||||
cveUrl20Base | Base URL for each year's CVE 2.0, the %d will be replaced with the year | http://static.nvd.nist.gov/feeds/xml/cve/nvdcve-2.0-%d.xml
|
||||
dataDirectory | Data directory to hold SQL CVEs contents. This should generally not be changed. |
|
||||
Property | Description | Default Value
|
||||
---------------------|--------------------------------------------------------------------------|------------------
|
||||
cveUrl12Modified | URL for the modified CVE 1.2. | http://nvd.nist.gov/download/nvdcve-modified.xml
|
||||
cveUrl20Modified | URL for the modified CVE 2.0. | http://static.nvd.nist.gov/feeds/xml/cve/nvdcve-2.0-modified.xml
|
||||
cveUrl12Base | Base URL for each year's CVE 1.2, the %d will be replaced with the year. | http://nvd.nist.gov/download/nvdcve-%d.xml
|
||||
cveUrl20Base | Base URL for each year's CVE 2.0, the %d will be replaced with the year. | http://static.nvd.nist.gov/feeds/xml/cve/nvdcve-2.0-%d.xml
|
||||
dataDirectory | Data directory that is used to store the local copy of the NVD. This should generally not be changed. | data
|
||||
databaseDriverName | The name of the database driver. Example: org.h2.Driver. |
|
||||
databaseDriverPath | The path to the database driver JAR file; only used if the driver is not in the class path. |
|
||||
connectionString | The connection string used to connect to the database. |
|
||||
|
||||
35
dependency-check-ant/src/site/markdown/index.md.vm
Normal file
35
dependency-check-ant/src/site/markdown/index.md.vm
Normal file
@@ -0,0 +1,35 @@
|
||||
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
|
||||
====================
|
||||
1. Download dependency-check-ant from [bintray here](http://dl.bintray.com/jeremy-long/owasp/dependency-check-ant-${project.version}-release.zip).
|
||||
2. Unzip the archive
|
||||
3. Add the taskdef to your build.xml:
|
||||
|
||||
```xml
|
||||
<!-- Set the value to the installation directory's path -->
|
||||
<property name="dependency-check.home" value="C:/tools/dependency-check-ant"/>
|
||||
<path id="dependency-check.path">
|
||||
<pathelement location="${dependency-check.home}/dependency-check-ant.jar"/>
|
||||
</path>
|
||||
<taskdef resource="dependency-check-taskdefs.properties">
|
||||
<classpath refid="dependency-check.path" />
|
||||
</taskdef>
|
||||
```
|
||||
4. Use the defined taskdefs:
|
||||
* [dependency-check](configuration.html) - the primary task used to check the project dependencies.
|
||||
* [dependency-check-purge](config-purge.html) - deletes the local copy of the NVD; this should rarely be used (if ever).
|
||||
* [dependency-check-update](config-update.html) - downloads and updates the local copy of the NVD.
|
||||
|
||||
|
||||
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,26 +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:
|
||||
|
||||
```xml
|
||||
<taskdef name="dependency-check" classname="org.owasp.dependencycheck.taskdefs.DependencyCheckTask"/>
|
||||
```
|
||||
|
||||
If you do not want to install dependency-check-ant into your ant's lib directory when you define the task def you
|
||||
must add the classpath to the taskdef:
|
||||
|
||||
```xml
|
||||
<taskdef name="dependency-check" classname="org.owasp.dependencycheck.taskdefs.DependencyCheckTask">
|
||||
<classpath path="[path]/[to]/dependency-check-ant-${project.version}.jar"/>
|
||||
</taskdef>
|
||||
```
|
||||
|
||||
It is important to understand that the first time this task is executed it may
|
||||
take 20 minutes or more as it downloads and processes the data from the National
|
||||
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,33 +0,0 @@
|
||||
Usage
|
||||
====================
|
||||
First, add the dependency-check-ant taskdef to your build.xml (see the [installation guide](installation.html):
|
||||
|
||||
```xml
|
||||
<taskdef name="dependency-check" classname="org.owasp.dependencycheck.taskdefs.DependencyCheckTask"/>
|
||||
```
|
||||
|
||||
Or
|
||||
|
||||
```xml
|
||||
<taskdef name="dependency-check" classname="org.owasp.dependencycheck.taskdefs.DependencyCheckTask">
|
||||
<classpath path="[path]/[to]/dependency-check-ant-${project.version}.jar"/>
|
||||
</taskdef>
|
||||
```
|
||||
|
||||
Next, add the task to a target of your choosing:
|
||||
|
||||
```xml
|
||||
<target name="dependency-check" description="Dependency-Check Analysis">
|
||||
<dependency-check applicationname="Hello World"
|
||||
autoupdate="true"
|
||||
reportoutputdirectory="${basedir}"
|
||||
reportformat="HTML">
|
||||
|
||||
<fileset dir="lib">
|
||||
<include name="**/*.jar"/>
|
||||
</fileset>
|
||||
</dependency-check>
|
||||
</target>
|
||||
```
|
||||
|
||||
See the [configuration guide](configuration.html) for more information.
|
||||
File diff suppressed because one or more lines are too long
|
After Width: | Height: | Size: 10 KiB |
@@ -18,18 +18,18 @@ Copyright (c) 2013 Jeremy Long. All Rights Reserved.
|
||||
-->
|
||||
<project name="dependency-check-ant">
|
||||
<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>
|
||||
<body>
|
||||
<breadcrumbs>
|
||||
<item name="dependency-check" href="../index.html"/>
|
||||
</breadcrumbs>
|
||||
<menu name="Getting Started">
|
||||
<item name="Installation" href="installation.html"/>
|
||||
<item name="Usage" href="usage.html"/>
|
||||
<item name="Installation" href="index.html"/>
|
||||
<item name="Configuration" href="configuration.html"/>
|
||||
</menu>
|
||||
<menu ref="Project Documentation" />
|
||||
<menu ref="reports" />
|
||||
</body>
|
||||
</project>
|
||||
@@ -18,34 +18,41 @@
|
||||
package org.owasp.dependencycheck.taskdefs;
|
||||
|
||||
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.Before;
|
||||
import org.junit.Rule;
|
||||
import org.junit.Test;
|
||||
import org.owasp.dependencycheck.data.nvdcve.BaseDBTestCase;
|
||||
import org.junit.rules.ExpectedException;
|
||||
import org.owasp.dependencycheck.BaseDBTestCase;
|
||||
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 {
|
||||
//TODO: The use of deprecated class BuildFileTestcan possibly
|
||||
//be replaced with BuildFileRule. However, it currently isn't included in the ant-testutil jar.
|
||||
//This should be fixed in ant-testutil 1.9.5, so we can check back once that has been released.
|
||||
//Reference: http://mail-archives.apache.org/mod_mbox/ant-user/201406.mbox/%3C000001cf87ba$8949b690$9bdd23b0$@de%3E
|
||||
public class DependencyCheckTaskTest {
|
||||
|
||||
@Rule
|
||||
public BuildFileRule buildFileRule = new BuildFileRule();
|
||||
|
||||
@Rule
|
||||
public ExpectedException expectedException = ExpectedException.none();
|
||||
|
||||
@Before
|
||||
@Override
|
||||
public void setUp() throws Exception {
|
||||
Settings.initialize();
|
||||
BaseDBTestCase.ensureDBExists();
|
||||
final String buildFile = this.getClass().getClassLoader().getResource("build.xml").getPath();
|
||||
configureProject(buildFile);
|
||||
buildFileRule.configureProject(buildFile);
|
||||
}
|
||||
|
||||
@After
|
||||
@Override
|
||||
public void tearDown() {
|
||||
//no cleanup...
|
||||
//executeTarget("cleanup");
|
||||
@@ -63,7 +70,7 @@ public class DependencyCheckTaskTest extends BuildFileTest {
|
||||
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());
|
||||
|
||||
@@ -82,7 +89,7 @@ public class DependencyCheckTaskTest extends BuildFileTest {
|
||||
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());
|
||||
}
|
||||
@@ -100,7 +107,7 @@ public class DependencyCheckTaskTest extends BuildFileTest {
|
||||
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());
|
||||
}
|
||||
|
||||
@@ -109,7 +116,7 @@ public class DependencyCheckTaskTest extends BuildFileTest {
|
||||
*/
|
||||
@Test
|
||||
public void testGetFailBuildOnCVSS() {
|
||||
expectBuildException("failCVSS", "asdfasdfscore");
|
||||
System.out.println(this.getOutput());
|
||||
expectedException.expect(BuildException.class);
|
||||
buildFileRule.executeTarget("failCVSS");
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project name="Dependency-Check Test Build" default="test.fileset" basedir=".">
|
||||
|
||||
<taskdef name="dependency-check" classname="org.owasp.dependencycheck.taskdefs.DependencyCheckTask" />
|
||||
<taskdef name="dependency-check" classname="org.owasp.dependencycheck.taskdefs.Check" />
|
||||
|
||||
<target name="test.fileset">
|
||||
<dependency-check
|
||||
|
||||
@@ -19,6 +19,6 @@ Copyright & License
|
||||
|
||||
Dependency-Check is Copyright (c) 2012-2014 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://raw.githubusercontent.com/jeremylong/DependencyCheck/master/LICENSE.txt) file for the full license.
|
||||
|
||||
Dependency-Check Command Line makes use of other open source libraries. Please see the [NOTICE.txt](https://github.com/jeremylong/DependencyCheck/dependency-check-cli/blob/master/NOTICES.txt) file for more information.
|
||||
Dependency-Check Command Line makes use of other open source libraries. Please see the [NOTICE.txt](https://raw.githubusercontent.com/jeremylong/DependencyCheck/master/dependency-check-cli/NOTICE.txt) file for more information.
|
||||
|
||||
@@ -20,7 +20,7 @@ Copyright (c) 2012 - Jeremy Long. All Rights Reserved.
|
||||
<parent>
|
||||
<groupId>org.owasp</groupId>
|
||||
<artifactId>dependency-check-parent</artifactId>
|
||||
<version>1.2.9</version>
|
||||
<version>1.3.5</version>
|
||||
</parent>
|
||||
|
||||
<artifactId>dependency-check-cli</artifactId>
|
||||
@@ -44,6 +44,7 @@ Copyright (c) 2012 - Jeremy Long. All Rights Reserved.
|
||||
<directory>src/main/resources</directory>
|
||||
<includes>
|
||||
<include>**/*.properties</include>
|
||||
<include>logback.xml</include>
|
||||
</includes>
|
||||
<filtering>true</filtering>
|
||||
</resource>
|
||||
@@ -123,10 +124,6 @@ Copyright (c) 2012 - Jeremy Long. All Rights Reserved.
|
||||
</systemProperties>
|
||||
</configuration>
|
||||
</plugin>
|
||||
<plugin>
|
||||
<groupId>org.apache.maven.plugins</groupId>
|
||||
<artifactId>maven-compiler-plugin</artifactId>
|
||||
</plugin>
|
||||
<plugin>
|
||||
<groupId>org.codehaus.mojo</groupId>
|
||||
<artifactId>appassembler-maven-plugin</artifactId>
|
||||
@@ -177,100 +174,10 @@ Copyright (c) 2012 - Jeremy Long. All Rights Reserved.
|
||||
</build>
|
||||
<reporting>
|
||||
<plugins>
|
||||
<plugin>
|
||||
<groupId>org.apache.maven.plugins</groupId>
|
||||
<artifactId>maven-project-info-reports-plugin</artifactId>
|
||||
<version>2.7</version>
|
||||
<reportSets>
|
||||
<reportSet>
|
||||
<reports>
|
||||
<report>index</report>
|
||||
<report>summary</report>
|
||||
<report>license</report>
|
||||
<report>help</report>
|
||||
</reports>
|
||||
</reportSet>
|
||||
</reportSets>
|
||||
</plugin>
|
||||
<plugin>
|
||||
<groupId>org.apache.maven.plugins</groupId>
|
||||
<artifactId>maven-javadoc-plugin</artifactId>
|
||||
<version>2.9.1</version>
|
||||
<configuration>
|
||||
<bottom>Copyright© 2012-15 Jeremy Long. All Rights Reserved.</bottom>
|
||||
</configuration>
|
||||
<reportSets>
|
||||
<reportSet>
|
||||
<id>default</id>
|
||||
<reports>
|
||||
<report>javadoc</report>
|
||||
</reports>
|
||||
</reportSet>
|
||||
</reportSets>
|
||||
</plugin>
|
||||
<plugin>
|
||||
<groupId>org.codehaus.mojo</groupId>
|
||||
<artifactId>versions-maven-plugin</artifactId>
|
||||
<version>2.1</version>
|
||||
<reportSets>
|
||||
<reportSet>
|
||||
<reports>
|
||||
<report>dependency-updates-report</report>
|
||||
<report>plugin-updates-report</report>
|
||||
</reports>
|
||||
</reportSet>
|
||||
</reportSets>
|
||||
</plugin>
|
||||
<plugin>
|
||||
<groupId>org.apache.maven.plugins</groupId>
|
||||
<artifactId>maven-jxr-plugin</artifactId>
|
||||
<version>2.4</version>
|
||||
</plugin>
|
||||
<plugin>
|
||||
<groupId>org.codehaus.mojo</groupId>
|
||||
<artifactId>cobertura-maven-plugin</artifactId>
|
||||
<version>2.6</version>
|
||||
</plugin>
|
||||
<plugin>
|
||||
<groupId>org.apache.maven.plugins</groupId>
|
||||
<artifactId>maven-surefire-report-plugin</artifactId>
|
||||
<version>2.16</version>
|
||||
<reportSets>
|
||||
<reportSet>
|
||||
<reports>
|
||||
<report>report-only</report>
|
||||
</reports>
|
||||
</reportSet>
|
||||
</reportSets>
|
||||
</plugin>
|
||||
<plugin>
|
||||
<groupId>org.codehaus.mojo</groupId>
|
||||
<artifactId>taglist-maven-plugin</artifactId>
|
||||
<version>2.4</version>
|
||||
<configuration>
|
||||
<tagListOptions>
|
||||
<tagClasses>
|
||||
<tagClass>
|
||||
<displayName>Todo Work</displayName>
|
||||
<tags>
|
||||
<tag>
|
||||
<matchString>todo</matchString>
|
||||
<matchType>ignoreCase</matchType>
|
||||
</tag>
|
||||
<tag>
|
||||
<matchString>FIXME</matchString>
|
||||
<matchType>exact</matchType>
|
||||
</tag>
|
||||
</tags>
|
||||
</tagClass>
|
||||
</tagClasses>
|
||||
</tagListOptions>
|
||||
</configuration>
|
||||
</plugin>
|
||||
<plugin>
|
||||
<groupId>org.apache.maven.plugins</groupId>
|
||||
<artifactId>maven-checkstyle-plugin</artifactId>
|
||||
<version>2.11</version>
|
||||
<version>${reporting.checkstyle-plugin.version}</version>
|
||||
<configuration>
|
||||
<enableRulesSummary>false</enableRulesSummary>
|
||||
<enableFilesSummary>false</enableFilesSummary>
|
||||
@@ -283,7 +190,7 @@ Copyright (c) 2012 - Jeremy Long. All Rights Reserved.
|
||||
<plugin>
|
||||
<groupId>org.apache.maven.plugins</groupId>
|
||||
<artifactId>maven-pmd-plugin</artifactId>
|
||||
<version>3.1</version>
|
||||
<version>${reporting.pmd-plugin.version}</version>
|
||||
<configuration>
|
||||
<targetJdk>1.6</targetJdk>
|
||||
<linkXref>true</linkXref>
|
||||
@@ -299,18 +206,12 @@ Copyright (c) 2012 - Jeremy Long. All Rights Reserved.
|
||||
</rulesets>
|
||||
</configuration>
|
||||
</plugin>
|
||||
<plugin>
|
||||
<groupId>org.codehaus.mojo</groupId>
|
||||
<artifactId>findbugs-maven-plugin</artifactId>
|
||||
<version>2.5.3</version>
|
||||
</plugin>
|
||||
</plugins>
|
||||
</reporting>
|
||||
<dependencies>
|
||||
<dependency>
|
||||
<groupId>commons-cli</groupId>
|
||||
<artifactId>commons-cli</artifactId>
|
||||
<version>1.2</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.owasp</groupId>
|
||||
@@ -322,5 +223,27 @@ Copyright (c) 2012 - Jeremy Long. All Rights Reserved.
|
||||
<artifactId>dependency-check-utils</artifactId>
|
||||
<version>${project.parent.version}</version>
|
||||
</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>
|
||||
<dependency>
|
||||
<groupId>org.apache.ant</groupId>
|
||||
<artifactId>ant</artifactId>
|
||||
<exclusions>
|
||||
<exclusion>
|
||||
<groupId>org.apache.ant</groupId>
|
||||
<artifactId>ant-launcher</artifactId>
|
||||
</exclusion>
|
||||
</exclusions>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
</project>
|
||||
|
||||
@@ -3,8 +3,7 @@
|
||||
xmlns="http://maven.apache.org/plugins/maven-assembly-plugin/assembly/1.1.2"
|
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:schemaLocation="http://maven.apache.org/plugins/maven-assembly-plugin/assembly/1.1.2
|
||||
http://maven.apache.org/xsd/assembly-1.1.2.xsd"
|
||||
>
|
||||
http://maven.apache.org/xsd/assembly-1.1.2.xsd">
|
||||
<id>release</id>
|
||||
<formats>
|
||||
<format>zip</format>
|
||||
@@ -12,25 +11,41 @@
|
||||
<includeBaseDirectory>false</includeBaseDirectory>
|
||||
<fileSets>
|
||||
<fileSet>
|
||||
<outputDirectory>/</outputDirectory>
|
||||
<directory>${project.build.directory}/release</directory>
|
||||
<outputDirectory>dependency-check/bin</outputDirectory>
|
||||
<directory>${project.build.directory}/release/bin</directory>
|
||||
<includes>
|
||||
<include>*.sh</include>
|
||||
</includes>
|
||||
<fileMode>0755</fileMode>
|
||||
</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>
|
||||
<include>LICENSE*</include>
|
||||
<include>NOTICE*</include>
|
||||
</includes>
|
||||
</fileSet>
|
||||
<fileSet>
|
||||
<outputDirectory>licenses</outputDirectory>
|
||||
<outputDirectory>dependency-check/licenses</outputDirectory>
|
||||
<directory>${basedir}/src/main/resources/META-INF/licenses</directory>
|
||||
</fileSet>
|
||||
<fileSet>
|
||||
<outputDirectory>licenses</outputDirectory>
|
||||
<outputDirectory>dependency-check/licenses</outputDirectory>
|
||||
<directory>${basedir}/../dependency-check-core/src/main/resources/META-INF/licenses</directory>
|
||||
</fileSet>
|
||||
<fileSet>
|
||||
<outputDirectory>/</outputDirectory>
|
||||
<outputDirectory>dependency-check</outputDirectory>
|
||||
<directory>${basedir}</directory>
|
||||
<includes>
|
||||
<include>README.md</include>
|
||||
|
||||
@@ -17,43 +17,39 @@
|
||||
*/
|
||||
package org.owasp.dependencycheck;
|
||||
|
||||
import ch.qos.logback.classic.LoggerContext;
|
||||
import ch.qos.logback.classic.encoder.PatternLayoutEncoder;
|
||||
import java.io.File;
|
||||
import java.io.FileNotFoundException;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
import java.util.logging.Level;
|
||||
import java.util.logging.Logger;
|
||||
import org.apache.commons.cli.ParseException;
|
||||
import org.owasp.dependencycheck.data.nvdcve.CveDB;
|
||||
import org.owasp.dependencycheck.data.nvdcve.DatabaseException;
|
||||
import org.owasp.dependencycheck.data.nvdcve.DatabaseProperties;
|
||||
import org.owasp.dependencycheck.dependency.Dependency;
|
||||
import org.owasp.dependencycheck.org.apache.tools.ant.DirectoryScanner;
|
||||
import org.apache.tools.ant.DirectoryScanner;
|
||||
import org.owasp.dependencycheck.reporting.ReportGenerator;
|
||||
import org.owasp.dependencycheck.utils.LogUtils;
|
||||
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.
|
||||
*
|
||||
* @author Jeremy Long <jeremy.long@owasp.org>
|
||||
* @author Jeremy Long
|
||||
*/
|
||||
public class App {
|
||||
|
||||
/**
|
||||
* The location of the log properties configuration file.
|
||||
*/
|
||||
private static final String LOG_PROPERTIES_FILE = "log.properties";
|
||||
|
||||
/**
|
||||
* 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.
|
||||
@@ -90,17 +86,43 @@ public class App {
|
||||
return;
|
||||
}
|
||||
|
||||
final InputStream in = App.class.getClassLoader().getResourceAsStream(LOG_PROPERTIES_FILE);
|
||||
LogUtils.prepareLogger(in, cli.getVerboseLog());
|
||||
if (cli.getVerboseLog() != null) {
|
||||
prepareLogger(cli.getVerboseLog());
|
||||
}
|
||||
|
||||
if (cli.isGetVersion()) {
|
||||
if (cli.isPurge()) {
|
||||
if (cli.getConnectionString() != null) {
|
||||
LOGGER.error("Unable to purge the database when using a non-default connection string");
|
||||
} else {
|
||||
populateSettings(cli);
|
||||
File db;
|
||||
try {
|
||||
db = new File(Settings.getDataDirectory(), "dc.h2.db");
|
||||
if (db.exists()) {
|
||||
if (db.delete()) {
|
||||
LOGGER.info("Database file purged; local copy of the NVD has been removed");
|
||||
} else {
|
||||
LOGGER.error("Unable to delete '{}'; please delete the file manually", db.getAbsolutePath());
|
||||
}
|
||||
} else {
|
||||
LOGGER.error("Unable to purge database; the database file does not exists: {}", db.getAbsolutePath());
|
||||
}
|
||||
} catch (IOException ex) {
|
||||
LOGGER.error("Unable to delete the database");
|
||||
}
|
||||
}
|
||||
} else if (cli.isGetVersion()) {
|
||||
cli.printVersionInfo();
|
||||
} else if (cli.isUpdateOnly()) {
|
||||
populateSettings(cli);
|
||||
runUpdateOnly();
|
||||
} else if (cli.isRunScan()) {
|
||||
populateSettings(cli);
|
||||
try {
|
||||
runScan(cli.getReportDirectory(), cli.getReportFormat(), cli.getApplicationName(), cli.getScanFiles(), cli.getExcludeList());
|
||||
runScan(cli.getReportDirectory(), cli.getReportFormat(), cli.getProjectName(), cli.getScanFiles(),
|
||||
cli.getExcludeList(), cli.getSymLinkDepth());
|
||||
} catch (InvalidScanPathException ex) {
|
||||
Logger.getLogger(App.class.getName()).log(Level.SEVERE, "An invalid scan path was detected; unable to scan '//*' paths");
|
||||
LOGGER.error("An invalid scan path was detected; unable to scan '//*' paths");
|
||||
}
|
||||
} else {
|
||||
cli.printHelp();
|
||||
@@ -115,55 +137,52 @@ public class App {
|
||||
* @param applicationName the application name for the report
|
||||
* @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,
|
||||
String[] excludes) throws InvalidScanPathException {
|
||||
String[] excludes, int symLinkDepth) throws InvalidScanPathException {
|
||||
Engine engine = null;
|
||||
try {
|
||||
engine = new Engine();
|
||||
List<String> antStylePaths = new ArrayList<String>();
|
||||
if (excludes == null || excludes.length == 0) {
|
||||
for (String file : files) {
|
||||
if (file.contains("*") || file.contains("?")) {
|
||||
antStylePaths.add(file);
|
||||
} else {
|
||||
engine.scan(file);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
antStylePaths = Arrays.asList(files);
|
||||
final List<String> antStylePaths = new ArrayList<String>();
|
||||
for (String file : files) {
|
||||
final String antPath = ensureCanonicalPath(file);
|
||||
antStylePaths.add(antPath);
|
||||
}
|
||||
|
||||
final Set<File> paths = new HashSet<File>();
|
||||
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 if (include.startsWith("./")) {
|
||||
baseDir = new File(".");
|
||||
include = include.substring(2);
|
||||
} else if (include.startsWith("/")) {
|
||||
baseDir = new File("/");
|
||||
include = include.substring(1);
|
||||
} else if (include.contains("/")) {
|
||||
final int pos = include.indexOf('/');
|
||||
final String tmp = include.substring(0, pos);
|
||||
if (tmp.contains("*") || tmp.contains("?")) {
|
||||
baseDir = new File(".");
|
||||
} else {
|
||||
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(tmp);
|
||||
include = include.substring(pos + 1);
|
||||
baseDir = new File(tmpBase, tmpInclude);
|
||||
include = "**/*";
|
||||
}
|
||||
} else { //no path info - must just be a file in the working directory
|
||||
baseDir = new File(".");
|
||||
}
|
||||
//LOGGER.debug("baseDir: {}", baseDir);
|
||||
//LOGGER.debug("include: {}", include);
|
||||
scanner.setBasedir(baseDir);
|
||||
scanner.setIncludes(include);
|
||||
final String[] includes = {include};
|
||||
scanner.setIncludes(includes);
|
||||
scanner.setMaxLevelsOfSymlinks(symLinkDepth);
|
||||
if (symLinkDepth <= 0) {
|
||||
scanner.setFollowSymlinks(false);
|
||||
}
|
||||
if (excludes != null && excludes.length > 0) {
|
||||
scanner.addExcludes(excludes);
|
||||
}
|
||||
@@ -171,6 +190,7 @@ public class App {
|
||||
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);
|
||||
}
|
||||
}
|
||||
@@ -186,7 +206,7 @@ public class App {
|
||||
cve.open();
|
||||
prop = cve.getDatabaseProperties();
|
||||
} catch (DatabaseException ex) {
|
||||
LOGGER.log(Level.FINE, "Unable to retrieve DB Properties", ex);
|
||||
LOGGER.debug("Unable to retrieve DB Properties", ex);
|
||||
} finally {
|
||||
if (cve != null) {
|
||||
cve.close();
|
||||
@@ -196,15 +216,33 @@ public class App {
|
||||
try {
|
||||
report.generateReports(reportDirectory, outputFormat);
|
||||
} catch (IOException ex) {
|
||||
LOGGER.log(Level.SEVERE, "There was an IO error while attempting to generate the report.");
|
||||
LOGGER.log(Level.FINE, null, ex);
|
||||
LOGGER.error("There was an IO error while attempting to generate the report.");
|
||||
LOGGER.debug("", ex);
|
||||
} catch (Throwable ex) {
|
||||
LOGGER.log(Level.SEVERE, "There was an error while attempting to generate the report.");
|
||||
LOGGER.log(Level.FINE, null, ex);
|
||||
LOGGER.error("There was an error while attempting to generate the report.");
|
||||
LOGGER.debug("", ex);
|
||||
}
|
||||
} catch (DatabaseException ex) {
|
||||
LOGGER.log(Level.SEVERE, "Unable to connect to the dependency-check database; analysis has stopped");
|
||||
LOGGER.log(Level.FINE, "", ex);
|
||||
LOGGER.error("Unable to connect to the dependency-check database; analysis has stopped");
|
||||
LOGGER.debug("", ex);
|
||||
} finally {
|
||||
if (engine != null) {
|
||||
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();
|
||||
@@ -215,8 +253,8 @@ public class App {
|
||||
/**
|
||||
* Updates the global Settings.
|
||||
*
|
||||
* @param cli a reference to the CLI Parser that contains the command line arguments used to set the corresponding
|
||||
* settings in the core engine.
|
||||
* @param cli a reference to the CLI Parser that contains the command line arguments used to set the corresponding settings in
|
||||
* the core engine.
|
||||
*/
|
||||
private void populateSettings(CliParser cli) {
|
||||
|
||||
@@ -229,12 +267,6 @@ public class App {
|
||||
final String dataDirectory = cli.getDataDirectory();
|
||||
final File propertiesFile = cli.getPropertiesFile();
|
||||
final String suppressionFile = cli.getSuppressionFile();
|
||||
final boolean jarDisabled = cli.isJarDisabled();
|
||||
final boolean archiveDisabled = cli.isArchiveDisabled();
|
||||
final boolean assemblyDisabled = cli.isAssemblyDisabled();
|
||||
final boolean nuspecDisabled = cli.isNuspecDisabled();
|
||||
final boolean centralDisabled = cli.isCentralDisabled();
|
||||
final boolean nexusDisabled = cli.isNexusDisabled();
|
||||
final String nexusUrl = cli.getNexusUrl();
|
||||
final String databaseDriverName = cli.getDatabaseDriverName();
|
||||
final String databaseDriverPath = cli.getDatabaseDriverPath();
|
||||
@@ -243,18 +275,21 @@ public class App {
|
||||
final String databasePassword = cli.getDatabasePassword();
|
||||
final String additionalZipExtensions = cli.getAdditionalZipExtensions();
|
||||
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();
|
||||
final Integer cveValidForHours = cli.getCveValidForHours();
|
||||
|
||||
if (propertiesFile != null) {
|
||||
try {
|
||||
Settings.mergeProperties(propertiesFile);
|
||||
} catch (FileNotFoundException ex) {
|
||||
final String msg = String.format("Unable to load properties file '%s'", propertiesFile.getPath());
|
||||
LOGGER.log(Level.SEVERE, msg);
|
||||
LOGGER.log(Level.FINE, null, ex);
|
||||
LOGGER.error("Unable to load properties file '{}'", propertiesFile.getPath());
|
||||
LOGGER.debug("", ex);
|
||||
} catch (IOException ex) {
|
||||
final String msg = String.format("Unable to find properties file '%s'", propertiesFile.getPath());
|
||||
LOGGER.log(Level.SEVERE, msg);
|
||||
LOGGER.log(Level.FINE, null, ex);
|
||||
LOGGER.error("Unable to find properties file '{}'", propertiesFile.getPath());
|
||||
LOGGER.debug("", ex);
|
||||
}
|
||||
}
|
||||
// We have to wait until we've merged the properties before attempting to set whether we use
|
||||
@@ -274,57 +309,134 @@ public class App {
|
||||
Settings.setString(Settings.KEYS.DATA_DIRECTORY, dataDir.getAbsolutePath());
|
||||
}
|
||||
Settings.setBoolean(Settings.KEYS.AUTO_UPDATE, autoUpdate);
|
||||
if (proxyServer != null && !proxyServer.isEmpty()) {
|
||||
Settings.setString(Settings.KEYS.PROXY_SERVER, proxyServer);
|
||||
}
|
||||
if (proxyPort != null && !proxyPort.isEmpty()) {
|
||||
Settings.setString(Settings.KEYS.PROXY_PORT, proxyPort);
|
||||
}
|
||||
if (proxyUser != null && !proxyUser.isEmpty()) {
|
||||
Settings.setString(Settings.KEYS.PROXY_USERNAME, proxyUser);
|
||||
}
|
||||
if (proxyPass != null && !proxyPass.isEmpty()) {
|
||||
Settings.setString(Settings.KEYS.PROXY_PASSWORD, proxyPass);
|
||||
}
|
||||
if (connectionTimeout != null && !connectionTimeout.isEmpty()) {
|
||||
Settings.setString(Settings.KEYS.CONNECTION_TIMEOUT, connectionTimeout);
|
||||
}
|
||||
if (suppressionFile != null && !suppressionFile.isEmpty()) {
|
||||
Settings.setString(Settings.KEYS.SUPPRESSION_FILE, suppressionFile);
|
||||
}
|
||||
Settings.setStringIfNotEmpty(Settings.KEYS.PROXY_SERVER, proxyServer);
|
||||
Settings.setStringIfNotEmpty(Settings.KEYS.PROXY_PORT, proxyPort);
|
||||
Settings.setStringIfNotEmpty(Settings.KEYS.PROXY_USERNAME, proxyUser);
|
||||
Settings.setStringIfNotEmpty(Settings.KEYS.PROXY_PASSWORD, proxyPass);
|
||||
Settings.setStringIfNotEmpty(Settings.KEYS.CONNECTION_TIMEOUT, connectionTimeout);
|
||||
Settings.setStringIfNotEmpty(Settings.KEYS.SUPPRESSION_FILE, suppressionFile);
|
||||
Settings.setIntIfNotNull(Settings.KEYS.CVE_CHECK_VALID_FOR_HOURS, cveValidForHours);
|
||||
|
||||
//File Type Analyzer Settings
|
||||
Settings.setBoolean(Settings.KEYS.ANALYZER_JAR_ENABLED, !jarDisabled);
|
||||
Settings.setBoolean(Settings.KEYS.ANALYZER_ARCHIVE_ENABLED, !archiveDisabled);
|
||||
Settings.setBoolean(Settings.KEYS.ANALYZER_NUSPEC_ENABLED, !nuspecDisabled);
|
||||
Settings.setBoolean(Settings.KEYS.ANALYZER_ASSEMBLY_ENABLED, !assemblyDisabled);
|
||||
Settings.setBoolean(Settings.KEYS.ANALYZER_JAR_ENABLED, !cli.isJarDisabled());
|
||||
Settings.setBoolean(Settings.KEYS.ANALYZER_ARCHIVE_ENABLED, !cli.isArchiveDisabled());
|
||||
Settings.setBoolean(Settings.KEYS.ANALYZER_PYTHON_DISTRIBUTION_ENABLED, !cli.isPythonDistributionDisabled());
|
||||
Settings.setBoolean(Settings.KEYS.ANALYZER_PYTHON_PACKAGE_ENABLED, !cli.isPythonPackageDisabled());
|
||||
Settings.setBoolean(Settings.KEYS.ANALYZER_AUTOCONF_ENABLED, !cli.isAutoconfDisabled());
|
||||
Settings.setBoolean(Settings.KEYS.ANALYZER_CMAKE_ENABLED, !cli.isCmakeDisabled());
|
||||
Settings.setBoolean(Settings.KEYS.ANALYZER_NUSPEC_ENABLED, !cli.isNuspecDisabled());
|
||||
Settings.setBoolean(Settings.KEYS.ANALYZER_ASSEMBLY_ENABLED, !cli.isAssemblyDisabled());
|
||||
Settings.setBoolean(Settings.KEYS.ANALYZER_BUNDLE_AUDIT_ENABLED, !cli.isBundleAuditDisabled());
|
||||
Settings.setBoolean(Settings.KEYS.ANALYZER_OPENSSL_ENABLED, !cli.isOpenSSLDisabled());
|
||||
Settings.setBoolean(Settings.KEYS.ANALYZER_COMPOSER_LOCK_ENABLED, !cli.isComposerDisabled());
|
||||
Settings.setBoolean(Settings.KEYS.ANALYZER_NODE_PACKAGE_ENABLED, !cli.isNodeJsDisabled());
|
||||
Settings.setBoolean(Settings.KEYS.ANALYZER_RUBY_GEMSPEC_ENABLED, !cli.isRubyGemspecDisabled());
|
||||
Settings.setBoolean(Settings.KEYS.ANALYZER_CENTRAL_ENABLED, !cli.isCentralDisabled());
|
||||
Settings.setBoolean(Settings.KEYS.ANALYZER_NEXUS_ENABLED, !cli.isNexusDisabled());
|
||||
|
||||
Settings.setBoolean(Settings.KEYS.ANALYZER_CENTRAL_ENABLED, !centralDisabled);
|
||||
Settings.setBoolean(Settings.KEYS.ANALYZER_NEXUS_ENABLED, !nexusDisabled);
|
||||
if (nexusUrl != null && !nexusUrl.isEmpty()) {
|
||||
Settings.setString(Settings.KEYS.ANALYZER_NEXUS_URL, nexusUrl);
|
||||
Settings.setStringIfNotEmpty(Settings.KEYS.ANALYZER_BUNDLE_AUDIT_PATH, cli.getPathToBundleAudit());
|
||||
Settings.setStringIfNotEmpty(Settings.KEYS.ANALYZER_NEXUS_URL, nexusUrl);
|
||||
Settings.setBoolean(Settings.KEYS.ANALYZER_NEXUS_USES_PROXY, nexusUsesProxy);
|
||||
Settings.setStringIfNotEmpty(Settings.KEYS.DB_DRIVER_NAME, databaseDriverName);
|
||||
Settings.setStringIfNotEmpty(Settings.KEYS.DB_DRIVER_PATH, databaseDriverPath);
|
||||
Settings.setStringIfNotEmpty(Settings.KEYS.DB_CONNECTION_STRING, connectionString);
|
||||
Settings.setStringIfNotEmpty(Settings.KEYS.DB_USER, databaseUser);
|
||||
Settings.setStringIfNotEmpty(Settings.KEYS.DB_PASSWORD, databasePassword);
|
||||
Settings.setStringIfNotEmpty(Settings.KEYS.ADDITIONAL_ZIP_EXTENSIONS, additionalZipExtensions);
|
||||
Settings.setStringIfNotEmpty(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);
|
||||
}
|
||||
Settings.setBoolean(Settings.KEYS.ANALYZER_NEXUS_PROXY, nexusUsesProxy);
|
||||
if (databaseDriverName != null && !databaseDriverName.isEmpty()) {
|
||||
Settings.setString(Settings.KEYS.DB_DRIVER_NAME, databaseDriverName);
|
||||
}
|
||||
|
||||
/**
|
||||
* 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);
|
||||
}
|
||||
if (databaseDriverPath != null && !databaseDriverPath.isEmpty()) {
|
||||
Settings.setString(Settings.KEYS.DB_DRIVER_PATH, databaseDriverPath);
|
||||
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;
|
||||
}
|
||||
if (connectionString != null && !connectionString.isEmpty()) {
|
||||
Settings.setString(Settings.KEYS.DB_CONNECTION_STRING, connectionString);
|
||||
|
||||
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);
|
||||
}
|
||||
if (databaseUser != null && !databaseUser.isEmpty()) {
|
||||
Settings.setString(Settings.KEYS.DB_USER, databaseUser);
|
||||
}
|
||||
if (databasePassword != null && !databasePassword.isEmpty()) {
|
||||
Settings.setString(Settings.KEYS.DB_PASSWORD, databasePassword);
|
||||
}
|
||||
if (additionalZipExtensions != null && !additionalZipExtensions.isEmpty()) {
|
||||
Settings.setString(Settings.KEYS.ADDITIONAL_ZIP_EXTENSIONS, additionalZipExtensions);
|
||||
}
|
||||
if (pathToMono != null && !pathToMono.isEmpty()) {
|
||||
Settings.setString(Settings.KEYS.ANALYZER_ASSEMBLY_MONO_PATH, pathToMono);
|
||||
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('/');
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -19,31 +19,32 @@ package org.owasp.dependencycheck;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.FileNotFoundException;
|
||||
import java.util.logging.Logger;
|
||||
|
||||
import org.apache.commons.cli.CommandLine;
|
||||
import org.apache.commons.cli.CommandLineParser;
|
||||
import org.apache.commons.cli.DefaultParser;
|
||||
import org.apache.commons.cli.HelpFormatter;
|
||||
import org.apache.commons.cli.Option;
|
||||
import org.apache.commons.cli.OptionBuilder;
|
||||
import org.apache.commons.cli.OptionGroup;
|
||||
import org.apache.commons.cli.Options;
|
||||
import org.apache.commons.cli.ParseException;
|
||||
import org.apache.commons.cli.PosixParser;
|
||||
import org.owasp.dependencycheck.reporting.ReportGenerator.Format;
|
||||
import org.owasp.dependencycheck.utils.InvalidSettingException;
|
||||
import org.owasp.dependencycheck.utils.Settings;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
/**
|
||||
* A utility to parse command line arguments for the DependencyCheck.
|
||||
*
|
||||
* @author Jeremy Long <jeremy.long@owasp.org>
|
||||
* @author Jeremy Long
|
||||
*/
|
||||
public final class CliParser {
|
||||
|
||||
/**
|
||||
* The logger.
|
||||
*/
|
||||
private static final Logger LOGGER = Logger.getLogger(CliParser.class.getName());
|
||||
private static final Logger LOGGER = LoggerFactory.getLogger(CliParser.class);
|
||||
/**
|
||||
* The command line.
|
||||
*/
|
||||
@@ -76,7 +77,7 @@ public final class CliParser {
|
||||
* @throws ParseException if the arguments are invalid
|
||||
*/
|
||||
private CommandLine parseArgs(String[] args) throws ParseException {
|
||||
final CommandLineParser parser = new PosixParser();
|
||||
final CommandLineParser parser = new DefaultParser();
|
||||
final Options options = createCommandLineOptions();
|
||||
return parser.parse(options, args);
|
||||
}
|
||||
@@ -89,14 +90,27 @@ public final class CliParser {
|
||||
* @throws ParseException is thrown if there is an exception parsing the command line.
|
||||
*/
|
||||
private void validateArgs() throws FileNotFoundException, ParseException {
|
||||
if (isUpdateOnly() || isRunScan()) {
|
||||
final String value = line.getOptionValue(ARGUMENT.CVE_VALID_FOR_HOURS);
|
||||
if (value != null) {
|
||||
try {
|
||||
final int i = Integer.parseInt(value);
|
||||
if (i < 0) {
|
||||
throw new ParseException("Invalid Setting: cveValidForHours must be a number greater than or equal to 0.");
|
||||
}
|
||||
} catch (NumberFormatException ex) {
|
||||
throw new ParseException("Invalid Setting: cveValidForHours must be a number greater than or equal to 0.");
|
||||
}
|
||||
}
|
||||
}
|
||||
if (isRunScan()) {
|
||||
validatePathExists(getScanFiles(), ARGUMENT.SCAN);
|
||||
validatePathExists(getReportDirectory(), ARGUMENT.OUT);
|
||||
if (getPathToMono() != null) {
|
||||
validatePathExists(getPathToMono(), ARGUMENT.PATH_TO_MONO);
|
||||
}
|
||||
if (!line.hasOption(ARGUMENT.APP_NAME)) {
|
||||
throw new ParseException("Missing 'app' argument; the scan cannot be run without the an application name.");
|
||||
if (!line.hasOption(ARGUMENT.APP_NAME) && !line.hasOption(ARGUMENT.PROJECT)) {
|
||||
throw new ParseException("Missing '" + ARGUMENT.PROJECT + "' argument; the scan cannot be run without the an project name.");
|
||||
}
|
||||
if (line.hasOption(ARGUMENT.OUTPUT_FORMAT)) {
|
||||
final String format = line.getOptionValue(ARGUMENT.OUTPUT_FORMAT);
|
||||
@@ -108,6 +122,21 @@ public final class CliParser {
|
||||
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.");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -191,8 +220,8 @@ public final class CliParser {
|
||||
final Option help = new Option(ARGUMENT.HELP_SHORT, ARGUMENT.HELP, false,
|
||||
"Print this message.");
|
||||
|
||||
final Option advancedHelp = OptionBuilder.withLongOpt(ARGUMENT.ADVANCED_HELP)
|
||||
.withDescription("Print the advanced help message.").create();
|
||||
final Option advancedHelp = Option.builder().longOpt(ARGUMENT.ADVANCED_HELP)
|
||||
.desc("Print the advanced help message.").build();
|
||||
|
||||
final Option version = new Option(ARGUMENT.VERSION_SHORT, ARGUMENT.VERSION,
|
||||
false, "Print the version information.");
|
||||
@@ -200,40 +229,48 @@ public final class CliParser {
|
||||
final Option noUpdate = new Option(ARGUMENT.DISABLE_AUTO_UPDATE_SHORT, ARGUMENT.DISABLE_AUTO_UPDATE,
|
||||
false, "Disables the automatic updating of the CPE data.");
|
||||
|
||||
final Option appName = OptionBuilder.withArgName("name").hasArg().withLongOpt(ARGUMENT.APP_NAME)
|
||||
.withDescription("The name of the application being scanned. This is a required argument.")
|
||||
.create(ARGUMENT.APP_NAME_SHORT);
|
||||
final Option projectName = Option.builder().hasArg().argName("name").longOpt(ARGUMENT.PROJECT)
|
||||
.desc("The name of the project being scanned. This is a required argument.")
|
||||
.build();
|
||||
|
||||
final Option path = OptionBuilder.withArgName("path").hasArg().withLongOpt(ARGUMENT.SCAN)
|
||||
.withDescription("The path to scan - this option can be specified multiple times. Ant style"
|
||||
final Option path = Option.builder(ARGUMENT.SCAN_SHORT).argName("path").hasArg().longOpt(ARGUMENT.SCAN)
|
||||
.desc("The path to scan - this option can be specified multiple times. Ant style"
|
||||
+ " paths are supported (e.g. path/**/*.jar).")
|
||||
.create(ARGUMENT.SCAN_SHORT);
|
||||
.build();
|
||||
|
||||
final Option excludes = OptionBuilder.withArgName("pattern").hasArg().withLongOpt(ARGUMENT.EXCLUDE)
|
||||
.withDescription("Specify and exclusion pattern. This option can be specified multiple times"
|
||||
final Option excludes = Option.builder().argName("pattern").hasArg().longOpt(ARGUMENT.EXCLUDE)
|
||||
.desc("Specify and exclusion pattern. This option can be specified multiple times"
|
||||
+ " and it accepts Ant style excludsions.")
|
||||
.create();
|
||||
.build();
|
||||
|
||||
final Option props = OptionBuilder.withArgName("file").hasArg().withLongOpt(ARGUMENT.PROP)
|
||||
.withDescription("A property file to load.")
|
||||
.create(ARGUMENT.PROP_SHORT);
|
||||
final Option props = Option.builder(ARGUMENT.PROP_SHORT).argName("file").hasArg().longOpt(ARGUMENT.PROP)
|
||||
.desc("A property file to load.")
|
||||
.build();
|
||||
|
||||
final Option out = OptionBuilder.withArgName("path").hasArg().withLongOpt(ARGUMENT.OUT)
|
||||
.withDescription("The folder to write reports to. This defaults to the current directory. "
|
||||
final Option out = Option.builder(ARGUMENT.OUT_SHORT).argName("path").hasArg().longOpt(ARGUMENT.OUT)
|
||||
.desc("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);
|
||||
.build();
|
||||
|
||||
final Option outputFormat = OptionBuilder.withArgName("format").hasArg().withLongOpt(ARGUMENT.OUTPUT_FORMAT)
|
||||
.withDescription("The output format to write to (XML, HTML, VULN, ALL). The default is HTML.")
|
||||
.create(ARGUMENT.OUTPUT_FORMAT_SHORT);
|
||||
final Option outputFormat = Option.builder(ARGUMENT.OUTPUT_FORMAT_SHORT).argName("format").hasArg().longOpt(ARGUMENT.OUTPUT_FORMAT)
|
||||
.desc("The output format to write to (XML, HTML, VULN, ALL). The default is HTML.")
|
||||
.build();
|
||||
|
||||
final Option verboseLog = OptionBuilder.withArgName("file").hasArg().withLongOpt(ARGUMENT.VERBOSE_LOG)
|
||||
.withDescription("The file path to write verbose logging information.")
|
||||
.create(ARGUMENT.VERBOSE_LOG_SHORT);
|
||||
final Option verboseLog = Option.builder(ARGUMENT.VERBOSE_LOG_SHORT).argName("file").hasArg().longOpt(ARGUMENT.VERBOSE_LOG)
|
||||
.desc("The file path to write verbose logging information.")
|
||||
.build();
|
||||
|
||||
final Option suppressionFile = OptionBuilder.withArgName("file").hasArg().withLongOpt(ARGUMENT.SUPPRESSION_FILE)
|
||||
.withDescription("The file path to the suppression XML file.")
|
||||
.create();
|
||||
final Option symLinkDepth = Option.builder().argName("depth").hasArg().longOpt(ARGUMENT.SYM_LINK_DEPTH)
|
||||
.desc("Sets how deep nested symbolic links will be followed; 0 indicates symbolic links will not be followed.")
|
||||
.build();
|
||||
|
||||
final Option suppressionFile = Option.builder().argName("file").hasArg().longOpt(ARGUMENT.SUPPRESSION_FILE)
|
||||
.desc("The file path to the suppression XML file.")
|
||||
.build();
|
||||
|
||||
final Option cveValidForHours = Option.builder().argName("hours").hasArg().longOpt(ARGUMENT.CVE_VALID_FOR_HOURS)
|
||||
.desc("The number of hours to wait before checking for new updates from the NVD.")
|
||||
.build();
|
||||
|
||||
//This is an option group because it can be specified more then once.
|
||||
final OptionGroup og = new OptionGroup();
|
||||
@@ -244,16 +281,18 @@ public final class CliParser {
|
||||
|
||||
options.addOptionGroup(og)
|
||||
.addOptionGroup(exog)
|
||||
.addOption(projectName)
|
||||
.addOption(out)
|
||||
.addOption(outputFormat)
|
||||
.addOption(appName)
|
||||
.addOption(version)
|
||||
.addOption(help)
|
||||
.addOption(advancedHelp)
|
||||
.addOption(noUpdate)
|
||||
.addOption(symLinkDepth)
|
||||
.addOption(props)
|
||||
.addOption(verboseLog)
|
||||
.addOption(suppressionFile);
|
||||
.addOption(suppressionFile)
|
||||
.addOption(cveValidForHours);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -266,91 +305,129 @@ public final class CliParser {
|
||||
@SuppressWarnings("static-access")
|
||||
private void addAdvancedOptions(final Options options) throws IllegalArgumentException {
|
||||
|
||||
final Option data = OptionBuilder.withArgName("path").hasArg().withLongOpt(ARGUMENT.DATA_DIRECTORY)
|
||||
.withDescription("The location of the H2 Database file. This option should generally not be set.")
|
||||
.create(ARGUMENT.DATA_DIRECTORY_SHORT);
|
||||
final Option cve12Base = Option.builder().argName("url").hasArg().longOpt(ARGUMENT.CVE_BASE_12)
|
||||
.desc("Base URL for each year’s CVE 1.2, the %d will be replaced with the year. ")
|
||||
.build();
|
||||
|
||||
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 cve20Base = Option.builder().argName("url").hasArg().longOpt(ARGUMENT.CVE_BASE_20)
|
||||
.desc("Base URL for each year’s CVE 2.0, the %d will be replaced with the year.")
|
||||
.build();
|
||||
|
||||
final Option proxyServer = OptionBuilder.withArgName("server").hasArg().withLongOpt(ARGUMENT.PROXY_SERVER)
|
||||
.withDescription("The proxy server to use when downloading resources.")
|
||||
.create();
|
||||
final Option cve12Modified = Option.builder().argName("url").hasArg().longOpt(ARGUMENT.CVE_MOD_12)
|
||||
.desc("URL for the modified CVE 1.2.")
|
||||
.build();
|
||||
|
||||
final Option proxyPort = OptionBuilder.withArgName("port").hasArg().withLongOpt(ARGUMENT.PROXY_PORT)
|
||||
.withDescription("The proxy port to use when downloading resources.")
|
||||
.create();
|
||||
final Option cve20Modified = Option.builder().argName("url").hasArg().longOpt(ARGUMENT.CVE_MOD_20)
|
||||
.desc("URL for the modified CVE 2.0.")
|
||||
.build();
|
||||
|
||||
final Option proxyUsername = OptionBuilder.withArgName("user").hasArg().withLongOpt(ARGUMENT.PROXY_USERNAME)
|
||||
.withDescription("The proxy username to use when downloading resources.")
|
||||
.create();
|
||||
final Option updateOnly = Option.builder().longOpt(ARGUMENT.UPDATE_ONLY)
|
||||
.desc("Only update the local NVD data cache; no scan will be executed.").build();
|
||||
|
||||
final Option proxyPassword = OptionBuilder.withArgName("pass").hasArg().withLongOpt(ARGUMENT.PROXY_PASSWORD)
|
||||
.withDescription("The proxy password to use when downloading resources.")
|
||||
.create();
|
||||
final Option data = Option.builder(ARGUMENT.DATA_DIRECTORY_SHORT).argName("path").hasArg().longOpt(ARGUMENT.DATA_DIRECTORY)
|
||||
.desc("The location of the H2 Database file. This option should generally not be set.")
|
||||
.build();
|
||||
|
||||
final Option connectionString = OptionBuilder.withArgName("connStr").hasArg().withLongOpt(ARGUMENT.CONNECTION_STRING)
|
||||
.withDescription("The connection string to the database.")
|
||||
.create();
|
||||
final Option nexusUrl = Option.builder().argName("url").hasArg().longOpt(ARGUMENT.NEXUS_URL)
|
||||
.desc("The url to the Nexus Server's REST API Endpoint (http://domain/nexus/service/local). "
|
||||
+ "If not set the Nexus Analyzer will be disabled.").build();
|
||||
|
||||
final Option dbUser = OptionBuilder.withArgName("user").hasArg().withLongOpt(ARGUMENT.DB_NAME)
|
||||
.withDescription("The username used to connect to the database.")
|
||||
.create();
|
||||
final Option nexusUsesProxy = Option.builder().argName("true/false").hasArg().longOpt(ARGUMENT.NEXUS_USES_PROXY)
|
||||
.desc("Whether or not the configured proxy should be used when connecting to Nexus.")
|
||||
.build();
|
||||
|
||||
final Option dbPassword = OptionBuilder.withArgName("password").hasArg().withLongOpt(ARGUMENT.DB_PASSWORD)
|
||||
.withDescription("The password for connecting to the database.")
|
||||
.create();
|
||||
final Option additionalZipExtensions = Option.builder().argName("extensions").hasArg()
|
||||
.longOpt(ARGUMENT.ADDITIONAL_ZIP_EXTENSIONS)
|
||||
.desc("A comma separated list of additional extensions to be scanned as ZIP files "
|
||||
+ "(ZIP, EAR, WAR are already treated as zip files)").build();
|
||||
|
||||
final Option dbDriver = OptionBuilder.withArgName("driver").hasArg().withLongOpt(ARGUMENT.DB_DRIVER)
|
||||
.withDescription("The database driver name.")
|
||||
.create();
|
||||
final Option pathToMono = Option.builder().argName("path").hasArg().longOpt(ARGUMENT.PATH_TO_MONO)
|
||||
.desc("The path to Mono for .NET Assembly analysis on non-windows systems.")
|
||||
.build();
|
||||
|
||||
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 pathToBundleAudit = Option.builder().argName("path").hasArg()
|
||||
.longOpt(ARGUMENT.PATH_TO_BUNDLE_AUDIT)
|
||||
.desc("The path to bundle-audit for Gem bundle analysis.").build();
|
||||
|
||||
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 connectionTimeout = Option.builder(ARGUMENT.CONNECTION_TIMEOUT_SHORT).argName("timeout").hasArg()
|
||||
.longOpt(ARGUMENT.CONNECTION_TIMEOUT).desc("The connection timeout (in milliseconds) to use when downloading resources.")
|
||||
.build();
|
||||
|
||||
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 proxyServer = Option.builder().argName("server").hasArg().longOpt(ARGUMENT.PROXY_SERVER)
|
||||
.desc("The proxy server to use when downloading resources.").build();
|
||||
|
||||
final Option disableNexusAnalyzer = OptionBuilder.withLongOpt(ARGUMENT.DISABLE_NEXUS)
|
||||
.withDescription("Disable the Nexus Analyzer.")
|
||||
.create();
|
||||
final Option proxyPort = Option.builder().argName("port").hasArg().longOpt(ARGUMENT.PROXY_PORT)
|
||||
.desc("The proxy port to use when downloading resources.").build();
|
||||
|
||||
final Option nexusUrl = OptionBuilder.withArgName("url").hasArg().withLongOpt(ARGUMENT.NEXUS_URL)
|
||||
.withDescription("The url to the Nexus Pro Server. If not set the Nexus Analyzer will be disabled.")
|
||||
.create();
|
||||
final Option proxyUsername = Option.builder().argName("user").hasArg().longOpt(ARGUMENT.PROXY_USERNAME)
|
||||
.desc("The proxy username to use when downloading resources.").build();
|
||||
|
||||
final Option nexusUsesProxy = OptionBuilder.withArgName("true/false").hasArg().withLongOpt(ARGUMENT.NEXUS_USES_PROXY)
|
||||
.withDescription("Whether or not the configured proxy should be used when connecting to Nexus.")
|
||||
.create();
|
||||
final Option proxyPassword = Option.builder().argName("pass").hasArg().longOpt(ARGUMENT.PROXY_PASSWORD)
|
||||
.desc("The proxy password to use when downloading resources.").build();
|
||||
|
||||
final Option additionalZipExtensions = OptionBuilder.withArgName("extensions").hasArg()
|
||||
.withLongOpt(ARGUMENT.ADDITIONAL_ZIP_EXTENSIONS)
|
||||
.withDescription("A comma separated list of additional extensions to be scanned as ZIP files "
|
||||
+ "(ZIP, EAR, WAR are already treated as zip files)")
|
||||
.create();
|
||||
final Option connectionString = Option.builder().argName("connStr").hasArg().longOpt(ARGUMENT.CONNECTION_STRING)
|
||||
.desc("The connection string to the database.").build();
|
||||
|
||||
final Option pathToMono = OptionBuilder.withArgName("path").hasArg().withLongOpt(ARGUMENT.PATH_TO_MONO)
|
||||
.withDescription("The path to Mono for .NET Assembly analysis on non-windows systems.")
|
||||
.create();
|
||||
final Option dbUser = Option.builder().argName("user").hasArg().longOpt(ARGUMENT.DB_NAME)
|
||||
.desc("The username used to connect to the database.").build();
|
||||
|
||||
options.addOption(proxyPort)
|
||||
final Option dbPassword = Option.builder().argName("password").hasArg().longOpt(ARGUMENT.DB_PASSWORD)
|
||||
.desc("The password for connecting to the database.").build();
|
||||
|
||||
final Option dbDriver = Option.builder().argName("driver").hasArg().longOpt(ARGUMENT.DB_DRIVER)
|
||||
.desc("The database driver name.").build();
|
||||
|
||||
final Option dbDriverPath = Option.builder().argName("path").hasArg().longOpt(ARGUMENT.DB_DRIVER_PATH)
|
||||
.desc("The path to the database driver; note, this does not need to be set unless the JAR is outside of the classpath.")
|
||||
.build();
|
||||
|
||||
final Option disableJarAnalyzer = Option.builder().longOpt(ARGUMENT.DISABLE_JAR)
|
||||
.desc("Disable the Jar Analyzer.").build();
|
||||
|
||||
final Option disableArchiveAnalyzer = Option.builder().longOpt(ARGUMENT.DISABLE_ARCHIVE)
|
||||
.desc("Disable the Archive Analyzer.").build();
|
||||
|
||||
final Option disableNuspecAnalyzer = Option.builder().longOpt(ARGUMENT.DISABLE_NUSPEC)
|
||||
.desc("Disable the Nuspec Analyzer.").build();
|
||||
|
||||
final Option disableAssemblyAnalyzer = Option.builder().longOpt(ARGUMENT.DISABLE_ASSEMBLY)
|
||||
.desc("Disable the .NET Assembly Analyzer.").build();
|
||||
|
||||
final Option disablePythonDistributionAnalyzer = Option.builder().longOpt(ARGUMENT.DISABLE_PY_DIST)
|
||||
.desc("Disable the Python Distribution Analyzer.").build();
|
||||
|
||||
final Option disablePythonPackageAnalyzer = Option.builder().longOpt(ARGUMENT.DISABLE_PY_PKG)
|
||||
.desc("Disable the Python Package Analyzer.").build();
|
||||
|
||||
final Option disableComposerAnalyzer = Option.builder().longOpt(ARGUMENT.DISABLE_COMPOSER)
|
||||
.desc("Disable the PHP Composer Analyzer.").build();
|
||||
|
||||
final Option disableAutoconfAnalyzer = Option.builder()
|
||||
.longOpt(ARGUMENT.DISABLE_AUTOCONF)
|
||||
.desc("Disable the Autoconf Analyzer.").build();
|
||||
|
||||
final Option disableOpenSSLAnalyzer = Option.builder().longOpt(ARGUMENT.DISABLE_OPENSSL)
|
||||
.desc("Disable the OpenSSL Analyzer.").build();
|
||||
final Option disableCmakeAnalyzer = Option.builder().longOpt(ARGUMENT.DISABLE_CMAKE)
|
||||
.desc("Disable the Cmake Analyzer.").build();
|
||||
|
||||
final Option disableCentralAnalyzer = Option.builder().longOpt(ARGUMENT.DISABLE_CENTRAL)
|
||||
.desc("Disable the Central Analyzer. If this analyzer is disabled it is likely you also want to disable "
|
||||
+ "the Nexus Analyzer.").build();
|
||||
|
||||
final Option disableNexusAnalyzer = Option.builder().longOpt(ARGUMENT.DISABLE_NEXUS)
|
||||
.desc("Disable the Nexus Analyzer.").build();
|
||||
|
||||
final Option purge = Option.builder().longOpt(ARGUMENT.PURGE_NVD)
|
||||
.desc("Purges the local NVD data cache")
|
||||
.build();
|
||||
|
||||
options.addOption(updateOnly)
|
||||
.addOption(cve12Base)
|
||||
.addOption(cve20Base)
|
||||
.addOption(cve12Modified)
|
||||
.addOption(cve20Modified)
|
||||
.addOption(proxyPort)
|
||||
.addOption(proxyServer)
|
||||
.addOption(proxyUsername)
|
||||
.addOption(proxyPassword)
|
||||
@@ -364,13 +441,28 @@ public final class CliParser {
|
||||
.addOption(disableJarAnalyzer)
|
||||
.addOption(disableArchiveAnalyzer)
|
||||
.addOption(disableAssemblyAnalyzer)
|
||||
.addOption(pathToBundleAudit)
|
||||
.addOption(disablePythonDistributionAnalyzer)
|
||||
.addOption(disableCmakeAnalyzer)
|
||||
.addOption(disablePythonPackageAnalyzer)
|
||||
.addOption(Option.builder().longOpt(ARGUMENT.DISABLE_RUBYGEMS)
|
||||
.desc("Disable the Ruby Gemspec Analyzer.").build())
|
||||
.addOption(Option.builder().longOpt(ARGUMENT.DISABLE_BUNDLE_AUDIT)
|
||||
.desc("Disable the Ruby Bundler-Audit Analyzer.").build())
|
||||
.addOption(disableAutoconfAnalyzer)
|
||||
.addOption(disableComposerAnalyzer)
|
||||
.addOption(disableOpenSSLAnalyzer)
|
||||
.addOption(disableNuspecAnalyzer)
|
||||
.addOption(disableCentralAnalyzer)
|
||||
.addOption(disableNexusAnalyzer)
|
||||
.addOption(Option.builder().longOpt(ARGUMENT.DISABLE_NODE_JS)
|
||||
.desc("Disable the Node.js Package Analyzer.").build())
|
||||
.addOption(nexusUrl)
|
||||
.addOption(nexusUsesProxy)
|
||||
.addOption(additionalZipExtensions)
|
||||
.addOption(pathToMono);
|
||||
.addOption(pathToMono)
|
||||
.addOption(pathToBundleAudit)
|
||||
.addOption(purge);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -380,14 +472,18 @@ public final class CliParser {
|
||||
* @param options a collection of command line arguments
|
||||
* @throws IllegalArgumentException thrown if there is an exception
|
||||
*/
|
||||
@SuppressWarnings("static-access")
|
||||
@SuppressWarnings({"static-access", "deprecation"})
|
||||
private void addDeprecatedOptions(final Options options) throws IllegalArgumentException {
|
||||
|
||||
final Option proxyServer = OptionBuilder.withArgName("url").hasArg().withLongOpt(ARGUMENT.PROXY_URL)
|
||||
.withDescription("The proxy url argument is deprecated, use proxyserver instead.")
|
||||
.create();
|
||||
final Option proxyServer = Option.builder().argName("url").hasArg().longOpt(ARGUMENT.PROXY_URL)
|
||||
.desc("The proxy url argument is deprecated, use proxyserver instead.")
|
||||
.build();
|
||||
final Option appName = Option.builder(ARGUMENT.APP_NAME_SHORT).argName("name").hasArg().longOpt(ARGUMENT.APP_NAME)
|
||||
.desc("The name of the project being scanned.")
|
||||
.build();
|
||||
|
||||
options.addOption(proxyServer);
|
||||
options.addOption(appName);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -417,6 +513,24 @@ public final class CliParser {
|
||||
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.
|
||||
*
|
||||
@@ -453,6 +567,69 @@ public final class CliParser {
|
||||
return (line != null) && line.hasOption(ARGUMENT.DISABLE_ASSEMBLY);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns true if the disableBundleAudit command line argument was specified.
|
||||
*
|
||||
* @return true if the disableBundleAudit command line argument was specified; otherwise false
|
||||
*/
|
||||
public boolean isBundleAuditDisabled() {
|
||||
return (line != null) && line.hasOption(ARGUMENT.DISABLE_BUNDLE_AUDIT);
|
||||
}
|
||||
|
||||
/**
|
||||
* 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 whether the Ruby gemspec analyzer is disabled.
|
||||
*
|
||||
* @return true if the {@link ARGUMENT#DISABLE_RUBYGEMS} command line argument was specified; otherwise false
|
||||
*/
|
||||
public boolean isRubyGemspecDisabled() {
|
||||
return (null != line) && line.hasOption(ARGUMENT.DISABLE_RUBYGEMS);
|
||||
}
|
||||
|
||||
/**
|
||||
* 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 disableComposer command line argument was specified.
|
||||
*
|
||||
* @return true if the disableComposer command line argument was specified; otherwise false
|
||||
*/
|
||||
public boolean isComposerDisabled() {
|
||||
return (line != null) && line.hasOption(ARGUMENT.DISABLE_COMPOSER);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns true if the disableNexus command line argument was specified.
|
||||
*
|
||||
@@ -462,6 +639,24 @@ public final class CliParser {
|
||||
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 disableNodeJS command line argument was specified.
|
||||
*
|
||||
* @return true if the disableNodeJS command line argument was specified; otherwise false
|
||||
*/
|
||||
public boolean isNodeJsDisabled() {
|
||||
return (line != null) && line.hasOption(ARGUMENT.DISABLE_NODE_JS);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns true if the disableCentral command line argument was specified.
|
||||
*
|
||||
@@ -494,7 +689,7 @@ public final class CliParser {
|
||||
// still honor the property if it's set.
|
||||
if (line == null || !line.hasOption(ARGUMENT.NEXUS_USES_PROXY)) {
|
||||
try {
|
||||
return Settings.getBoolean(Settings.KEYS.ANALYZER_NEXUS_PROXY);
|
||||
return Settings.getBoolean(Settings.KEYS.ANALYZER_NEXUS_USES_PROXY);
|
||||
} catch (InvalidSettingException ise) {
|
||||
return true;
|
||||
}
|
||||
@@ -562,6 +757,15 @@ public final class CliParser {
|
||||
return line.getOptionValue(ARGUMENT.PATH_TO_MONO);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the path to bundle-audit for Ruby bundle analysis.
|
||||
*
|
||||
* @return the path to Mono
|
||||
*/
|
||||
public String getPathToBundleAudit() {
|
||||
return line.getOptionValue(ARGUMENT.PATH_TO_BUNDLE_AUDIT);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the output format specified on the command line. Defaults to HTML if no format was specified.
|
||||
*
|
||||
@@ -576,8 +780,50 @@ public final class CliParser {
|
||||
*
|
||||
* @return the application name.
|
||||
*/
|
||||
public String getApplicationName() {
|
||||
return line.getOptionValue(ARGUMENT.APP_NAME);
|
||||
public String getProjectName() {
|
||||
final String appName = line.getOptionValue(ARGUMENT.APP_NAME);
|
||||
String name = line.getOptionValue(ARGUMENT.PROJECT);
|
||||
if (name == null && appName != null) {
|
||||
name = appName;
|
||||
LOGGER.warn("The '" + ARGUMENT.APP_NAME + "' argument should no longer be used; use '" + ARGUMENT.PROJECT + "' instead.");
|
||||
}
|
||||
return 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);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -594,13 +840,14 @@ public final class CliParser {
|
||||
*
|
||||
* @return the proxy server
|
||||
*/
|
||||
@SuppressWarnings("deprecation")
|
||||
public String getProxyServer() {
|
||||
|
||||
String server = line.getOptionValue(ARGUMENT.PROXY_SERVER);
|
||||
if (server == null) {
|
||||
server = line.getOptionValue(ARGUMENT.PROXY_URL);
|
||||
if (server != null) {
|
||||
LOGGER.warning("An old command line argument 'proxyurl' was detected; use proxyserver instead");
|
||||
LOGGER.warn("An old command line argument 'proxyurl' was detected; use proxyserver instead");
|
||||
}
|
||||
}
|
||||
return server;
|
||||
@@ -689,10 +936,28 @@ public final class CliParser {
|
||||
/**
|
||||
* Checks if the auto update feature has been disabled. If it has been disabled via the command line this will return false.
|
||||
*
|
||||
* @return if auto-update is allowed.
|
||||
* @return <code>true</code> if auto-update is allowed; otherwise <code>false</code>
|
||||
*/
|
||||
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);
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks if the purge NVD flag has been set.
|
||||
*
|
||||
* @return <code>true</code> if the purge nvd flag has been set; otherwise <code>false</code>.
|
||||
*/
|
||||
public boolean isPurge() {
|
||||
return line != null && line.hasOption(ARGUMENT.PURGE_NVD);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -749,6 +1014,19 @@ public final class CliParser {
|
||||
return line.getOptionValue(ARGUMENT.ADDITIONAL_ZIP_EXTENSIONS);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the value of cveValidForHours.
|
||||
*
|
||||
* @return the value of cveValidForHours
|
||||
*/
|
||||
public Integer getCveValidForHours() {
|
||||
final String v = line.getOptionValue(ARGUMENT.CVE_VALID_FOR_HOURS);
|
||||
if (v != null) {
|
||||
return Integer.parseInt(v);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* A collection of static final strings that represent the possible command line arguments.
|
||||
*/
|
||||
@@ -770,6 +1048,14 @@ public final class CliParser {
|
||||
* 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";
|
||||
/**
|
||||
* 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 that only the update phase should be executed; no scan should be run.
|
||||
*/
|
||||
public static final String PURGE_NVD = "purge";
|
||||
/**
|
||||
* The long CLI argument name specifying the directory to write the reports to.
|
||||
*/
|
||||
@@ -787,12 +1073,22 @@ public final class CliParser {
|
||||
*/
|
||||
public static final String OUTPUT_FORMAT_SHORT = "f";
|
||||
/**
|
||||
* The long CLI argument name specifying the name of the application to be scanned.
|
||||
* The long CLI argument name specifying the name of the project to be scanned.
|
||||
*/
|
||||
public static final String PROJECT = "project";
|
||||
/**
|
||||
* The long CLI argument name specifying the name of the application to be scanned.
|
||||
*
|
||||
* @deprecated project should be used instead
|
||||
*/
|
||||
@Deprecated
|
||||
public static final String APP_NAME = "app";
|
||||
/**
|
||||
* The short CLI argument name specifying the name of the application to be scanned.
|
||||
*
|
||||
* @deprecated project should be used instead
|
||||
*/
|
||||
@Deprecated
|
||||
public static final String APP_NAME_SHORT = "a";
|
||||
/**
|
||||
* The long CLI argument name asking for help.
|
||||
@@ -825,7 +1121,7 @@ public final class CliParser {
|
||||
/**
|
||||
* 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
|
||||
public static final String PROXY_URL = "proxyurl";
|
||||
@@ -857,6 +1153,22 @@ public final class CliParser {
|
||||
* The CLI argument name for setting the location of the data directory.
|
||||
*/
|
||||
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.
|
||||
*/
|
||||
@@ -869,10 +1181,19 @@ public final class CliParser {
|
||||
* The short CLI argument name for setting the location of the data directory.
|
||||
*/
|
||||
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.
|
||||
*/
|
||||
public static final String SUPPRESSION_FILE = "suppression";
|
||||
/**
|
||||
* The CLI argument name for setting the location of the suppression file.
|
||||
*/
|
||||
public static final String CVE_VALID_FOR_HOURS = "cveValidForHours";
|
||||
/**
|
||||
* Disables the Jar Analyzer.
|
||||
*/
|
||||
@@ -881,10 +1202,38 @@ public final class CliParser {
|
||||
* Disables the Archive Analyzer.
|
||||
*/
|
||||
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 Python Package Analyzer.
|
||||
*/
|
||||
public static final String DISABLE_COMPOSER = "disableComposer";
|
||||
/**
|
||||
* Disables the Ruby Gemspec Analyzer.
|
||||
*/
|
||||
public static final String DISABLE_RUBYGEMS = "disableRubygems";
|
||||
/**
|
||||
* 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.
|
||||
*/
|
||||
public static final String DISABLE_ASSEMBLY = "disableAssembly";
|
||||
/**
|
||||
* Disables the Ruby Bundler Audit Analyzer.
|
||||
*/
|
||||
public static final String DISABLE_BUNDLE_AUDIT = "disableBundleAudit";
|
||||
/**
|
||||
* Disables the Nuspec Analyzer.
|
||||
*/
|
||||
@@ -897,6 +1246,14 @@ public final class CliParser {
|
||||
* Disables the Nexus Analyzer.
|
||||
*/
|
||||
public static final String DISABLE_NEXUS = "disableNexus";
|
||||
/**
|
||||
* Disables the OpenSSL Analyzer.
|
||||
*/
|
||||
public static final String DISABLE_OPENSSL = "disableOpenSSL";
|
||||
/**
|
||||
* Disables the Node.js Package Analyzer.
|
||||
*/
|
||||
public static final String DISABLE_NODE_JS = "disableNodeJS";
|
||||
/**
|
||||
* The URL of the nexus server.
|
||||
*/
|
||||
@@ -937,5 +1294,9 @@ public final class CliParser {
|
||||
* Exclude path argument.
|
||||
*/
|
||||
public static final String EXCLUDE = "exclude";
|
||||
/**
|
||||
* The CLI argument name for setting the path to bundle-audit for Ruby bundle analysis.
|
||||
*/
|
||||
public static final String PATH_TO_BUNDLE_AUDIT = "bundleAudit";
|
||||
}
|
||||
}
|
||||
|
||||
@@ -20,9 +20,14 @@ package org.owasp.dependencycheck;
|
||||
/**
|
||||
* Thrown if an invalid path is encountered.
|
||||
*
|
||||
* @author Jeremy Long <jeremy.long@owasp.org>
|
||||
* @author Jeremy Long
|
||||
*/
|
||||
class InvalidScanPathException extends Exception {
|
||||
public class InvalidScanPathException extends Exception {
|
||||
|
||||
/**
|
||||
* The serial version UID for serialization.
|
||||
*/
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
/**
|
||||
* Creates a new InvalidScanPathException.
|
||||
|
||||
@@ -1,12 +1,4 @@
|
||||
/**
|
||||
* <html>
|
||||
* <head>
|
||||
* <title>org.owasp.dependencycheck</title>
|
||||
* </head>
|
||||
* <body>
|
||||
* Includes the main entry point for the DependencyChecker.
|
||||
* </body>
|
||||
* </html>
|
||||
*/
|
||||
|
||||
*/
|
||||
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>
|
||||
@@ -5,41 +5,60 @@ The following table lists the command line arguments:
|
||||
|
||||
Short | Argument Name | Parameter | Description | Requirement
|
||||
-------|-----------------------|-----------------|-------------|------------
|
||||
\-a | \-\-app | \<name\> | The name of the application being scanned. This is a required argument. | Required
|
||||
| \-\-project | \<name\> | The name of the project being scanned. | Required
|
||||
\-s | \-\-scan | \<path\> | The path to scan \- this option can be specified multiple times. It is also possible to specify Ant style paths (e.g. directory/**/*.jar). | Required
|
||||
| \-\-exclude | \<pattern\> | The path patterns to exclude from the scan \- this option can be specified multiple times. This accepts Ant style path patterns (e.g. **/exclude/**) . | Optional
|
||||
| \-\-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
|
||||
\-l | \-\-log | \<file\> | The file path to write verbose logging information. | Optional
|
||||
\-n | \-\-noupdate | | Disables the automatic updating of the CPE data. | Optional
|
||||
| \-\-suppression | \<file\> | The file path to the suppression XML file; used to suppress [false positives](../suppression.html). | Optional
|
||||
| \-\-suppression | \<file\> | The file path to the suppression XML file; used to suppress [false positives](../general/suppression.html). | Optional
|
||||
\-h | \-\-help | | Print the help message. | Optional
|
||||
| \-\-advancedHelp | | Print the advanced help message. | Optional
|
||||
\-v | \-\-version | | Print the version information. | Optional
|
||||
| \-\-cveValidForHours | \<hours\> | The number of hours to wait before checking for new updates from the NVD. The default is 4 hours. | Optional
|
||||
|
||||
|
||||
Advanced Options
|
||||
================
|
||||
Short | Argument Name | Parameter | Description | Default Value
|
||||
-------|-----------------------|-----------------|-----------------------------------------------------------------------------|---------------
|
||||
Short | Argument Name | Parameter | Description | Default Value
|
||||
-------|-----------------------|-----------------|----------------------------------------------------------------------------------|-------------------
|
||||
| \-\-cveUrl12Modified | \<url\> | URL for the modified CVE 1.2 | https://nvd.nist.gov/download/nvdcve-Modified.xml.gz
|
||||
| \-\-cveUrl20Modified | \<url\> | URL for the modified CVE 2.0 | https://nvd.nist.gov/feeds/xml/cve/nvdcve-2.0-Modified.xml.gz
|
||||
| \-\-cveUrl12Base | \<url\> | Base URL for each year's CVE 1.2, the %d will be replaced with the year | https://nvd.nist.gov/download/nvdcve-%d.xml.gz
|
||||
| \-\-cveUrl20Base | \<url\> | Base URL for each year's CVE 2.0, the %d will be replaced with the year | https://nvd.nist.gov/feeds/xml/cve/nvdcve-2.0-%d.xml.gz
|
||||
\-P | \-\-propertyfile | \<file\> | Specifies a file that contains properties to use instead of applicaion defaults. |
|
||||
| \-\-disableArchive | | Sets whether the Archive Analyzer will be used. | false
|
||||
| \-\-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
|
||||
| \-\-disableNodeJS | | Sets whether the Node.js Package Analyzer will be used. | false
|
||||
| \-\-disableRubygems | | Sets whether the Ruby Gemspec Analyzer will be used. | false
|
||||
| \-\-disableBundleAudit | | Sets whether the Ruby Bundler Audit 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 disabled. | false
|
||||
| \-\-disableArchive | | Sets whether the Archive Analyzer will be disabled. | false
|
||||
| \-\-zipExtensions | \<strings\> | A comma-separated list of additional file extensions to be treated like a ZIP file, the contents will be extracted and analyzed. |
|
||||
| \-\-disableJar | | Sets whether the Jar Analyzer will be used. | false
|
||||
| \-\-disableJar | | Sets whether the Jar Analyzer will be disabled. | false
|
||||
| \-\-disableComposer | | Sets whether the PHP Composer Lock File Analyzer will be disabled. | false
|
||||
| \-\-disableCentral | | Sets whether the Central Analyzer will be used. **Disabling this analyzer is not recommended as it could lead to false negatives (e.g. libraries that have vulnerabilities may not be reported correctly).** If this analyzer is being disabled there is a good chance you also want to disable the Nexus Analyzer. | false
|
||||
| \-\-disableNexus | | Sets whether the Nexus Analyzer will be used. Note, this has been superceded by the Central Analyzer. However, you can configure the Nexus URL to utilize an internally hosted Nexus Pro server. | false
|
||||
| \-\-nexus | \<url\> | The url to the Nexus Pro Server. If not set the Nexus Analyzer will be disabled. |
|
||||
| \-\-nexusUsesProxy | \<true\|false\> | Whether or not the defined proxy should be used when connecting to Nexus. | true
|
||||
| \-\-disableNuspec | | Sets whether or not the .NET Nuget Nuspec Analyzer will be used. | false
|
||||
| \-\-disableAssembly | | Sets whether or not the .NET Assembly Analyzer should be used. | false
|
||||
| \-\-pathToMono | \<path\> | The path to Mono for .NET Assembly analysis on non-windows systems. |
|
||||
| \-\-proxyserver | \<server\> | The proxy server to use when downloading resources. |
|
||||
| \-\-proxyport | \<port\> | The proxy port to use when downloading resources. |
|
||||
| \-\-connectiontimeout | \<timeout\> | The connection timeout (in milliseconds) to use when downloading resources. |
|
||||
| \-\-proxypass | \<pass\> | The proxy password to use when downloading resources. |
|
||||
| \-\-proxyuser | \<user\> | The proxy username to use when downloading resources. |
|
||||
| \-\-connectionString | \<connStr\> | The connection string to the database. |
|
||||
| \-\-dbDriverName | \<driver\> | The database driver name. |
|
||||
| \-\-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
|
||||
| \-\-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
|
||||
| \-\-mono | \<path\> | The path to Mono for .NET Assembly analysis on non-windows systems. |
|
||||
| \-\-bundleAudit | | The path to the bundle-audit executable. |
|
||||
| \-\-proxyserver | \<server\> | The proxy server to use when downloading resources. |
|
||||
| \-\-proxyport | \<port\> | The proxy port to use when downloading resources. |
|
||||
| \-\-connectiontimeout | \<timeout\> | The connection timeout (in milliseconds) to use when downloading resources. |
|
||||
| \-\-proxypass | \<pass\> | The proxy password to use when downloading resources. |
|
||||
| \-\-proxyuser | \<user\> | The proxy username to use when downloading resources. |
|
||||
| \-\-connectionString | \<connStr\> | The connection string to the database. |
|
||||
| \-\-dbDriverName | \<driver\> | The database driver name. |
|
||||
| \-\-dbDriverPath | \<path\> | The path to the database driver; note, this does not need to be set unless the JAR is outside of the class path. |
|
||||
| \-\-dbPassword | \<password\> | The password for connecting to the database. |
|
||||
| \-\-dbUser | \<user\> | The username used to connect to the database. |
|
||||
| \-\-dbPassword | \<password\> | The password for connecting to the database. |
|
||||
| \-\-dbUser | \<user\> | The username used to connect to the database. |
|
||||
\-d | \-\-data | \<path\> | The location of the data directory used to store persistent data. This option should generally not be set. |
|
||||
| \-\-purge | | Delete the local copy of the NVD. This is used to force a refresh of the data. |
|
||||
39
dependency-check-cli/src/site/markdown/index.md.vm
Normal file
39
dependency-check-cli/src/site/markdown/index.md.vm
Normal file
@@ -0,0 +1,39 @@
|
||||
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
|
||||
====================
|
||||
Download the dependency-check command line tool [here](http://dl.bintray.com/jeremy-long/owasp/dependency-check-${project.version}-release.zip).
|
||||
Extract the zip file to a location on your computer and put the 'bin' directory into the
|
||||
path environment variable. On \*nix systems you will likely need to make the shell
|
||||
script executable:
|
||||
|
||||
$ chmod +777 dependency-check.sh
|
||||
|
||||
#set( $H = '#' )
|
||||
|
||||
$H$H$H Homebrew
|
||||
$ brew install dependency-check
|
||||
|
||||
This puts an executable `dependency-check` script in the `/bin` directory of
|
||||
your homebrew installation.
|
||||
|
||||
To scan a folder on the system you can run:
|
||||
|
||||
$H$H$H Windows
|
||||
dependency-check.bat --project "My App Name" --scan "c:\java\application\lib"
|
||||
|
||||
$H$H$H *nix
|
||||
dependency-check.sh --project "My App Name" --scan "/java/application/lib"
|
||||
|
||||
To view the command line arguments, see the <a href="arguments.html">arguments page</a>, or you can run:
|
||||
|
||||
$H$H$H Windows
|
||||
dependency-check.bat --help
|
||||
|
||||
$H$H$H *nix
|
||||
dependency-check.sh --help
|
||||
@@ -1,25 +0,0 @@
|
||||
Installation & Usage
|
||||
====================
|
||||
Download the dependency-check command line tool [here](http://dl.bintray.com/jeremy-long/owasp/dependency-check-${project.version}-release.zip).
|
||||
Extract the zip file to a location on your computer and put the 'bin' directory into the
|
||||
path environment variable. On \*nix systems you will likely need to make the shell
|
||||
script executable:
|
||||
|
||||
$ chmod +777 dependency-check.sh
|
||||
|
||||
To scan a folder on the system you can run:
|
||||
#set( $H = '#' )
|
||||
|
||||
$H$H$H Windows
|
||||
dependency-check.bat --app "My App Name" --scan "c:\java\application\lib"
|
||||
|
||||
$H$H$H *nix
|
||||
dependency-check.sh --app "My App Name" --scan "/java/application/lib"
|
||||
|
||||
To view the command line arguments, see the <a href="arguments.html">arguments page</a>, or you can run:
|
||||
|
||||
$H$H$H Windows
|
||||
dependency-check.bat --help
|
||||
|
||||
$H$H$H *nix
|
||||
dependency-check.sh --help
|
||||
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">
|
||||
<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>
|
||||
<body>
|
||||
<breadcrumbs>
|
||||
<item name="dependency-check" href="../index.html"/>
|
||||
</breadcrumbs>
|
||||
<menu name="Getting Started">
|
||||
<item name="Installation" href="installation.html"/>
|
||||
<item name="Installation" href="index.html"/>
|
||||
<item name="Configuration" href="arguments.html"/>
|
||||
</menu>
|
||||
<menu ref="Project Documentation" />
|
||||
<menu ref="reports" />
|
||||
</body>
|
||||
</project>
|
||||
@@ -0,0 +1,75 @@
|
||||
/*
|
||||
* This file is part of dependency-check-core.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*
|
||||
* Copyright (c) 2015 The OWASP Foundatio. All Rights Reserved.
|
||||
*/
|
||||
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));
|
||||
}
|
||||
}
|
||||
@@ -34,7 +34,7 @@ import org.owasp.dependencycheck.utils.Settings;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author Jeremy Long <jeremy.long@owasp.org>
|
||||
* @author Jeremy Long
|
||||
*/
|
||||
public class CliParserTest {
|
||||
|
||||
|
||||
@@ -17,7 +17,7 @@ Copyright & License
|
||||
|
||||
Dependency-Check is Copyright (c) 2012-2014 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://raw.githubusercontent.com/jeremylong/DependencyCheck/master/LICENSE.txt) file for the full license.
|
||||
|
||||
Dependency-Check makes use of several other open source libraries. Please see the [NOTICE.txt] [notices] file for more information.
|
||||
|
||||
@@ -25,4 +25,4 @@ Dependency-Check makes use of several other open source libraries. Please see th
|
||||
[wiki]: https://github.com/jeremylong/DependencyCheck/wiki
|
||||
[subscribe]: mailto:dependency-check+subscribe@googlegroups.com
|
||||
[post]: mailto:dependency-check@googlegroups.com
|
||||
[notices]: https://github.com/jeremylong/DependencyCheck/blob/master/NOTICES.txt
|
||||
[notices]: https://raw.githubusercontent.com/jeremylong/DependencyCheck/master/NOTICE.txt
|
||||
@@ -20,7 +20,7 @@ Copyright (c) 2012 Jeremy Long. All Rights Reserved.
|
||||
<parent>
|
||||
<groupId>org.owasp</groupId>
|
||||
<artifactId>dependency-check-parent</artifactId>
|
||||
<version>1.2.9</version>
|
||||
<version>1.3.5</version>
|
||||
</parent>
|
||||
|
||||
<artifactId>dependency-check-core</artifactId>
|
||||
@@ -101,7 +101,7 @@ Copyright (c) 2012 Jeremy Long. All Rights Reserved.
|
||||
</goals>
|
||||
<configuration>
|
||||
<outputDirectory>${project.build.directory}/test-classes</outputDirectory>
|
||||
<includeScope>provided</includeScope>
|
||||
<includeScope>test</includeScope>
|
||||
</configuration>
|
||||
</execution>
|
||||
</executions>
|
||||
@@ -110,19 +110,17 @@ Copyright (c) 2012 Jeremy Long. All Rights Reserved.
|
||||
<groupId>org.apache.maven.plugins</groupId>
|
||||
<artifactId>maven-jar-plugin</artifactId>
|
||||
<executions>
|
||||
<execution>
|
||||
<id>jar</id>
|
||||
<phase>package</phase>
|
||||
<goals>
|
||||
<goal>jar</goal>
|
||||
</goals>
|
||||
</execution>
|
||||
<execution>
|
||||
<id>test-jar</id>
|
||||
<phase>package</phase>
|
||||
<goals>
|
||||
<goal>test-jar</goal>
|
||||
</goals>
|
||||
<configuration>
|
||||
<includes>
|
||||
<include>**/*.class</include>
|
||||
</includes>
|
||||
</configuration>
|
||||
</execution>
|
||||
</executions>
|
||||
</plugin>
|
||||
@@ -205,69 +203,21 @@ Copyright (c) 2012 Jeremy Long. All Rights Reserved.
|
||||
<name>data.directory</name>
|
||||
<value>${project.build.directory}/data</value>
|
||||
</property>
|
||||
<property>
|
||||
<name>temp.directory</name>
|
||||
<value>${project.build.directory}/temp</value>
|
||||
</property>
|
||||
</systemProperties>
|
||||
</configuration>
|
||||
</plugin>
|
||||
<plugin>
|
||||
<groupId>org.apache.maven.plugins</groupId>
|
||||
<artifactId>maven-compiler-plugin</artifactId>
|
||||
<configuration>
|
||||
<compilerArgument>-Xlint:unchecked</compilerArgument>
|
||||
</configuration>
|
||||
</plugin>
|
||||
</plugins>
|
||||
</build>
|
||||
<reporting>
|
||||
<plugins>
|
||||
<plugin>
|
||||
<groupId>org.apache.maven.plugins</groupId>
|
||||
<artifactId>maven-javadoc-plugin</artifactId>
|
||||
<version>2.9.1</version>
|
||||
<configuration>
|
||||
<bottom>Copyright© 2012-15 Jeremy Long. All Rights Reserved.</bottom>
|
||||
</configuration>
|
||||
<reportSets>
|
||||
<reportSet>
|
||||
<id>default</id>
|
||||
<reports>
|
||||
<report>javadoc</report>
|
||||
</reports>
|
||||
</reportSet>
|
||||
</reportSets>
|
||||
</plugin>
|
||||
<plugin>
|
||||
<groupId>org.codehaus.mojo</groupId>
|
||||
<artifactId>versions-maven-plugin</artifactId>
|
||||
<version>2.1</version>
|
||||
<reportSets>
|
||||
<reportSet>
|
||||
<reports>
|
||||
<report>dependency-updates-report</report>
|
||||
<report>plugin-updates-report</report>
|
||||
</reports>
|
||||
</reportSet>
|
||||
</reportSets>
|
||||
</plugin>
|
||||
<plugin>
|
||||
<groupId>org.apache.maven.plugins</groupId>
|
||||
<artifactId>maven-jxr-plugin</artifactId>
|
||||
<version>2.4</version>
|
||||
</plugin>
|
||||
<plugin>
|
||||
<groupId>org.codehaus.mojo</groupId>
|
||||
<artifactId>cobertura-maven-plugin</artifactId>
|
||||
<version>2.6</version>
|
||||
</plugin>
|
||||
<plugin>
|
||||
<groupId>org.apache.maven.plugins</groupId>
|
||||
<artifactId>maven-surefire-report-plugin</artifactId>
|
||||
<version>2.16</version>
|
||||
<reportSets>
|
||||
<reportSet>
|
||||
<reports>
|
||||
<report>report-only</report>
|
||||
</reports>
|
||||
</reportSet>
|
||||
<reportSet>
|
||||
<id>integration-tests</id>
|
||||
<reports>
|
||||
@@ -277,34 +227,10 @@ Copyright (c) 2012 Jeremy Long. All Rights Reserved.
|
||||
</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>
|
||||
<version>${reporting.checkstyle-plugin.version}</version>
|
||||
<configuration>
|
||||
<enableRulesSummary>false</enableRulesSummary>
|
||||
<enableFilesSummary>false</enableFilesSummary>
|
||||
@@ -317,7 +243,7 @@ Copyright (c) 2012 Jeremy Long. All Rights Reserved.
|
||||
<plugin>
|
||||
<groupId>org.apache.maven.plugins</groupId>
|
||||
<artifactId>maven-pmd-plugin</artifactId>
|
||||
<version>3.1</version>
|
||||
<version>${reporting.pmd-plugin.version}</version>
|
||||
<configuration>
|
||||
<targetJdk>1.6</targetJdk>
|
||||
<linkXref>true</linkXref>
|
||||
@@ -333,15 +259,25 @@ Copyright (c) 2012 Jeremy Long. All Rights Reserved.
|
||||
</rulesets>
|
||||
</configuration>
|
||||
</plugin>
|
||||
<plugin>
|
||||
<groupId>org.codehaus.mojo</groupId>
|
||||
<artifactId>findbugs-maven-plugin</artifactId>
|
||||
<version>2.5.3</version>
|
||||
</plugin>
|
||||
</plugins>
|
||||
</reporting>
|
||||
<dependencies>
|
||||
<!-- Note, to stay compatible with Jenkins installations only JARs compiled to 1.6 can be used -->
|
||||
<dependency>
|
||||
<groupId>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-classic</artifactId>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.owasp</groupId>
|
||||
<artifactId>dependency-check-utils</artifactId>
|
||||
@@ -350,7 +286,6 @@ Copyright (c) 2012 Jeremy Long. All Rights Reserved.
|
||||
<dependency>
|
||||
<groupId>org.apache.lucene</groupId>
|
||||
<artifactId>lucene-test-framework</artifactId>
|
||||
<version>${apache.lucene.version}</version>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
@@ -358,120 +293,113 @@ Copyright (c) 2012 Jeremy Long. All Rights Reserved.
|
||||
<artifactId>jmockit</artifactId>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>com.google.code.findbugs</groupId>
|
||||
<artifactId>annotations</artifactId>
|
||||
<version>3.0.0</version>
|
||||
<optional>true</optional>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.apache.commons</groupId>
|
||||
<artifactId>commons-compress</artifactId>
|
||||
<version>1.9</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>commons-io</groupId>
|
||||
<artifactId>commons-io</artifactId>
|
||||
<version>2.4</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>commons-lang</groupId>
|
||||
<artifactId>commons-lang</artifactId>
|
||||
<version>2.6</version>
|
||||
<groupId>org.apache.commons</groupId>
|
||||
<artifactId>commons-lang3</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.apache.lucene</groupId>
|
||||
<artifactId>lucene-core</artifactId>
|
||||
<version>${apache.lucene.version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.apache.lucene</groupId>
|
||||
<artifactId>lucene-analyzers-common</artifactId>
|
||||
<version>${apache.lucene.version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.apache.lucene</groupId>
|
||||
<artifactId>lucene-queryparser</artifactId>
|
||||
<version>${apache.lucene.version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.apache.velocity</groupId>
|
||||
<artifactId>velocity</artifactId>
|
||||
<version>1.7</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>com.h2database</groupId>
|
||||
<artifactId>h2</artifactId>
|
||||
<version>1.3.176</version>
|
||||
<scope>runtime</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.glassfish</groupId>
|
||||
<artifactId>javax.json</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.jsoup</groupId>
|
||||
<artifactId>jsoup</artifactId>
|
||||
<version>1.7.2</version>
|
||||
<type>jar</type>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>com.sun.mail</groupId>
|
||||
<artifactId>mailapi</artifactId>
|
||||
</dependency>
|
||||
<!-- The following dependencies are only used during testing -->
|
||||
<dependency>
|
||||
<groupId>org.apache.maven.scm</groupId>
|
||||
<artifactId>maven-scm-provider-cvsexe</artifactId>
|
||||
<version>1.8.1</version>
|
||||
<scope>provided</scope>
|
||||
<scope>test</scope>
|
||||
<optional>true</optional>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.springframework</groupId>
|
||||
<artifactId>spring-webmvc</artifactId>
|
||||
<version>2.5.5</version>
|
||||
<scope>provided</scope>
|
||||
<scope>test</scope>
|
||||
<optional>true</optional>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.springframework.security</groupId>
|
||||
<artifactId>spring-security-web</artifactId>
|
||||
<version>3.0.0.RELEASE</version>
|
||||
<scope>provided</scope>
|
||||
<scope>test</scope>
|
||||
<optional>true</optional>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>com.hazelcast</groupId>
|
||||
<artifactId>hazelcast</artifactId>
|
||||
<version>2.5</version>
|
||||
<scope>provided</scope>
|
||||
<scope>test</scope>
|
||||
<optional>true</optional>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>net.sf.ehcache</groupId>
|
||||
<artifactId>ehcache-core</artifactId>
|
||||
<version>2.2.0</version>
|
||||
<scope>provided</scope>
|
||||
<scope>test</scope>
|
||||
<optional>true</optional>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.apache.struts</groupId>
|
||||
<artifactId>struts2-core</artifactId>
|
||||
<version>2.1.2</version>
|
||||
<scope>provided</scope>
|
||||
<scope>test</scope>
|
||||
<optional>true</optional>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.mortbay.jetty</groupId>
|
||||
<artifactId>jetty</artifactId>
|
||||
<version>6.1.0</version>
|
||||
<scope>provided</scope>
|
||||
<scope>test</scope>
|
||||
<optional>true</optional>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.apache.axis2</groupId>
|
||||
<artifactId>axis2-spring</artifactId>
|
||||
<version>1.4.1</version>
|
||||
<scope>provided</scope>
|
||||
<scope>test</scope>
|
||||
<optional>true</optional>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.apache.axis2</groupId>
|
||||
<artifactId>axis2-adb</artifactId>
|
||||
<version>1.4.1</version>
|
||||
<scope>provided</scope>
|
||||
<scope>test</scope>
|
||||
<optional>true</optional>
|
||||
</dependency>
|
||||
<dependency>
|
||||
@@ -479,7 +407,7 @@ Copyright (c) 2012 Jeremy Long. All Rights Reserved.
|
||||
<artifactId>daytrader-ear</artifactId>
|
||||
<version>2.1.7</version>
|
||||
<type>ear</type>
|
||||
<scope>provided</scope>
|
||||
<scope>test</scope>
|
||||
<optional>true</optional>
|
||||
</dependency>
|
||||
<dependency>
|
||||
@@ -487,7 +415,7 @@ Copyright (c) 2012 Jeremy Long. All Rights Reserved.
|
||||
<artifactId>war</artifactId>
|
||||
<version>4.0</version>
|
||||
<type>war</type>
|
||||
<scope>provided</scope>
|
||||
<scope>test</scope>
|
||||
<optional>true</optional>
|
||||
</dependency>
|
||||
<dependency>
|
||||
@@ -495,28 +423,42 @@ Copyright (c) 2012 Jeremy Long. All Rights Reserved.
|
||||
<artifactId>dojo-war</artifactId>
|
||||
<version>1.3.0</version>
|
||||
<type>war</type>
|
||||
<scope>provided</scope>
|
||||
<scope>test</scope>
|
||||
<optional>true</optional>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.apache.openjpa</groupId>
|
||||
<artifactId>openjpa</artifactId>
|
||||
<version>2.0.1</version>
|
||||
<scope>provided</scope>
|
||||
<scope>test</scope>
|
||||
<optional>true</optional>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>com.google.inject</groupId>
|
||||
<artifactId>guice</artifactId>
|
||||
<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>provided</scope>
|
||||
<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>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>xalan</groupId>
|
||||
<artifactId>xalan</artifactId>
|
||||
<version>2.7.0</version>
|
||||
<scope>test</scope>
|
||||
<optional>true</optional>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
@@ -526,7 +468,6 @@ Copyright (c) 2012 Jeremy Long. All Rights Reserved.
|
||||
<activation>
|
||||
<property>
|
||||
<name>mysql</name>
|
||||
<!--value>test</value-->
|
||||
</property>
|
||||
</activation>
|
||||
<build>
|
||||
@@ -534,7 +475,6 @@ Copyright (c) 2012 Jeremy Long. All Rights Reserved.
|
||||
<plugin>
|
||||
<groupId>org.apache.maven.plugins</groupId>
|
||||
<artifactId>maven-surefire-plugin</artifactId>
|
||||
<version>2.18.1</version>
|
||||
<configuration>
|
||||
<skip>true</skip>
|
||||
</configuration>
|
||||
@@ -542,12 +482,68 @@ Copyright (c) 2012 Jeremy Long. All Rights Reserved.
|
||||
<plugin>
|
||||
<groupId>org.apache.maven.plugins</groupId>
|
||||
<artifactId>maven-failsafe-plugin</artifactId>
|
||||
<version>2.18.1</version>
|
||||
<configuration>
|
||||
<systemProperties>
|
||||
<property>
|
||||
<name>data.driver_path</name>
|
||||
<value>${basedir}/${driver_path}</value>
|
||||
<value>${driver_path}</value>
|
||||
</property>
|
||||
<property>
|
||||
<name>data.driver_name</name>
|
||||
<value>${driver_name}</value>
|
||||
</property>
|
||||
<property>
|
||||
<name>data.connection_string</name>
|
||||
<value>${connection_string}</value>
|
||||
</property>
|
||||
</systemProperties>
|
||||
<includes>
|
||||
<include>**/*MySQLTest.java</include>
|
||||
</includes>
|
||||
</configuration>
|
||||
<executions>
|
||||
<execution>
|
||||
<goals>
|
||||
<goal>integration-test</goal>
|
||||
<goal>verify</goal>
|
||||
</goals>
|
||||
</execution>
|
||||
</executions>
|
||||
</plugin>
|
||||
</plugins>
|
||||
</build>
|
||||
</profile>
|
||||
<profile>
|
||||
<id>Postgresql-IntegrationTest</id>
|
||||
<activation>
|
||||
<property>
|
||||
<name>postgresql</name>
|
||||
</property>
|
||||
</activation>
|
||||
<dependencies>
|
||||
<dependency>
|
||||
<groupId>org.postgresql</groupId>
|
||||
<artifactId>postgresql</artifactId>
|
||||
<version>9.4-1204-jdbc42</version>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
<build>
|
||||
<plugins>
|
||||
<plugin>
|
||||
<groupId>org.apache.maven.plugins</groupId>
|
||||
<artifactId>maven-surefire-plugin</artifactId>
|
||||
<configuration>
|
||||
<skip>true</skip>
|
||||
</configuration>
|
||||
</plugin>
|
||||
<plugin>
|
||||
<groupId>org.apache.maven.plugins</groupId>
|
||||
<artifactId>maven-failsafe-plugin</artifactId>
|
||||
<configuration>
|
||||
<systemProperties>
|
||||
<property>
|
||||
<name>data.driver_path</name>
|
||||
<value>${driver_path}</value>
|
||||
</property>
|
||||
<property>
|
||||
<name>data.driver_name</name>
|
||||
@@ -590,99 +586,150 @@ Copyright (c) 2012 Jeremy Long. All Rights Reserved.
|
||||
<groupId>org.apache.xmlgraphics</groupId>
|
||||
<artifactId>batik-util</artifactId>
|
||||
<version>1.7</version>
|
||||
<scope>provided</scope>
|
||||
<scope>test</scope>
|
||||
<optional>true</optional>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>com.thoughtworks.xstream</groupId>
|
||||
<artifactId>xstream</artifactId>
|
||||
<version>1.4.2</version>
|
||||
<scope>provided</scope>
|
||||
<scope>test</scope>
|
||||
<optional>true</optional>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.apache.ws.security</groupId>
|
||||
<artifactId>wss4j</artifactId>
|
||||
<version>1.5.7</version>
|
||||
<scope>provided</scope>
|
||||
<scope>test</scope>
|
||||
<optional>true</optional>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>com.ganyo</groupId>
|
||||
<artifactId>gcm-server</artifactId>
|
||||
<version>1.0.2</version>
|
||||
<scope>provided</scope>
|
||||
<scope>test</scope>
|
||||
<optional>true</optional>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.python</groupId>
|
||||
<artifactId>jython-standalone</artifactId>
|
||||
<version>2.7-b1</version>
|
||||
<scope>provided</scope>
|
||||
<scope>test</scope>
|
||||
<optional>true</optional>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.jruby</groupId>
|
||||
<artifactId>jruby-complete</artifactId>
|
||||
<version>1.7.4</version>
|
||||
<scope>provided</scope>
|
||||
<scope>test</scope>
|
||||
<optional>true</optional>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.jruby</groupId>
|
||||
<artifactId>jruby</artifactId>
|
||||
<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>provided</scope>
|
||||
<scope>test</scope>
|
||||
<optional>true</optional>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>com.sun.jersey</groupId>
|
||||
<artifactId>jersey-client</artifactId>
|
||||
<version>1.11.1</version>
|
||||
<scope>provided</scope>
|
||||
<scope>test</scope>
|
||||
<optional>true</optional>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>com.sun.faces</groupId>
|
||||
<artifactId>jsf-impl</artifactId>
|
||||
<version>2.2.8-02</version>
|
||||
<scope>provided</scope>
|
||||
<scope>test</scope>
|
||||
<optional>true</optional>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>com.google.inject</groupId>
|
||||
<artifactId>guice</artifactId>
|
||||
<version>3.0</version>
|
||||
<scope>provided</scope>
|
||||
<scope>test</scope>
|
||||
<optional>true</optional>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.opensaml</groupId>
|
||||
<artifactId>xmltooling</artifactId>
|
||||
<version>1.4.1</version>
|
||||
<scope>provided</scope>
|
||||
<scope>test</scope>
|
||||
<optional>true</optional>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.springframework</groupId>
|
||||
<artifactId>spring-webmvc</artifactId>
|
||||
<version>3.2.12.RELEASE</version>
|
||||
<scope>provided</scope>
|
||||
<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>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
</profile>
|
||||
</profiles>
|
||||
<properties>
|
||||
<!-- new versions of lucene are compiled with JDK 1.7 and cannot be used ubiquitously in Jenkins
|
||||
this, we cannot upgrade beyond 4.7.2 -->
|
||||
<apache.lucene.version>4.7.2</apache.lucene.version>
|
||||
</properties>
|
||||
</project>
|
||||
|
||||
@@ -17,15 +17,6 @@
|
||||
*/
|
||||
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.Analyzer;
|
||||
import org.owasp.dependencycheck.analyzer.AnalyzerService;
|
||||
@@ -39,18 +30,29 @@ import org.owasp.dependencycheck.data.update.UpdateService;
|
||||
import org.owasp.dependencycheck.data.update.exception.UpdateException;
|
||||
import org.owasp.dependencycheck.dependency.Dependency;
|
||||
import org.owasp.dependencycheck.exception.NoDataException;
|
||||
import org.owasp.dependencycheck.utils.FileUtils;
|
||||
import org.owasp.dependencycheck.utils.InvalidSettingException;
|
||||
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.Collection;
|
||||
import java.util.EnumMap;
|
||||
import java.util.HashSet;
|
||||
import java.util.Iterator;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
|
||||
/**
|
||||
* Scans files, directories, etc. for Dependencies. Analyzers are loaded and used to process the files found by the
|
||||
* scan, if a file is encountered and an Analyzer is associated with the file type then the file is turned into a
|
||||
* dependency.
|
||||
* Scans files, directories, etc. for Dependencies. Analyzers are loaded and used to process the files found by the scan, if a
|
||||
* file is encountered and an Analyzer is associated with the file type then the file is turned into a dependency.
|
||||
*
|
||||
* @author Jeremy Long <jeremy.long@owasp.org>
|
||||
* @author Jeremy Long
|
||||
*/
|
||||
public class Engine {
|
||||
public class Engine implements FileFilter {
|
||||
|
||||
/**
|
||||
* The list of dependencies.
|
||||
@@ -59,7 +61,7 @@ public class Engine {
|
||||
/**
|
||||
* A Map of analyzers grouped by Analysis phase.
|
||||
*/
|
||||
private EnumMap<AnalysisPhase, List<Analyzer>> analyzers = new EnumMap<AnalysisPhase, List<Analyzer>>(AnalysisPhase.class);
|
||||
private Map<AnalysisPhase, List<Analyzer>> analyzers = new EnumMap<AnalysisPhase, List<Analyzer>>(AnalysisPhase.class);
|
||||
|
||||
/**
|
||||
* A Map of analyzers grouped by Analysis phase.
|
||||
@@ -73,7 +75,7 @@ public class Engine {
|
||||
/**
|
||||
* 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.
|
||||
@@ -163,19 +165,17 @@ public class Engine {
|
||||
}
|
||||
|
||||
/**
|
||||
* 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.
|
||||
* 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 paths an array of paths to files or directories to be analyzed
|
||||
* @return the list of dependencies scanned
|
||||
*
|
||||
* @since v0.3.2.5
|
||||
*/
|
||||
public List<Dependency> scan(String[] paths) {
|
||||
final List<Dependency> deps = new ArrayList<Dependency>();
|
||||
for (String path : paths) {
|
||||
final File file = new File(path);
|
||||
final List<Dependency> d = scan(file);
|
||||
final List<Dependency> d = scan(path);
|
||||
if (d != null) {
|
||||
deps.addAll(d);
|
||||
}
|
||||
@@ -184,8 +184,8 @@ public class Engine {
|
||||
}
|
||||
|
||||
/**
|
||||
* 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.
|
||||
* 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
|
||||
* @return the list of dependencies scanned
|
||||
@@ -196,12 +196,11 @@ public class Engine {
|
||||
}
|
||||
|
||||
/**
|
||||
* 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.
|
||||
* 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.
|
||||
* @return the list of dependencies
|
||||
*
|
||||
* @since v0.3.2.5
|
||||
*/
|
||||
public List<Dependency> scan(File[] files) {
|
||||
@@ -216,54 +215,31 @@ public class Engine {
|
||||
}
|
||||
|
||||
/**
|
||||
* 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
|
||||
* Scans a collection 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(Collection<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()) {
|
||||
@@ -313,35 +289,30 @@ public class Engine {
|
||||
* @return the scanned dependency
|
||||
*/
|
||||
protected Dependency scanFile(File file) {
|
||||
if (!file.isFile()) {
|
||||
final String msg = String.format("Path passed to scanFile(File) is not a file: %s. Skipping the file.", file.toString());
|
||||
LOGGER.log(Level.FINE, msg);
|
||||
return null;
|
||||
}
|
||||
final String fileName = file.getName();
|
||||
final String extension = FileUtils.getFileExtension(fileName);
|
||||
Dependency dependency = null;
|
||||
if (extension != null) {
|
||||
if (supportsExtension(extension)) {
|
||||
if (file.isFile()) {
|
||||
if (accept(file)) {
|
||||
dependency = new Dependency(file);
|
||||
dependencies.add(dependency);
|
||||
}
|
||||
} else {
|
||||
final String msg = String.format("No file extension found on file '%s'. The file was not analyzed.", file.toString());
|
||||
LOGGER.log(Level.FINE, msg);
|
||||
LOGGER.debug("Path passed to scanFile(File) is not a file: {}. Skipping the file.", file);
|
||||
}
|
||||
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() {
|
||||
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.");
|
||||
LOGGER.debug("Invalid setting for auto-update; using true.");
|
||||
}
|
||||
if (autoUpdate) {
|
||||
doUpdates();
|
||||
@@ -351,24 +322,19 @@ public class Engine {
|
||||
try {
|
||||
ensureDataExists();
|
||||
} catch (NoDataException ex) {
|
||||
final String msg = String.format("%s%n%nUnable to continue dependency-check analysis.", ex.getMessage());
|
||||
LOGGER.log(Level.SEVERE, msg);
|
||||
LOGGER.log(Level.FINE, null, ex);
|
||||
LOGGER.error("{}\n\nUnable to continue dependency-check analysis.", ex.getMessage());
|
||||
LOGGER.debug("", ex);
|
||||
return;
|
||||
} catch (DatabaseException ex) {
|
||||
final String msg = String.format("%s%n%nUnable to continue dependency-check analysis.", ex.getMessage());
|
||||
LOGGER.log(Level.SEVERE, msg);
|
||||
LOGGER.log(Level.FINE, null, ex);
|
||||
LOGGER.error("{}\n\nUnable to continue dependency-check analysis.", ex.getMessage());
|
||||
LOGGER.debug("", ex);
|
||||
return;
|
||||
|
||||
}
|
||||
|
||||
final String logHeader = String.format("%n"
|
||||
+ "----------------------------------------------------%n"
|
||||
+ "BEGIN ANALYSIS%n"
|
||||
+ "----------------------------------------------------");
|
||||
LOGGER.log(Level.FINE, logHeader);
|
||||
LOGGER.log(Level.INFO, "Analysis Starting");
|
||||
LOGGER.debug("\n----------------------------------------------------\nBEGIN ANALYSIS\n----------------------------------------------------");
|
||||
LOGGER.info("Analysis Starting");
|
||||
final long analysisStart = System.currentTimeMillis();
|
||||
|
||||
// analysis phases
|
||||
for (AnalysisPhase phase : AnalysisPhase.values()) {
|
||||
@@ -381,30 +347,25 @@ public class Engine {
|
||||
* analyzers may modify it. This prevents ConcurrentModificationExceptions.
|
||||
* This is okay for adds/deletes because it happens per analyzer.
|
||||
*/
|
||||
final String msg = String.format("Begin Analyzer '%s'", a.getName());
|
||||
LOGGER.log(Level.FINE, msg);
|
||||
final Set<Dependency> dependencySet = new HashSet<Dependency>();
|
||||
dependencySet.addAll(dependencies);
|
||||
LOGGER.debug("Begin Analyzer '{}'", a.getName());
|
||||
final Set<Dependency> dependencySet = new HashSet<Dependency>(dependencies);
|
||||
for (Dependency d : dependencySet) {
|
||||
boolean shouldAnalyze = true;
|
||||
if (a instanceof FileTypeAnalyzer) {
|
||||
final FileTypeAnalyzer fAnalyzer = (FileTypeAnalyzer) a;
|
||||
shouldAnalyze = fAnalyzer.supportsExtension(d.getFileExtension());
|
||||
shouldAnalyze = fAnalyzer.accept(d.getActualFile());
|
||||
}
|
||||
if (shouldAnalyze) {
|
||||
final String msgFile = String.format("Begin Analysis of '%s'", d.getActualFilePath());
|
||||
LOGGER.log(Level.FINE, msgFile);
|
||||
LOGGER.debug("Begin Analysis of '{}'", d.getActualFilePath());
|
||||
try {
|
||||
a.analyze(d, this);
|
||||
} catch (AnalysisException ex) {
|
||||
final String exMsg = String.format("An error occurred while analyzing '%s'.", d.getActualFilePath());
|
||||
LOGGER.log(Level.WARNING, exMsg);
|
||||
LOGGER.log(Level.FINE, "", ex);
|
||||
LOGGER.warn("An error occurred while analyzing '{}'.", d.getActualFilePath());
|
||||
LOGGER.debug("", 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);
|
||||
LOGGER.log(Level.WARNING, axMsg);
|
||||
LOGGER.log(Level.FINE, "", ex);
|
||||
LOGGER.warn("An unexpected error occurred during analysis of '{}'", d.getActualFilePath());
|
||||
LOGGER.debug("", ex);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -418,12 +379,8 @@ public class Engine {
|
||||
}
|
||||
}
|
||||
|
||||
final String logFooter = String.format("%n"
|
||||
+ "----------------------------------------------------%n"
|
||||
+ "END ANALYSIS%n"
|
||||
+ "----------------------------------------------------");
|
||||
LOGGER.log(Level.FINE, logFooter);
|
||||
LOGGER.log(Level.INFO, "Analysis Complete");
|
||||
LOGGER.debug("\n----------------------------------------------------\nEND ANALYSIS\n----------------------------------------------------");
|
||||
LOGGER.info("Analysis Complete ({} ms)", System.currentTimeMillis() - analysisStart);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -434,17 +391,15 @@ public class Engine {
|
||||
*/
|
||||
protected Analyzer initializeAnalyzer(Analyzer analyzer) {
|
||||
try {
|
||||
final String msg = String.format("Initializing %s", analyzer.getName());
|
||||
LOGGER.log(Level.FINE, msg);
|
||||
LOGGER.debug("Initializing {}", analyzer.getName());
|
||||
analyzer.initialize();
|
||||
} catch (Throwable ex) {
|
||||
final String msg = String.format("Exception occurred initializing %s.", analyzer.getName());
|
||||
LOGGER.log(Level.SEVERE, msg);
|
||||
LOGGER.log(Level.FINE, null, ex);
|
||||
LOGGER.error("Exception occurred initializing {}.", analyzer.getName());
|
||||
LOGGER.debug("", ex);
|
||||
try {
|
||||
analyzer.close();
|
||||
} catch (Throwable ex1) {
|
||||
LOGGER.log(Level.FINEST, null, ex1);
|
||||
LOGGER.trace("", ex1);
|
||||
}
|
||||
}
|
||||
return analyzer;
|
||||
@@ -456,20 +411,20 @@ public class Engine {
|
||||
* @param analyzer the analyzer to close
|
||||
*/
|
||||
protected void closeAnalyzer(Analyzer analyzer) {
|
||||
final String msg = String.format("Closing Analyzer '%s'", analyzer.getName());
|
||||
LOGGER.log(Level.FINE, msg);
|
||||
LOGGER.debug("Closing Analyzer '{}'", analyzer.getName());
|
||||
try {
|
||||
analyzer.close();
|
||||
} 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.
|
||||
*/
|
||||
private void doUpdates() {
|
||||
public void doUpdates() {
|
||||
LOGGER.info("Checking for updates");
|
||||
final long updateStart = System.currentTimeMillis();
|
||||
final UpdateService service = new UpdateService(serviceClassLoader);
|
||||
final Iterator<CachedWebDataSource> iterator = service.getDataSources();
|
||||
while (iterator.hasNext()) {
|
||||
@@ -477,12 +432,12 @@ public class Engine {
|
||||
try {
|
||||
source.update();
|
||||
} 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.");
|
||||
LOGGER.log(Level.FINE, String.format("Unable to update details for %s", source.getClass().getName()), ex);
|
||||
LOGGER.debug("Unable to update details for {}", source.getClass().getName(), ex);
|
||||
}
|
||||
}
|
||||
LOGGER.info("Check for updates complete");
|
||||
LOGGER.info("Check for updates complete ({} ms)", System.currentTimeMillis() - updateStart);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -502,18 +457,19 @@ public class Engine {
|
||||
/**
|
||||
* 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
|
||||
*/
|
||||
public boolean supportsExtension(String ext) {
|
||||
if (ext == null) {
|
||||
@Override
|
||||
public boolean accept(File file) {
|
||||
if (file == null) {
|
||||
return false;
|
||||
}
|
||||
boolean scan = false;
|
||||
for (FileTypeAnalyzer a : this.fileTypeAnalyzers) {
|
||||
/* note, we can't break early on this loop as the analyzers need to know if
|
||||
they have files to work on prior to initialization */
|
||||
scan |= a.supportsExtension(ext);
|
||||
scan |= a.accept(file);
|
||||
}
|
||||
return scan;
|
||||
}
|
||||
|
||||
@@ -20,8 +20,6 @@ package org.owasp.dependencycheck.agent;
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.util.List;
|
||||
import java.util.logging.Level;
|
||||
import java.util.logging.Logger;
|
||||
import org.owasp.dependencycheck.Engine;
|
||||
import org.owasp.dependencycheck.data.nvdcve.CveDB;
|
||||
import org.owasp.dependencycheck.data.nvdcve.DatabaseException;
|
||||
@@ -32,16 +30,18 @@ import org.owasp.dependencycheck.dependency.Vulnerability;
|
||||
import org.owasp.dependencycheck.exception.ScanAgentException;
|
||||
import org.owasp.dependencycheck.reporting.ReportGenerator;
|
||||
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
|
||||
* evidence from the files themselves. This class is based on the Ant task and Maven plugin with the exception that it
|
||||
* takes a list of dependencies that can be programmatically added from data in a spreadsheet, database or some other
|
||||
* datasource and conduct a scan based on this pre-defined evidence.
|
||||
* This class provides a way to easily conduct a scan solely based on existing evidence metadata rather than collecting evidence
|
||||
* from the files themselves. This class is based on the Ant task and Maven plugin with the exception that it takes a list of
|
||||
* dependencies that can be programmatically added from data in a spreadsheet, database or some other datasource and conduct a
|
||||
* scan based on this pre-defined evidence.
|
||||
*
|
||||
* <h2>Example:</h2>
|
||||
* <pre>
|
||||
* List<Dependency> dependencies = new ArrayList<Dependency>();
|
||||
* List<Dependency> dependencies = new ArrayList<Dependency>();
|
||||
* Dependency dependency = new Dependency(new File(FileUtils.getBitBucket()));
|
||||
* dependency.getProductEvidence().addEvidence("my-datasource", "name", "Jetty", Confidence.HIGH);
|
||||
* dependency.getVersionEvidence().addEvidence("my-datasource", "version", "5.1.10", Confidence.HIGH);
|
||||
@@ -55,7 +55,7 @@ import org.owasp.dependencycheck.utils.Settings;
|
||||
* scan.execute();
|
||||
* </pre>
|
||||
*
|
||||
* @author Steve Springett <steve.springett@owasp.org>
|
||||
* @author Steve Springett
|
||||
*/
|
||||
@SuppressWarnings("unused")
|
||||
public class DependencyCheckScanAgent {
|
||||
@@ -67,7 +67,7 @@ public class DependencyCheckScanAgent {
|
||||
/**
|
||||
* 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.
|
||||
*/
|
||||
@@ -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
|
||||
* which means since the CVSS scores are 0-10, by default the build will never fail and the CVSS score is set to 11.
|
||||
* The valid range for the fail build on CVSS is 0 to 11, where anything above 10 will not cause the build to fail.
|
||||
* Specifies if the build should be failed if a CVSS score above a specified level is identified. The default is 11 which
|
||||
* means since the CVSS scores are 0-10, by default the build will never fail and the CVSS score is set to 11. The valid range
|
||||
* for the fail build on CVSS is 0 to 11, where anything above 10 will not cause the build to fail.
|
||||
*/
|
||||
private float failBuildOnCVSS = 11;
|
||||
|
||||
@@ -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
|
||||
* false. Default is true.
|
||||
* Sets whether auto-updating of the NVD CVE/CPE data is enabled. It is not recommended that this be turned to false. Default
|
||||
* is true.
|
||||
*/
|
||||
private boolean autoUpdate = true;
|
||||
|
||||
@@ -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
|
||||
* within the Site plugin unless the externalReport is set to true. Default is HTML.
|
||||
* flag indicating whether or not to generate a report of findings.
|
||||
*/
|
||||
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;
|
||||
|
||||
@@ -671,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
|
||||
* like ZIP files.
|
||||
* Additional ZIP File extensions to add analyze. This should be a comma-separated list of file extensions to treat like ZIP
|
||||
* files.
|
||||
*/
|
||||
private String zipExtensions;
|
||||
|
||||
@@ -813,13 +836,11 @@ public class DependencyCheckScanAgent {
|
||||
* Executes the Dependency-Check on the dependent libraries.
|
||||
*
|
||||
* @return the Engine used to scan the dependencies.
|
||||
* @throws org.owasp.dependencycheck.data.nvdcve.DatabaseException thrown if there is an exception connecting to the
|
||||
* database
|
||||
* @throws org.owasp.dependencycheck.data.nvdcve.DatabaseException thrown if there is an exception connecting to the database
|
||||
*/
|
||||
private Engine executeDependencyCheck() throws DatabaseException {
|
||||
populateSettings();
|
||||
Engine engine = null;
|
||||
engine = new Engine();
|
||||
final Engine engine = new Engine();
|
||||
engine.setDependencies(this.dependencies);
|
||||
engine.analyzeDependencies();
|
||||
return engine;
|
||||
@@ -839,7 +860,7 @@ public class DependencyCheckScanAgent {
|
||||
cve.open();
|
||||
prop = cve.getDatabaseProperties();
|
||||
} catch (DatabaseException ex) {
|
||||
LOGGER.log(Level.FINE, "Unable to retrieve DB Properties", ex);
|
||||
LOGGER.debug("Unable to retrieve DB Properties", ex);
|
||||
} finally {
|
||||
if (cve != null) {
|
||||
cve.close();
|
||||
@@ -849,19 +870,19 @@ public class DependencyCheckScanAgent {
|
||||
try {
|
||||
r.generateReports(outDirectory.getCanonicalPath(), this.reportFormat.name());
|
||||
} catch (IOException ex) {
|
||||
LOGGER.log(Level.SEVERE,
|
||||
LOGGER.error(
|
||||
"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) {
|
||||
LOGGER.log(Level.SEVERE,
|
||||
LOGGER.error(
|
||||
"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
|
||||
* properties required to change the proxy server, port, and connection timeout.
|
||||
* Takes the properties supplied and updates the dependency-check settings. Additionally, this sets the system properties
|
||||
* required to change the proxy server, port, and connection timeout.
|
||||
*/
|
||||
private void populateSettings() {
|
||||
Settings.initialize();
|
||||
@@ -876,80 +897,43 @@ public class DependencyCheckScanAgent {
|
||||
}
|
||||
|
||||
Settings.setBoolean(Settings.KEYS.AUTO_UPDATE, autoUpdate);
|
||||
|
||||
if (proxyServer != null && !proxyServer.isEmpty()) {
|
||||
Settings.setString(Settings.KEYS.PROXY_SERVER, proxyServer);
|
||||
}
|
||||
if (proxyPort != null && !proxyPort.isEmpty()) {
|
||||
Settings.setString(Settings.KEYS.PROXY_PORT, proxyPort);
|
||||
}
|
||||
if (proxyUsername != null && !proxyUsername.isEmpty()) {
|
||||
Settings.setString(Settings.KEYS.PROXY_USERNAME, proxyUsername);
|
||||
}
|
||||
if (proxyPassword != null && !proxyPassword.isEmpty()) {
|
||||
Settings.setString(Settings.KEYS.PROXY_PASSWORD, proxyPassword);
|
||||
}
|
||||
if (connectionTimeout != null && !connectionTimeout.isEmpty()) {
|
||||
Settings.setString(Settings.KEYS.CONNECTION_TIMEOUT, connectionTimeout);
|
||||
}
|
||||
if (suppressionFile != null && !suppressionFile.isEmpty()) {
|
||||
Settings.setString(Settings.KEYS.SUPPRESSION_FILE, suppressionFile);
|
||||
}
|
||||
Settings.setStringIfNotEmpty(Settings.KEYS.PROXY_SERVER, proxyServer);
|
||||
Settings.setStringIfNotEmpty(Settings.KEYS.PROXY_PORT, proxyPort);
|
||||
Settings.setStringIfNotEmpty(Settings.KEYS.PROXY_USERNAME, proxyUsername);
|
||||
Settings.setStringIfNotEmpty(Settings.KEYS.PROXY_PASSWORD, proxyPassword);
|
||||
Settings.setStringIfNotEmpty(Settings.KEYS.CONNECTION_TIMEOUT, connectionTimeout);
|
||||
Settings.setStringIfNotEmpty(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.setStringIfNotEmpty(Settings.KEYS.ANALYZER_CENTRAL_URL, centralUrl);
|
||||
Settings.setBoolean(Settings.KEYS.ANALYZER_NEXUS_ENABLED, nexusAnalyzerEnabled);
|
||||
if (nexusUrl != null && !nexusUrl.isEmpty()) {
|
||||
Settings.setString(Settings.KEYS.ANALYZER_NEXUS_URL, nexusUrl);
|
||||
}
|
||||
Settings.setBoolean(Settings.KEYS.ANALYZER_NEXUS_PROXY, nexusUsesProxy);
|
||||
if (databaseDriverName != null && !databaseDriverName.isEmpty()) {
|
||||
Settings.setString(Settings.KEYS.DB_DRIVER_NAME, databaseDriverName);
|
||||
}
|
||||
if (databaseDriverPath != null && !databaseDriverPath.isEmpty()) {
|
||||
Settings.setString(Settings.KEYS.DB_DRIVER_PATH, databaseDriverPath);
|
||||
}
|
||||
if (connectionString != null && !connectionString.isEmpty()) {
|
||||
Settings.setString(Settings.KEYS.DB_CONNECTION_STRING, connectionString);
|
||||
}
|
||||
if (databaseUser != null && !databaseUser.isEmpty()) {
|
||||
Settings.setString(Settings.KEYS.DB_USER, databaseUser);
|
||||
}
|
||||
if (databasePassword != null && !databasePassword.isEmpty()) {
|
||||
Settings.setString(Settings.KEYS.DB_PASSWORD, databasePassword);
|
||||
}
|
||||
if (zipExtensions != null && !zipExtensions.isEmpty()) {
|
||||
Settings.setString(Settings.KEYS.ADDITIONAL_ZIP_EXTENSIONS, zipExtensions);
|
||||
}
|
||||
if (cveUrl12Modified != null && !cveUrl12Modified.isEmpty()) {
|
||||
Settings.setString(Settings.KEYS.CVE_MODIFIED_12_URL, cveUrl12Modified);
|
||||
}
|
||||
if (cveUrl20Modified != null && !cveUrl20Modified.isEmpty()) {
|
||||
Settings.setString(Settings.KEYS.CVE_MODIFIED_20_URL, cveUrl20Modified);
|
||||
}
|
||||
if (cveUrl12Base != null && !cveUrl12Base.isEmpty()) {
|
||||
Settings.setString(Settings.KEYS.CVE_SCHEMA_1_2, cveUrl12Base);
|
||||
}
|
||||
if (cveUrl20Base != null && !cveUrl20Base.isEmpty()) {
|
||||
Settings.setString(Settings.KEYS.CVE_SCHEMA_2_0, cveUrl20Base);
|
||||
}
|
||||
if (pathToMono != null && !pathToMono.isEmpty()) {
|
||||
Settings.setString(Settings.KEYS.ANALYZER_ASSEMBLY_MONO_PATH, pathToMono);
|
||||
}
|
||||
Settings.setStringIfNotEmpty(Settings.KEYS.ANALYZER_NEXUS_URL, nexusUrl);
|
||||
Settings.setBoolean(Settings.KEYS.ANALYZER_NEXUS_USES_PROXY, nexusUsesProxy);
|
||||
Settings.setStringIfNotEmpty(Settings.KEYS.DB_DRIVER_NAME, databaseDriverName);
|
||||
Settings.setStringIfNotEmpty(Settings.KEYS.DB_DRIVER_PATH, databaseDriverPath);
|
||||
Settings.setStringIfNotEmpty(Settings.KEYS.DB_CONNECTION_STRING, connectionString);
|
||||
Settings.setStringIfNotEmpty(Settings.KEYS.DB_USER, databaseUser);
|
||||
Settings.setStringIfNotEmpty(Settings.KEYS.DB_PASSWORD, databasePassword);
|
||||
Settings.setStringIfNotEmpty(Settings.KEYS.ADDITIONAL_ZIP_EXTENSIONS, zipExtensions);
|
||||
Settings.setStringIfNotEmpty(Settings.KEYS.CVE_MODIFIED_12_URL, cveUrl12Modified);
|
||||
Settings.setStringIfNotEmpty(Settings.KEYS.CVE_MODIFIED_20_URL, cveUrl20Modified);
|
||||
Settings.setStringIfNotEmpty(Settings.KEYS.CVE_SCHEMA_1_2, cveUrl12Base);
|
||||
Settings.setStringIfNotEmpty(Settings.KEYS.CVE_SCHEMA_2_0, cveUrl20Base);
|
||||
Settings.setStringIfNotEmpty(Settings.KEYS.ANALYZER_ASSEMBLY_MONO_PATH, pathToMono);
|
||||
}
|
||||
|
||||
/**
|
||||
* Executes the dependency-check and generates the report.
|
||||
*
|
||||
* @throws org.owasp.dependencycheck.exception.ScanAgentException thrown if there is an exception executing the
|
||||
* scan.
|
||||
* @return a reference to the engine used to perform the 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;
|
||||
try {
|
||||
engine = executeDependencyCheck();
|
||||
generateExternalReports(engine, new File(this.reportOutputDirectory));
|
||||
if (this.generateReport) {
|
||||
generateExternalReports(engine, new File(this.reportOutputDirectory));
|
||||
}
|
||||
if (this.showSummary) {
|
||||
showSummary(engine.getDependencies());
|
||||
}
|
||||
@@ -957,15 +941,16 @@ public class DependencyCheckScanAgent {
|
||||
checkForFailure(engine.getDependencies());
|
||||
}
|
||||
} catch (DatabaseException ex) {
|
||||
LOGGER.log(Level.SEVERE,
|
||||
LOGGER.error(
|
||||
"Unable to connect to the dependency-check database; analysis has stopped");
|
||||
LOGGER.log(Level.FINE, "", ex);
|
||||
LOGGER.debug("", ex);
|
||||
} finally {
|
||||
Settings.cleanup(true);
|
||||
if (engine != null) {
|
||||
engine.cleanup();
|
||||
}
|
||||
}
|
||||
return engine;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -973,8 +958,7 @@ public class DependencyCheckScanAgent {
|
||||
* configuration.
|
||||
*
|
||||
* @param dependencies the list of dependency objects
|
||||
* @throws org.owasp.dependencycheck.exception.ScanAgentException thrown if there is an exception executing the
|
||||
* scan.
|
||||
* @throws org.owasp.dependencycheck.exception.ScanAgentException thrown if there is an exception executing the scan.
|
||||
*/
|
||||
private void checkForFailure(List<Dependency> dependencies) throws ScanAgentException {
|
||||
final StringBuilder ids = new StringBuilder();
|
||||
@@ -1034,10 +1018,9 @@ public class DependencyCheckScanAgent {
|
||||
}
|
||||
}
|
||||
if (summary.length() > 0) {
|
||||
final String msg = String.format("%n%n"
|
||||
+ "One or more dependencies were identified with known vulnerabilities:%n%n%s"
|
||||
+ "%n%nSee the dependency-check report for more details.%n%n", summary.toString());
|
||||
LOGGER.log(Level.WARNING, msg);
|
||||
LOGGER.warn("\n\nOne or more dependencies were identified with known vulnerabilities:\n\n{}\n\n"
|
||||
+ "See the dependency-check report for more details.\n\n",
|
||||
summary.toString());
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -1,13 +1,6 @@
|
||||
/**
|
||||
* <html>
|
||||
* <head>
|
||||
* <title>org.owasp.dependencycheck.agent</title>
|
||||
* </head>
|
||||
* <body>
|
||||
* The agent package holds an agent API that can be used by other applications that have information about dependencies;
|
||||
* but would rather implement something in their code directly rather then spawn a process to run the entire
|
||||
* dependency-check engine. This basically provides programmatic access to running a scan.
|
||||
* </body>
|
||||
* </html>
|
||||
* 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.
|
||||
*/
|
||||
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 {
|
||||
|
||||
|
||||
@@ -17,28 +17,30 @@
|
||||
*/
|
||||
package org.owasp.dependencycheck.analyzer;
|
||||
|
||||
import java.util.Collections;
|
||||
import java.util.HashSet;
|
||||
import java.util.Set;
|
||||
import java.util.logging.Level;
|
||||
import java.util.logging.Logger;
|
||||
import org.owasp.dependencycheck.Engine;
|
||||
import org.owasp.dependencycheck.analyzer.exception.AnalysisException;
|
||||
import org.owasp.dependencycheck.dependency.Dependency;
|
||||
import org.owasp.dependencycheck.utils.InvalidSettingException;
|
||||
import org.owasp.dependencycheck.utils.Settings;
|
||||
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.
|
||||
*
|
||||
* @author Jeremy Long <jeremy.long@owasp.org>
|
||||
* @author Jeremy Long
|
||||
*/
|
||||
public abstract class AbstractFileTypeAnalyzer extends AbstractAnalyzer implements FileTypeAnalyzer {
|
||||
|
||||
//<editor-fold defaultstate="collapsed" desc="Constructor">
|
||||
/**
|
||||
* Base constructor that all children must call. This checks the configuration to determine if the analyzer is
|
||||
* enabled.
|
||||
* Base constructor that all children must call. This checks the configuration to determine if the analyzer is enabled.
|
||||
*/
|
||||
public AbstractFileTypeAnalyzer() {
|
||||
reset();
|
||||
@@ -49,7 +51,7 @@ public abstract class AbstractFileTypeAnalyzer extends AbstractAnalyzer implemen
|
||||
/**
|
||||
* 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.
|
||||
*/
|
||||
@@ -100,19 +102,15 @@ public abstract class AbstractFileTypeAnalyzer extends AbstractAnalyzer implemen
|
||||
//<editor-fold defaultstate="collapsed" desc="Abstract methods children must implement">
|
||||
/**
|
||||
* <p>
|
||||
* Returns a list of supported file extensions. An example would be an analyzer that inspected java jar files. The
|
||||
* getSupportedExtensions function would return a set with a single element "jar".</p>
|
||||
*
|
||||
* Returns the {@link java.io.FileFilter} used to determine which files are to be analyzed. An example would be an analyzer
|
||||
* that inspected Java jar files. Implementors may use {@link org.owasp.dependencycheck.utils.FileFilterBuilder}.</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>
|
||||
* @return the file filter used to determine which files are to be analyzed
|
||||
*/
|
||||
protected abstract Set<String> getSupportedExtensions();
|
||||
protected abstract FileFilter getFileFilter();
|
||||
|
||||
/**
|
||||
* Initializes the file type analyzer.
|
||||
@@ -122,8 +120,8 @@ public abstract class AbstractFileTypeAnalyzer extends AbstractAnalyzer implemen
|
||||
protected abstract void initializeFileTypeAnalyzer() throws Exception;
|
||||
|
||||
/**
|
||||
* Analyzes a given dependency. If the dependency is an archive, such as a WAR or EAR, the contents are extracted,
|
||||
* scanned, and added to the list of dependencies within the engine.
|
||||
* Analyzes a given dependency. If the dependency is an archive, such as a WAR or EAR, the contents are extracted, scanned,
|
||||
* and added to the list of dependencies within the engine.
|
||||
*
|
||||
* @param dependency the dependency to analyze
|
||||
* @param engine the engine scanning
|
||||
@@ -164,17 +162,15 @@ public abstract class AbstractFileTypeAnalyzer extends AbstractAnalyzer implemen
|
||||
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);
|
||||
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.
|
||||
* Analyzes a given dependency. If the dependency is an archive, such as a WAR or EAR, the contents are extracted, scanned,
|
||||
* and added to the list of dependencies within the engine.
|
||||
*
|
||||
* @param dependency the dependency to analyze
|
||||
* @param engine the engine scanning
|
||||
@@ -187,39 +183,27 @@ 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
|
||||
public final boolean supportsExtension(String extension) {
|
||||
if (!enabled) {
|
||||
return false;
|
||||
}
|
||||
final Set<String> ext = getSupportedExtensions();
|
||||
if (ext == null) {
|
||||
final String msg = String.format("The '%s' analyzer is misconfigured and does not have any file extensions;"
|
||||
+ " it will be disabled", getName());
|
||||
LOGGER.log(Level.SEVERE, msg);
|
||||
return false;
|
||||
} else {
|
||||
final boolean match = ext.contains(extension);
|
||||
if (match) {
|
||||
filesMatched = match;
|
||||
public boolean accept(File pathname) {
|
||||
final FileFilter filter = getFileFilter();
|
||||
boolean accepted = false;
|
||||
if (null == filter) {
|
||||
LOGGER.error("The '{}' analyzer is misconfigured and does not have a file filter; it will be disabled", getName());
|
||||
} else if (enabled) {
|
||||
accepted = filter.accept(pathname);
|
||||
if (accepted) {
|
||||
filesMatched = true;
|
||||
}
|
||||
return match;
|
||||
}
|
||||
return accepted;
|
||||
}
|
||||
//</editor-fold>
|
||||
|
||||
//</editor-fold>
|
||||
//<editor-fold defaultstate="collapsed" desc="Static utility methods">
|
||||
/**
|
||||
* <p>
|
||||
* Utility method to help in the creation of the extensions set. This constructs a new Set that can be used in a
|
||||
* final static declaration.</p>
|
||||
*
|
||||
* Utility method to help in the creation of the extensions set. This constructs a new Set that can be used in a final static
|
||||
* declaration.</p>
|
||||
* <p>
|
||||
* This implementation was copied from
|
||||
* http://stackoverflow.com/questions/2041778/initialize-java-hashset-values-by-construction</p>
|
||||
@@ -228,10 +212,10 @@ public abstract class AbstractFileTypeAnalyzer extends AbstractAnalyzer implemen
|
||||
* @return a Set of strings.
|
||||
*/
|
||||
protected static Set<String> newHashSet(String... strings) {
|
||||
final Set<String> set = new HashSet<String>();
|
||||
|
||||
final Set<String> set = new HashSet<String>(strings.length);
|
||||
Collections.addAll(set, strings);
|
||||
return set;
|
||||
}
|
||||
|
||||
//</editor-fold>
|
||||
}
|
||||
|
||||
@@ -24,8 +24,6 @@ import java.net.MalformedURLException;
|
||||
import java.net.URL;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
import java.util.logging.Level;
|
||||
import java.util.logging.Logger;
|
||||
import java.util.regex.Pattern;
|
||||
import org.owasp.dependencycheck.suppression.SuppressionParseException;
|
||||
import org.owasp.dependencycheck.suppression.SuppressionParser;
|
||||
@@ -34,18 +32,20 @@ import org.owasp.dependencycheck.utils.DownloadFailedException;
|
||||
import org.owasp.dependencycheck.utils.Downloader;
|
||||
import org.owasp.dependencycheck.utils.FileUtils;
|
||||
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.
|
||||
*
|
||||
* @author Jeremy Long <jeremy.long@owasp.org>
|
||||
* @author Jeremy Long
|
||||
*/
|
||||
public abstract class AbstractSuppressionAnalyzer extends AbstractAnalyzer {
|
||||
|
||||
/**
|
||||
* 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">
|
||||
/**
|
||||
@@ -103,7 +103,7 @@ public abstract class AbstractSuppressionAnalyzer extends AbstractAnalyzer {
|
||||
try {
|
||||
rules = parser.parseSuppressionRules(this.getClass().getClassLoader().getResourceAsStream("dependencycheck-base-suppression.xml"));
|
||||
} catch (SuppressionParseException ex) {
|
||||
LOGGER.log(Level.FINE, "Unable to parse the base suppression data file", ex);
|
||||
LOGGER.debug("Unable to parse the base suppression data file", ex);
|
||||
}
|
||||
final String suppressionFilePath = Settings.getString(Settings.KEYS.SUPPRESSION_FILE);
|
||||
if (suppressionFilePath == null) {
|
||||
@@ -141,12 +141,11 @@ public abstract class AbstractSuppressionAnalyzer extends AbstractAnalyzer {
|
||||
try {
|
||||
//rules = 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) {
|
||||
final String msg = String.format("Unable to parse suppression xml file '%s'", file.getPath());
|
||||
LOGGER.log(Level.WARNING, msg);
|
||||
LOGGER.log(Level.WARNING, ex.getMessage());
|
||||
LOGGER.log(Level.FINE, "", ex);
|
||||
LOGGER.warn("Unable to parse suppression xml file '{}'", file.getPath());
|
||||
LOGGER.warn(ex.getMessage());
|
||||
LOGGER.debug("", ex);
|
||||
throw ex;
|
||||
}
|
||||
}
|
||||
@@ -171,8 +170,8 @@ public abstract class AbstractSuppressionAnalyzer extends AbstractAnalyzer {
|
||||
* @throws SuppressionParseException throws the generated SuppressionParseException
|
||||
*/
|
||||
private void throwSuppressionParseException(String message, Exception exception) throws SuppressionParseException {
|
||||
LOGGER.log(Level.WARNING, message);
|
||||
LOGGER.log(Level.FINE, "", exception);
|
||||
LOGGER.warn(message);
|
||||
LOGGER.debug("", exception);
|
||||
throw new SuppressionParseException(message, exception);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -20,7 +20,7 @@ package org.owasp.dependencycheck.analyzer;
|
||||
/**
|
||||
* An enumeration defining the phases of analysis.
|
||||
*
|
||||
* @author Jeremy Long <jeremy.long@owasp.org>
|
||||
* @author Jeremy Long
|
||||
*/
|
||||
public enum AnalysisPhase {
|
||||
|
||||
@@ -28,6 +28,10 @@ public enum AnalysisPhase {
|
||||
* Initialization phase.
|
||||
*/
|
||||
INITIAL,
|
||||
/**
|
||||
* Pre information collection phase.
|
||||
*/
|
||||
PRE_INFORMATION_COLLECTION,
|
||||
/**
|
||||
* Information collection phase.
|
||||
*/
|
||||
|
||||
@@ -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
|
||||
* about the dependency in the form of Evidence.
|
||||
*
|
||||
* @author Jeremy Long <jeremy.long@owasp.org>
|
||||
* @author Jeremy Long
|
||||
*/
|
||||
public interface Analyzer {
|
||||
|
||||
|
||||
@@ -24,7 +24,7 @@ import java.util.ServiceLoader;
|
||||
* The Analyzer Service Loader. This class loads all services that implement
|
||||
* org.owasp.dependencycheck.analyzer.Analyzer.
|
||||
*
|
||||
* @author Jeremy Long <jeremy.long@owasp.org>
|
||||
* @author Jeremy Long
|
||||
*/
|
||||
public class AnalyzerService {
|
||||
|
||||
|
||||
@@ -18,21 +18,20 @@
|
||||
package org.owasp.dependencycheck.analyzer;
|
||||
|
||||
import java.io.BufferedInputStream;
|
||||
import java.io.BufferedOutputStream;
|
||||
import java.io.Closeable;
|
||||
import java.io.File;
|
||||
import java.io.FileFilter;
|
||||
import java.io.FileInputStream;
|
||||
import java.io.FileNotFoundException;
|
||||
import java.io.FileOutputStream;
|
||||
import java.io.IOException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.Collections;
|
||||
import java.util.Enumeration;
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
import java.util.logging.Level;
|
||||
import java.util.logging.Logger;
|
||||
|
||||
import org.apache.commons.compress.archivers.ArchiveEntry;
|
||||
import org.apache.commons.compress.archivers.ArchiveInputStream;
|
||||
import org.apache.commons.compress.archivers.tar.TarArchiveInputStream;
|
||||
@@ -40,32 +39,36 @@ import org.apache.commons.compress.archivers.zip.ZipArchiveEntry;
|
||||
import org.apache.commons.compress.archivers.zip.ZipArchiveInputStream;
|
||||
import org.apache.commons.compress.archivers.zip.ZipFile;
|
||||
import org.apache.commons.compress.compressors.CompressorInputStream;
|
||||
import org.apache.commons.compress.compressors.bzip2.BZip2CompressorInputStream;
|
||||
import org.apache.commons.compress.compressors.bzip2.BZip2Utils;
|
||||
import org.apache.commons.compress.compressors.gzip.GzipCompressorInputStream;
|
||||
import org.apache.commons.compress.compressors.gzip.GzipUtils;
|
||||
import org.apache.commons.compress.utils.IOUtils;
|
||||
|
||||
import org.owasp.dependencycheck.Engine;
|
||||
import org.owasp.dependencycheck.analyzer.exception.AnalysisException;
|
||||
import org.owasp.dependencycheck.analyzer.exception.ArchiveExtractionException;
|
||||
import org.owasp.dependencycheck.dependency.Dependency;
|
||||
import org.owasp.dependencycheck.utils.FileFilterBuilder;
|
||||
import org.owasp.dependencycheck.utils.FileUtils;
|
||||
import org.owasp.dependencycheck.utils.Settings;
|
||||
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
/**
|
||||
* <p>
|
||||
* An analyzer that extracts files from archives and ensures any supported files contained within the archive are added
|
||||
* to the dependency list.</p>
|
||||
* An analyzer that extracts files from archives and ensures any supported files contained within the archive are added to the
|
||||
* dependency list.</p>
|
||||
*
|
||||
* @author Jeremy Long <jeremy.long@owasp.org>
|
||||
* @author Jeremy Long
|
||||
*/
|
||||
public class ArchiveAnalyzer extends AbstractFileTypeAnalyzer {
|
||||
|
||||
/**
|
||||
* The logger.
|
||||
*/
|
||||
private static final Logger LOGGER = Logger.getLogger(ArchiveAnalyzer.class.getName());
|
||||
/**
|
||||
* The buffer size to use when extracting files from the archive.
|
||||
*/
|
||||
private static final int BUFFER_SIZE = 4096;
|
||||
private static final Logger LOGGER = LoggerFactory.getLogger(ArchiveAnalyzer.class);
|
||||
/**
|
||||
* The count of directories created during analysis. This is used for creating temporary directories.
|
||||
*/
|
||||
@@ -97,35 +100,41 @@ public class ArchiveAnalyzer extends AbstractFileTypeAnalyzer {
|
||||
*/
|
||||
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
|
||||
* to be explicitly handled in extractFiles().
|
||||
* The set of file extensions supported by this analyzer. Note for developers, any additions to this list will need to be
|
||||
* explicitly handled in {@link #extractFiles(File, File, Engine)}.
|
||||
*/
|
||||
private static final Set<String> EXTENSIONS = newHashSet("tar", "gz", "tgz");
|
||||
private static final Set<String> EXTENSIONS = newHashSet("tar", "gz", "tgz", "bz2", "tbz2");
|
||||
|
||||
/**
|
||||
* 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", "bz2", "tbz2")
|
||||
.build();
|
||||
|
||||
static {
|
||||
final String additionalZipExt = Settings.getString(Settings.KEYS.ADDITIONAL_ZIP_EXTENSIONS);
|
||||
if (additionalZipExt != null) {
|
||||
final Set<String> ext = new HashSet<String>(Arrays.asList(additionalZipExt));
|
||||
ZIPPABLES.addAll(ext);
|
||||
final String[] ext = additionalZipExt.split("\\s*,\\s*");
|
||||
Collections.addAll(ZIPPABLES, ext);
|
||||
}
|
||||
EXTENSIONS.addAll(ZIPPABLES);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a list of file EXTENSIONS supported by this analyzer.
|
||||
*
|
||||
* @return a list of file EXTENSIONS supported by this analyzer.
|
||||
* The file filter used to filter supported files.
|
||||
*/
|
||||
private static final FileFilter FILTER = FileFilterBuilder.newInstance().addExtensions(EXTENSIONS).build();
|
||||
|
||||
@Override
|
||||
public Set<String> getSupportedExtensions() {
|
||||
return EXTENSIONS;
|
||||
protected FileFilter getFileFilter() {
|
||||
return FILTER;
|
||||
}
|
||||
|
||||
/**
|
||||
* Detects files with .zip extension.
|
||||
*/
|
||||
private static final FileFilter ZIP_FILTER = FileFilterBuilder.newInstance().addExtensions("zip").build();
|
||||
|
||||
/**
|
||||
* Returns the name of the analyzer.
|
||||
*
|
||||
@@ -184,17 +193,20 @@ public class ArchiveAnalyzer extends AbstractFileTypeAnalyzer {
|
||||
@Override
|
||||
public void close() throws Exception {
|
||||
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);
|
||||
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");
|
||||
if (!success && tempFileLocation.exists()) {
|
||||
final String[] l = tempFileLocation.list();
|
||||
if (l != null && l.length > 0) {
|
||||
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,
|
||||
* scanned, and added to the list of dependencies within the engine.
|
||||
* Analyzes a given dependency. If the dependency is an archive, such as a WAR or EAR, the contents are extracted, scanned,
|
||||
* and added to the list of dependencies within the engine.
|
||||
*
|
||||
* @param dependency the dependency to analyze
|
||||
* @param engine the engine scanning
|
||||
@@ -207,15 +219,8 @@ public class ArchiveAnalyzer extends AbstractFileTypeAnalyzer {
|
||||
extractFiles(f, tmpDir, engine);
|
||||
|
||||
//make a copy
|
||||
List<Dependency> dependencies = new ArrayList<Dependency>(engine.getDependencies());
|
||||
engine.scan(tmpDir);
|
||||
List<Dependency> newDependencies = engine.getDependencies();
|
||||
if (dependencies.size() != newDependencies.size()) {
|
||||
//get the new dependencies
|
||||
final Set<Dependency> dependencySet = new HashSet<Dependency>();
|
||||
dependencySet.addAll(newDependencies);
|
||||
dependencySet.removeAll(dependencies);
|
||||
|
||||
final Set<Dependency> dependencySet = findMoreDependencies(engine, tmpDir);
|
||||
if (!dependencySet.isEmpty()) {
|
||||
for (Dependency d : dependencySet) {
|
||||
//fix the dependency's display name and path
|
||||
final String displayPath = String.format("%s%s",
|
||||
@@ -229,50 +234,81 @@ public class ArchiveAnalyzer extends AbstractFileTypeAnalyzer {
|
||||
|
||||
//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.
|
||||
if (this.supportsExtension(d.getFileExtension()) && scanDepth < MAX_SCAN_DEPTH) {
|
||||
if (this.accept(d.getActualFile()) && scanDepth < MAX_SCAN_DEPTH) {
|
||||
scanDepth += 1;
|
||||
analyze(d, engine);
|
||||
scanDepth -= 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (this.REMOVE_FROM_ANALYSIS.contains(dependency.getFileExtension())) {
|
||||
if ("zip".equals(dependency.getFileExtension()) && isZipFileActuallyJarFile(dependency)) {
|
||||
final File tdir = getNextTempDirectory();
|
||||
final String fileName = dependency.getFileName();
|
||||
|
||||
LOGGER.info(String.format("The zip file '%s' appears to be a JAR file, making a copy and analyzing it as a JAR.", fileName));
|
||||
|
||||
final File tmpLoc = new File(tdir, fileName.substring(0, fileName.length() - 3) + "jar");
|
||||
try {
|
||||
org.apache.commons.io.FileUtils.copyFile(tdir, tmpLoc);
|
||||
dependencies = new ArrayList<Dependency>(engine.getDependencies());
|
||||
engine.scan(tmpLoc);
|
||||
newDependencies = engine.getDependencies();
|
||||
if (dependencies.size() != newDependencies.size()) {
|
||||
//get the new dependencies
|
||||
final Set<Dependency> dependencySet = new HashSet<Dependency>();
|
||||
dependencySet.addAll(newDependencies);
|
||||
dependencySet.removeAll(dependencies);
|
||||
if (dependencySet.size() != 1) {
|
||||
LOGGER.info("Deep copy of ZIP to JAR file resulted in more then one dependency?");
|
||||
}
|
||||
for (Dependency d : dependencySet) {
|
||||
//fix the dependency's display name and path
|
||||
d.setFilePath(dependency.getFilePath());
|
||||
d.setDisplayFileName(dependency.getFileName());
|
||||
}
|
||||
}
|
||||
} catch (IOException ex) {
|
||||
final String msg = String.format("Unable to perform deep copy on '%s'", dependency.getActualFile().getPath());
|
||||
LOGGER.log(Level.FINE, msg, ex);
|
||||
}
|
||||
}
|
||||
if (REMOVE_FROM_ANALYSIS.accept(dependency.getActualFile())) {
|
||||
addDisguisedJarsToDependencies(dependency, engine);
|
||||
engine.getDependencies().remove(dependency);
|
||||
}
|
||||
Collections.sort(engine.getDependencies());
|
||||
}
|
||||
|
||||
/**
|
||||
* If a zip file was identified as a possible JAR, this method will add the zip to the list of dependencies.
|
||||
*
|
||||
* @param dependency the zip file
|
||||
* @param engine the engine
|
||||
* @throws AnalysisException thrown if there is an issue
|
||||
*/
|
||||
private void addDisguisedJarsToDependencies(Dependency dependency, Engine engine) throws AnalysisException {
|
||||
if (ZIP_FILTER.accept(dependency.getActualFile()) && isZipFileActuallyJarFile(dependency)) {
|
||||
final File tdir = getNextTempDirectory();
|
||||
final String fileName = dependency.getFileName();
|
||||
|
||||
LOGGER.info("The zip file '{}' appears to be a JAR file, making a copy and analyzing it as a JAR.", fileName);
|
||||
|
||||
final File tmpLoc = new File(tdir, fileName.substring(0, fileName.length() - 3) + "jar");
|
||||
try {
|
||||
org.apache.commons.io.FileUtils.copyFile(tdir, tmpLoc);
|
||||
final Set<Dependency> dependencySet = findMoreDependencies(engine, tmpLoc);
|
||||
if (!dependencySet.isEmpty()) {
|
||||
if (dependencySet.size() != 1) {
|
||||
LOGGER.info("Deep copy of ZIP to JAR file resulted in more than one dependency?");
|
||||
}
|
||||
for (Dependency d : dependencySet) {
|
||||
//fix the dependency's display name and path
|
||||
d.setFilePath(dependency.getFilePath());
|
||||
d.setDisplayFileName(dependency.getFileName());
|
||||
}
|
||||
}
|
||||
} catch (IOException ex) {
|
||||
LOGGER.debug("Unable to perform deep copy on '{}'", dependency.getActualFile().getPath(), ex);
|
||||
}
|
||||
}
|
||||
}
|
||||
/**
|
||||
* An empty dependency set.
|
||||
*/
|
||||
private static final Set<Dependency> EMPTY_DEPENDENCY_SET = Collections.emptySet();
|
||||
|
||||
/**
|
||||
* Scan the given file/folder, and return any new dependencies found.
|
||||
*
|
||||
* @param engine used to scan
|
||||
* @param file target of scanning
|
||||
* @return any dependencies that weren't known to the engine before
|
||||
*/
|
||||
private static Set<Dependency> findMoreDependencies(Engine engine, File file) {
|
||||
final List<Dependency> before = new ArrayList<Dependency>(engine.getDependencies());
|
||||
engine.scan(file);
|
||||
final List<Dependency> after = engine.getDependencies();
|
||||
final boolean sizeChanged = before.size() != after.size();
|
||||
final Set<Dependency> newDependencies;
|
||||
if (sizeChanged) {
|
||||
//get the new dependencies
|
||||
newDependencies = new HashSet<Dependency>(after);
|
||||
newDependencies.removeAll(before);
|
||||
} else {
|
||||
newDependencies = EMPTY_DEPENDENCY_SET;
|
||||
}
|
||||
return newDependencies;
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieves the next temporary directory to extract an archive too.
|
||||
*
|
||||
@@ -302,43 +338,41 @@ public class ArchiveAnalyzer extends AbstractFileTypeAnalyzer {
|
||||
* @throws AnalysisException thrown if the archive is not found
|
||||
*/
|
||||
private void extractFiles(File archive, File destination, Engine engine) throws AnalysisException {
|
||||
if (archive == null || destination == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
FileInputStream fis = null;
|
||||
try {
|
||||
fis = new FileInputStream(archive);
|
||||
} catch (FileNotFoundException ex) {
|
||||
LOGGER.log(Level.FINE, null, ex);
|
||||
throw new AnalysisException("Archive file was not found.", ex);
|
||||
}
|
||||
final String archiveExt = FileUtils.getFileExtension(archive.getName()).toLowerCase();
|
||||
try {
|
||||
if (ZIPPABLES.contains(archiveExt)) {
|
||||
extractArchive(new ZipArchiveInputStream(new BufferedInputStream(fis)), destination, engine);
|
||||
} else if ("tar".equals(archiveExt)) {
|
||||
extractArchive(new TarArchiveInputStream(new BufferedInputStream(fis)), destination, engine);
|
||||
} else if ("gz".equals(archiveExt) || "tgz".equals(archiveExt)) {
|
||||
final String uncompressedName = GzipUtils.getUncompressedFilename(archive.getName());
|
||||
final String uncompressedExt = FileUtils.getFileExtension(uncompressedName).toLowerCase();
|
||||
if (engine.supportsExtension(uncompressedExt)) {
|
||||
decompressFile(new GzipCompressorInputStream(new BufferedInputStream(fis)), new File(destination, uncompressedName));
|
||||
}
|
||||
}
|
||||
} catch (ArchiveExtractionException ex) {
|
||||
final String msg = String.format("Exception extracting archive '%s'.", archive.getName());
|
||||
LOGGER.log(Level.WARNING, msg);
|
||||
LOGGER.log(Level.FINE, null, ex);
|
||||
} catch (IOException ex) {
|
||||
final String msg = String.format("Exception reading archive '%s'.", archive.getName());
|
||||
LOGGER.log(Level.WARNING, msg);
|
||||
LOGGER.log(Level.FINE, null, ex);
|
||||
} finally {
|
||||
if (archive != null && destination != null) {
|
||||
FileInputStream fis;
|
||||
try {
|
||||
fis.close();
|
||||
fis = new FileInputStream(archive);
|
||||
} catch (FileNotFoundException ex) {
|
||||
LOGGER.debug("", ex);
|
||||
throw new AnalysisException("Archive file was not found.", ex);
|
||||
}
|
||||
final String archiveExt = FileUtils.getFileExtension(archive.getName()).toLowerCase();
|
||||
try {
|
||||
if (ZIPPABLES.contains(archiveExt)) {
|
||||
extractArchive(new ZipArchiveInputStream(new BufferedInputStream(fis)), destination, engine);
|
||||
} else if ("tar".equals(archiveExt)) {
|
||||
extractArchive(new TarArchiveInputStream(new BufferedInputStream(fis)), destination, engine);
|
||||
} else if ("gz".equals(archiveExt) || "tgz".equals(archiveExt)) {
|
||||
final String uncompressedName = GzipUtils.getUncompressedFilename(archive.getName());
|
||||
final File f = new File(destination, uncompressedName);
|
||||
if (engine.accept(f)) {
|
||||
decompressFile(new GzipCompressorInputStream(new BufferedInputStream(fis)), f);
|
||||
}
|
||||
} else if ("bz2".equals(archiveExt) || "tbz2".equals(archiveExt)) {
|
||||
final String uncompressedName = BZip2Utils.getUncompressedFilename(archive.getName());
|
||||
final File f = new File(destination, uncompressedName);
|
||||
if (engine.accept(f)) {
|
||||
decompressFile(new BZip2CompressorInputStream(new BufferedInputStream(fis)), f);
|
||||
}
|
||||
}
|
||||
} catch (ArchiveExtractionException ex) {
|
||||
LOGGER.warn("Exception extracting archive '{}'.", archive.getName());
|
||||
LOGGER.debug("", ex);
|
||||
} catch (IOException ex) {
|
||||
LOGGER.log(Level.FINE, null, ex);
|
||||
LOGGER.warn("Exception reading archive '{}'.", archive.getName());
|
||||
LOGGER.debug("", ex);
|
||||
} finally {
|
||||
close(fis);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -355,77 +389,51 @@ public class ArchiveAnalyzer extends AbstractFileTypeAnalyzer {
|
||||
ArchiveEntry entry;
|
||||
try {
|
||||
while ((entry = input.getNextEntry()) != null) {
|
||||
final File file = new File(destination, entry.getName());
|
||||
if (entry.isDirectory()) {
|
||||
final File d = new File(destination, entry.getName());
|
||||
if (!d.exists()) {
|
||||
if (!d.mkdirs()) {
|
||||
final String msg = String.format("Unable to create directory '%s'.", d.getAbsolutePath());
|
||||
throw new AnalysisException(msg);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
final File file = new File(destination, entry.getName());
|
||||
final String ext = FileUtils.getFileExtension(file.getName());
|
||||
if (engine.supportsExtension(ext)) {
|
||||
final String extracting = String.format("Extracting '%s'", file.getPath());
|
||||
LOGGER.fine(extracting);
|
||||
BufferedOutputStream bos = null;
|
||||
FileOutputStream fos = null;
|
||||
try {
|
||||
final File parent = file.getParentFile();
|
||||
if (!parent.isDirectory()) {
|
||||
if (!parent.mkdirs()) {
|
||||
final String msg = String.format("Unable to build directory '%s'.", parent.getAbsolutePath());
|
||||
throw new AnalysisException(msg);
|
||||
}
|
||||
}
|
||||
fos = new FileOutputStream(file);
|
||||
bos = new BufferedOutputStream(fos, BUFFER_SIZE);
|
||||
int count;
|
||||
final byte[] data = new byte[BUFFER_SIZE];
|
||||
while ((count = input.read(data, 0, BUFFER_SIZE)) != -1) {
|
||||
bos.write(data, 0, count);
|
||||
}
|
||||
bos.flush();
|
||||
} catch (FileNotFoundException ex) {
|
||||
LOGGER.log(Level.FINE, null, ex);
|
||||
final String msg = String.format("Unable to find file '%s'.", file.getName());
|
||||
throw new AnalysisException(msg, ex);
|
||||
} catch (IOException ex) {
|
||||
LOGGER.log(Level.FINE, null, ex);
|
||||
final String msg = String.format("IO Exception while parsing file '%s'.", file.getName());
|
||||
throw new AnalysisException(msg, ex);
|
||||
} finally {
|
||||
if (bos != null) {
|
||||
try {
|
||||
bos.close();
|
||||
} catch (IOException ex) {
|
||||
LOGGER.log(Level.FINEST, null, ex);
|
||||
}
|
||||
}
|
||||
if (fos != null) {
|
||||
try {
|
||||
fos.close();
|
||||
} catch (IOException ex) {
|
||||
LOGGER.log(Level.FINEST, null, ex);
|
||||
}
|
||||
}
|
||||
}
|
||||
if (!file.exists() && !file.mkdirs()) {
|
||||
final String msg = String.format("Unable to create directory '%s'.", file.getAbsolutePath());
|
||||
throw new AnalysisException(msg);
|
||||
}
|
||||
} else if (engine.accept(file)) {
|
||||
extractAcceptedFile(input, file);
|
||||
}
|
||||
}
|
||||
} catch (IOException ex) {
|
||||
throw new ArchiveExtractionException(ex);
|
||||
} catch (Throwable ex) {
|
||||
throw new ArchiveExtractionException(ex);
|
||||
} finally {
|
||||
if (input != null) {
|
||||
try {
|
||||
input.close();
|
||||
} catch (IOException ex) {
|
||||
LOGGER.log(Level.FINEST, null, ex);
|
||||
}
|
||||
close(input);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Extracts a file from an archive.
|
||||
*
|
||||
* @param input the archives input stream
|
||||
* @param file the file to extract
|
||||
* @throws AnalysisException thrown if there is an error
|
||||
*/
|
||||
private static void extractAcceptedFile(ArchiveInputStream input, File file) throws AnalysisException {
|
||||
LOGGER.debug("Extracting '{}'", file.getPath());
|
||||
FileOutputStream fos = null;
|
||||
try {
|
||||
final File parent = file.getParentFile();
|
||||
if (!parent.isDirectory() && !parent.mkdirs()) {
|
||||
final String msg = String.format("Unable to build directory '%s'.", parent.getAbsolutePath());
|
||||
throw new AnalysisException(msg);
|
||||
}
|
||||
fos = new FileOutputStream(file);
|
||||
IOUtils.copy(input, fos);
|
||||
} catch (FileNotFoundException ex) {
|
||||
LOGGER.debug("", ex);
|
||||
final String msg = String.format("Unable to find file '%s'.", file.getName());
|
||||
throw new AnalysisException(msg, ex);
|
||||
} catch (IOException ex) {
|
||||
LOGGER.debug("", ex);
|
||||
final String msg = String.format("IO Exception while parsing file '%s'.", file.getName());
|
||||
throw new AnalysisException(msg, ex);
|
||||
} finally {
|
||||
close(fos);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -437,29 +445,33 @@ public class ArchiveAnalyzer extends AbstractFileTypeAnalyzer {
|
||||
* @throws ArchiveExtractionException thrown if there is an exception decompressing the file
|
||||
*/
|
||||
private void decompressFile(CompressorInputStream inputStream, File outputFile) throws ArchiveExtractionException {
|
||||
final String msg = String.format("Decompressing '%s'", outputFile.getPath());
|
||||
LOGGER.fine(msg);
|
||||
LOGGER.debug("Decompressing '{}'", outputFile.getPath());
|
||||
FileOutputStream out = null;
|
||||
try {
|
||||
out = new FileOutputStream(outputFile);
|
||||
final byte[] buffer = new byte[BUFFER_SIZE];
|
||||
int n = 0;
|
||||
while (-1 != (n = inputStream.read(buffer))) {
|
||||
out.write(buffer, 0, n);
|
||||
}
|
||||
IOUtils.copy(inputStream, out);
|
||||
} catch (FileNotFoundException ex) {
|
||||
LOGGER.log(Level.FINE, null, ex);
|
||||
LOGGER.debug("", ex);
|
||||
throw new ArchiveExtractionException(ex);
|
||||
} catch (IOException ex) {
|
||||
LOGGER.log(Level.FINE, null, ex);
|
||||
LOGGER.debug("", ex);
|
||||
throw new ArchiveExtractionException(ex);
|
||||
} finally {
|
||||
if (out != null) {
|
||||
try {
|
||||
out.close();
|
||||
} catch (IOException ex) {
|
||||
LOGGER.log(Level.FINEST, null, ex);
|
||||
}
|
||||
close(out);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Close the given {@link Closeable} instance, ignoring nulls, and logging any thrown {@link IOException}.
|
||||
*
|
||||
* @param closeable to be closed
|
||||
*/
|
||||
private static void close(Closeable closeable) {
|
||||
if (null != closeable) {
|
||||
try {
|
||||
closeable.close();
|
||||
} catch (IOException ex) {
|
||||
LOGGER.trace("", ex);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -490,7 +502,7 @@ public class ArchiveAnalyzer extends AbstractFileTypeAnalyzer {
|
||||
}
|
||||
}
|
||||
} 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 {
|
||||
ZipFile.closeQuietly(zip);
|
||||
}
|
||||
|
||||
@@ -17,31 +17,33 @@
|
||||
*/
|
||||
package org.owasp.dependencycheck.analyzer;
|
||||
|
||||
import java.io.BufferedReader;
|
||||
import java.io.File;
|
||||
import java.io.FileFilter;
|
||||
import java.io.FileOutputStream;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.io.InputStreamReader;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
import java.util.logging.Level;
|
||||
import java.util.logging.Logger;
|
||||
import javax.xml.parsers.DocumentBuilder;
|
||||
import javax.xml.parsers.DocumentBuilderFactory;
|
||||
import javax.xml.xpath.XPath;
|
||||
import javax.xml.xpath.XPathExpressionException;
|
||||
import javax.xml.xpath.XPathFactory;
|
||||
import org.apache.commons.io.IOUtils;
|
||||
import org.apache.commons.io.output.NullOutputStream;
|
||||
import org.owasp.dependencycheck.Engine;
|
||||
import org.owasp.dependencycheck.analyzer.exception.AnalysisException;
|
||||
import org.owasp.dependencycheck.dependency.Confidence;
|
||||
import org.owasp.dependencycheck.dependency.Dependency;
|
||||
import org.owasp.dependencycheck.dependency.Evidence;
|
||||
import org.owasp.dependencycheck.utils.FileFilterBuilder;
|
||||
import org.owasp.dependencycheck.utils.Settings;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import org.w3c.dom.Document;
|
||||
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;
|
||||
|
||||
/**
|
||||
* Analyzer for getting company, product, and version information from a .NET assembly.
|
||||
*
|
||||
@@ -61,7 +63,7 @@ public class AssemblyAnalyzer extends AbstractFileTypeAnalyzer {
|
||||
/**
|
||||
* 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
|
||||
*/
|
||||
@@ -73,7 +75,7 @@ public class AssemblyAnalyzer extends AbstractFileTypeAnalyzer {
|
||||
/**
|
||||
* 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
|
||||
@@ -106,45 +108,44 @@ public class AssemblyAnalyzer extends AbstractFileTypeAnalyzer {
|
||||
public void analyzeFileType(Dependency dependency, Engine engine)
|
||||
throws AnalysisException {
|
||||
if (grokAssemblyExe == null) {
|
||||
LOGGER.warning("analyzer.AssemblyAnalyzer.notdeployed");
|
||||
LOGGER.warn("GrokAssembly didn't get deployed");
|
||||
return;
|
||||
}
|
||||
|
||||
final List<String> args = buildArgumentList();
|
||||
args.add(dependency.getActualFilePath());
|
||||
final ProcessBuilder pb = new ProcessBuilder(args);
|
||||
BufferedReader rdr = null;
|
||||
Document doc = null;
|
||||
try {
|
||||
final Process proc = pb.start();
|
||||
// Try evacuating the error stream
|
||||
rdr = new BufferedReader(new InputStreamReader(proc.getErrorStream(), "UTF-8"));
|
||||
String line = null;
|
||||
// CHECKSTYLE:OFF
|
||||
while (rdr.ready() && (line = rdr.readLine()) != null) {
|
||||
LOGGER.log(Level.WARNING, "analyzer.AssemblyAnalyzer.grokassembly.stderr", line);
|
||||
}
|
||||
// CHECKSTYLE:ON
|
||||
int rc = 0;
|
||||
|
||||
doc = builder.parse(proc.getInputStream());
|
||||
|
||||
// Try evacuating the error stream
|
||||
final String errorStream = IOUtils.toString(proc.getErrorStream(), "UTF-8");
|
||||
if (null != errorStream && !errorStream.isEmpty()) {
|
||||
LOGGER.warn("Error from GrokAssembly: {}", errorStream);
|
||||
}
|
||||
|
||||
int rc = 0;
|
||||
try {
|
||||
rc = proc.waitFor();
|
||||
} catch (InterruptedException ie) {
|
||||
return;
|
||||
}
|
||||
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;
|
||||
} 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();
|
||||
|
||||
// First, see if there was an error
|
||||
final String error = xpath.evaluate("/assembly/error", doc);
|
||||
if (error != null && !"".equals(error)) {
|
||||
if (error != null && !error.isEmpty()) {
|
||||
throw new AnalysisException(error);
|
||||
}
|
||||
|
||||
@@ -173,14 +174,6 @@ public class AssemblyAnalyzer extends AbstractFileTypeAnalyzer {
|
||||
} catch (XPathExpressionException xpe) {
|
||||
// This shouldn't happen
|
||||
throw new AnalysisException(xpe);
|
||||
} finally {
|
||||
if (rdr != null) {
|
||||
try {
|
||||
rdr.close();
|
||||
} catch (IOException ex) {
|
||||
LOGGER.log(Level.FINEST, "ignore", ex);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -197,80 +190,68 @@ public class AssemblyAnalyzer extends AbstractFileTypeAnalyzer {
|
||||
try {
|
||||
fos = new FileOutputStream(tempFile);
|
||||
is = AssemblyAnalyzer.class.getClassLoader().getResourceAsStream("GrokAssembly.exe");
|
||||
final byte[] buff = new byte[4096];
|
||||
int bread = -1;
|
||||
while ((bread = is.read(buff)) >= 0) {
|
||||
fos.write(buff, 0, bread);
|
||||
}
|
||||
IOUtils.copy(is, fos);
|
||||
|
||||
grokAssemblyExe = tempFile;
|
||||
// Set the temp file to get deleted when we're done
|
||||
grokAssemblyExe.deleteOnExit();
|
||||
LOGGER.log(Level.FINE, "analyzer.AssemblyAnalyzer.grokassembly.deployed", grokAssemblyExe.getPath());
|
||||
LOGGER.debug("Extracted GrokAssembly.exe to {}", grokAssemblyExe.getPath());
|
||||
} catch (IOException ioe) {
|
||||
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);
|
||||
} finally {
|
||||
if (fos != null) {
|
||||
try {
|
||||
fos.close();
|
||||
} catch (Throwable e) {
|
||||
LOGGER.fine("Error closing output stream");
|
||||
LOGGER.debug("Error closing output stream");
|
||||
}
|
||||
}
|
||||
if (is != null) {
|
||||
try {
|
||||
is.close();
|
||||
} catch (Throwable e) {
|
||||
LOGGER.fine("Error closing input stream");
|
||||
LOGGER.debug("Error closing input stream");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Now, need to see if GrokAssembly actually runs from this location.
|
||||
final List<String> args = buildArgumentList();
|
||||
BufferedReader rdr = null;
|
||||
try {
|
||||
final ProcessBuilder pb = new ProcessBuilder(args);
|
||||
final Process p = pb.start();
|
||||
// Try evacuating the error stream
|
||||
rdr = new BufferedReader(new InputStreamReader(p.getErrorStream(), "UTF-8"));
|
||||
// CHECKSTYLE:OFF
|
||||
while (rdr.ready() && rdr.readLine() != null) {
|
||||
// We expect this to complain
|
||||
}
|
||||
// CHECKSTYLE:ON
|
||||
IOUtils.copy(p.getErrorStream(), NullOutputStream.NULL_OUTPUT_STREAM);
|
||||
|
||||
final Document doc = DocumentBuilderFactory.newInstance().newDocumentBuilder().parse(p.getInputStream());
|
||||
final XPath xpath = XPathFactory.newInstance().newXPath();
|
||||
final String error = xpath.evaluate("/assembly/error", doc);
|
||||
if (p.waitFor() != 1 || error == null || "".equals(error)) {
|
||||
LOGGER.warning("An error occurred with the .NET AssemblyAnalyzer, please see the log for more details.");
|
||||
LOGGER.fine("GrokAssembly.exe is not working properly");
|
||||
if (p.waitFor() != 1 || error == null || error.isEmpty()) {
|
||||
LOGGER.warn("An error occurred with the .NET AssemblyAnalyzer, please see the log for more details.");
|
||||
LOGGER.debug("GrokAssembly.exe is not working properly");
|
||||
grokAssemblyExe = null;
|
||||
this.setEnabled(false);
|
||||
throw new AnalysisException("Could not execute .NET AssemblyAnalyzer");
|
||||
}
|
||||
} catch (AnalysisException e) {
|
||||
throw e;
|
||||
} catch (Throwable e) {
|
||||
if (e instanceof AnalysisException) {
|
||||
throw (AnalysisException) e;
|
||||
} else {
|
||||
LOGGER.warning("analyzer.AssemblyAnalyzer.grokassembly.initialization.failed");
|
||||
LOGGER.log(Level.FINE, "analyzer.AssemblyAnalyzer.grokassembly.initialization.message", e.getMessage());
|
||||
this.setEnabled(false);
|
||||
throw new AnalysisException("An error occured with the .NET AssemblyAnalyzer", e);
|
||||
}
|
||||
} finally {
|
||||
if (rdr != null) {
|
||||
try {
|
||||
rdr.close();
|
||||
} catch (IOException ex) {
|
||||
LOGGER.log(Level.FINEST, "ignore", ex);
|
||||
}
|
||||
}
|
||||
LOGGER.warn("An error occurred with the .NET AssemblyAnalyzer;\n"
|
||||
+ "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);
|
||||
throw new AnalysisException("An error occurred with the .NET AssemblyAnalyzer", e);
|
||||
}
|
||||
builder = DocumentBuilderFactory.newInstance().newDocumentBuilder();
|
||||
}
|
||||
|
||||
/**
|
||||
* Removes resources used from the local file system.
|
||||
*
|
||||
* @throws Exception thrown if there is a problem closing the analyzer
|
||||
*/
|
||||
@Override
|
||||
public void close() throws Exception {
|
||||
super.close();
|
||||
@@ -279,18 +260,19 @@ public class AssemblyAnalyzer extends AbstractFileTypeAnalyzer {
|
||||
grokAssemblyExe.deleteOnExit();
|
||||
}
|
||||
} 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.
|
||||
*
|
||||
* @return the list of supported extensions
|
||||
* The File Filter used to filter supported extensions.
|
||||
*/
|
||||
private static final FileFilter FILTER = FileFilterBuilder.newInstance().addExtensions(
|
||||
SUPPORTED_EXTENSIONS).build();
|
||||
|
||||
@Override
|
||||
public Set<String> getSupportedExtensions() {
|
||||
return SUPPORTED_EXTENSIONS;
|
||||
protected FileFilter getFileFilter() {
|
||||
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
|
||||
* @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> dependencies = new ArrayList<Dependency>(
|
||||
engine.getDependencies());
|
||||
dependencies.remove(dependency);
|
||||
engine.setDependencies(dependencies);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 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 occurred 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,237 @@
|
||||
/*
|
||||
* This file is part of dependency-check-core.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*
|
||||
* Copyright (c) 2015 Institute for Defense Analyses. All Rights Reserved.
|
||||
*/
|
||||
package org.owasp.dependencycheck.analyzer;
|
||||
|
||||
import org.apache.commons.io.FileUtils;
|
||||
import org.apache.commons.lang3.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.io.UnsupportedEncodingException;
|
||||
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>
|
||||
* 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
|
||||
*/
|
||||
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;
|
||||
|
||||
/**
|
||||
* Regex to extract the product information.
|
||||
*/
|
||||
private static final Pattern PROJECT = Pattern.compile(
|
||||
"^ *project *\\([ \\n]*(\\w+)[ \\n]*.*?\\)", REGEX_OPTIONS);
|
||||
|
||||
/**
|
||||
* Regex to extract product and version information.
|
||||
*
|
||||
* 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("Found {} matches.", count);
|
||||
analyzeSetVersionCommand(dependency, engine, contents);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Extracts the version information from the contents. If more then one version is found additional dependencies are added to
|
||||
* the dependency list.
|
||||
*
|
||||
* @param dependency the dependency being analyzed
|
||||
* @param engine the dependency-check engine
|
||||
* @param contents the version information
|
||||
*/
|
||||
private void analyzeSetVersionCommand(Dependency dependency, Engine engine, String contents) {
|
||||
Dependency currentDep = dependency;
|
||||
|
||||
final Matcher m = SET_VERSION.matcher(contents);
|
||||
int count = 0;
|
||||
while (m.find()) {
|
||||
count++;
|
||||
LOGGER.debug("Found project command match with {} groups: {}",
|
||||
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)
|
||||
currentDep = new Dependency(dependency.getActualFile());
|
||||
currentDep.setDisplayFileName(String.format("%s:%s", dependency.getDisplayFileName(), product));
|
||||
final String filePath = String.format("%s:%s", dependency.getFilePath(), product);
|
||||
currentDep.setFilePath(filePath);
|
||||
|
||||
byte[] path;
|
||||
try {
|
||||
path = filePath.getBytes("UTF-8");
|
||||
} catch (UnsupportedEncodingException ex) {
|
||||
path = filePath.getBytes();
|
||||
}
|
||||
currentDep.setSha1sum(Checksum.getHex(sha1.digest(path)));
|
||||
engine.getDependencies().add(currentDep);
|
||||
}
|
||||
final String source = currentDep.getDisplayFileName();
|
||||
currentDep.getProductEvidence().addEvidence(source, "Product",
|
||||
product, Confidence.MEDIUM);
|
||||
currentDep.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.Set;
|
||||
import java.util.StringTokenizer;
|
||||
import java.util.logging.Level;
|
||||
import java.util.logging.Logger;
|
||||
import org.apache.lucene.document.Document;
|
||||
import org.apache.lucene.index.CorruptIndexException;
|
||||
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.utils.DependencyVersion;
|
||||
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. It uses
|
||||
* 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 {
|
||||
|
||||
/**
|
||||
* 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.
|
||||
*/
|
||||
@@ -134,16 +134,19 @@ public class CPEAnalyzer implements Analyzer {
|
||||
* process.
|
||||
*/
|
||||
public void open() throws IOException, DatabaseException {
|
||||
LOGGER.log(Level.FINE, "Opening the CVE Database");
|
||||
cve = new CveDB();
|
||||
cve.open();
|
||||
LOGGER.log(Level.FINE, "Creating the Lucene CPE Index");
|
||||
cpe = CpeMemoryIndex.getInstance();
|
||||
try {
|
||||
cpe.open(cve);
|
||||
} catch (IndexException ex) {
|
||||
LOGGER.log(Level.FINE, "IndexException", ex);
|
||||
throw new DatabaseException(ex);
|
||||
if (!isOpen()) {
|
||||
cve = new CveDB();
|
||||
cve.open();
|
||||
cpe = CpeMemoryIndex.getInstance();
|
||||
try {
|
||||
LOGGER.info("Creating the CPE Index");
|
||||
final long creationStart = System.currentTimeMillis();
|
||||
cpe.open(cve);
|
||||
LOGGER.info("CPE Index Created ({} ms)", System.currentTimeMillis() - creationStart);
|
||||
} catch (IndexException ex) {
|
||||
LOGGER.debug("IndexException", ex);
|
||||
throw new DatabaseException(ex);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -154,12 +157,18 @@ public class CPEAnalyzer implements Analyzer {
|
||||
public void close() {
|
||||
if (cpe != null) {
|
||||
cpe.close();
|
||||
cpe = null;
|
||||
}
|
||||
if (cve != null) {
|
||||
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 contained
|
||||
* within. The dependency passed in is updated with any identified CPE values.
|
||||
@@ -176,11 +185,11 @@ public class CPEAnalyzer implements Analyzer {
|
||||
for (Confidence confidence : Confidence.values()) {
|
||||
if (dependency.getVendorEvidence().contains(confidence)) {
|
||||
vendors = addEvidenceWithoutDuplicateTerms(vendors, dependency.getVendorEvidence(), confidence);
|
||||
LOGGER.fine(String.format("vendor search: %s", vendors));
|
||||
LOGGER.debug("vendor search: {}", vendors);
|
||||
}
|
||||
if (dependency.getProductEvidence().contains(confidence)) {
|
||||
products = addEvidenceWithoutDuplicateTerms(products, dependency.getProductEvidence(), confidence);
|
||||
LOGGER.fine(String.format("product search: %s", products));
|
||||
LOGGER.debug("product search: {}", products);
|
||||
}
|
||||
if (!vendors.isEmpty() && !products.isEmpty()) {
|
||||
final List<IndexEntry> entries = searchCPE(vendors, products, dependency.getProductEvidence().getWeighting(),
|
||||
@@ -190,11 +199,11 @@ public class CPEAnalyzer implements Analyzer {
|
||||
}
|
||||
boolean identifierAdded = false;
|
||||
for (IndexEntry e : entries) {
|
||||
LOGGER.fine(String.format("Verifying entry: %s", e.toString()));
|
||||
LOGGER.debug("Verifying entry: {}", e);
|
||||
if (verifyEntry(e, dependency)) {
|
||||
final String vendor = e.getVendor();
|
||||
final String product = e.getProduct();
|
||||
LOGGER.fine(String.format("identified vendor/product: %s/%s", vendor, product));
|
||||
LOGGER.debug("identified vendor/product: {}/{}", vendor, product);
|
||||
identifierAdded |= determineIdentifiers(dependency, vendor, product, confidence);
|
||||
}
|
||||
}
|
||||
@@ -277,13 +286,11 @@ public class CPEAnalyzer implements Analyzer {
|
||||
}
|
||||
return ret;
|
||||
} catch (ParseException ex) {
|
||||
final String msg = String.format("Unable to parse: %s", searchString);
|
||||
LOGGER.log(Level.WARNING, "An error occured querying the CPE data. See the log for more details.");
|
||||
LOGGER.log(Level.INFO, msg, ex);
|
||||
LOGGER.warn("An error occurred querying the CPE data. See the log for more details.");
|
||||
LOGGER.info("Unable to parse: {}", searchString, ex);
|
||||
} catch (IOException ex) {
|
||||
final String msg = String.format("IO Error with search string: %s", searchString);
|
||||
LOGGER.log(Level.WARNING, "An error occured reading CPE data. See the log for more details.");
|
||||
LOGGER.log(Level.INFO, msg, ex);
|
||||
LOGGER.warn("An error occurred reading CPE data. See the log for more details.");
|
||||
LOGGER.info("IO Error with search string: {}", searchString, ex);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
@@ -330,11 +337,11 @@ public class CPEAnalyzer implements Analyzer {
|
||||
* @return if the append was successful.
|
||||
*/
|
||||
private boolean appendWeightedSearch(StringBuilder sb, String field, String searchText, Set<String> weightedText) {
|
||||
sb.append(" ").append(field).append(":( ");
|
||||
sb.append(' ').append(field).append(":( ");
|
||||
|
||||
final String cleanText = cleanseText(searchText);
|
||||
|
||||
if ("".equals(cleanText)) {
|
||||
if (cleanText.isEmpty()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -344,20 +351,27 @@ public class CPEAnalyzer implements Analyzer {
|
||||
final StringTokenizer tokens = new StringTokenizer(cleanText);
|
||||
while (tokens.hasMoreElements()) {
|
||||
final String word = tokens.nextToken();
|
||||
String temp = null;
|
||||
StringBuilder temp = null;
|
||||
for (String weighted : weightedText) {
|
||||
final String weightedStr = cleanseText(weighted);
|
||||
if (equalsIgnoreCaseAndNonAlpha(word, weightedStr)) {
|
||||
temp = LuceneUtils.escapeLuceneQuery(word) + WEIGHTING_BOOST;
|
||||
temp = new StringBuilder(word.length() + 2);
|
||||
LuceneUtils.appendEscapedLuceneQuery(temp, word);
|
||||
temp.append(WEIGHTING_BOOST);
|
||||
if (!word.equalsIgnoreCase(weightedStr)) {
|
||||
temp += " " + LuceneUtils.escapeLuceneQuery(weightedStr) + WEIGHTING_BOOST;
|
||||
temp.append(' ');
|
||||
LuceneUtils.appendEscapedLuceneQuery(temp, weightedStr);
|
||||
temp.append(WEIGHTING_BOOST);
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
sb.append(' ');
|
||||
if (temp == null) {
|
||||
temp = LuceneUtils.escapeLuceneQuery(word);
|
||||
LuceneUtils.appendEscapedLuceneQuery(sb, word);
|
||||
} else {
|
||||
sb.append(temp);
|
||||
}
|
||||
sb.append(" ").append(temp);
|
||||
}
|
||||
}
|
||||
sb.append(" ) ");
|
||||
@@ -402,6 +416,8 @@ public class CPEAnalyzer implements Analyzer {
|
||||
private boolean verifyEntry(final IndexEntry entry, final Dependency dependency) {
|
||||
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())
|
||||
&& collectionContainsString(dependency.getVendorEvidence(), entry.getVendor())) {
|
||||
//&& collectionContainsVersion(dependency.getVersionEvidence(), entry.getVersion())
|
||||
@@ -418,17 +434,6 @@ public class CPEAnalyzer implements Analyzer {
|
||||
* @return whether or not the EvidenceCollection contains the string
|
||||
*/
|
||||
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
|
||||
if (text == null) {
|
||||
return false;
|
||||
@@ -450,9 +455,16 @@ public class CPEAnalyzer implements Analyzer {
|
||||
list.add(word);
|
||||
}
|
||||
}
|
||||
if (tempWord != null && !list.isEmpty()) {
|
||||
final String tmp = list.get(list.size() - 1) + tempWord;
|
||||
list.add(tmp);
|
||||
if (tempWord != null) {
|
||||
if (!list.isEmpty()) {
|
||||
final String tmp = list.get(list.size() - 1) + tempWord;
|
||||
list.add(tmp);
|
||||
} else {
|
||||
list.add(tempWord);
|
||||
}
|
||||
}
|
||||
if (list.isEmpty()) {
|
||||
return false;
|
||||
}
|
||||
boolean contains = true;
|
||||
for (String word : list) {
|
||||
@@ -469,7 +481,7 @@ public class CPEAnalyzer implements Analyzer {
|
||||
* @throws AnalysisException is thrown if there is an issue analyzing the dependency.
|
||||
*/
|
||||
@Override
|
||||
public void analyze(Dependency dependency, Engine engine) throws AnalysisException {
|
||||
public synchronized void analyze(Dependency dependency, Engine engine) throws AnalysisException {
|
||||
try {
|
||||
determineCPE(dependency);
|
||||
} catch (CorruptIndexException ex) {
|
||||
@@ -511,8 +523,8 @@ public class CPEAnalyzer implements Analyzer {
|
||||
}
|
||||
for (VulnerableSoftware vs : cpes) {
|
||||
DependencyVersion dbVer;
|
||||
if (vs.getRevision() != null && !vs.getRevision().isEmpty()) {
|
||||
dbVer = DependencyVersionUtil.parseVersion(vs.getVersion() + "." + vs.getRevision());
|
||||
if (vs.getUpdate() != null && !vs.getUpdate().isEmpty()) {
|
||||
dbVer = DependencyVersionUtil.parseVersion(vs.getVersion() + '.' + vs.getUpdate());
|
||||
} else {
|
||||
dbVer = DependencyVersionUtil.parseVersion(vs.getVersion());
|
||||
}
|
||||
|
||||
@@ -17,14 +17,6 @@
|
||||
*/
|
||||
package org.owasp.dependencycheck.analyzer;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.FileNotFoundException;
|
||||
import java.io.IOException;
|
||||
import java.net.URL;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
import java.util.logging.Level;
|
||||
import java.util.logging.Logger;
|
||||
import org.apache.commons.io.FileUtils;
|
||||
import org.owasp.dependencycheck.Engine;
|
||||
import org.owasp.dependencycheck.analyzer.exception.AnalysisException;
|
||||
@@ -33,9 +25,19 @@ import org.owasp.dependencycheck.data.nexus.MavenArtifact;
|
||||
import org.owasp.dependencycheck.dependency.Confidence;
|
||||
import org.owasp.dependencycheck.dependency.Dependency;
|
||||
import org.owasp.dependencycheck.dependency.Evidence;
|
||||
import org.owasp.dependencycheck.jaxb.pom.PomUtils;
|
||||
import org.owasp.dependencycheck.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;
|
||||
|
||||
@@ -50,7 +52,7 @@ public class CentralAnalyzer extends AbstractFileTypeAnalyzer {
|
||||
/**
|
||||
* The logger.
|
||||
*/
|
||||
private static final Logger LOGGER = Logger.getLogger(CentralAnalyzer.class.getName());
|
||||
private static final Logger LOGGER = LoggerFactory.getLogger(CentralAnalyzer.class);
|
||||
|
||||
/**
|
||||
* The name of the analyzer.
|
||||
@@ -65,7 +67,7 @@ public class CentralAnalyzer extends AbstractFileTypeAnalyzer {
|
||||
/**
|
||||
* 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 analyzer should be disabled if there are errors, so this is a flag to determine if such an error has occurred.
|
||||
@@ -76,10 +78,6 @@ public class CentralAnalyzer extends AbstractFileTypeAnalyzer {
|
||||
* The searcher itself.
|
||||
*/
|
||||
private CentralSearch searcher;
|
||||
/**
|
||||
* Utility to read POM files.
|
||||
*/
|
||||
private PomUtils pomUtil = new PomUtils();
|
||||
/**
|
||||
* Field indicating if the analyzer is enabled.
|
||||
*/
|
||||
@@ -107,7 +105,7 @@ public class CentralAnalyzer extends AbstractFileTypeAnalyzer {
|
||||
if (Settings.getBoolean(Settings.KEYS.ANALYZER_CENTRAL_ENABLED)) {
|
||||
if (!Settings.getBoolean(Settings.KEYS.ANALYZER_NEXUS_ENABLED)
|
||||
|| NexusAnalyzer.DEFAULT_URL.equals(Settings.getString(Settings.KEYS.ANALYZER_NEXUS_URL))) {
|
||||
LOGGER.fine("Enabling the Central analyzer");
|
||||
LOGGER.debug("Enabling the Central analyzer");
|
||||
retval = true;
|
||||
} else {
|
||||
LOGGER.info("Nexus analyzer is enabled, disabling the Central Analyzer");
|
||||
@@ -116,7 +114,7 @@ public class CentralAnalyzer extends AbstractFileTypeAnalyzer {
|
||||
LOGGER.info("Central analyzer disabled");
|
||||
}
|
||||
} catch (InvalidSettingException ise) {
|
||||
LOGGER.warning("Invalid setting. Disabling the Central analyzer");
|
||||
LOGGER.warn("Invalid setting. Disabling the Central analyzer");
|
||||
}
|
||||
return retval;
|
||||
}
|
||||
@@ -128,11 +126,11 @@ public class CentralAnalyzer extends AbstractFileTypeAnalyzer {
|
||||
*/
|
||||
@Override
|
||||
public void initializeFileTypeAnalyzer() throws Exception {
|
||||
LOGGER.fine("Initializing Central analyzer");
|
||||
LOGGER.fine(String.format("Central analyzer enabled: %s", isEnabled()));
|
||||
LOGGER.debug("Initializing Central analyzer");
|
||||
LOGGER.debug("Central analyzer enabled: {}", isEnabled());
|
||||
if (isEnabled()) {
|
||||
final String searchUrl = Settings.getString(Settings.KEYS.ANALYZER_CENTRAL_URL);
|
||||
LOGGER.fine(String.format("Central Analyzer URL: %s", searchUrl));
|
||||
LOGGER.debug("Central Analyzer URL: {}", searchUrl);
|
||||
searcher = new CentralSearch(new URL(searchUrl));
|
||||
}
|
||||
}
|
||||
@@ -168,13 +166,13 @@ public class CentralAnalyzer extends AbstractFileTypeAnalyzer {
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the extensions for which this Analyzer runs.
|
||||
*
|
||||
* @return 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();
|
||||
|
||||
@Override
|
||||
public Set<String> getSupportedExtensions() {
|
||||
return SUPPORTED_EXTENSIONS;
|
||||
protected FileFilter getFileFilter() {
|
||||
return FILTER;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -194,7 +192,7 @@ public class CentralAnalyzer extends AbstractFileTypeAnalyzer {
|
||||
final List<MavenArtifact> mas = searcher.searchSha1(dependency.getSha1sum());
|
||||
final Confidence confidence = mas.size() > 1 ? Confidence.HIGH : Confidence.HIGHEST;
|
||||
for (MavenArtifact ma : mas) {
|
||||
LOGGER.fine(String.format("Central analyzer found artifact (%s) for dependency (%s)", ma.toString(), dependency.getFileName()));
|
||||
LOGGER.debug("Central analyzer found artifact ({}) for dependency ({})", ma, dependency.getFileName());
|
||||
dependency.addAsEvidence("central", ma, confidence);
|
||||
boolean pomAnalyzed = false;
|
||||
for (Evidence e : dependency.getVendorEvidence()) {
|
||||
@@ -209,19 +207,17 @@ public class CentralAnalyzer extends AbstractFileTypeAnalyzer {
|
||||
final File baseDir = Settings.getTempDirectory();
|
||||
pomFile = File.createTempFile("pom", ".xml", baseDir);
|
||||
if (!pomFile.delete()) {
|
||||
final String msg = String.format("Unable to fetch pom.xml for %s from Central; "
|
||||
LOGGER.warn("Unable to fetch pom.xml for {} from Central; "
|
||||
+ "this could result in undetected CPE/CVEs.", dependency.getFileName());
|
||||
LOGGER.warning(msg);
|
||||
LOGGER.fine("Unable to delete temp file");
|
||||
LOGGER.debug("Unable to delete temp file");
|
||||
}
|
||||
LOGGER.fine(String.format("Downloading %s", ma.getPomUrl()));
|
||||
LOGGER.debug("Downloading {}", ma.getPomUrl());
|
||||
Downloader.fetchFile(new URL(ma.getPomUrl()), pomFile);
|
||||
pomUtil.analyzePOM(dependency, pomFile);
|
||||
PomUtils.analyzePOM(dependency, pomFile);
|
||||
|
||||
} catch (DownloadFailedException ex) {
|
||||
final String msg = String.format("Unable to download pom.xml for %s from Central; "
|
||||
LOGGER.warn("Unable to download pom.xml for {} from Central; "
|
||||
+ "this could result in undetected CPE/CVEs.", dependency.getFileName());
|
||||
LOGGER.warning(msg);
|
||||
} finally {
|
||||
if (pomFile != null && !FileUtils.deleteQuietly(pomFile)) {
|
||||
pomFile.deleteOnExit();
|
||||
@@ -231,13 +227,12 @@ public class CentralAnalyzer extends AbstractFileTypeAnalyzer {
|
||||
|
||||
}
|
||||
} catch (IllegalArgumentException iae) {
|
||||
LOGGER.info(String.format("invalid sha1-hash on %s", dependency.getFileName()));
|
||||
LOGGER.info("invalid sha1-hash on {}", dependency.getFileName());
|
||||
} catch (FileNotFoundException fnfe) {
|
||||
LOGGER.fine(String.format("Artifact not found in repository: '%s", dependency.getFileName()));
|
||||
LOGGER.debug("Artifact not found in repository: '{}", dependency.getFileName());
|
||||
} catch (IOException ioe) {
|
||||
LOGGER.log(Level.FINE, "Could not connect to Central search", ioe);
|
||||
LOGGER.debug("Could not connect to Central search", ioe);
|
||||
errorFlag = true;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -0,0 +1,162 @@
|
||||
/*
|
||||
* 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 The OWASP Foundation. All Rights Reserved.
|
||||
*/
|
||||
package org.owasp.dependencycheck.analyzer;
|
||||
|
||||
import org.owasp.dependencycheck.Engine;
|
||||
import org.owasp.dependencycheck.analyzer.exception.AnalysisException;
|
||||
import org.owasp.dependencycheck.data.composer.ComposerDependency;
|
||||
import org.owasp.dependencycheck.data.composer.ComposerException;
|
||||
import org.owasp.dependencycheck.data.composer.ComposerLockParser;
|
||||
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.FileFilter;
|
||||
import java.io.FileInputStream;
|
||||
import java.io.FileNotFoundException;
|
||||
import java.nio.charset.Charset;
|
||||
import java.security.MessageDigest;
|
||||
|
||||
/**
|
||||
* Used to analyze a composer.lock file for a composer PHP app.
|
||||
*
|
||||
* @author colezlaw
|
||||
*/
|
||||
public class ComposerLockAnalyzer extends AbstractFileTypeAnalyzer {
|
||||
|
||||
/**
|
||||
* The logger.
|
||||
*/
|
||||
private static final Logger LOGGER = LoggerFactory.getLogger(ComposerLockAnalyzer.class);
|
||||
|
||||
/**
|
||||
* The analyzer name.
|
||||
*/
|
||||
private static final String ANALYZER_NAME = "Composer.lock analyzer";
|
||||
|
||||
/**
|
||||
* composer.json.
|
||||
*/
|
||||
private static final String COMPOSER_LOCK = "composer.lock";
|
||||
|
||||
/**
|
||||
* The FileFilter.
|
||||
*/
|
||||
private static final FileFilter FILE_FILTER = FileFilterBuilder.newInstance().addFilenames(COMPOSER_LOCK).build();
|
||||
|
||||
/**
|
||||
* Returns the FileFilter.
|
||||
*
|
||||
* @return the FileFilter
|
||||
*/
|
||||
@Override
|
||||
protected FileFilter getFileFilter() {
|
||||
return FILE_FILTER;
|
||||
}
|
||||
|
||||
/**
|
||||
* Initializes the analyzer.
|
||||
*
|
||||
* @throws Exception thrown if an exception occurs getting an instance of SHA1
|
||||
*/
|
||||
@Override
|
||||
protected void initializeFileTypeAnalyzer() throws Exception {
|
||||
sha1 = MessageDigest.getInstance("SHA1");
|
||||
}
|
||||
|
||||
/**
|
||||
* The MessageDigest for calculating a new digest for the new dependencies added.
|
||||
*/
|
||||
private MessageDigest sha1 = null;
|
||||
|
||||
/**
|
||||
* Entry point for the analyzer.
|
||||
*
|
||||
* @param dependency the dependency to analyze
|
||||
* @param engine the engine scanning
|
||||
* @throws AnalysisException if there's a failure during analysis
|
||||
*/
|
||||
@Override
|
||||
protected void analyzeFileType(Dependency dependency, Engine engine) throws AnalysisException {
|
||||
FileInputStream fis = null;
|
||||
try {
|
||||
fis = new FileInputStream(dependency.getActualFile());
|
||||
final ComposerLockParser clp = new ComposerLockParser(fis);
|
||||
LOGGER.info("Checking composer.lock file {}", dependency.getActualFilePath());
|
||||
clp.process();
|
||||
for (ComposerDependency dep : clp.getDependencies()) {
|
||||
final Dependency d = new Dependency(dependency.getActualFile());
|
||||
d.setDisplayFileName(String.format("%s:%s/%s", dependency.getDisplayFileName(), dep.getGroup(), dep.getProject()));
|
||||
final String filePath = String.format("%s:%s/%s", dependency.getFilePath(), dep.getGroup(), dep.getProject());
|
||||
d.setFilePath(filePath);
|
||||
d.setSha1sum(Checksum.getHex(sha1.digest(filePath.getBytes(Charset.defaultCharset()))));
|
||||
d.getVendorEvidence().addEvidence(COMPOSER_LOCK, "vendor", dep.getGroup(), Confidence.HIGHEST);
|
||||
d.getProductEvidence().addEvidence(COMPOSER_LOCK, "product", dep.getProject(), Confidence.HIGHEST);
|
||||
d.getVersionEvidence().addEvidence(COMPOSER_LOCK, "version", dep.getVersion(), Confidence.HIGHEST);
|
||||
LOGGER.info("Adding dependency {}", d);
|
||||
engine.getDependencies().add(d);
|
||||
}
|
||||
} catch (FileNotFoundException fnfe) {
|
||||
LOGGER.warn("Error opening dependency {}", dependency.getActualFilePath());
|
||||
} catch (ComposerException ce) {
|
||||
LOGGER.warn("Error parsing composer.json {}", dependency.getActualFilePath(), ce);
|
||||
} finally {
|
||||
if (fis != null) {
|
||||
try {
|
||||
fis.close();
|
||||
} catch (Exception e) {
|
||||
LOGGER.debug("Unable to close file", e);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the key to determine whether the analyzer is enabled.
|
||||
*
|
||||
* @return the key specifying whether the analyzer is enabled
|
||||
*/
|
||||
@Override
|
||||
protected String getAnalyzerEnabledSettingKey() {
|
||||
return Settings.KEYS.ANALYZER_COMPOSER_LOCK_ENABLED;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the analyzer's name.
|
||||
*
|
||||
* @return the analyzer's name
|
||||
*/
|
||||
@Override
|
||||
public String getName() {
|
||||
return ANALYZER_NAME;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the phase this analyzer should run under.
|
||||
*
|
||||
* @return the analysis phase
|
||||
*/
|
||||
@Override
|
||||
public AnalysisPhase getAnalysisPhase() {
|
||||
return AnalysisPhase.INFORMATION_COLLECTION;
|
||||
}
|
||||
}
|
||||
@@ -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.
|
||||
* 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 {
|
||||
|
||||
|
||||
@@ -22,8 +22,6 @@ import java.util.HashSet;
|
||||
import java.util.Iterator;
|
||||
import java.util.ListIterator;
|
||||
import java.util.Set;
|
||||
import java.util.logging.Level;
|
||||
import java.util.logging.Logger;
|
||||
import java.util.regex.Matcher;
|
||||
import java.util.regex.Pattern;
|
||||
import org.owasp.dependencycheck.Engine;
|
||||
@@ -32,7 +30,8 @@ import org.owasp.dependencycheck.dependency.Dependency;
|
||||
import org.owasp.dependencycheck.dependency.Identifier;
|
||||
import org.owasp.dependencycheck.utils.DependencyVersion;
|
||||
import org.owasp.dependencycheck.utils.DependencyVersionUtil;
|
||||
import org.owasp.dependencycheck.utils.LogUtils;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
/**
|
||||
* <p>
|
||||
@@ -42,14 +41,14 @@ import org.owasp.dependencycheck.utils.LogUtils;
|
||||
* <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 {
|
||||
|
||||
/**
|
||||
* 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">
|
||||
/**
|
||||
@@ -76,6 +75,7 @@ public class DependencyBundlingAnalyzer extends AbstractAnalyzer implements Anal
|
||||
*
|
||||
* @return the name of the analyzer.
|
||||
*/
|
||||
@Override
|
||||
public String getName() {
|
||||
return ANALYZER_NAME;
|
||||
}
|
||||
@@ -85,6 +85,7 @@ public class DependencyBundlingAnalyzer extends AbstractAnalyzer implements Anal
|
||||
*
|
||||
* @return the phase that the analyzer is intended to run in.
|
||||
*/
|
||||
@Override
|
||||
public AnalysisPhase getAnalysisPhase() {
|
||||
return ANALYSIS_PHASE;
|
||||
}
|
||||
@@ -111,7 +112,8 @@ public class DependencyBundlingAnalyzer extends AbstractAnalyzer implements Anal
|
||||
final ListIterator<Dependency> subIterator = engine.getDependencies().listIterator(mainIterator.nextIndex());
|
||||
while (subIterator.hasNext()) {
|
||||
final Dependency nextDependency = subIterator.next();
|
||||
if (hashesMatch(dependency, nextDependency)) {
|
||||
if (hashesMatch(dependency, nextDependency) && !containedInWar(dependency.getFilePath())
|
||||
&& !containedInWar(nextDependency.getFilePath())) {
|
||||
if (firstPathIsShortest(dependency.getFilePath(), nextDependency.getFilePath())) {
|
||||
mergeDependencies(dependency, nextDependency, dependenciesToRemove);
|
||||
} else {
|
||||
@@ -125,7 +127,7 @@ public class DependencyBundlingAnalyzer extends AbstractAnalyzer implements Anal
|
||||
break;
|
||||
} else {
|
||||
mergeDependencies(dependency, nextDependency, dependenciesToRemove);
|
||||
nextDependency.getRelatedDependencies().remove(nextDependency);
|
||||
dependency.getRelatedDependencies().remove(nextDependency);
|
||||
}
|
||||
} else if (cpeIdentifiersMatch(dependency, nextDependency)
|
||||
&& hasSameBasePath(dependency, nextDependency)
|
||||
@@ -211,10 +213,8 @@ public class DependencyBundlingAnalyzer extends AbstractAnalyzer implements Anal
|
||||
//version check
|
||||
final DependencyVersion version1 = DependencyVersionUtil.parseVersion(fileName1);
|
||||
final DependencyVersion version2 = DependencyVersionUtil.parseVersion(fileName2);
|
||||
if (version1 != null && version2 != null) {
|
||||
if (!version1.equals(version2)) {
|
||||
return false;
|
||||
}
|
||||
if (version1 != null && version2 != null && !version1.equals(version2)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
//filename check
|
||||
@@ -262,10 +262,7 @@ public class DependencyBundlingAnalyzer extends AbstractAnalyzer implements Anal
|
||||
}
|
||||
}
|
||||
}
|
||||
if (LogUtils.isVerboseLoggingEnabled()) {
|
||||
final String msg = String.format("IdentifiersMatch=%s (%s, %s)", matches, dependency1.getFileName(), dependency2.getFileName());
|
||||
LOGGER.log(Level.FINE, msg);
|
||||
}
|
||||
LOGGER.debug("IdentifiersMatch={} ({}, {})", matches, dependency1.getFileName(), dependency2.getFileName());
|
||||
return matches;
|
||||
}
|
||||
|
||||
@@ -343,10 +340,7 @@ public class DependencyBundlingAnalyzer extends AbstractAnalyzer implements Anal
|
||||
*/
|
||||
returnVal = leftName.length() <= rightName.length();
|
||||
}
|
||||
if (LogUtils.isVerboseLoggingEnabled()) {
|
||||
final String msg = String.format("IsCore=%s (%s, %s)", returnVal, left.getFileName(), right.getFileName());
|
||||
LOGGER.log(Level.FINE, msg);
|
||||
}
|
||||
LOGGER.debug("IsCore={} ({}, {})", returnVal, left.getFileName(), right.getFileName());
|
||||
return returnVal;
|
||||
}
|
||||
|
||||
@@ -421,4 +415,14 @@ public class DependencyBundlingAnalyzer extends AbstractAnalyzer implements Anal
|
||||
}
|
||||
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;
|
||||
|
||||
import java.io.FileFilter;
|
||||
import java.io.UnsupportedEncodingException;
|
||||
import java.net.URLEncoder;
|
||||
import java.util.ArrayList;
|
||||
@@ -25,8 +26,6 @@ import java.util.Iterator;
|
||||
import java.util.List;
|
||||
import java.util.ListIterator;
|
||||
import java.util.Set;
|
||||
import java.util.logging.Level;
|
||||
import java.util.logging.Logger;
|
||||
import java.util.regex.Matcher;
|
||||
import java.util.regex.Pattern;
|
||||
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.Identifier;
|
||||
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.
|
||||
*
|
||||
* @author Jeremy Long <jeremy.long@owasp.org>
|
||||
* @author Jeremy Long
|
||||
*/
|
||||
public class FalsePositiveAnalyzer extends AbstractAnalyzer {
|
||||
|
||||
/**
|
||||
* 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">
|
||||
/**
|
||||
* The name of the analyzer.
|
||||
@@ -61,6 +69,7 @@ public class FalsePositiveAnalyzer extends AbstractAnalyzer {
|
||||
*
|
||||
* @return the name of the analyzer.
|
||||
*/
|
||||
@Override
|
||||
public String getName() {
|
||||
return ANALYZER_NAME;
|
||||
}
|
||||
@@ -70,6 +79,7 @@ public class FalsePositiveAnalyzer extends AbstractAnalyzer {
|
||||
*
|
||||
* @return the phase that the analyzer is intended to run in.
|
||||
*/
|
||||
@Override
|
||||
public AnalysisPhase getAnalysisPhase() {
|
||||
return ANALYSIS_PHASE;
|
||||
}
|
||||
@@ -103,7 +113,7 @@ public class FalsePositiveAnalyzer extends AbstractAnalyzer {
|
||||
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);
|
||||
final int endPoint = i.getValue().indexOf(':', 19);
|
||||
if (endPoint >= 0) {
|
||||
mustContain = i.getValue().substring(19, endPoint).toLowerCase();
|
||||
break;
|
||||
@@ -146,8 +156,7 @@ public class FalsePositiveAnalyzer extends AbstractAnalyzer {
|
||||
*/
|
||||
@SuppressWarnings("null")
|
||||
private void removeSpuriousCPE(Dependency dependency) {
|
||||
final List<Identifier> ids = new ArrayList<Identifier>();
|
||||
ids.addAll(dependency.getIdentifiers());
|
||||
final List<Identifier> ids = new ArrayList<Identifier>(dependency.getIdentifiers());
|
||||
Collections.sort(ids);
|
||||
final ListIterator<Identifier> mainItr = ids.listIterator();
|
||||
while (mainItr.hasNext()) {
|
||||
@@ -171,7 +180,7 @@ public class FalsePositiveAnalyzer extends AbstractAnalyzer {
|
||||
final String nextVersion = nextCpe.getVersion();
|
||||
if (currentVersion == null && nextVersion == null) {
|
||||
//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) {
|
||||
dependency.getIdentifiers().remove(currentId);
|
||||
} else if (nextVersion == null && currentVersion != null) {
|
||||
@@ -248,15 +257,15 @@ public class FalsePositiveAnalyzer extends AbstractAnalyzer {
|
||||
try {
|
||||
cpe.parseName(value);
|
||||
} catch (UnsupportedEncodingException ex) {
|
||||
LOGGER.log(Level.FINEST, null, ex);
|
||||
LOGGER.trace("", ex);
|
||||
return null;
|
||||
}
|
||||
return cpe;
|
||||
}
|
||||
|
||||
/**
|
||||
* Removes bad CPE matches for a dependency. Unfortunately, right now these are hard-coded patches for specific
|
||||
* problems identified when testing this on a LARGE volume of jar files.
|
||||
* Removes bad CPE matches for a dependency. Unfortunately, right now these are hard-coded patches for specific problems
|
||||
* identified when testing this on a LARGE volume of jar files.
|
||||
*
|
||||
* @param dependency the dependency to analyze
|
||||
*/
|
||||
@@ -273,7 +282,7 @@ public class FalsePositiveAnalyzer extends AbstractAnalyzer {
|
||||
//Set<Evidence> artifactId = dependency.getVendorEvidence().getEvidence("pom", "artifactid");
|
||||
while (itr.hasNext()) {
|
||||
final Identifier i = itr.next();
|
||||
//TODO move this startsWith expression to a configuration file?
|
||||
//TODO move this startsWith expression to the base suppression file
|
||||
if ("cpe".equals(i.getType())) {
|
||||
if ((i.getValue().matches(".*c\\+\\+.*")
|
||||
|| i.getValue().startsWith("cpe:/a:file:file")
|
||||
@@ -288,7 +297,14 @@ public class FalsePositiveAnalyzer extends AbstractAnalyzer {
|
||||
|| dependency.getFileName().toLowerCase().endsWith(".dll")
|
||||
|| dependency.getFileName().toLowerCase().endsWith(".exe")
|
||||
|| 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();
|
||||
} else if ((i.getValue().startsWith("cpe:/a:jquery:jquery")
|
||||
|| i.getValue().startsWith("cpe:/a:prototypejs:prototype")
|
||||
@@ -302,8 +318,11 @@ public class FalsePositiveAnalyzer extends AbstractAnalyzer {
|
||||
|| i.getValue().startsWith("cpe:/a:microsoft:word")
|
||||
|| i.getValue().startsWith("cpe:/a:microsoft:visio")
|
||||
|| i.getValue().startsWith("cpe:/a:microsoft:powerpoint")
|
||||
|| i.getValue().startsWith("cpe:/a:microsoft:office"))
|
||||
|| 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(".ear")
|
||||
|| dependency.getFileName().toLowerCase().endsWith(".war")
|
||||
|| dependency.getFileName().toLowerCase().endsWith("pom.xml"))) {
|
||||
itr.remove();
|
||||
} else if (i.getValue().startsWith("cpe:/a:apache:maven")
|
||||
@@ -354,26 +373,23 @@ public class FalsePositiveAnalyzer extends AbstractAnalyzer {
|
||||
}
|
||||
|
||||
/**
|
||||
* There are some known CPE entries, specifically regarding sun and oracle products due to the acquisition and
|
||||
* changes in product names, that based on given evidence we can add the related CPE entries to ensure a complete
|
||||
* list of CVE entries.
|
||||
* There are some known CPE entries, specifically regarding sun and oracle products due to the acquisition and changes in
|
||||
* product names, that based on given evidence we can add the related CPE entries to ensure a complete list of CVE entries.
|
||||
*
|
||||
* @param dependency the dependency being analyzed
|
||||
*/
|
||||
private void addFalseNegativeCPEs(Dependency dependency) {
|
||||
//TODO move this to the hint analyzer
|
||||
final Iterator<Identifier> itr = dependency.getIdentifiers().iterator();
|
||||
while (itr.hasNext()) {
|
||||
final Identifier i = itr.next();
|
||||
if ("cpe".equals(i.getType()) && i.getValue() != null
|
||||
&& (i.getValue().startsWith("cpe:/a:oracle:opensso:")
|
||||
|| i.getValue().startsWith("cpe:/a:oracle:opensso_enterprise:")
|
||||
|| i.getValue().startsWith("cpe:/a:sun:opensso_enterprise:")
|
||||
|| i.getValue().startsWith("cpe:/a:sun:opensso:"))) {
|
||||
final String newCpe = String.format("cpe:/a:sun:opensso_enterprise:%s", i.getValue().substring(22));
|
||||
final String newCpe2 = String.format("cpe:/a:oracle:opensso_enterprise:%s", i.getValue().substring(22));
|
||||
final String newCpe3 = String.format("cpe:/a:sun:opensso:%s", i.getValue().substring(22));
|
||||
final String newCpe4 = String.format("cpe:/a:oracle:opensso:%s", i.getValue().substring(22));
|
||||
for (final Identifier identifier : dependency.getIdentifiers()) {
|
||||
if ("cpe".equals(identifier.getType()) && identifier.getValue() != null
|
||||
&& (identifier.getValue().startsWith("cpe:/a:oracle:opensso:")
|
||||
|| identifier.getValue().startsWith("cpe:/a:oracle:opensso_enterprise:")
|
||||
|| identifier.getValue().startsWith("cpe:/a:sun:opensso_enterprise:")
|
||||
|| identifier.getValue().startsWith("cpe:/a:sun:opensso:"))) {
|
||||
final String newCpe = String.format("cpe:/a:sun:opensso_enterprise:%s", identifier.getValue().substring(22));
|
||||
final String newCpe2 = String.format("cpe:/a:oracle:opensso_enterprise:%s", identifier.getValue().substring(22));
|
||||
final String newCpe3 = String.format("cpe:/a:sun:opensso:%s", identifier.getValue().substring(22));
|
||||
final String newCpe4 = String.format("cpe:/a:oracle:opensso:%s", identifier.getValue().substring(22));
|
||||
try {
|
||||
dependency.addIdentifier("cpe",
|
||||
newCpe,
|
||||
@@ -388,23 +404,22 @@ public class FalsePositiveAnalyzer extends AbstractAnalyzer {
|
||||
newCpe4,
|
||||
String.format(CPEAnalyzer.NVD_SEARCH_URL, URLEncoder.encode(newCpe4, "UTF-8")));
|
||||
} 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
|
||||
* entries or other types of files (such as DLLs and EXEs) being contained within the JAR.
|
||||
* Removes duplicate entries identified that are contained within JAR files. These occasionally crop up due to POM entries or
|
||||
* other types of files (such as DLLs and EXEs) being contained within the JAR.
|
||||
*
|
||||
* @param dependency the dependency that might be a duplicate
|
||||
* @param engine the engine used to scan all dependencies
|
||||
*/
|
||||
private void removeDuplicativeEntriesFromJar(Dependency dependency, Engine engine) {
|
||||
if (dependency.getFileName().toLowerCase().endsWith("pom.xml")
|
||||
|| "dll".equals(dependency.getFileExtension())
|
||||
|| "exe".equals(dependency.getFileExtension())) {
|
||||
|| DLL_EXE_FILTER.accept(dependency.getActualFile())) {
|
||||
String parentPath = dependency.getFilePath().toLowerCase();
|
||||
if (parentPath.contains(".jar")) {
|
||||
parentPath = parentPath.substring(0, parentPath.indexOf(".jar") + 4);
|
||||
@@ -457,8 +472,8 @@ public class FalsePositiveAnalyzer extends AbstractAnalyzer {
|
||||
*/
|
||||
private String trimCpeToVendor(String value) {
|
||||
//cpe:/a:jruby:jruby:1.0.8
|
||||
final int pos1 = value.indexOf(":", 7); //right of vendor
|
||||
final int pos2 = value.indexOf(":", pos1 + 1); //right of product
|
||||
final int pos1 = value.indexOf(':', 7); //right of vendor
|
||||
final int pos2 = value.indexOf(':', pos1 + 1); //right of product
|
||||
if (pos2 < 0) {
|
||||
return value;
|
||||
} else {
|
||||
|
||||
@@ -18,6 +18,7 @@
|
||||
package org.owasp.dependencycheck.analyzer;
|
||||
|
||||
import java.io.File;
|
||||
import org.apache.commons.io.FilenameUtils;
|
||||
import org.owasp.dependencycheck.Engine;
|
||||
import org.owasp.dependencycheck.analyzer.exception.AnalysisException;
|
||||
import org.owasp.dependencycheck.dependency.Confidence;
|
||||
@@ -29,7 +30,7 @@ import org.owasp.dependencycheck.utils.DependencyVersionUtil;
|
||||
*
|
||||
* 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 {
|
||||
|
||||
@@ -48,6 +49,7 @@ public class FileNameAnalyzer extends AbstractAnalyzer implements Analyzer {
|
||||
*
|
||||
* @return the name of the analyzer.
|
||||
*/
|
||||
@Override
|
||||
public String getName() {
|
||||
return ANALYZER_NAME;
|
||||
}
|
||||
@@ -57,6 +59,7 @@ public class FileNameAnalyzer extends AbstractAnalyzer implements Analyzer {
|
||||
*
|
||||
* @return the phase that the analyzer is intended to run in.
|
||||
*/
|
||||
@Override
|
||||
public AnalysisPhase getAnalysisPhase() {
|
||||
return ANALYSIS_PHASE;
|
||||
}
|
||||
@@ -74,13 +77,7 @@ public class FileNameAnalyzer extends AbstractAnalyzer implements Analyzer {
|
||||
|
||||
//strip any path information that may get added by ArchiveAnalyzer, etc.
|
||||
final File f = dependency.getActualFile();
|
||||
String fileName = f.getName();
|
||||
|
||||
//remove file extension
|
||||
final int pos = fileName.lastIndexOf(".");
|
||||
if (pos > 0) {
|
||||
fileName = fileName.substring(0, pos);
|
||||
}
|
||||
final String fileName = FilenameUtils.removeExtension(f.getName());
|
||||
|
||||
//add version evidence
|
||||
final DependencyVersion version = DependencyVersionUtil.parseVersion(fileName);
|
||||
|
||||
@@ -17,20 +17,14 @@
|
||||
*/
|
||||
package org.owasp.dependencycheck.analyzer;
|
||||
|
||||
import java.io.FileFilter;
|
||||
|
||||
/**
|
||||
* An Analyzer that scans specific file types.
|
||||
*
|
||||
* @author Jeremy Long <jeremy.long@owasp.org>
|
||||
* @author Jeremy Long
|
||||
*/
|
||||
public interface FileTypeAnalyzer extends Analyzer {
|
||||
|
||||
/**
|
||||
* Returns whether or not this analyzer can process the given extension.
|
||||
*
|
||||
* @param extension the file extension to test for support.
|
||||
* @return whether or not the specified file extension is supported by this analyzer.
|
||||
*/
|
||||
boolean supportsExtension(String extension);
|
||||
public interface FileTypeAnalyzer extends Analyzer, FileFilter {
|
||||
|
||||
/**
|
||||
* Resets the analyzers state.
|
||||
|
||||
@@ -29,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 {
|
||||
|
||||
@@ -89,30 +89,70 @@ public class HintAnalyzer extends AbstractAnalyzer implements Analyzer {
|
||||
"spring-core",
|
||||
Confidence.HIGH);
|
||||
|
||||
final Evidence springTest4 = new Evidence("Manifest",
|
||||
"Bundle-Vendor",
|
||||
"SpringSource",
|
||||
Confidence.HIGH);
|
||||
|
||||
final Evidence springTest5 = new Evidence("jar",
|
||||
final Evidence springTest4 = new Evidence("jar",
|
||||
"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);
|
||||
|
||||
final Evidence symfony = new Evidence("composer.lock",
|
||||
"vendor",
|
||||
"symfony",
|
||||
Confidence.HIGHEST);
|
||||
|
||||
final Evidence zendframeworkVendor = new Evidence("composer.lock",
|
||||
"vendor",
|
||||
"zendframework",
|
||||
Confidence.HIGHEST);
|
||||
|
||||
final Evidence zendframeworkProduct = new Evidence("composer.lock",
|
||||
"product",
|
||||
"zendframework",
|
||||
Confidence.HIGHEST);
|
||||
|
||||
//springsource/vware problem
|
||||
final Set<Evidence> product = dependency.getProductEvidence().getEvidence();
|
||||
final Set<Evidence> vendor = dependency.getVendorEvidence().getEvidence();
|
||||
|
||||
if (product.contains(springTest1) || product.contains(springTest2) || product.contains(springTest3)
|
||||
|| (dependency.getFileName().contains("spring") && (product.contains(springTest5) || vendor.contains(springTest5)))) {
|
||||
|| (dependency.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.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", "vmware", Confidence.HIGH);
|
||||
}
|
||||
|
||||
if (vendor.contains(symfony)) {
|
||||
dependency.getVendorEvidence().addEvidence("hint analyzer", "vendor", "sensiolabs", Confidence.HIGHEST);
|
||||
}
|
||||
|
||||
if (vendor.contains(zendframeworkVendor)) {
|
||||
dependency.getVendorEvidence().addEvidence("hint analyzer", "vendor", "zend", Confidence.HIGHEST);
|
||||
}
|
||||
|
||||
if (product.contains(zendframeworkProduct)) {
|
||||
dependency.getProductEvidence().addEvidence("hint analyzer", "vendor", "zend_framework", Confidence.HIGHEST);
|
||||
}
|
||||
|
||||
//sun/oracle problem
|
||||
|
||||
@@ -17,21 +17,19 @@
|
||||
*/
|
||||
package org.owasp.dependencycheck.analyzer;
|
||||
|
||||
import java.io.BufferedOutputStream;
|
||||
import java.io.File;
|
||||
import java.io.FileInputStream;
|
||||
import java.io.FileNotFoundException;
|
||||
import java.io.FileFilter;
|
||||
import java.io.FileOutputStream;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.io.InputStreamReader;
|
||||
import java.io.OutputStream;
|
||||
import java.io.Reader;
|
||||
import java.io.UnsupportedEncodingException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.Enumeration;
|
||||
import java.util.HashMap;
|
||||
import java.util.Iterator;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Map.Entry;
|
||||
@@ -42,30 +40,29 @@ import java.util.jar.Attributes;
|
||||
import java.util.jar.JarEntry;
|
||||
import java.util.jar.JarFile;
|
||||
import java.util.jar.Manifest;
|
||||
import java.util.logging.Level;
|
||||
import java.util.logging.Logger;
|
||||
import java.util.regex.Pattern;
|
||||
import java.util.zip.ZipEntry;
|
||||
import javax.xml.transform.sax.SAXSource;
|
||||
import org.apache.commons.compress.utils.IOUtils;
|
||||
import org.apache.commons.io.FilenameUtils;
|
||||
import org.jsoup.Jsoup;
|
||||
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.jaxb.pom.PomUtils;
|
||||
import org.owasp.dependencycheck.jaxb.pom.generated.License;
|
||||
import org.owasp.dependencycheck.jaxb.pom.generated.Model;
|
||||
import org.owasp.dependencycheck.jaxb.pom.generated.Organization;
|
||||
import org.owasp.dependencycheck.utils.FileFilterBuilder;
|
||||
import org.owasp.dependencycheck.xml.pom.License;
|
||||
import org.owasp.dependencycheck.xml.pom.PomUtils;
|
||||
import org.owasp.dependencycheck.xml.pom.Model;
|
||||
import org.owasp.dependencycheck.utils.FileUtils;
|
||||
import org.owasp.dependencycheck.utils.NonClosingStream;
|
||||
import org.owasp.dependencycheck.utils.Settings;
|
||||
import org.xml.sax.InputSource;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
/**
|
||||
* 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 {
|
||||
|
||||
@@ -73,11 +70,7 @@ public class JarAnalyzer extends AbstractFileTypeAnalyzer {
|
||||
/**
|
||||
* The logger.
|
||||
*/
|
||||
private static final Logger LOGGER = Logger.getLogger(JarAnalyzer.class.getName());
|
||||
/**
|
||||
* The buffer size to use when extracting files from the archive.
|
||||
*/
|
||||
private static final int BUFFER_SIZE = 4096;
|
||||
private static final Logger LOGGER = LoggerFactory.getLogger(JarAnalyzer.class);
|
||||
/**
|
||||
* The count of directories created during analysis. This is used for creating temporary directories.
|
||||
*/
|
||||
@@ -123,11 +116,18 @@ public class JarAnalyzer extends AbstractFileTypeAnalyzer {
|
||||
"tool",
|
||||
"bundle-manifestversion",
|
||||
"bundlemanifestversion",
|
||||
"bundle-vendor",
|
||||
"include-resource",
|
||||
"embed-dependency",
|
||||
"ipojo-components",
|
||||
"ipojo-extension",
|
||||
"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.
|
||||
*/
|
||||
@@ -140,26 +140,16 @@ public class JarAnalyzer extends AbstractFileTypeAnalyzer {
|
||||
* item in some manifest, should be considered medium confidence.
|
||||
*/
|
||||
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.
|
||||
*/
|
||||
private static final Pattern HTML_DETECTION_PATTERN = Pattern.compile("\\<[a-z]+.*/?\\>", Pattern.CASE_INSENSITIVE);
|
||||
|
||||
/**
|
||||
* The POM Utility for parsing POM files.
|
||||
*/
|
||||
private PomUtils pomUtils = null;
|
||||
//</editor-fold>
|
||||
|
||||
/**
|
||||
* Constructs a new JarAnalyzer.
|
||||
*/
|
||||
public JarAnalyzer() {
|
||||
pomUtils = new PomUtils();
|
||||
}
|
||||
|
||||
//<editor-fold defaultstate="collapsed" desc="All standard implmentation details of Analyzer">
|
||||
@@ -174,16 +164,21 @@ public class JarAnalyzer extends AbstractFileTypeAnalyzer {
|
||||
/**
|
||||
* 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
|
||||
public Set<String> getSupportedExtensions() {
|
||||
return EXTENSIONS;
|
||||
protected FileFilter getFileFilter() {
|
||||
return FILTER;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -201,6 +196,7 @@ public class JarAnalyzer extends AbstractFileTypeAnalyzer {
|
||||
*
|
||||
* @return the phase that the analyzer is intended to run in.
|
||||
*/
|
||||
@Override
|
||||
public AnalysisPhase getAnalysisPhase() {
|
||||
return ANALYSIS_PHASE;
|
||||
}
|
||||
@@ -261,26 +257,21 @@ public class JarAnalyzer extends AbstractFileTypeAnalyzer {
|
||||
try {
|
||||
jar = new JarFile(dependency.getActualFilePath());
|
||||
} catch (IOException ex) {
|
||||
final String msg = String.format("Unable to read JarFile '%s'.", dependency.getActualFilePath());
|
||||
//final AnalysisException ax = new AnalysisException(msg, ex);
|
||||
LOGGER.log(Level.WARNING, msg);
|
||||
LOGGER.log(Level.FINE, "", ex);
|
||||
LOGGER.warn("Unable to read JarFile '{}'.", dependency.getActualFilePath());
|
||||
LOGGER.trace("", ex);
|
||||
return false;
|
||||
}
|
||||
List<String> pomEntries;
|
||||
try {
|
||||
pomEntries = retrievePomListing(jar);
|
||||
} catch (IOException ex) {
|
||||
final String msg = String.format("Unable to read Jar file entries in '%s'.", dependency.getActualFilePath());
|
||||
//final AnalysisException ax = new AnalysisException(msg, ex);
|
||||
LOGGER.log(Level.WARNING, msg);
|
||||
LOGGER.log(Level.FINE, msg, ex);
|
||||
LOGGER.warn("Unable to read Jar file entries in '{}'.", dependency.getActualFilePath());
|
||||
LOGGER.trace("", ex);
|
||||
return false;
|
||||
}
|
||||
File externalPom = null;
|
||||
if (pomEntries.isEmpty()) {
|
||||
String pomPath = dependency.getActualFilePath();
|
||||
pomPath = pomPath.substring(0, pomPath.lastIndexOf('.')) + ".pom";
|
||||
final String pomPath = FilenameUtils.removeExtension(dependency.getActualFilePath()) + ".pom";
|
||||
externalPom = new File(pomPath);
|
||||
if (externalPom.isFile()) {
|
||||
pomEntries.add(pomPath);
|
||||
@@ -289,13 +280,14 @@ public class JarAnalyzer extends AbstractFileTypeAnalyzer {
|
||||
}
|
||||
}
|
||||
for (String path : pomEntries) {
|
||||
LOGGER.debug("Reading pom entry: {}", path);
|
||||
Properties pomProperties = null;
|
||||
try {
|
||||
if (externalPom == null) {
|
||||
pomProperties = retrievePomProperties(path, jar);
|
||||
}
|
||||
} 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;
|
||||
try {
|
||||
@@ -315,21 +307,22 @@ public class JarAnalyzer extends AbstractFileTypeAnalyzer {
|
||||
|
||||
newDependency.setFileName(displayName);
|
||||
newDependency.setFilePath(displayPath);
|
||||
setPomEvidence(newDependency, pom, pomProperties, null);
|
||||
pom.processProperties(pomProperties);
|
||||
setPomEvidence(newDependency, pom, null);
|
||||
engine.getDependencies().add(newDependency);
|
||||
Collections.sort(engine.getDependencies());
|
||||
} else {
|
||||
if (externalPom == null) {
|
||||
pom = retrievePom(path, jar);
|
||||
pom = PomUtils.readPom(path, jar);
|
||||
} else {
|
||||
pom = pomUtils.readPom(externalPom);
|
||||
pom = PomUtils.readPom(externalPom);
|
||||
}
|
||||
foundSomething |= setPomEvidence(dependency, pom, pomProperties, classes);
|
||||
pom.processProperties(pomProperties);
|
||||
foundSomething |= setPomEvidence(dependency, pom, classes);
|
||||
}
|
||||
} catch (AnalysisException ex) {
|
||||
final String msg = String.format("An error occured while analyzing '%s'.", dependency.getActualFilePath());
|
||||
LOGGER.log(Level.WARNING, msg);
|
||||
LOGGER.log(Level.FINE, "", ex);
|
||||
LOGGER.warn("An error occurred while analyzing '{}'.", dependency.getActualFilePath());
|
||||
LOGGER.trace("", ex);
|
||||
}
|
||||
}
|
||||
return foundSomething;
|
||||
@@ -353,12 +346,13 @@ public class JarAnalyzer extends AbstractFileTypeAnalyzer {
|
||||
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.log(Level.FINEST, "close error", ex);
|
||||
LOGGER.trace("close error", ex);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -380,6 +374,7 @@ public class JarAnalyzer extends AbstractFileTypeAnalyzer {
|
||||
final JarEntry entry = entries.nextElement();
|
||||
final String entryName = (new File(entry.getName())).getName().toLowerCase();
|
||||
if (!entry.isDirectory() && "pom.xml".equals(entryName)) {
|
||||
LOGGER.trace("POM Entry found: {}", entry.getName());
|
||||
pomEntries.add(entry.getName());
|
||||
}
|
||||
}
|
||||
@@ -394,62 +389,27 @@ public class JarAnalyzer extends AbstractFileTypeAnalyzer {
|
||||
* @param dependency the dependency being analyzed
|
||||
* @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
|
||||
* {@link org.owasp.dependencycheck.xml.pom.Model} object
|
||||
*/
|
||||
private Model extractPom(String path, JarFile jar, Dependency dependency) throws AnalysisException {
|
||||
InputStream input = null;
|
||||
FileOutputStream fos = null;
|
||||
BufferedOutputStream bos = null;
|
||||
final File tmpDir = getNextTempDirectory();
|
||||
final File file = new File(tmpDir, "pom.xml");
|
||||
try {
|
||||
final ZipEntry entry = jar.getEntry(path);
|
||||
input = jar.getInputStream(entry);
|
||||
fos = new FileOutputStream(file);
|
||||
bos = new BufferedOutputStream(fos, BUFFER_SIZE);
|
||||
int count;
|
||||
final byte[] data = new byte[BUFFER_SIZE];
|
||||
while ((count = input.read(data, 0, BUFFER_SIZE)) != -1) {
|
||||
bos.write(data, 0, count);
|
||||
}
|
||||
bos.flush();
|
||||
IOUtils.copy(input, fos);
|
||||
dependency.setActualFilePath(file.getAbsolutePath());
|
||||
} catch (IOException ex) {
|
||||
final String msg = String.format("An error occurred reading '%s' from '%s'.", path, dependency.getFilePath());
|
||||
LOGGER.warning(msg);
|
||||
LOGGER.log(Level.SEVERE, "", ex);
|
||||
LOGGER.warn("An error occurred reading '{}' from '{}'.", path, dependency.getFilePath());
|
||||
LOGGER.error("", ex);
|
||||
} finally {
|
||||
closeStream(bos);
|
||||
closeStream(fos);
|
||||
closeStream(input);
|
||||
}
|
||||
Model model = null;
|
||||
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 = pomUtils.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;
|
||||
return PomUtils.readPom(file);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -462,7 +422,7 @@ public class JarAnalyzer extends AbstractFileTypeAnalyzer {
|
||||
try {
|
||||
stream.close();
|
||||
} catch (IOException ex) {
|
||||
LOGGER.log(Level.FINEST, null, ex);
|
||||
LOGGER.trace("", ex);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -477,76 +437,60 @@ public class JarAnalyzer extends AbstractFileTypeAnalyzer {
|
||||
try {
|
||||
stream.close();
|
||||
} 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 = pomUtils.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;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets evidence from the pom on the supplied dependency.
|
||||
*
|
||||
* @param dependency the dependency to set data on
|
||||
* @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
|
||||
* file being analyzed
|
||||
* @return true if there was evidence within the pom that we could use; otherwise false
|
||||
*/
|
||||
private boolean setPomEvidence(Dependency dependency, Model pom, Properties pomProperties, List<ClassNameInformation> classes) {
|
||||
public static boolean setPomEvidence(Dependency dependency, Model pom, List<ClassNameInformation> classes) {
|
||||
boolean foundSomething = false;
|
||||
boolean addAsIdentifier = true;
|
||||
if (pom == null) {
|
||||
return foundSomething;
|
||||
}
|
||||
String groupid = interpolateString(pom.getGroupId(), pomProperties);
|
||||
String parentGroupId = null;
|
||||
String groupid = pom.getGroupId();
|
||||
String parentGroupId = pom.getParentGroupId();
|
||||
String artifactid = pom.getArtifactId();
|
||||
String parentArtifactId = pom.getParentArtifactId();
|
||||
String version = pom.getVersion();
|
||||
String parentVersion = pom.getParentVersion();
|
||||
|
||||
if (pom.getParent() != null) {
|
||||
parentGroupId = interpolateString(pom.getParent().getGroupId(), pomProperties);
|
||||
if ((groupid == null || groupid.isEmpty()) && parentGroupId != null && !parentGroupId.isEmpty()) {
|
||||
groupid = parentGroupId;
|
||||
}
|
||||
if ("org.sonatype.oss".equals(parentGroupId) && "oss-parent".equals(parentArtifactId)) {
|
||||
parentGroupId = null;
|
||||
parentArtifactId = null;
|
||||
parentVersion = null;
|
||||
}
|
||||
|
||||
if ((groupid == null || groupid.isEmpty()) && parentGroupId != null && !parentGroupId.isEmpty()) {
|
||||
groupid = parentGroupId;
|
||||
}
|
||||
|
||||
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()) {
|
||||
foundSomething = true;
|
||||
@@ -564,20 +508,7 @@ public class JarAnalyzer extends AbstractFileTypeAnalyzer {
|
||||
addAsIdentifier = false;
|
||||
}
|
||||
|
||||
String artifactid = interpolateString(pom.getArtifactId(), pomProperties);
|
||||
String parentArtifactId = null;
|
||||
|
||||
if (pom.getParent() != null) {
|
||||
parentArtifactId = interpolateString(pom.getParent().getArtifactId(), pomProperties);
|
||||
if ((artifactid == null || artifactid.isEmpty()) && parentArtifactId != null && !parentArtifactId.isEmpty()) {
|
||||
artifactid = parentArtifactId;
|
||||
}
|
||||
}
|
||||
final String originalArtifactID = artifactid;
|
||||
if (artifactid != null && !artifactid.isEmpty()) {
|
||||
if (artifactid.startsWith("org.") || artifactid.startsWith("com.")) {
|
||||
artifactid = artifactid.substring(4);
|
||||
}
|
||||
foundSomething = true;
|
||||
dependency.getProductEvidence().addEvidence("pom", "artifactid", artifactid, Confidence.HIGHEST);
|
||||
dependency.getVendorEvidence().addEvidence("pom", "artifactid", artifactid, Confidence.LOW);
|
||||
@@ -592,16 +523,6 @@ public class JarAnalyzer extends AbstractFileTypeAnalyzer {
|
||||
} else {
|
||||
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()) {
|
||||
foundSomething = true;
|
||||
@@ -614,22 +535,21 @@ public class JarAnalyzer extends AbstractFileTypeAnalyzer {
|
||||
}
|
||||
|
||||
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
|
||||
final Organization org = pom.getOrganization();
|
||||
if (org != null && org.getName() != null) {
|
||||
foundSomething = true;
|
||||
final String orgName = interpolateString(org.getName(), pomProperties);
|
||||
if (orgName != null && !orgName.isEmpty()) {
|
||||
dependency.getVendorEvidence().addEvidence("pom", "organization name", orgName, Confidence.HIGH);
|
||||
addMatchingValues(classes, orgName, dependency.getVendorEvidence());
|
||||
}
|
||||
final String org = pom.getOrganization();
|
||||
if (org != null && !org.isEmpty()) {
|
||||
dependency.getVendorEvidence().addEvidence("pom", "organization name", org, Confidence.HIGH);
|
||||
dependency.getProductEvidence().addEvidence("pom", "organization name", org, Confidence.LOW);
|
||||
addMatchingValues(classes, org, dependency.getVendorEvidence());
|
||||
addMatchingValues(classes, org, dependency.getProductEvidence());
|
||||
}
|
||||
//pom name
|
||||
final String pomName = interpolateString(pom.getName(), pomProperties);
|
||||
if (pomName != null && !pomName.isEmpty()) {
|
||||
final String pomName = pom.getName();
|
||||
if (pomName
|
||||
!= null && !pomName.isEmpty()) {
|
||||
foundSomething = true;
|
||||
dependency.getProductEvidence().addEvidence("pom", "name", pomName, Confidence.HIGH);
|
||||
dependency.getVendorEvidence().addEvidence("pom", "name", pomName, Confidence.HIGH);
|
||||
@@ -638,16 +558,15 @@ public class JarAnalyzer extends AbstractFileTypeAnalyzer {
|
||||
}
|
||||
|
||||
//Description
|
||||
if (pom.getDescription() != null) {
|
||||
final String description = pom.getDescription();
|
||||
if (description != null && !description.isEmpty() && !description.startsWith("POM was created by")) {
|
||||
foundSomething = true;
|
||||
final String description = interpolateString(pom.getDescription(), pomProperties);
|
||||
if (description != null && !description.isEmpty()) {
|
||||
final String trimmedDescription = addDescription(dependency, description, "pom", "description");
|
||||
addMatchingValues(classes, trimmedDescription, dependency.getVendorEvidence());
|
||||
addMatchingValues(classes, trimmedDescription, dependency.getProductEvidence());
|
||||
}
|
||||
final String trimmedDescription = addDescription(dependency, description, "pom", "description");
|
||||
addMatchingValues(classes, trimmedDescription, dependency.getVendorEvidence());
|
||||
addMatchingValues(classes, trimmedDescription, dependency.getProductEvidence());
|
||||
}
|
||||
extractLicense(pom, pomProperties, dependency);
|
||||
|
||||
extractLicense(pom, dependency);
|
||||
return foundSomething;
|
||||
}
|
||||
|
||||
@@ -709,29 +628,27 @@ public class JarAnalyzer extends AbstractFileTypeAnalyzer {
|
||||
JarFile jar = null;
|
||||
try {
|
||||
jar = new JarFile(dependency.getActualFilePath());
|
||||
|
||||
final Manifest manifest = jar.getManifest();
|
||||
|
||||
if (manifest == null) {
|
||||
//don't log this for javadoc or sources jar files
|
||||
if (!dependency.getFileName().toLowerCase().endsWith("-sources.jar")
|
||||
&& !dependency.getFileName().toLowerCase().endsWith("-javadoc.jar")
|
||||
&& !dependency.getFileName().toLowerCase().endsWith("-src.jar")
|
||||
&& !dependency.getFileName().toLowerCase().endsWith("-doc.jar")) {
|
||||
LOGGER.log(Level.FINE,
|
||||
String.format("Jar file '%s' does not contain a manifest.",
|
||||
dependency.getFileName()));
|
||||
LOGGER.debug("Jar file '{}' does not contain a manifest.",
|
||||
dependency.getFileName());
|
||||
}
|
||||
return false;
|
||||
}
|
||||
final Attributes atts = manifest.getMainAttributes();
|
||||
|
||||
final EvidenceCollection vendorEvidence = dependency.getVendorEvidence();
|
||||
final EvidenceCollection productEvidence = dependency.getProductEvidence();
|
||||
final EvidenceCollection versionEvidence = dependency.getVersionEvidence();
|
||||
|
||||
final String source = "Manifest";
|
||||
String source = "Manifest";
|
||||
String specificationVersion = null;
|
||||
boolean hasImplementationVersion = false;
|
||||
|
||||
Attributes atts = manifest.getMainAttributes();
|
||||
for (Entry<Object, Object> entry : atts.entrySet()) {
|
||||
String key = entry.getKey().toString();
|
||||
String value = atts.getValue(key);
|
||||
@@ -745,13 +662,16 @@ public class JarAnalyzer extends AbstractFileTypeAnalyzer {
|
||||
productEvidence.addEvidence(source, key, value, Confidence.HIGH);
|
||||
addMatchingValues(classInformation, value, productEvidence);
|
||||
} else if (key.equalsIgnoreCase(Attributes.Name.IMPLEMENTATION_VERSION.toString())) {
|
||||
hasImplementationVersion = true;
|
||||
foundSomething = true;
|
||||
versionEvidence.addEvidence(source, key, value, Confidence.HIGH);
|
||||
} else if ("specification-version".equalsIgnoreCase(key)) {
|
||||
specificationVersion = key;
|
||||
} else if (key.equalsIgnoreCase(Attributes.Name.IMPLEMENTATION_VENDOR.toString())) {
|
||||
foundSomething = true;
|
||||
vendorEvidence.addEvidence(source, key, value, Confidence.HIGH);
|
||||
addMatchingValues(classInformation, value, vendorEvidence);
|
||||
} else if (key.equalsIgnoreCase(Attributes.Name.IMPLEMENTATION_VENDOR_ID.toString())) {
|
||||
} else if (key.equalsIgnoreCase(IMPLEMENTATION_VENDOR_ID)) {
|
||||
foundSomething = true;
|
||||
vendorEvidence.addEvidence(source, key, value, Confidence.MEDIUM);
|
||||
addMatchingValues(classInformation, value, vendorEvidence);
|
||||
@@ -764,10 +684,11 @@ public class JarAnalyzer extends AbstractFileTypeAnalyzer {
|
||||
foundSomething = true;
|
||||
productEvidence.addEvidence(source, key, value, Confidence.MEDIUM);
|
||||
addMatchingValues(classInformation, value, productEvidence);
|
||||
} else if (key.equalsIgnoreCase(BUNDLE_VENDOR)) {
|
||||
foundSomething = true;
|
||||
vendorEvidence.addEvidence(source, key, value, Confidence.HIGH);
|
||||
addMatchingValues(classInformation, value, vendorEvidence);
|
||||
// //the following caused false positives.
|
||||
// } else if (key.equalsIgnoreCase(BUNDLE_VENDOR)) {
|
||||
// foundSomething = true;
|
||||
// vendorEvidence.addEvidence(source, key, value, Confidence.HIGH);
|
||||
// addMatchingValues(classInformation, value, vendorEvidence);
|
||||
} else if (key.equalsIgnoreCase(BUNDLE_VERSION)) {
|
||||
foundSomething = true;
|
||||
versionEvidence.addEvidence(source, key, value, Confidence.HIGH);
|
||||
@@ -783,7 +704,6 @@ public class JarAnalyzer extends AbstractFileTypeAnalyzer {
|
||||
// addMatchingValues(classInformation, value, productEvidence);
|
||||
} else {
|
||||
key = key.toLowerCase();
|
||||
|
||||
if (!IGNORE_KEYS.contains(key)
|
||||
&& !key.endsWith("jdk")
|
||||
&& !key.contains("lastmodified")
|
||||
@@ -798,9 +718,7 @@ public class JarAnalyzer extends AbstractFileTypeAnalyzer {
|
||||
|
||||
foundSomething = true;
|
||||
if (key.contains("version")) {
|
||||
if (key.contains("specification")) {
|
||||
versionEvidence.addEvidence(source, key, value, Confidence.LOW);
|
||||
} else {
|
||||
if (!key.contains("specification")) {
|
||||
versionEvidence.addEvidence(source, key, value, Confidence.MEDIUM);
|
||||
}
|
||||
} else if ("build-id".equals(key)) {
|
||||
@@ -852,6 +770,37 @@ public class JarAnalyzer extends AbstractFileTypeAnalyzer {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
final Map<String, Attributes> entries = manifest.getEntries();
|
||||
for (Iterator<String> it = entries.keySet().iterator(); it.hasNext();) {
|
||||
final String name = it.next();
|
||||
source = "manifest: " + name;
|
||||
atts = entries.get(name);
|
||||
for (Entry<Object, Object> entry : atts.entrySet()) {
|
||||
final String key = entry.getKey().toString();
|
||||
final String value = atts.getValue(key);
|
||||
if (key.equalsIgnoreCase(Attributes.Name.IMPLEMENTATION_TITLE.toString())) {
|
||||
foundSomething = true;
|
||||
productEvidence.addEvidence(source, key, value, Confidence.MEDIUM);
|
||||
addMatchingValues(classInformation, value, productEvidence);
|
||||
} else if (key.equalsIgnoreCase(Attributes.Name.IMPLEMENTATION_VERSION.toString())) {
|
||||
foundSomething = true;
|
||||
versionEvidence.addEvidence(source, key, value, Confidence.MEDIUM);
|
||||
} else if (key.equalsIgnoreCase(Attributes.Name.IMPLEMENTATION_VENDOR.toString())) {
|
||||
foundSomething = true;
|
||||
vendorEvidence.addEvidence(source, key, value, Confidence.MEDIUM);
|
||||
addMatchingValues(classInformation, value, vendorEvidence);
|
||||
} else if (key.equalsIgnoreCase(Attributes.Name.SPECIFICATION_TITLE.toString())) {
|
||||
foundSomething = true;
|
||||
productEvidence.addEvidence(source, key, value, Confidence.MEDIUM);
|
||||
addMatchingValues(classInformation, value, productEvidence);
|
||||
}
|
||||
}
|
||||
}
|
||||
if (specificationVersion != null && !hasImplementationVersion) {
|
||||
foundSomething = true;
|
||||
versionEvidence.addEvidence(source, "specification-version", specificationVersion, Confidence.HIGH);
|
||||
}
|
||||
} finally {
|
||||
if (jar != null) {
|
||||
jar.close();
|
||||
@@ -907,10 +856,7 @@ public class JarAnalyzer extends AbstractFileTypeAnalyzer {
|
||||
}
|
||||
|
||||
if (pos > 0) {
|
||||
final StringBuilder sb = new StringBuilder(pos + 3);
|
||||
sb.append(desc.substring(0, pos));
|
||||
sb.append("...");
|
||||
desc = sb.toString();
|
||||
desc = desc.substring(0, pos) + "...";
|
||||
}
|
||||
dependency.getProductEvidence().addEvidence(source, key, desc, Confidence.LOW);
|
||||
dependency.getVendorEvidence().addEvidence(source, key, desc, Confidence.LOW);
|
||||
@@ -965,71 +911,14 @@ public class JarAnalyzer extends AbstractFileTypeAnalyzer {
|
||||
@Override
|
||||
public void close() {
|
||||
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);
|
||||
if (!success) {
|
||||
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");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* <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.
|
||||
*/
|
||||
public static String interpolateString(String text, Properties properties) {
|
||||
final Properties props = properties;
|
||||
if (text == null) {
|
||||
return text;
|
||||
}
|
||||
if (props == null) {
|
||||
return text;
|
||||
}
|
||||
|
||||
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.
|
||||
*
|
||||
@@ -1055,9 +944,9 @@ public class JarAnalyzer extends AbstractFileTypeAnalyzer {
|
||||
JarFile jar = null;
|
||||
try {
|
||||
jar = new JarFile(dependency.getActualFilePath());
|
||||
final Enumeration entries = jar.entries();
|
||||
final Enumeration<JarEntry> entries = jar.entries();
|
||||
while (entries.hasMoreElements()) {
|
||||
final JarEntry entry = (JarEntry) entries.nextElement();
|
||||
final JarEntry entry = entries.nextElement();
|
||||
final String name = entry.getName().toLowerCase();
|
||||
//no longer stripping "|com\\.sun" - there are some com.sun jar files with CVEs.
|
||||
if (name.endsWith(".class") && !name.matches("^javax?\\..*$")) {
|
||||
@@ -1066,15 +955,14 @@ public class JarAnalyzer extends AbstractFileTypeAnalyzer {
|
||||
}
|
||||
}
|
||||
} catch (IOException ex) {
|
||||
final String msg = String.format("Unable to open jar file '%s'.", dependency.getFileName());
|
||||
LOGGER.log(Level.WARNING, msg);
|
||||
LOGGER.log(Level.FINE, null, ex);
|
||||
LOGGER.warn("Unable to open jar file '{}'.", dependency.getFileName());
|
||||
LOGGER.debug("", ex);
|
||||
} finally {
|
||||
if (jar != null) {
|
||||
try {
|
||||
jar.close();
|
||||
} catch (IOException ex) {
|
||||
LOGGER.log(Level.FINEST, null, ex);
|
||||
LOGGER.trace("", ex);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1137,14 +1025,16 @@ public class JarAnalyzer extends AbstractFileTypeAnalyzer {
|
||||
* @param value the value to check to see if it contains a package name
|
||||
* @param evidence the evidence collection to add new entries too
|
||||
*/
|
||||
private void addMatchingValues(List<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()) {
|
||||
return;
|
||||
}
|
||||
final String text = value.toLowerCase();
|
||||
for (ClassNameInformation cni : classes) {
|
||||
for (String key : cni.getPackageStructure()) {
|
||||
if (text.contains(key)) { //note, package structure elements are already lowercase.
|
||||
final Pattern p = Pattern.compile("\b" + key + "\b");
|
||||
if (p.matcher(text).find()) {
|
||||
//if (text.contains(key)) { //note, package structure elements are already lowercase.
|
||||
evidence.addEvidence("jar", "package name", key, Confidence.HIGHEST);
|
||||
}
|
||||
}
|
||||
@@ -1169,23 +1059,22 @@ public class JarAnalyzer extends AbstractFileTypeAnalyzer {
|
||||
* Extracts the license information from the pom and adds it to the dependency.
|
||||
*
|
||||
* @param pom the pom object
|
||||
* @param pomProperties the properties, used for string interpolation
|
||||
* @param dependency the dependency to add license information too
|
||||
*/
|
||||
public static void extractLicense(Model pom, Properties pomProperties, Dependency dependency) {
|
||||
public static void extractLicense(Model pom, Dependency dependency) {
|
||||
//license
|
||||
if (pom.getLicenses() != null) {
|
||||
String license = null;
|
||||
for (License lic : pom.getLicenses().getLicense()) {
|
||||
for (License lic : pom.getLicenses()) {
|
||||
String tmp = null;
|
||||
if (lic.getName() != null) {
|
||||
tmp = interpolateString(lic.getName(), pomProperties);
|
||||
tmp = lic.getName();
|
||||
}
|
||||
if (lic.getUrl() != null) {
|
||||
if (tmp == null) {
|
||||
tmp = interpolateString(lic.getUrl(), pomProperties);
|
||||
tmp = lic.getUrl();
|
||||
} else {
|
||||
tmp += ": " + interpolateString(lic.getUrl(), pomProperties);
|
||||
tmp += ": " + lic.getUrl();
|
||||
}
|
||||
}
|
||||
if (tmp == null) {
|
||||
@@ -1202,6 +1091,7 @@ public class JarAnalyzer extends AbstractFileTypeAnalyzer {
|
||||
}
|
||||
if (license != null) {
|
||||
dependency.setLicense(license);
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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,14 +17,6 @@
|
||||
*/
|
||||
package org.owasp.dependencycheck.analyzer;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.FileNotFoundException;
|
||||
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.apache.commons.io.FileUtils;
|
||||
import org.owasp.dependencycheck.Engine;
|
||||
import org.owasp.dependencycheck.analyzer.exception.AnalysisException;
|
||||
@@ -33,10 +25,20 @@ import org.owasp.dependencycheck.data.nexus.NexusSearch;
|
||||
import org.owasp.dependencycheck.dependency.Confidence;
|
||||
import org.owasp.dependencycheck.dependency.Dependency;
|
||||
import org.owasp.dependencycheck.dependency.Evidence;
|
||||
import org.owasp.dependencycheck.jaxb.pom.PomUtils;
|
||||
import org.owasp.dependencycheck.utils.InvalidSettingException;
|
||||
import org.owasp.dependencycheck.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;
|
||||
|
||||
/**
|
||||
@@ -45,10 +47,10 @@ import org.owasp.dependencycheck.utils.Settings;
|
||||
* There are two settings which govern this behavior:
|
||||
*
|
||||
* <ul>
|
||||
* <li>{@link org.owasp.dependencycheck.utils.Settings.KEYS#ANALYZER_NEXUS_ENABLED} determines whether this analyzer is
|
||||
* even 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
|
||||
* SHA-1. There is an expected <code>%s</code> in this where the SHA-1 will get entered.</li>
|
||||
* <li>{@link org.owasp.dependencycheck.utils.Settings.KEYS#ANALYZER_NEXUS_ENABLED} determines whether this analyzer is even
|
||||
* 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 SHA-1.
|
||||
* There is an expected <code>%s</code> in this where the SHA-1 will get entered.</li>
|
||||
* </ul>
|
||||
*
|
||||
* @author colezlaw
|
||||
@@ -63,7 +65,7 @@ public class NexusAnalyzer extends AbstractFileTypeAnalyzer {
|
||||
/**
|
||||
* 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.
|
||||
@@ -78,7 +80,7 @@ public class NexusAnalyzer extends AbstractFileTypeAnalyzer {
|
||||
/**
|
||||
* 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.
|
||||
@@ -89,10 +91,6 @@ public class NexusAnalyzer extends AbstractFileTypeAnalyzer {
|
||||
* Field indicating if the analyzer is enabled.
|
||||
*/
|
||||
private final boolean enabled = checkEnabled();
|
||||
/**
|
||||
* Field for doing POM work
|
||||
*/
|
||||
private final PomUtils pomUtil = new PomUtils();
|
||||
|
||||
/**
|
||||
* Determines if this analyzer is enabled
|
||||
@@ -106,15 +104,15 @@ public class NexusAnalyzer extends AbstractFileTypeAnalyzer {
|
||||
*/
|
||||
boolean retval = false;
|
||||
try {
|
||||
if ((!DEFAULT_URL.equals(Settings.getString(Settings.KEYS.ANALYZER_NEXUS_URL)))
|
||||
if (!DEFAULT_URL.equals(Settings.getString(Settings.KEYS.ANALYZER_NEXUS_URL))
|
||||
&& Settings.getBoolean(Settings.KEYS.ANALYZER_NEXUS_ENABLED)) {
|
||||
LOGGER.info("Enabling Nexus analyzer");
|
||||
retval = true;
|
||||
} else {
|
||||
LOGGER.fine("Nexus analyzer disabled, using Central instead");
|
||||
LOGGER.debug("Nexus analyzer disabled, using Central instead");
|
||||
}
|
||||
} catch (InvalidSettingException ise) {
|
||||
LOGGER.warning("Invalid setting. Disabling Nexus analyzer");
|
||||
LOGGER.warn("Invalid setting. Disabling Nexus analyzer");
|
||||
}
|
||||
|
||||
return retval;
|
||||
@@ -137,21 +135,21 @@ public class NexusAnalyzer extends AbstractFileTypeAnalyzer {
|
||||
*/
|
||||
@Override
|
||||
public void initializeFileTypeAnalyzer() throws Exception {
|
||||
LOGGER.fine("Initializing Nexus Analyzer");
|
||||
LOGGER.fine(String.format("Nexus Analyzer enabled: %s", isEnabled()));
|
||||
LOGGER.debug("Initializing Nexus Analyzer");
|
||||
LOGGER.debug("Nexus Analyzer enabled: {}", isEnabled());
|
||||
if (isEnabled()) {
|
||||
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 {
|
||||
searcher = new NexusSearch(new URL(searchUrl));
|
||||
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);
|
||||
}
|
||||
} catch (MalformedURLException mue) {
|
||||
// I know that initialize can throw an exception, but we'll
|
||||
// just disable the analyzer if the URL isn't valid
|
||||
LOGGER.warning(String.format("Property %s not a valid URL. Nexus Analyzer disabled", searchUrl));
|
||||
LOGGER.warn("Property {} not a valid URL. Nexus Analyzer disabled", searchUrl);
|
||||
setEnabled(false);
|
||||
}
|
||||
}
|
||||
@@ -188,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
|
||||
public Set<String> getSupportedExtensions() {
|
||||
return SUPPORTED_EXTENSIONS;
|
||||
protected FileFilter getFileFilter() {
|
||||
return FILTER;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -213,7 +216,7 @@ public class NexusAnalyzer extends AbstractFileTypeAnalyzer {
|
||||
final MavenArtifact ma = searcher.searchSha1(dependency.getSha1sum());
|
||||
dependency.addAsEvidence("nexus", ma, Confidence.HIGH);
|
||||
boolean pomAnalyzed = false;
|
||||
LOGGER.fine("POM URL " + ma.getPomUrl());
|
||||
LOGGER.debug("POM URL {}", ma.getPomUrl());
|
||||
for (Evidence e : dependency.getVendorEvidence()) {
|
||||
if ("pom".equals(e.getSource())) {
|
||||
pomAnalyzed = true;
|
||||
@@ -226,18 +229,16 @@ public class NexusAnalyzer extends AbstractFileTypeAnalyzer {
|
||||
final File baseDir = Settings.getTempDirectory();
|
||||
pomFile = File.createTempFile("pom", ".xml", baseDir);
|
||||
if (!pomFile.delete()) {
|
||||
final String msg = String.format("Unable to fetch pom.xml for %s from Nexus repository; "
|
||||
LOGGER.warn("Unable to fetch pom.xml for {} from Nexus repository; "
|
||||
+ "this could result in undetected CPE/CVEs.", dependency.getFileName());
|
||||
LOGGER.warning(msg);
|
||||
LOGGER.fine("Unable to delete temp file");
|
||||
LOGGER.debug("Unable to delete temp file");
|
||||
}
|
||||
LOGGER.fine(String.format("Downloading %s", ma.getPomUrl()));
|
||||
LOGGER.debug("Downloading {}", ma.getPomUrl());
|
||||
Downloader.fetchFile(new URL(ma.getPomUrl()), pomFile);
|
||||
pomUtil.analyzePOM(dependency, pomFile);
|
||||
PomUtils.analyzePOM(dependency, pomFile);
|
||||
} catch (DownloadFailedException ex) {
|
||||
final String msg = String.format("Unable to download pom.xml for %s from Nexus repository; "
|
||||
LOGGER.warn("Unable to download pom.xml for {} from Nexus repository; "
|
||||
+ "this could result in undetected CPE/CVEs.", dependency.getFileName());
|
||||
LOGGER.warning(msg);
|
||||
} finally {
|
||||
if (pomFile != null && !FileUtils.deleteQuietly(pomFile)) {
|
||||
pomFile.deleteOnExit();
|
||||
@@ -246,14 +247,14 @@ public class NexusAnalyzer extends AbstractFileTypeAnalyzer {
|
||||
}
|
||||
} catch (IllegalArgumentException iae) {
|
||||
//dependency.addAnalysisException(new AnalysisException("Invalid SHA-1"));
|
||||
LOGGER.info(String.format("invalid sha-1 hash on %s", dependency.getFileName()));
|
||||
LOGGER.info("invalid sha-1 hash on {}", dependency.getFileName());
|
||||
} catch (FileNotFoundException fnfe) {
|
||||
//dependency.addAnalysisException(new AnalysisException("Artifact not found on repository"));
|
||||
LOGGER.fine(String.format("Artifact not found in repository '%s'", dependency.getFileName()));
|
||||
LOGGER.log(Level.FINE, fnfe.getMessage(), fnfe);
|
||||
LOGGER.debug("Artifact not found in repository '{}'", dependency.getFileName());
|
||||
LOGGER.debug(fnfe.getMessage(), fnfe);
|
||||
} catch (IOException 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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,187 @@
|
||||
/*
|
||||
* 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.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.FileFilter;
|
||||
import java.io.IOException;
|
||||
import java.util.Map;
|
||||
import javax.json.Json;
|
||||
import javax.json.JsonException;
|
||||
import javax.json.JsonObject;
|
||||
import javax.json.JsonReader;
|
||||
import javax.json.JsonString;
|
||||
import javax.json.JsonValue;
|
||||
|
||||
/**
|
||||
* Used to analyze Node Package Manager (npm) package.json files, and collect information that can be used to determine the
|
||||
* associated CPE.
|
||||
*
|
||||
* @author Dale Visser
|
||||
*/
|
||||
public class NodePackageAnalyzer extends AbstractFileTypeAnalyzer {
|
||||
|
||||
/**
|
||||
* The logger.
|
||||
*/
|
||||
private static final Logger LOGGER = LoggerFactory.getLogger(NodePackageAnalyzer.class);
|
||||
|
||||
/**
|
||||
* The name of the analyzer.
|
||||
*/
|
||||
private static final String ANALYZER_NAME = "Node.js Package Analyzer";
|
||||
|
||||
/**
|
||||
* The phase that this analyzer is intended to run in.
|
||||
*/
|
||||
private static final AnalysisPhase ANALYSIS_PHASE = AnalysisPhase.INFORMATION_COLLECTION;
|
||||
|
||||
/**
|
||||
* The file name to scan.
|
||||
*/
|
||||
public static final String PACKAGE_JSON = "package.json";
|
||||
/**
|
||||
* Filter that detects files named "package.json".
|
||||
*/
|
||||
private static final FileFilter PACKAGE_JSON_FILTER = FileFilterBuilder.newInstance()
|
||||
.addFilenames(PACKAGE_JSON).build();
|
||||
|
||||
/**
|
||||
* Returns the FileFilter
|
||||
*
|
||||
* @return the FileFilter
|
||||
*/
|
||||
@Override
|
||||
protected FileFilter getFileFilter() {
|
||||
return PACKAGE_JSON_FILTER;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void initializeFileTypeAnalyzer() throws Exception {
|
||||
// NO-OP
|
||||
}
|
||||
|
||||
/**
|
||||
* 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_NODE_PACKAGE_ENABLED;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void analyzeFileType(Dependency dependency, Engine engine)
|
||||
throws AnalysisException {
|
||||
final File file = dependency.getActualFile();
|
||||
JsonReader jsonReader;
|
||||
try {
|
||||
jsonReader = Json.createReader(FileUtils.openInputStream(file));
|
||||
} catch (IOException e) {
|
||||
throw new AnalysisException(
|
||||
"Problem occurred while reading dependency file.", e);
|
||||
}
|
||||
try {
|
||||
final JsonObject json = jsonReader.readObject();
|
||||
final EvidenceCollection productEvidence = dependency.getProductEvidence();
|
||||
final EvidenceCollection vendorEvidence = dependency.getVendorEvidence();
|
||||
if (json.containsKey("name")) {
|
||||
final Object value = json.get("name");
|
||||
if (value instanceof JsonString) {
|
||||
final String valueString = ((JsonString) value).getString();
|
||||
productEvidence.addEvidence(PACKAGE_JSON, "name", valueString, Confidence.HIGHEST);
|
||||
vendorEvidence.addEvidence(PACKAGE_JSON, "name_project", String.format("%s_project", valueString), Confidence.LOW);
|
||||
} else {
|
||||
LOGGER.warn("JSON value not string as expected: {}", value);
|
||||
}
|
||||
}
|
||||
addToEvidence(json, productEvidence, "description");
|
||||
addToEvidence(json, vendorEvidence, "author");
|
||||
addToEvidence(json, dependency.getVersionEvidence(), "version");
|
||||
dependency.setDisplayFileName(String.format("%s/%s", file.getParentFile().getName(), file.getName()));
|
||||
} catch (JsonException e) {
|
||||
LOGGER.warn("Failed to parse package.json file.", e);
|
||||
} finally {
|
||||
jsonReader.close();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds information to an evidence collection from the node json configuration.
|
||||
*
|
||||
* @param json information from node.js
|
||||
* @param collection a set of evidence about a dependency
|
||||
* @param key the key to obtain the data from the json information
|
||||
*/
|
||||
private void addToEvidence(JsonObject json, EvidenceCollection collection, String key) {
|
||||
if (json.containsKey(key)) {
|
||||
final JsonValue value = json.get(key);
|
||||
if (value instanceof JsonString) {
|
||||
collection.addEvidence(PACKAGE_JSON, key, ((JsonString) value).getString(), Confidence.HIGHEST);
|
||||
} else if (value instanceof JsonObject) {
|
||||
final JsonObject jsonObject = (JsonObject) value;
|
||||
for (final Map.Entry<String, JsonValue> entry : jsonObject.entrySet()) {
|
||||
final String property = entry.getKey();
|
||||
final JsonValue subValue = entry.getValue();
|
||||
if (subValue instanceof JsonString) {
|
||||
collection.addEvidence(PACKAGE_JSON,
|
||||
String.format("%s.%s", key, property),
|
||||
((JsonString) subValue).getString(),
|
||||
Confidence.HIGHEST);
|
||||
} else {
|
||||
LOGGER.warn("JSON sub-value not string as expected: {}", subValue);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
LOGGER.warn("JSON value not string or JSON object as expected: {}", value);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -17,12 +17,6 @@
|
||||
*/
|
||||
package org.owasp.dependencycheck.analyzer;
|
||||
|
||||
import java.io.FileInputStream;
|
||||
import java.io.FileNotFoundException;
|
||||
import java.io.IOException;
|
||||
import java.util.Set;
|
||||
import java.util.logging.Level;
|
||||
import java.util.logging.Logger;
|
||||
import org.owasp.dependencycheck.Engine;
|
||||
import org.owasp.dependencycheck.analyzer.exception.AnalysisException;
|
||||
import org.owasp.dependencycheck.data.nuget.NugetPackage;
|
||||
@@ -31,7 +25,15 @@ import org.owasp.dependencycheck.data.nuget.NuspecParser;
|
||||
import org.owasp.dependencycheck.data.nuget.XPathNuspecParser;
|
||||
import org.owasp.dependencycheck.dependency.Confidence;
|
||||
import org.owasp.dependencycheck.dependency.Dependency;
|
||||
import org.owasp.dependencycheck.utils.FileFilterBuilder;
|
||||
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.
|
||||
@@ -43,7 +45,7 @@ public class NuspecAnalyzer extends AbstractFileTypeAnalyzer {
|
||||
/**
|
||||
* 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.
|
||||
@@ -58,7 +60,7 @@ public class NuspecAnalyzer extends AbstractFileTypeAnalyzer {
|
||||
/**
|
||||
* 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.
|
||||
@@ -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
|
||||
public Set<String> getSupportedExtensions() {
|
||||
return SUPPORTED_EXTENSIONS;
|
||||
protected FileFilter getFileFilter() {
|
||||
return FILTER;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -118,7 +126,7 @@ public class NuspecAnalyzer extends AbstractFileTypeAnalyzer {
|
||||
*/
|
||||
@Override
|
||||
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);
|
||||
try {
|
||||
final NuspecParser parser = new XPathNuspecParser();
|
||||
NugetPackage np = null;
|
||||
@@ -135,7 +143,7 @@ public class NuspecAnalyzer extends AbstractFileTypeAnalyzer {
|
||||
try {
|
||||
fis.close();
|
||||
} 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
|
||||
* 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 {
|
||||
|
||||
@@ -73,7 +73,7 @@ public class NvdCveAnalyzer implements Analyzer {
|
||||
* @return true or false.
|
||||
*/
|
||||
public boolean isOpen() {
|
||||
return (cveDB != null);
|
||||
return cveDB != null;
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -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
|
||||
*/
|
||||
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,374 @@
|
||||
/*
|
||||
* 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.lang3.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
|
||||
*/
|
||||
public class PythonDistributionAnalyzer extends AbstractFileTypeAnalyzer {
|
||||
|
||||
/**
|
||||
* Name of egg metadata 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
|
||||
*/
|
||||
private static void collectWheelMetadata(Dependency dependency, File file) {
|
||||
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 destination 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,316 @@
|
||||
/*
|
||||
* 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 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 a Python package, and collect information that can be used to determine the associated CPE.
|
||||
*
|
||||
* @author Dale Visser
|
||||
*/
|
||||
public class PythonPackageAnalyzer extends AbstractFileTypeAnalyzer {
|
||||
|
||||
/**
|
||||
* Used when compiling file scanning regex patterns.
|
||||
*/
|
||||
private static final int REGEX_OPTIONS = Pattern.DOTALL
|
||||
| Pattern.CASE_INSENSITIVE;
|
||||
|
||||
/**
|
||||
* 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)) {
|
||||
final File[] fileList = parent.listFiles(PY_FILTER);
|
||||
if (fileList != null) {
|
||||
for (final File sourceFile : fileList) {
|
||||
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> dependencies = new ArrayList<Dependency>(
|
||||
engine.getDependencies());
|
||||
dependencies.remove(dependency);
|
||||
engine.setDependencies(dependencies);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 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);
|
||||
found |= gatherHomePageEvidence(URI_PATTERN, vendorEvidence,
|
||||
source, "URL", contents);
|
||||
found |= gatherHomePageEvidence(HOMEPAGE_PATTERN,
|
||||
vendorEvidence, source, "HomePage", contents);
|
||||
}
|
||||
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
|
||||
*/
|
||||
private boolean gatherHomePageEvidence(Pattern pattern,
|
||||
EvidenceCollection evidence, String source, String name,
|
||||
String contents) {
|
||||
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 using 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;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,326 @@
|
||||
/*
|
||||
* 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.Reference;
|
||||
import org.owasp.dependencycheck.dependency.Vulnerability;
|
||||
import org.owasp.dependencycheck.utils.FileFilterBuilder;
|
||||
import org.owasp.dependencycheck.utils.Settings;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import java.io.*;
|
||||
import java.util.*;
|
||||
|
||||
/**
|
||||
* Used to analyze Ruby Bundler Gemspec.lock files utilizing the 3rd party bundle-audit tool.
|
||||
*
|
||||
* @author Dale Visser
|
||||
*/
|
||||
public class RubyBundleAuditAnalyzer extends AbstractFileTypeAnalyzer {
|
||||
|
||||
private static final Logger LOGGER = LoggerFactory.getLogger(RubyBundleAuditAnalyzer.class);
|
||||
|
||||
/**
|
||||
* The name of the analyzer.
|
||||
*/
|
||||
private static final String ANALYZER_NAME = "Ruby Bundle Audit Analyzer";
|
||||
|
||||
/**
|
||||
* The phase that this analyzer is intended to run in.
|
||||
*/
|
||||
private static final AnalysisPhase ANALYSIS_PHASE = AnalysisPhase.PRE_INFORMATION_COLLECTION;
|
||||
|
||||
private static final FileFilter FILTER
|
||||
= FileFilterBuilder.newInstance().addFilenames("Gemfile.lock").build();
|
||||
public static final String NAME = "Name: ";
|
||||
public static final String VERSION = "Version: ";
|
||||
public static final String ADVISORY = "Advisory: ";
|
||||
public static final String CRITICALITY = "Criticality: ";
|
||||
|
||||
/**
|
||||
* @return a filter that accepts files named Gemfile.lock
|
||||
*/
|
||||
@Override
|
||||
protected FileFilter getFileFilter() {
|
||||
return FILTER;
|
||||
}
|
||||
|
||||
/**
|
||||
* Launch bundle-audit.
|
||||
*
|
||||
* @return a handle to the process
|
||||
*/
|
||||
private Process launchBundleAudit(File folder) throws AnalysisException {
|
||||
if (!folder.isDirectory()) {
|
||||
throw new AnalysisException(String.format("%s should have been a directory.", folder.getAbsolutePath()));
|
||||
}
|
||||
final List<String> args = new ArrayList<String>();
|
||||
final String bundleAuditPath = Settings.getString(Settings.KEYS.ANALYZER_BUNDLE_AUDIT_PATH);
|
||||
args.add(null == bundleAuditPath ? "bundle-audit" : bundleAuditPath);
|
||||
args.add("check");
|
||||
args.add("--verbose");
|
||||
final ProcessBuilder builder = new ProcessBuilder(args);
|
||||
builder.directory(folder);
|
||||
try {
|
||||
return builder.start();
|
||||
} catch (IOException ioe) {
|
||||
throw new AnalysisException("bundle-audit failure", ioe);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Initialize the analyzer. In this case, extract GrokAssembly.exe to a temporary location.
|
||||
*
|
||||
* @throws Exception if anything goes wrong
|
||||
*/
|
||||
@Override
|
||||
public void initializeFileTypeAnalyzer() throws Exception {
|
||||
// Now, need to see if bundle-audit actually runs from this location.
|
||||
Process process = launchBundleAudit(Settings.getTempDirectory());
|
||||
int exitValue = process.waitFor();
|
||||
if (0 == exitValue) {
|
||||
LOGGER.warn("Unexpected exit code from bundle-audit process. Disabling {}: {}", ANALYZER_NAME, exitValue);
|
||||
setEnabled(false);
|
||||
throw new AnalysisException("Unexpected exit code from bundle-audit process.");
|
||||
} else {
|
||||
BufferedReader reader = null;
|
||||
try {
|
||||
reader = new BufferedReader(new InputStreamReader(process.getErrorStream(), "UTF-8"));
|
||||
if (!reader.ready()) {
|
||||
LOGGER.warn("Bundle-audit error stream unexpectedly not ready. Disabling " + ANALYZER_NAME);
|
||||
setEnabled(false);
|
||||
throw new AnalysisException("Bundle-audit error stream unexpectedly not ready.");
|
||||
} else {
|
||||
final String line = reader.readLine();
|
||||
if (line == null || !line.contains("Errno::ENOENT")) {
|
||||
LOGGER.warn("Unexpected bundle-audit output. Disabling {}: {}", ANALYZER_NAME, line);
|
||||
setEnabled(false);
|
||||
throw new AnalysisException("Unexpected bundle-audit output.");
|
||||
}
|
||||
}
|
||||
} finally {
|
||||
if (null != reader) {
|
||||
reader.close();
|
||||
}
|
||||
}
|
||||
}
|
||||
if (isEnabled()) {
|
||||
LOGGER.info(ANALYZER_NAME + " is enabled. It is necessary to manually run \"bundle-audit update\" "
|
||||
+ "occasionally to keep its database up to date.");
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 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_BUNDLE_AUDIT_ENABLED;
|
||||
}
|
||||
|
||||
/**
|
||||
* If {@link #analyzeFileType(Dependency, Engine)} is called, then we have successfully initialized, and it will be necessary
|
||||
* to disable {@link RubyGemspecAnalyzer}.
|
||||
*/
|
||||
private boolean needToDisableGemspecAnalyzer = true;
|
||||
|
||||
@Override
|
||||
protected void analyzeFileType(Dependency dependency, Engine engine)
|
||||
throws AnalysisException {
|
||||
if (needToDisableGemspecAnalyzer) {
|
||||
boolean failed = true;
|
||||
final String className = RubyGemspecAnalyzer.class.getName();
|
||||
for (FileTypeAnalyzer analyzer : engine.getFileTypeAnalyzers()) {
|
||||
if (analyzer instanceof RubyGemspecAnalyzer) {
|
||||
((RubyGemspecAnalyzer) analyzer).setEnabled(false);
|
||||
LOGGER.info("Disabled " + className + " to avoid noisy duplicate results.");
|
||||
failed = false;
|
||||
}
|
||||
}
|
||||
if (failed) {
|
||||
LOGGER.warn("Did not find" + className + '.');
|
||||
}
|
||||
needToDisableGemspecAnalyzer = false;
|
||||
}
|
||||
final File parentFile = dependency.getActualFile().getParentFile();
|
||||
final Process process = launchBundleAudit(parentFile);
|
||||
try {
|
||||
process.waitFor();
|
||||
} catch (InterruptedException ie) {
|
||||
throw new AnalysisException("bundle-audit process interrupted", ie);
|
||||
}
|
||||
BufferedReader rdr = null;
|
||||
try {
|
||||
rdr = new BufferedReader(new InputStreamReader(process.getInputStream(), "UTF-8"));
|
||||
processBundlerAuditOutput(dependency, engine, rdr);
|
||||
} catch (IOException ioe) {
|
||||
LOGGER.warn("bundle-audit failure", ioe);
|
||||
} finally {
|
||||
if (null != rdr) {
|
||||
try {
|
||||
rdr.close();
|
||||
} catch (IOException ioe) {
|
||||
LOGGER.warn("bundle-audit close failure", ioe);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
private void processBundlerAuditOutput(Dependency original, Engine engine, BufferedReader rdr) throws IOException {
|
||||
final String parentName = original.getActualFile().getParentFile().getName();
|
||||
final String fileName = original.getFileName();
|
||||
Dependency dependency = null;
|
||||
Vulnerability vulnerability = null;
|
||||
String gem = null;
|
||||
final Map<String, Dependency> map = new HashMap<String, Dependency>();
|
||||
boolean appendToDescription = false;
|
||||
while (rdr.ready()) {
|
||||
final String nextLine = rdr.readLine();
|
||||
if (null == nextLine) {
|
||||
break;
|
||||
} else if (nextLine.startsWith(NAME)) {
|
||||
appendToDescription = false;
|
||||
gem = nextLine.substring(NAME.length());
|
||||
if (!map.containsKey(gem)) {
|
||||
map.put(gem, createDependencyForGem(engine, parentName, fileName, gem));
|
||||
}
|
||||
dependency = map.get(gem);
|
||||
LOGGER.debug(String.format("bundle-audit (%s): %s", parentName, nextLine));
|
||||
} else if (nextLine.startsWith(VERSION)) {
|
||||
vulnerability = createVulnerability(parentName, dependency, vulnerability, gem, nextLine);
|
||||
} else if (nextLine.startsWith(ADVISORY)) {
|
||||
setVulnerabilityName(parentName, dependency, vulnerability, nextLine);
|
||||
} else if (nextLine.startsWith(CRITICALITY)) {
|
||||
addCriticalityToVulnerability(parentName, vulnerability, nextLine);
|
||||
} else if (nextLine.startsWith("URL: ")) {
|
||||
addReferenceToVulnerability(parentName, vulnerability, nextLine);
|
||||
} else if (nextLine.startsWith("Description:")) {
|
||||
appendToDescription = true;
|
||||
if (null != vulnerability) {
|
||||
vulnerability.setDescription("*** Vulnerability obtained from bundle-audit verbose report. Title link may not work. CPE below is guessed. CVSS score is estimated (-1.0 indicates unknown). See link below for full details. *** ");
|
||||
}
|
||||
} else if (appendToDescription) {
|
||||
if (null != vulnerability) {
|
||||
vulnerability.setDescription(vulnerability.getDescription() + nextLine + "\n");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void setVulnerabilityName(String parentName, Dependency dependency, Vulnerability vulnerability, String nextLine) {
|
||||
final String advisory = nextLine.substring((ADVISORY.length()));
|
||||
if (null != vulnerability) {
|
||||
vulnerability.setName(advisory);
|
||||
}
|
||||
if (null != dependency) {
|
||||
dependency.getVulnerabilities().add(vulnerability); // needed to wait for vulnerability name to avoid NPE
|
||||
}
|
||||
LOGGER.debug(String.format("bundle-audit (%s): %s", parentName, nextLine));
|
||||
}
|
||||
|
||||
private void addReferenceToVulnerability(String parentName, Vulnerability vulnerability, String nextLine) {
|
||||
final String url = nextLine.substring(("URL: ").length());
|
||||
if (null != vulnerability) {
|
||||
Reference ref = new Reference();
|
||||
ref.setName(vulnerability.getName());
|
||||
ref.setSource("bundle-audit");
|
||||
ref.setUrl(url);
|
||||
vulnerability.getReferences().add(ref);
|
||||
}
|
||||
LOGGER.debug(String.format("bundle-audit (%s): %s", parentName, nextLine));
|
||||
}
|
||||
|
||||
private void addCriticalityToVulnerability(String parentName, Vulnerability vulnerability, String nextLine) {
|
||||
if (null != vulnerability) {
|
||||
final String criticality = nextLine.substring(CRITICALITY.length()).trim();
|
||||
if ("High".equals(criticality)) {
|
||||
vulnerability.setCvssScore(8.5f);
|
||||
} else if ("Medium".equals(criticality)) {
|
||||
vulnerability.setCvssScore(5.5f);
|
||||
} else if ("Low".equals(criticality)) {
|
||||
vulnerability.setCvssScore(2.0f);
|
||||
} else {
|
||||
vulnerability.setCvssScore(-1.0f);
|
||||
}
|
||||
}
|
||||
LOGGER.debug(String.format("bundle-audit (%s): %s", parentName, nextLine));
|
||||
}
|
||||
|
||||
private Vulnerability createVulnerability(String parentName, Dependency dependency, Vulnerability vulnerability, String gem, String nextLine) {
|
||||
if (null != dependency) {
|
||||
final String version = nextLine.substring(VERSION.length());
|
||||
dependency.getVersionEvidence().addEvidence(
|
||||
"bundler-audit",
|
||||
"Version",
|
||||
version,
|
||||
Confidence.HIGHEST);
|
||||
vulnerability = new Vulnerability(); // don't add to dependency until we have name set later
|
||||
vulnerability.setMatchedCPE(
|
||||
String.format("cpe:/a:%1$s_project:%1$s:%2$s::~~~ruby~~", gem, version),
|
||||
null);
|
||||
vulnerability.setCvssAccessVector("-");
|
||||
vulnerability.setCvssAccessComplexity("-");
|
||||
vulnerability.setCvssAuthentication("-");
|
||||
vulnerability.setCvssAvailabilityImpact("-");
|
||||
vulnerability.setCvssConfidentialityImpact("-");
|
||||
vulnerability.setCvssIntegrityImpact("-");
|
||||
}
|
||||
LOGGER.debug(String.format("bundle-audit (%s): %s", parentName, nextLine));
|
||||
return vulnerability;
|
||||
}
|
||||
|
||||
private Dependency createDependencyForGem(Engine engine, String parentName, String fileName, String gem) throws IOException {
|
||||
final File tempFile = File.createTempFile("Gemfile-" + gem, ".lock", Settings.getTempDirectory());
|
||||
final String displayFileName = String.format("%s%c%s:%s", parentName, File.separatorChar, fileName, gem);
|
||||
FileUtils.write(tempFile, displayFileName); // unique contents to avoid dependency bundling
|
||||
final Dependency dependency = new Dependency(tempFile);
|
||||
dependency.getProductEvidence().addEvidence("bundler-audit", "Name", gem, Confidence.HIGHEST);
|
||||
dependency.setDisplayFileName(displayFileName);
|
||||
engine.getDependencies().add(dependency);
|
||||
return dependency;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,161 @@
|
||||
/*
|
||||
* This file is part of dependency-check-core.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*
|
||||
* Copyright (c) 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 java.io.FileFilter;
|
||||
import java.io.IOException;
|
||||
import java.util.regex.Matcher;
|
||||
import java.util.regex.Pattern;
|
||||
|
||||
/**
|
||||
* Used to analyze Ruby Gem specifications and collect information that can be used to determine the associated CPE. Regular
|
||||
* expressions are used to parse the well-defined Ruby syntax that forms the specification.
|
||||
*
|
||||
* @author Dale Visser
|
||||
*/
|
||||
public class RubyGemspecAnalyzer extends AbstractFileTypeAnalyzer {
|
||||
|
||||
/**
|
||||
* The name of the analyzer.
|
||||
*/
|
||||
private static final String ANALYZER_NAME = "Ruby Gemspec Analyzer";
|
||||
|
||||
/**
|
||||
* The phase that this analyzer is intended to run in.
|
||||
*/
|
||||
private static final AnalysisPhase ANALYSIS_PHASE = AnalysisPhase.INFORMATION_COLLECTION;
|
||||
|
||||
private static final String GEMSPEC = "gemspec";
|
||||
|
||||
private static final FileFilter FILTER
|
||||
= FileFilterBuilder.newInstance().addExtensions(GEMSPEC).addFilenames("Rakefile").build();
|
||||
|
||||
private static final String EMAIL = "email";
|
||||
|
||||
/**
|
||||
* @return a filter that accepts files named Rakefile or matching the glob pattern, *.gemspec
|
||||
*/
|
||||
@Override
|
||||
protected FileFilter getFileFilter() {
|
||||
return FILTER;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void initializeFileTypeAnalyzer() throws Exception {
|
||||
// NO-OP
|
||||
}
|
||||
|
||||
/**
|
||||
* 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_RUBY_GEMSPEC_ENABLED;
|
||||
}
|
||||
|
||||
/**
|
||||
* The capture group #1 is the block variable.
|
||||
*/
|
||||
private static final Pattern GEMSPEC_BLOCK_INIT
|
||||
= Pattern.compile("Gem::Specification\\.new\\s+?do\\s+?\\|(.+?)\\|");
|
||||
|
||||
@Override
|
||||
protected void analyzeFileType(Dependency dependency, Engine engine)
|
||||
throws AnalysisException {
|
||||
String contents;
|
||||
try {
|
||||
contents = FileUtils.readFileToString(dependency.getActualFile());
|
||||
} catch (IOException e) {
|
||||
throw new AnalysisException(
|
||||
"Problem occurred while reading dependency file.", e);
|
||||
}
|
||||
final Matcher matcher = GEMSPEC_BLOCK_INIT.matcher(contents);
|
||||
if (matcher.find()) {
|
||||
contents = contents.substring(matcher.end());
|
||||
final String blockVariable = matcher.group(1);
|
||||
final EvidenceCollection vendor = dependency.getVendorEvidence();
|
||||
addStringEvidence(vendor, contents, blockVariable, "author", Confidence.HIGHEST);
|
||||
addListEvidence(vendor, contents, blockVariable, "authors", Confidence.HIGHEST);
|
||||
final String email = addStringEvidence(vendor, contents, blockVariable, EMAIL, Confidence.MEDIUM);
|
||||
if (email.isEmpty()) {
|
||||
addListEvidence(vendor, contents, blockVariable, EMAIL, Confidence.MEDIUM);
|
||||
}
|
||||
addStringEvidence(vendor, contents, blockVariable, "homepage", Confidence.MEDIUM);
|
||||
final EvidenceCollection product = dependency.getProductEvidence();
|
||||
final String name = addStringEvidence(product, contents, blockVariable, "name", Confidence.HIGHEST);
|
||||
if (!name.isEmpty()) {
|
||||
vendor.addEvidence(GEMSPEC, "name_project", name + "_project", Confidence.LOW);
|
||||
}
|
||||
addStringEvidence(product, contents, blockVariable, "summary", Confidence.LOW);
|
||||
addStringEvidence(dependency.getVersionEvidence(), contents, blockVariable, "version", Confidence.HIGHEST);
|
||||
}
|
||||
}
|
||||
|
||||
private void addListEvidence(EvidenceCollection evidences, String contents,
|
||||
String blockVariable, String field, Confidence confidence) {
|
||||
final Matcher matcher = Pattern.compile(
|
||||
String.format("\\s+?%s\\.%s\\s*?=\\s*?\\[(.*?)\\]", blockVariable, field)).matcher(contents);
|
||||
if (matcher.find()) {
|
||||
final String value = matcher.group(1).replaceAll("['\"]", " ").trim();
|
||||
evidences.addEvidence(GEMSPEC, field, value, confidence);
|
||||
}
|
||||
}
|
||||
|
||||
private String addStringEvidence(EvidenceCollection evidences, String contents,
|
||||
String blockVariable, String field, Confidence confidence) {
|
||||
final Matcher matcher = Pattern.compile(
|
||||
String.format("\\s+?%s\\.%s\\s*?=\\s*?(['\"])(.*?)\\1", blockVariable, field)).matcher(contents);
|
||||
String value = "";
|
||||
if (matcher.find()) {
|
||||
value = matcher.group(2);
|
||||
evidences.addEvidence(GEMSPEC, field, value, confidence);
|
||||
}
|
||||
return value;
|
||||
}
|
||||
}
|
||||
@@ -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.
|
||||
* 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 {
|
||||
|
||||
|
||||
@@ -20,7 +20,7 @@ package org.owasp.dependencycheck.analyzer.exception;
|
||||
/**
|
||||
* 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 {
|
||||
|
||||
|
||||
@@ -20,7 +20,7 @@ package org.owasp.dependencycheck.analyzer.exception;
|
||||
/**
|
||||
* 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 {
|
||||
|
||||
|
||||
@@ -1,12 +1,4 @@
|
||||
/**
|
||||
* <html>
|
||||
* <head>
|
||||
* <title>org.owasp.dependencycheck.analyzer.exception</title>
|
||||
* </head>
|
||||
* <body>
|
||||
* <p>
|
||||
* A collection of exception classes used within the analyzers.</p>
|
||||
* </body>
|
||||
* </html>
|
||||
* A collection of exception classes used within the analyzers.
|
||||
*/
|
||||
package org.owasp.dependencycheck.analyzer.exception;
|
||||
|
||||
@@ -1,13 +1,4 @@
|
||||
/**
|
||||
* <html>
|
||||
* <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>
|
||||
*/
|
||||
|
||||
* Analyzers are used to inspect the identified dependencies, collect Evidence, and process the dependencies.
|
||||
*/
|
||||
package org.owasp.dependencycheck.analyzer;
|
||||
|
||||
@@ -23,7 +23,6 @@ import java.net.HttpURLConnection;
|
||||
import java.net.URL;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.logging.Logger;
|
||||
import javax.xml.parsers.DocumentBuilder;
|
||||
import javax.xml.parsers.DocumentBuilderFactory;
|
||||
import javax.xml.xpath.XPath;
|
||||
@@ -32,6 +31,8 @@ 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;
|
||||
|
||||
@@ -55,7 +56,7 @@ public class CentralSearch {
|
||||
/**
|
||||
* Used for logging.
|
||||
*/
|
||||
private static final Logger LOGGER = Logger.getLogger(CentralSearch.class.getName());
|
||||
private static final Logger LOGGER = LoggerFactory.getLogger(CentralSearch.class);
|
||||
|
||||
/**
|
||||
* Creates a NexusSearch for the given repository URL.
|
||||
@@ -67,10 +68,10 @@ public class CentralSearch {
|
||||
this.rootURL = rootURL;
|
||||
if (null != Settings.getString(Settings.KEYS.PROXY_SERVER)) {
|
||||
useProxy = true;
|
||||
LOGGER.fine("Using proxy");
|
||||
LOGGER.debug("Using proxy");
|
||||
} else {
|
||||
useProxy = false;
|
||||
LOGGER.fine("Not using proxy");
|
||||
LOGGER.debug("Not using proxy");
|
||||
}
|
||||
}
|
||||
|
||||
@@ -89,7 +90,7 @@ public class CentralSearch {
|
||||
|
||||
final URL url = new URL(rootURL + String.format("?q=1:\"%s\"&wt=xml", sha1));
|
||||
|
||||
LOGGER.fine(String.format("Searching Central url %s", url.toString()));
|
||||
LOGGER.debug("Searching Central url {}", url);
|
||||
|
||||
// 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
|
||||
@@ -115,15 +116,15 @@ public class CentralSearch {
|
||||
if ("0".equals(numFound)) {
|
||||
missing = true;
|
||||
} else {
|
||||
final ArrayList<MavenArtifact> result = new ArrayList<MavenArtifact>();
|
||||
final List<MavenArtifact> result = new ArrayList<MavenArtifact>();
|
||||
final NodeList docs = (NodeList) xpath.evaluate("/response/result/doc", doc, XPathConstants.NODESET);
|
||||
for (int i = 0; i < docs.getLength(); i++) {
|
||||
final String g = xpath.evaluate("./str[@name='g']", docs.item(i));
|
||||
LOGGER.finest(String.format("GroupId: %s", g));
|
||||
LOGGER.trace("GroupId: {}", g);
|
||||
final String a = xpath.evaluate("./str[@name='a']", docs.item(i));
|
||||
LOGGER.finest(String.format("ArtifactId: %s", a));
|
||||
LOGGER.trace("ArtifactId: {}", a);
|
||||
final String v = xpath.evaluate("./str[@name='v']", docs.item(i));
|
||||
final NodeList atts = (NodeList) xpath.evaluate("./arr[@name='ec']/str", docs.item(i), XPathConstants.NODESET);
|
||||
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++) {
|
||||
@@ -134,8 +135,18 @@ public class CentralSearch {
|
||||
jarAvailable = true;
|
||||
}
|
||||
}
|
||||
LOGGER.finest(String.format("Version: %s", v));
|
||||
result.add(new MavenArtifact(g, a, v, jarAvailable, pomAvailable));
|
||||
|
||||
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;
|
||||
@@ -150,10 +161,9 @@ public class CentralSearch {
|
||||
throw new FileNotFoundException("Artifact not found in Central");
|
||||
}
|
||||
} else {
|
||||
final String msg = String.format("Could not connect to Central received response code: %d %s",
|
||||
conn.getResponseCode(), conn.getResponseMessage());
|
||||
LOGGER.fine(msg);
|
||||
throw new IOException(msg);
|
||||
LOGGER.debug("Could not connect to Central received response code: {} {}",
|
||||
conn.getResponseCode(), conn.getResponseMessage());
|
||||
throw new IOException("Could not connect to Central");
|
||||
}
|
||||
|
||||
return null;
|
||||
|
||||
@@ -1,14 +1,7 @@
|
||||
/**
|
||||
* <html>
|
||||
* <head>
|
||||
* <title>org.owasp.dependencycheck.data.central</title>
|
||||
* </head>
|
||||
* <body>
|
||||
* <p>
|
||||
* Contains classes related to searching Maven Central.</p>
|
||||
* <p>
|
||||
* These are used to abstract Maven Central searching away from OWASP Dependency Check so they can be reused elsewhere.</p>
|
||||
* </body>
|
||||
* </html>
|
||||
*
|
||||
* 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;
|
||||
|
||||
@@ -0,0 +1,110 @@
|
||||
/*
|
||||
* 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 The OWASP Foundation. All Rights Reserved.
|
||||
*/
|
||||
package org.owasp.dependencycheck.data.composer;
|
||||
|
||||
/**
|
||||
* Reperesents a dependency (GAV, right now) from a Composer dependency.
|
||||
*
|
||||
* @author colezlaw
|
||||
*/
|
||||
public final class ComposerDependency {
|
||||
|
||||
/**
|
||||
* The group
|
||||
*/
|
||||
private final String group;
|
||||
|
||||
/**
|
||||
* The project
|
||||
*/
|
||||
private final String project;
|
||||
|
||||
/**
|
||||
* The version
|
||||
*/
|
||||
private final String version;
|
||||
|
||||
/**
|
||||
* Create a ComposerDependency from group, project, and version.
|
||||
*
|
||||
* @param group the group
|
||||
* @param project the project
|
||||
* @param version the version
|
||||
*/
|
||||
public ComposerDependency(String group, String project, String version) {
|
||||
this.group = group;
|
||||
this.project = project;
|
||||
this.version = version;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the group.
|
||||
*
|
||||
* @return the group
|
||||
*/
|
||||
public String getGroup() {
|
||||
return group;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the project.
|
||||
*
|
||||
* @return the project
|
||||
*/
|
||||
public String getProject() {
|
||||
return project;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the version.
|
||||
*
|
||||
* @return the version
|
||||
*/
|
||||
public String getVersion() {
|
||||
return version;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object o) {
|
||||
if (this == o) {
|
||||
return true;
|
||||
}
|
||||
if (!(o instanceof ComposerDependency)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
final ComposerDependency that = (ComposerDependency) o;
|
||||
|
||||
if (group != null ? !group.equals(that.group) : that.group != null) {
|
||||
return false;
|
||||
}
|
||||
if (project != null ? !project.equals(that.project) : that.project != null) {
|
||||
return false;
|
||||
}
|
||||
return !(version != null ? !version.equals(that.version) : that.version != null);
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
int result = group != null ? group.hashCode() : 0;
|
||||
result = 31 * result + (project != null ? project.hashCode() : 0);
|
||||
result = 31 * result + (version != null ? version.hashCode() : 0);
|
||||
return result;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,57 @@
|
||||
/*
|
||||
* 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 The OWASP Foundation. All Rights Reserved.
|
||||
*/
|
||||
package org.owasp.dependencycheck.data.composer;
|
||||
|
||||
/**
|
||||
* Represents an exception when handling a composer.json or composer.lock file. Generally used to wrap a downstream exception.
|
||||
*
|
||||
* @author colezlaw
|
||||
*/
|
||||
public class ComposerException extends RuntimeException {
|
||||
|
||||
/**
|
||||
* The serial version UID for serialization.
|
||||
*/
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
/**
|
||||
* Creates a ComposerException with default message.
|
||||
*/
|
||||
public ComposerException() {
|
||||
super();
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a ComposerException with the specified message.
|
||||
*
|
||||
* @param message the exception message
|
||||
*/
|
||||
public ComposerException(String message) {
|
||||
super(message);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a Composer exception with the specified message and cause.
|
||||
*
|
||||
* @param message the message
|
||||
* @param cause the underlying cause
|
||||
*/
|
||||
public ComposerException(String message, Throwable cause) {
|
||||
super(message, cause);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,124 @@
|
||||
/*
|
||||
* 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 The OWASP Foundation. All Rights Reserved.
|
||||
*/
|
||||
package org.owasp.dependencycheck.data.composer;
|
||||
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import javax.json.Json;
|
||||
import javax.json.JsonArray;
|
||||
import javax.json.JsonException;
|
||||
import javax.json.JsonObject;
|
||||
import javax.json.JsonReader;
|
||||
import javax.json.stream.JsonParsingException;
|
||||
import java.io.InputStream;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* Parses a Composer.lock file from an input stream. In a separate class so it can hopefully be injected.
|
||||
*
|
||||
* @author colezlaw
|
||||
*/
|
||||
public class ComposerLockParser {
|
||||
|
||||
/**
|
||||
* The JsonReader for parsing JSON
|
||||
*/
|
||||
private final JsonReader jsonReader;
|
||||
|
||||
/**
|
||||
* The input stream we'll read
|
||||
*/
|
||||
private final InputStream inputStream; // NOPMD - it gets set in the constructor, read later
|
||||
|
||||
/**
|
||||
* The List of ComposerDependencies found
|
||||
*/
|
||||
private final List<ComposerDependency> composerDependencies;
|
||||
|
||||
/**
|
||||
* The LOGGER
|
||||
*/
|
||||
private static final Logger LOGGER = LoggerFactory.getLogger(ComposerLockParser.class);
|
||||
|
||||
/**
|
||||
* Createas a ComposerLockParser from a JsonReader and an InputStream.
|
||||
*
|
||||
* @param inputStream the InputStream to parse
|
||||
*/
|
||||
public ComposerLockParser(InputStream inputStream) {
|
||||
LOGGER.info("Creating a ComposerLockParser");
|
||||
this.inputStream = inputStream;
|
||||
this.jsonReader = Json.createReader(inputStream);
|
||||
this.composerDependencies = new ArrayList<ComposerDependency>();
|
||||
}
|
||||
|
||||
/**
|
||||
* Process the input stream to create the list of dependencies.
|
||||
*/
|
||||
public void process() {
|
||||
LOGGER.info("Beginning Composer lock processing");
|
||||
try {
|
||||
final JsonObject composer = jsonReader.readObject();
|
||||
if (composer.containsKey("packages")) {
|
||||
LOGGER.debug("Found packages");
|
||||
final JsonArray packages = composer.getJsonArray("packages");
|
||||
for (JsonObject pkg : packages.getValuesAs(JsonObject.class)) {
|
||||
if (pkg.containsKey("name")) {
|
||||
final String groupName = pkg.getString("name");
|
||||
if (groupName.indexOf('/') >= 0 && groupName.indexOf('/') <= groupName.length() - 1) {
|
||||
if (pkg.containsKey("version")) {
|
||||
final String group = groupName.substring(0, groupName.indexOf('/'));
|
||||
final String project = groupName.substring(groupName.indexOf('/') + 1);
|
||||
String version = pkg.getString("version");
|
||||
// Some version nubmers begin with v - which doesn't end up matching CPE's
|
||||
if (version.startsWith("v")) {
|
||||
version = version.substring(1);
|
||||
}
|
||||
LOGGER.debug("Got package {}/{}/{}", group, project, version);
|
||||
composerDependencies.add(new ComposerDependency(group, project, version));
|
||||
} else {
|
||||
LOGGER.debug("Group/package {} does not have a version", groupName);
|
||||
}
|
||||
} else {
|
||||
LOGGER.debug("Got a dependency with no name");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
} catch (JsonParsingException jsonpe) {
|
||||
throw new ComposerException("Error parsing stream", jsonpe);
|
||||
} catch (JsonException jsone) {
|
||||
throw new ComposerException("Error reading stream", jsone);
|
||||
} catch (IllegalStateException ise) {
|
||||
throw new ComposerException("Illegal state in composer stream", ise);
|
||||
} catch (ClassCastException cce) {
|
||||
throw new ComposerException("Not exactly composer lock", cce);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the list of dependencies.
|
||||
*
|
||||
* @return the list of dependencies
|
||||
*/
|
||||
public List<ComposerDependency> getDependencies() {
|
||||
return composerDependencies;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,4 @@
|
||||
/**
|
||||
* Model elements for PHP Composer files
|
||||
*/
|
||||
package org.owasp.dependencycheck.data.composer;
|
||||
@@ -21,8 +21,6 @@ import java.io.IOException;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
import java.util.logging.Level;
|
||||
import java.util.logging.Logger;
|
||||
import org.apache.lucene.analysis.Analyzer;
|
||||
import org.apache.lucene.analysis.core.KeywordAnalyzer;
|
||||
import org.apache.lucene.analysis.miscellaneous.PerFieldAnalyzerWrapper;
|
||||
@@ -46,19 +44,21 @@ import org.owasp.dependencycheck.data.lucene.SearchFieldAnalyzer;
|
||||
import org.owasp.dependencycheck.data.nvdcve.CveDB;
|
||||
import org.owasp.dependencycheck.data.nvdcve.DatabaseException;
|
||||
import org.owasp.dependencycheck.utils.Pair;
|
||||
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 the NVD
|
||||
* CVE data.
|
||||
*
|
||||
* @author Jeremy Long <jeremy.long@owasp.org>
|
||||
* @author Jeremy Long
|
||||
*/
|
||||
public final class CpeMemoryIndex {
|
||||
|
||||
/**
|
||||
* The logger.
|
||||
*/
|
||||
private static final Logger LOGGER = Logger.getLogger(CpeMemoryIndex.class.getName());
|
||||
private static final Logger LOGGER = LoggerFactory.getLogger(CpeMemoryIndex.class);
|
||||
/**
|
||||
* singleton instance.
|
||||
*/
|
||||
@@ -149,9 +149,8 @@ public final class CpeMemoryIndex {
|
||||
*
|
||||
* @return the CPE Analyzer.
|
||||
*/
|
||||
@SuppressWarnings("unchecked")
|
||||
private Analyzer createIndexingAnalyzer() {
|
||||
final Map fieldAnalyzers = new HashMap();
|
||||
final Map<String, Analyzer> fieldAnalyzers = new HashMap<String, Analyzer>();
|
||||
fieldAnalyzers.put(Fields.DOCUMENT_KEY, new KeywordAnalyzer());
|
||||
return new PerFieldAnalyzerWrapper(new FieldAnalyzer(LuceneUtils.CURRENT_VERSION), fieldAnalyzers);
|
||||
}
|
||||
@@ -161,7 +160,6 @@ public final class CpeMemoryIndex {
|
||||
*
|
||||
* @return the CPE Analyzer.
|
||||
*/
|
||||
@SuppressWarnings("unchecked")
|
||||
private Analyzer createSearchingAnalyzer() {
|
||||
final Map<String, Analyzer> fieldAnalyzers = new HashMap<String, Analyzer>();
|
||||
fieldAnalyzers.put(Fields.DOCUMENT_KEY, new KeywordAnalyzer());
|
||||
@@ -173,24 +171,6 @@ public final class CpeMemoryIndex {
|
||||
return new PerFieldAnalyzerWrapper(new FieldAnalyzer(LuceneUtils.CURRENT_VERSION), fieldAnalyzers);
|
||||
}
|
||||
|
||||
/**
|
||||
* Saves a CPE IndexEntry into the Lucene index.
|
||||
*
|
||||
* @param vendor the vendor to index
|
||||
* @param product the product to index
|
||||
* @param indexWriter the index writer to write the entry into
|
||||
* @throws CorruptIndexException is thrown if the index is corrupt
|
||||
* @throws IOException is thrown if an IOException occurs
|
||||
*/
|
||||
public void saveEntry(String vendor, String product, IndexWriter indexWriter) throws CorruptIndexException, IOException {
|
||||
final Document doc = new Document();
|
||||
final Field v = new TextField(Fields.VENDOR, vendor, Field.Store.YES);
|
||||
final Field p = new TextField(Fields.PRODUCT, product, Field.Store.YES);
|
||||
doc.add(v);
|
||||
doc.add(p);
|
||||
indexWriter.addDocument(doc);
|
||||
}
|
||||
|
||||
/**
|
||||
* Closes the CPE Index.
|
||||
*/
|
||||
@@ -203,7 +183,7 @@ public final class CpeMemoryIndex {
|
||||
try {
|
||||
indexReader.close();
|
||||
} catch (IOException ex) {
|
||||
LOGGER.log(Level.FINEST, null, ex);
|
||||
LOGGER.trace("", ex);
|
||||
}
|
||||
indexReader = null;
|
||||
}
|
||||
@@ -230,12 +210,23 @@ public final class CpeMemoryIndex {
|
||||
final IndexWriterConfig conf = new IndexWriterConfig(LuceneUtils.CURRENT_VERSION, analyzer);
|
||||
indexWriter = new IndexWriter(index, conf);
|
||||
try {
|
||||
// Tip: reuse the Document and Fields for performance...
|
||||
// See "Re-use Document and Field instances" from
|
||||
// http://wiki.apache.org/lucene-java/ImproveIndexingSpeed
|
||||
final Document doc = new Document();
|
||||
final Field v = new TextField(Fields.VENDOR, Fields.VENDOR, Field.Store.YES);
|
||||
final Field p = new TextField(Fields.PRODUCT, Fields.PRODUCT, Field.Store.YES);
|
||||
doc.add(v);
|
||||
doc.add(p);
|
||||
|
||||
final Set<Pair<String, String>> data = cve.getVendorProductList();
|
||||
for (Pair<String, String> pair : data) {
|
||||
saveEntry(pair.getLeft(), pair.getRight(), indexWriter);
|
||||
v.setStringValue(pair.getLeft());
|
||||
p.setStringValue(pair.getRight());
|
||||
indexWriter.addDocument(doc);
|
||||
}
|
||||
} catch (DatabaseException ex) {
|
||||
LOGGER.log(Level.FINE, null, ex);
|
||||
LOGGER.debug("", ex);
|
||||
throw new IndexException("Error reading CPE data", ex);
|
||||
}
|
||||
} catch (CorruptIndexException ex) {
|
||||
@@ -287,8 +278,9 @@ public final class CpeMemoryIndex {
|
||||
if (searchString == null || searchString.trim().isEmpty()) {
|
||||
throw new ParseException("Query is null or empty");
|
||||
}
|
||||
LOGGER.debug(searchString);
|
||||
final Query query = queryParser.parse(searchString);
|
||||
return indexSearcher.search(query, maxQueryResults);
|
||||
return search(query, maxQueryResults);
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -20,7 +20,7 @@ package org.owasp.dependencycheck.data.cpe;
|
||||
/**
|
||||
* 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 final class Fields {
|
||||
|
||||
|
||||
@@ -24,7 +24,7 @@ import java.net.URLDecoder;
|
||||
/**
|
||||
* 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 {
|
||||
|
||||
@@ -48,7 +48,7 @@ public class IndexEntry implements Serializable {
|
||||
*/
|
||||
public String getDocumentId() {
|
||||
if (documentId == null && vendor != null && product != null) {
|
||||
documentId = vendor + ":" + product;
|
||||
documentId = vendor + ':' + product;
|
||||
}
|
||||
return documentId;
|
||||
}
|
||||
|
||||
@@ -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.
|
||||
*
|
||||
* @author Jeremy Long <jeremy.long@owasp.org>
|
||||
* @author Jeremy Long
|
||||
*/
|
||||
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.
|
||||
* </body>
|
||||
* </html>
|
||||
*/
|
||||
|
||||
*/
|
||||
package org.owasp.dependencycheck.data.cpe;
|
||||
|
||||
@@ -17,23 +17,25 @@
|
||||
*/
|
||||
package org.owasp.dependencycheck.data.cwe;
|
||||
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.io.ObjectInputStream;
|
||||
import java.util.HashMap;
|
||||
import java.util.logging.Level;
|
||||
import java.util.logging.Logger;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author Jeremy Long <jeremy.long@owasp.org>
|
||||
* @author Jeremy Long
|
||||
*/
|
||||
public final class CweDB {
|
||||
|
||||
/**
|
||||
* 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.
|
||||
@@ -44,34 +46,34 @@ public final class CweDB {
|
||||
/**
|
||||
* A HashMap of the CWE data.
|
||||
*/
|
||||
private static final HashMap<String, String> CWE = loadData();
|
||||
private static final Map<String, String> CWE = loadData();
|
||||
|
||||
/**
|
||||
* Loads a HashMap containing the CWE data from a resource found in the jar.
|
||||
*
|
||||
* @return a HashMap of CWE data
|
||||
*/
|
||||
private static HashMap<String, String> loadData() {
|
||||
private static Map<String, String> loadData() {
|
||||
ObjectInputStream oin = null;
|
||||
try {
|
||||
final String filePath = "data/cwe.hashmap.serialized";
|
||||
final InputStream input = CweDB.class.getClassLoader().getResourceAsStream(filePath);
|
||||
oin = new ObjectInputStream(input);
|
||||
@SuppressWarnings("unchecked")
|
||||
final HashMap<String, String> ret = (HashMap<String, String>) oin.readObject();
|
||||
final Map<String, String> ret = (HashMap<String, String>) oin.readObject();
|
||||
return ret;
|
||||
} catch (ClassNotFoundException ex) {
|
||||
LOGGER.log(Level.WARNING, "Unable to load CWE data. This should not be an issue.");
|
||||
LOGGER.log(Level.FINE, null, ex);
|
||||
LOGGER.warn("Unable to load CWE data. This should not be an issue.");
|
||||
LOGGER.debug("", 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.log(Level.FINE, null, ex);
|
||||
LOGGER.warn("Unable to load CWE data due to an IO Error. This should not be an issue.");
|
||||
LOGGER.debug("", ex);
|
||||
} finally {
|
||||
if (oin != null) {
|
||||
try {
|
||||
oin.close();
|
||||
} 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.
|
||||
*
|
||||
* @author Jeremy Long <jeremy.long@owasp.org>
|
||||
* @author Jeremy Long
|
||||
*/
|
||||
public class CweHandler extends DefaultHandler {
|
||||
|
||||
@@ -37,7 +37,7 @@ public class CweHandler extends DefaultHandler {
|
||||
/**
|
||||
* Returns the HashMap of CWE entries (CWE-ID, Full CWE Name).
|
||||
*
|
||||
* @return a HashMap of CWE entries <String, String>
|
||||
* @return a HashMap of CWE entries <String, String>
|
||||
*/
|
||||
public HashMap<String, String> getCwe() {
|
||||
return cwe;
|
||||
|
||||
@@ -1,12 +1,4 @@
|
||||
/**
|
||||
* <html>
|
||||
* <head>
|
||||
* <title>org.owasp.dependencycheck.data.cwe</title>
|
||||
* </head>
|
||||
* <body>
|
||||
* Contains classes for working with the CWE Database.
|
||||
* </body>
|
||||
* </html>
|
||||
*/
|
||||
|
||||
*/
|
||||
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.
|
||||
*
|
||||
* @author Jeremy Long <jeremy.long@owasp.org>
|
||||
* @author Jeremy Long
|
||||
*/
|
||||
public abstract class AbstractTokenizingFilter extends TokenFilter {
|
||||
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user