mirror of
https://github.com/ysoftdevs/DependencyCheck.git
synced 2026-01-14 15:53:36 +01:00
Compare commits
708 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
bc656c6218 | ||
|
|
f46226d055 | ||
|
|
c5ffc21660 | ||
|
|
d89b1fdc6a | ||
|
|
8324287bd6 | ||
|
|
6be161a546 | ||
|
|
027350e1ba | ||
|
|
a2309e1c2e | ||
|
|
c34dc97bd4 | ||
|
|
7e8749146e | ||
|
|
8680ecd033 | ||
|
|
4e4417c7af | ||
|
|
7909bbbbe9 | ||
|
|
6fd831e688 | ||
|
|
59a4825c70 | ||
|
|
1ba3681457 | ||
|
|
78becffb2e | ||
|
|
e7efd7070b | ||
|
|
ec6471e8c7 | ||
|
|
b01ae2c6d3 | ||
|
|
ef4a260615 | ||
|
|
f6b80630dd | ||
|
|
f43589589d | ||
|
|
06b59cf79b | ||
|
|
a2187205e0 | ||
|
|
52f269a289 | ||
|
|
310ca967a1 | ||
|
|
c4b423cb0f | ||
|
|
8a6c940aaf | ||
|
|
b295e927b7 | ||
|
|
63d24737dd | ||
|
|
60ce02ba28 | ||
|
|
95939ed66c | ||
|
|
7f609a35be | ||
|
|
f7b534f1ee | ||
|
|
cd5f9e2f13 | ||
|
|
e79da72711 | ||
|
|
1ba081959b | ||
|
|
578dc63652 | ||
|
|
fccd683b50 | ||
|
|
f3d3a25856 | ||
|
|
6d70c92795 | ||
|
|
3c525d8e3a | ||
|
|
a6b47c7c43 | ||
|
|
5b52f01f3d | ||
|
|
d13bbd43f3 | ||
|
|
0394d1a24f | ||
|
|
446222e127 | ||
|
|
05d7aa898d | ||
|
|
73f7fc1d51 | ||
|
|
f0262466d4 | ||
|
|
1ecde9bbc1 | ||
|
|
ae5a766092 | ||
|
|
6a807bc002 | ||
|
|
c0384bb0ee | ||
|
|
2906b315b3 | ||
|
|
425fd65bd8 | ||
|
|
7d83362a85 | ||
|
|
0b26894112 | ||
|
|
17f810a720 | ||
|
|
71ef8061f9 | ||
|
|
353b17690f | ||
|
|
6790727260 | ||
|
|
e129f7db85 | ||
|
|
ea942398e3 | ||
|
|
5ad72cae3f | ||
|
|
5f945bc696 | ||
|
|
6f451736ba | ||
|
|
30856f4a4f | ||
|
|
9d1408be20 | ||
|
|
f21f371751 | ||
|
|
d5e8f54214 | ||
|
|
83f83d4eee | ||
|
|
b0f4ab9ba5 | ||
|
|
06dad8f79c | ||
|
|
83ab122ddf | ||
|
|
8a42fe4ae1 | ||
|
|
94c6778b89 | ||
|
|
c0e5973517 | ||
|
|
4de3fb1f2a | ||
|
|
ee77fccffd | ||
|
|
189da08885 | ||
|
|
9e63ac6d5b | ||
|
|
4d7ab8b187 | ||
|
|
4de9818bee | ||
|
|
7a2e1fd221 | ||
|
|
d0ca800a23 | ||
|
|
35ffd56ea9 | ||
|
|
84b992d3a1 | ||
|
|
9e46364759 | ||
|
|
0f37c2b59c | ||
|
|
33852ea7e3 | ||
|
|
4fbed1cdac | ||
|
|
42c61ab457 | ||
|
|
8c6b9f9c68 | ||
|
|
abebecac4a | ||
|
|
87efe429da | ||
|
|
35128b0bd4 | ||
|
|
186cb2270f | ||
|
|
deda02f879 | ||
|
|
bcc2478ef7 | ||
|
|
8d54654482 | ||
|
|
08318107c1 | ||
|
|
a5e77c85a6 | ||
|
|
1e8d2aff75 | ||
|
|
bc0a0f9902 | ||
|
|
da82f975e4 | ||
|
|
48af120db8 | ||
|
|
8722eae766 | ||
|
|
53776936ca | ||
|
|
dca465b801 | ||
|
|
43cd115dc7 | ||
|
|
e7ba08e52c | ||
|
|
9df12e6ff2 | ||
|
|
b5c7fb747c | ||
|
|
a40a4afe80 | ||
|
|
739f595f13 | ||
|
|
e07e892969 | ||
|
|
d4a6c58cc8 | ||
|
|
d644431a4e | ||
|
|
33bbb50b43 | ||
|
|
f89d7df305 | ||
|
|
3b02cd0e39 | ||
|
|
52cd50e0a8 | ||
|
|
996a970081 | ||
|
|
6c0b65acd4 | ||
|
|
f4df263dfe | ||
|
|
8c659acc82 | ||
|
|
7aba2429af | ||
|
|
ab48d2c2ff | ||
|
|
0b699d45bf | ||
|
|
54beafa262 | ||
|
|
531d4923eb | ||
|
|
b160a4d1dd | ||
|
|
ca54daf456 | ||
|
|
a22fc550b3 | ||
|
|
0650d93953 | ||
|
|
5633258fa7 | ||
|
|
12278cda58 | ||
|
|
84d1f08fda | ||
|
|
c184292a57 | ||
|
|
4cdfcb9f9d | ||
|
|
343a78917c | ||
|
|
ff7d0fdb9d | ||
|
|
db26b46be0 | ||
|
|
d77a70c360 | ||
|
|
42f4ae65d1 | ||
|
|
88daac31d2 | ||
|
|
ac04c173a8 | ||
|
|
8401494fbc | ||
|
|
97af118cb9 | ||
|
|
091e6026bc | ||
|
|
c798ede7bf | ||
|
|
225851f067 | ||
|
|
9dd65ecf70 | ||
|
|
1a9cc4b6be | ||
|
|
a612f206bf | ||
|
|
e51031c62a | ||
|
|
e30c29ef50 | ||
|
|
91ddcadbcd | ||
|
|
8c145860e5 | ||
|
|
a19dd7687e | ||
|
|
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 |
1
.gitignore
vendored
1
.gitignore
vendored
@@ -26,3 +26,4 @@ _site/**
|
||||
.LCKpom.xml~
|
||||
#coverity
|
||||
/cov-int/
|
||||
/dependency-check-core/nbproject/
|
||||
2
.travis.yml
Normal file
2
.travis.yml
Normal file
@@ -0,0 +1,2 @@
|
||||
language: java
|
||||
jdk: oraclejdk7
|
||||
23
README.md
23
README.md
@@ -1,3 +1,4 @@
|
||||
[](https://travis-ci.org/jeremylong/DependencyCheck) [](https://www.apache.org/licenses/LICENSE-2.0.txt)
|
||||
Dependency-Check
|
||||
================
|
||||
|
||||
@@ -9,7 +10,7 @@ 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
|
||||
|
||||
@@ -21,23 +22,23 @@ The latest CLI can be downloaded from bintray's
|
||||
On *nix
|
||||
```
|
||||
$ ./bin/dependency-check.sh -h
|
||||
$ ./bin/dependency-check.sh --app Testing --out . --scan [path to jar files to be scanned]
|
||||
$ ./bin/dependency-check.sh --project Testing --out . --scan [path to jar files to be scanned]
|
||||
```
|
||||
On Windows
|
||||
```
|
||||
> bin/dependency-check.bat -h
|
||||
> bin/dependency-check.bat --app Testing --out . --scan [path to jar files to be scanned]
|
||||
> bin/dependency-check.bat --project 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]
|
||||
$ dependency-check --project 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
|
||||
@@ -66,7 +67,7 @@ The plugin can be configured using the following:
|
||||
|
||||
### Ant Task
|
||||
|
||||
For instructions on the use of the Ant Task, please see the [dependency-check-ant github page](http://jeremylong.github.io/DependencyCheck/dependency-check-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
|
||||
-------------
|
||||
@@ -84,13 +85,13 @@ On *nix
|
||||
```
|
||||
$ mvn install
|
||||
$ ./dependency-check-cli/target/release/bin/dependency-check.sh -h
|
||||
$ ./dependency-check-cli/target/release/bin/dependency-check.sh --app Testing --out . --scan ./src/test/resources
|
||||
$ ./dependency-check-cli/target/release/bin/dependency-check.sh --project Testing --out . --scan ./src/test/resources
|
||||
```
|
||||
On Windows
|
||||
```
|
||||
> mvn install
|
||||
> dependency-check-cli/target/release/bin/dependency-check.bat -h
|
||||
> dependency-check-cli/target/release/bin/dependency-check.bat --app Testing --out . --scan ./src/test/resources
|
||||
> dependency-check-cli/target/release/bin/dependency-check.bat --project Testing --out . --scan ./src/test/resources
|
||||
```
|
||||
|
||||
Then load the resulting 'DependencyCheck-Report.html' into your favorite browser.
|
||||
@@ -107,9 +108,9 @@ Archive: [google group](https://groups.google.com/forum/#!forum/dependency-check
|
||||
Copyright & License
|
||||
-
|
||||
|
||||
Dependency-Check is Copyright (c) 2012-2015 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.
|
||||
|
||||
@@ -117,4 +118,4 @@ Dependency-Check makes use of several other open source libraries. Please see th
|
||||
[wiki]: https://github.com/jeremylong/DependencyCheck/wiki
|
||||
[subscribe]: mailto:dependency-check+subscribe@googlegroups.com
|
||||
[post]: mailto:dependency-check@googlegroups.com
|
||||
[notices]: https://github.com/jeremylong/DependencyCheck/blob/master/NOTICES.txt
|
||||
[notices]: https://github.com/jeremylong/DependencyCheck/blob/master/NOTICE.txt
|
||||
|
||||
@@ -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.
|
||||
|
||||
-----------------------------
|
||||
@@ -6,7 +6,7 @@ performed are a "best effort" and as such, there could be false positives as wel
|
||||
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).
|
||||
|
||||
Documentation and links to production binary releases can be found on the [github pages](http://jeremylong.github.io/DependencyCheck/dependency-check-ant/installation.html).
|
||||
Documentation and links to production binary releases can be found on the [github pages](http://jeremylong.github.io/DependencyCheck/dependency-check-ant/index.html).
|
||||
|
||||
Mailing List
|
||||
------------
|
||||
@@ -20,6 +20,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-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.
|
||||
Dependency-Check-Ant makes use of other open source libraries. Please see the [NOTICE.txt](https://raw.githubusercontent.com/jeremylong/DependencyCheck/master/dependency-check-ant/NOTICE.txt) file for more information.
|
||||
|
||||
@@ -20,7 +20,7 @@ Copyright (c) 2013 - Jeremy Long. All Rights Reserved.
|
||||
<parent>
|
||||
<groupId>org.owasp</groupId>
|
||||
<artifactId>dependency-check-parent</artifactId>
|
||||
<version>1.3.0</version>
|
||||
<version>1.4.0</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>
|
||||
@@ -261,6 +256,7 @@ Copyright (c) 2013 - Jeremy Long. All Rights Reserved.
|
||||
<groupId>org.apache.maven.plugins</groupId>
|
||||
<artifactId>maven-surefire-plugin</artifactId>
|
||||
<configuration>
|
||||
<argLine>-Dfile.encoding=UTF-8</argLine>
|
||||
<systemProperties>
|
||||
<property>
|
||||
<name>data.directory</name>
|
||||
@@ -273,96 +269,6 @@ 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>${reporting.project-info-reports-plugin.version}</version>
|
||||
<reportSets>
|
||||
<reportSet>
|
||||
<reports>
|
||||
<report>summary</report>
|
||||
<report>license</report>
|
||||
<report>help</report>
|
||||
</reports>
|
||||
</reportSet>
|
||||
</reportSets>
|
||||
</plugin>
|
||||
<plugin>
|
||||
<groupId>org.apache.maven.plugins</groupId>
|
||||
<artifactId>maven-javadoc-plugin</artifactId>
|
||||
<version>${reporting.javadoc-plugin.version}</version>
|
||||
<configuration>
|
||||
<failOnError>false</failOnError>
|
||||
<bottom>Copyright© 2012-15 Jeremy Long. All Rights Reserved.</bottom>
|
||||
</configuration>
|
||||
<reportSets>
|
||||
<reportSet>
|
||||
<id>default</id>
|
||||
<reports>
|
||||
<report>javadoc</report>
|
||||
</reports>
|
||||
</reportSet>
|
||||
</reportSets>
|
||||
</plugin>
|
||||
<plugin>
|
||||
<groupId>org.codehaus.mojo</groupId>
|
||||
<artifactId>versions-maven-plugin</artifactId>
|
||||
<version>${reporting.versions-plugin.version}</version>
|
||||
<reportSets>
|
||||
<reportSet>
|
||||
<reports>
|
||||
<report>dependency-updates-report</report>
|
||||
<report>plugin-updates-report</report>
|
||||
</reports>
|
||||
</reportSet>
|
||||
</reportSets>
|
||||
</plugin>
|
||||
<plugin>
|
||||
<groupId>org.apache.maven.plugins</groupId>
|
||||
<artifactId>maven-jxr-plugin</artifactId>
|
||||
<version>${reporting.jxr-plugin.version}</version>
|
||||
</plugin>
|
||||
<plugin>
|
||||
<groupId>org.codehaus.mojo</groupId>
|
||||
<artifactId>cobertura-maven-plugin</artifactId>
|
||||
<version>${reporting.cobertura-plugin.version}</version>
|
||||
</plugin>
|
||||
<plugin>
|
||||
<groupId>org.apache.maven.plugins</groupId>
|
||||
<artifactId>maven-surefire-report-plugin</artifactId>
|
||||
<version>${reporting.surefire-report-plugin.version}</version>
|
||||
<reportSets>
|
||||
<reportSet>
|
||||
<reports>
|
||||
<report>report-only</report>
|
||||
</reports>
|
||||
</reportSet>
|
||||
</reportSets>
|
||||
</plugin>
|
||||
<plugin>
|
||||
<groupId>org.codehaus.mojo</groupId>
|
||||
<artifactId>taglist-maven-plugin</artifactId>
|
||||
<version>${reporting.taglist-plugin.version}</version>
|
||||
<configuration>
|
||||
<tagListOptions>
|
||||
<tagClasses>
|
||||
<tagClass>
|
||||
<displayName>Todo Work</displayName>
|
||||
<tags>
|
||||
<tag>
|
||||
<matchString>todo</matchString>
|
||||
<matchType>ignoreCase</matchType>
|
||||
</tag>
|
||||
<tag>
|
||||
<matchString>FIXME</matchString>
|
||||
<matchType>exact</matchType>
|
||||
</tag>
|
||||
</tags>
|
||||
</tagClass>
|
||||
</tagClasses>
|
||||
</tagListOptions>
|
||||
</configuration>
|
||||
</plugin>
|
||||
<plugin>
|
||||
<groupId>org.apache.maven.plugins</groupId>
|
||||
<artifactId>maven-checkstyle-plugin</artifactId>
|
||||
@@ -395,11 +301,6 @@ Copyright (c) 2013 - Jeremy Long. All Rights Reserved.
|
||||
</rulesets>
|
||||
</configuration>
|
||||
</plugin>
|
||||
<plugin>
|
||||
<groupId>org.codehaus.mojo</groupId>
|
||||
<artifactId>findbugs-maven-plugin</artifactId>
|
||||
<version>${reporting.findbugs-plugin.version}</version>
|
||||
</plugin>
|
||||
</plugins>
|
||||
</reporting>
|
||||
<dependencies>
|
||||
@@ -423,6 +324,7 @@ Copyright (c) 2013 - Jeremy Long. All Rights Reserved.
|
||||
<dependency>
|
||||
<groupId>org.apache.ant</groupId>
|
||||
<artifactId>ant</artifactId>
|
||||
<scope>provided</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.apache.ant</groupId>
|
||||
|
||||
@@ -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>
|
||||
|
||||
@@ -24,7 +24,7 @@ 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
|
||||
* An instance of {@link org.slf4j.Logger} which simply calls the log method on the delegate Ant task.
|
||||
*
|
||||
* @author colezlaw
|
||||
*/
|
||||
@@ -63,7 +63,9 @@ public class AntLoggerAdapter extends MarkerIgnoringBase {
|
||||
|
||||
@Override
|
||||
public void trace(String msg) {
|
||||
task.log(msg, Project.MSG_VERBOSE);
|
||||
if (task != null) {
|
||||
task.log(msg, Project.MSG_VERBOSE);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
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");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -23,16 +23,18 @@ import org.slf4j.ILoggerFactory;
|
||||
import org.slf4j.spi.LoggerFactoryBinder;
|
||||
|
||||
/**
|
||||
* The binding of {@link LoggerFactory} class with an actual instance of {@link ILoggerFactory} is performed using information
|
||||
* returned by this class.
|
||||
* 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
|
||||
*/
|
||||
//CSOFF: FinalClass
|
||||
public class StaticLoggerBinder implements LoggerFactoryBinder {
|
||||
//CSON: FinalClass
|
||||
|
||||
/**
|
||||
* The unique instance of this class
|
||||
*
|
||||
*/
|
||||
private static final StaticLoggerBinder SINGLETON = new StaticLoggerBinder();
|
||||
|
||||
@@ -46,7 +48,8 @@ public class StaticLoggerBinder implements LoggerFactoryBinder {
|
||||
}
|
||||
|
||||
/**
|
||||
* Ant tasks have the log method we actually want to call. So we hang onto the task as a delegate
|
||||
* Ant tasks have the log method we actually want to call. So we hang onto
|
||||
* the task as a delegate
|
||||
*/
|
||||
private Task task = null;
|
||||
|
||||
@@ -61,16 +64,24 @@ public class StaticLoggerBinder implements LoggerFactoryBinder {
|
||||
}
|
||||
|
||||
/**
|
||||
* Declare the version of the SLF4J API this implementation is compiled against. The value of this filed is usually modified
|
||||
* with each release.
|
||||
* 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
|
||||
//CSOFF: StaticVariableName
|
||||
//CSOFF: VisibilityModifier
|
||||
public static String REQUESTED_API_VERSION = "1.7.12"; // final
|
||||
//CSON: VisibilityModifier
|
||||
//CSON: StaticVariableName
|
||||
|
||||
/**
|
||||
* The logger factory class string.
|
||||
*/
|
||||
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
|
||||
* The ILoggerFactory instance returned by the {@link #getLoggerFactory}
|
||||
* method should always be the smae object
|
||||
*/
|
||||
private ILoggerFactory loggerFactory;
|
||||
|
||||
|
||||
@@ -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,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,25 @@ 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 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
|
||||
updateOnly | If set to true only the update phase of dependency-check will be executed; no scan will be executed and no report will be generated. | false
|
||||
externalReport | When using as a Site plugin this parameter sets whether or not the external report format should be used. | false
|
||||
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'
|
||||
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
|
||||
reportFormat | The report format to be generated (HTML, XML, VULN, ALL). This configuration option has no affect if using this within the Site plugin unless the externalReport is set to true. | HTML
|
||||
suppressionFile | The file path to the XML suppression file \- used to suppress [false positives](../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. |
|
||||
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; see the [proxy configuration](../data/proxy.html) page for more information. |
|
||||
proxyPort | The Proxy Port. |
|
||||
proxyUsername | Defines the proxy user name. |
|
||||
proxyPassword | Defines the proxy password. |
|
||||
connectionTimeout | The URL Connection Timeout. |
|
||||
enableExperimental | Enable the [experimental analyzers](../analyzers/index.html). If not enabled the experimental analyzers (see below) will not be loaded or used. | false
|
||||
|
||||
Analyzer Configuration
|
||||
====================
|
||||
@@ -46,18 +53,26 @@ 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 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
|
||||
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 [experimental](../analyzers/index.html) Python Distribution Analyzer will be used. | true
|
||||
pyPackageAnalyzerEnabled | Sets whether the [experimental](../analyzers/index.html) Python Package Analyzer will be used. | true
|
||||
rubygemsAnalyzerEnabled | Sets whether the [experimental](../analyzers/index.html) Ruby Gemspec Analyzer will be used. | true
|
||||
opensslAnalyzerEnabled | Sets whether the openssl Analyzer should be used. | true
|
||||
cmakeAnalyzerEnabled | Sets whether the [experimental](../analyzers/index.html) CMake Analyzer should be used. | true
|
||||
autoconfAnalyzerEnabled | Sets whether the [experimental](../analyzers/index.html) autoconf Analyzer should be used. | true
|
||||
composerAnalyzerEnabled | Sets whether the [experimental](../analyzers/index.html) PHP Composer Lock File Analyzer should be used. | true
|
||||
nodeAnalyzerEnabled | Sets whether the [experimental](../analyzers/index.html) Node.js Analyzer should be used. | true
|
||||
nuspecAnalyzerEnabled | Sets whether the .NET Nuget Nuspec Analyzer will be used. | true
|
||||
assemblyAnalyzerEnabled | Sets whether the .NET Assembly Analyzer should be used. | true
|
||||
pathToMono | The path to Mono for .NET assembly analysis on non-windows systems. |
|
||||
|
||||
Advanced Configuration
|
||||
====================
|
||||
@@ -70,7 +85,7 @@ cveUrl12Modified | URL for the modified CVE 1.2.
|
||||
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. |
|
||||
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. |
|
||||
|
||||
@@ -7,23 +7,28 @@ identifiers, and the associated Common Vulnerability and Exposure (CVE) entries.
|
||||
|
||||
Installation
|
||||
====================
|
||||
Download dependency-check-ant from [bintray here](http://dl.bintray.com/jeremy-long/owasp/dependency-check-ant-${project.version}.jar).
|
||||
To install dependency-check-ant place the dependency-check-ant-${project.version}.jar into
|
||||
the lib directory of your Ant instalation directory. Once installed you can add
|
||||
the taskdef to you build.xml and add the task to a new or existing target:
|
||||
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
|
||||
<taskdef name="dependency-check" classname="org.owasp.dependencycheck.taskdefs.DependencyCheckTask"/>
|
||||
```
|
||||
```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"/>
|
||||
<fileset dir="${dependency-check.home}/lib">
|
||||
<include name="*.jar"/>
|
||||
</fileset>
|
||||
</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.
|
||||
|
||||
If you do not want to install dependency-check-ant into your ant's lib directory when you define the task def you
|
||||
must add the classpath to the taskdef:
|
||||
|
||||
```xml
|
||||
<taskdef name="dependency-check" classname="org.owasp.dependencycheck.taskdefs.DependencyCheckTask">
|
||||
<classpath path="[path]/[to]/dependency-check-ant-${project.version}.jar"/>
|
||||
</taskdef>
|
||||
```
|
||||
|
||||
It is important to understand that the first time this task is executed it may
|
||||
take 10 minutes or more as it downloads and processes the data from the National
|
||||
|
||||
@@ -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.
|
||||
@@ -27,8 +27,7 @@ Copyright (c) 2013 Jeremy Long. All Rights Reserved.
|
||||
<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="reports" />
|
||||
|
||||
@@ -26,7 +26,7 @@ import org.junit.Before;
|
||||
import org.junit.Rule;
|
||||
import org.junit.Test;
|
||||
import org.junit.rules.ExpectedException;
|
||||
import org.owasp.dependencycheck.data.nvdcve.BaseDBTestCase;
|
||||
import org.owasp.dependencycheck.BaseDBTestCase;
|
||||
import org.owasp.dependencycheck.utils.Settings;
|
||||
|
||||
import static org.junit.Assert.assertTrue;
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -5,7 +5,7 @@ performed are a "best effort" and as such, there could be false positives as wel
|
||||
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).
|
||||
|
||||
Documentation and links to production binary releases can be found on the [github pages](http://jeremylong.github.io/DependencyCheck/dependency-check-cli/installation.html).
|
||||
Documentation and links to production binary releases can be found on the [github pages](http://jeremylong.github.io/DependencyCheck/dependency-check-cli/index.html).
|
||||
|
||||
Mailing List
|
||||
------------
|
||||
@@ -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.3.0</version>
|
||||
<version>1.4.0</version>
|
||||
</parent>
|
||||
|
||||
<artifactId>dependency-check-cli</artifactId>
|
||||
@@ -110,6 +110,7 @@ Copyright (c) 2012 - Jeremy Long. All Rights Reserved.
|
||||
<groupId>org.apache.maven.plugins</groupId>
|
||||
<artifactId>maven-surefire-plugin</artifactId>
|
||||
<configuration>
|
||||
<argLine>-Dfile.encoding=UTF-8</argLine>
|
||||
<systemProperties>
|
||||
<property>
|
||||
<name>cpe</name>
|
||||
@@ -124,10 +125,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>
|
||||
@@ -178,96 +175,6 @@ 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>${reporting.project-info-reports-plugin.version}</version>
|
||||
<reportSets>
|
||||
<reportSet>
|
||||
<reports>
|
||||
<report>summary</report>
|
||||
<report>license</report>
|
||||
<report>help</report>
|
||||
</reports>
|
||||
</reportSet>
|
||||
</reportSets>
|
||||
</plugin>
|
||||
<plugin>
|
||||
<groupId>org.apache.maven.plugins</groupId>
|
||||
<artifactId>maven-javadoc-plugin</artifactId>
|
||||
<version>${reporting.javadoc-plugin.version}</version>
|
||||
<configuration>
|
||||
<failOnError>false</failOnError>
|
||||
<bottom>Copyright<EFBFBD> 2012-15 Jeremy Long. All Rights Reserved.</bottom>
|
||||
</configuration>
|
||||
<reportSets>
|
||||
<reportSet>
|
||||
<id>default</id>
|
||||
<reports>
|
||||
<report>javadoc</report>
|
||||
</reports>
|
||||
</reportSet>
|
||||
</reportSets>
|
||||
</plugin>
|
||||
<plugin>
|
||||
<groupId>org.codehaus.mojo</groupId>
|
||||
<artifactId>versions-maven-plugin</artifactId>
|
||||
<version>${reporting.versions-plugin.version}</version>
|
||||
<reportSets>
|
||||
<reportSet>
|
||||
<reports>
|
||||
<report>dependency-updates-report</report>
|
||||
<report>plugin-updates-report</report>
|
||||
</reports>
|
||||
</reportSet>
|
||||
</reportSets>
|
||||
</plugin>
|
||||
<plugin>
|
||||
<groupId>org.apache.maven.plugins</groupId>
|
||||
<artifactId>maven-jxr-plugin</artifactId>
|
||||
<version>${reporting.jxr-plugin.version}</version>
|
||||
</plugin>
|
||||
<plugin>
|
||||
<groupId>org.codehaus.mojo</groupId>
|
||||
<artifactId>cobertura-maven-plugin</artifactId>
|
||||
<version>${reporting.cobertura-plugin.version}</version>
|
||||
</plugin>
|
||||
<plugin>
|
||||
<groupId>org.apache.maven.plugins</groupId>
|
||||
<artifactId>maven-surefire-report-plugin</artifactId>
|
||||
<version>${reporting.surefire-report-plugin.version}</version>
|
||||
<reportSets>
|
||||
<reportSet>
|
||||
<reports>
|
||||
<report>report-only</report>
|
||||
</reports>
|
||||
</reportSet>
|
||||
</reportSets>
|
||||
</plugin>
|
||||
<plugin>
|
||||
<groupId>org.codehaus.mojo</groupId>
|
||||
<artifactId>taglist-maven-plugin</artifactId>
|
||||
<version>${reporting.taglist-plugin.version}</version>
|
||||
<configuration>
|
||||
<tagListOptions>
|
||||
<tagClasses>
|
||||
<tagClass>
|
||||
<displayName>Todo Work</displayName>
|
||||
<tags>
|
||||
<tag>
|
||||
<matchString>todo</matchString>
|
||||
<matchType>ignoreCase</matchType>
|
||||
</tag>
|
||||
<tag>
|
||||
<matchString>FIXME</matchString>
|
||||
<matchType>exact</matchType>
|
||||
</tag>
|
||||
</tags>
|
||||
</tagClass>
|
||||
</tagClasses>
|
||||
</tagListOptions>
|
||||
</configuration>
|
||||
</plugin>
|
||||
<plugin>
|
||||
<groupId>org.apache.maven.plugins</groupId>
|
||||
<artifactId>maven-checkstyle-plugin</artifactId>
|
||||
@@ -300,11 +207,6 @@ Copyright (c) 2012 - Jeremy Long. All Rights Reserved.
|
||||
</rulesets>
|
||||
</configuration>
|
||||
</plugin>
|
||||
<plugin>
|
||||
<groupId>org.codehaus.mojo</groupId>
|
||||
<artifactId>findbugs-maven-plugin</artifactId>
|
||||
<version>${reporting.findbugs-plugin.version}</version>
|
||||
</plugin>
|
||||
</plugins>
|
||||
</reporting>
|
||||
<dependencies>
|
||||
@@ -334,5 +236,15 @@ Copyright (c) 2012 - Jeremy Long. All Rights Reserved.
|
||||
<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>
|
||||
|
||||
@@ -31,7 +31,7 @@ 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.Settings;
|
||||
import org.slf4j.Logger;
|
||||
@@ -90,7 +90,28 @@ public class App {
|
||||
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);
|
||||
@@ -98,7 +119,7 @@ public class App {
|
||||
} else if (cli.isRunScan()) {
|
||||
populateSettings(cli);
|
||||
try {
|
||||
runScan(cli.getReportDirectory(), cli.getReportFormat(), cli.getApplicationName(), cli.getScanFiles(),
|
||||
runScan(cli.getReportDirectory(), cli.getReportFormat(), cli.getProjectName(), cli.getScanFiles(),
|
||||
cli.getExcludeList(), cli.getSymLinkDepth());
|
||||
} catch (InvalidScanPathException ex) {
|
||||
LOGGER.error("An invalid scan path was detected; unable to scan '//*' paths");
|
||||
@@ -156,7 +177,8 @@ public class App {
|
||||
//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);
|
||||
@@ -245,16 +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 pyDistDisabled = cli.isPythonDistributionDisabled();
|
||||
final boolean cMakeDisabled = cli.isCmakeDisabled();
|
||||
final boolean pyPkgDisabled = cli.isPythonPackageDisabled();
|
||||
final boolean autoconfDisabled = cli.isAutoconfDisabled();
|
||||
final boolean assemblyDisabled = cli.isAssemblyDisabled();
|
||||
final boolean 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();
|
||||
@@ -267,6 +279,8 @@ public class App {
|
||||
final String cveMod20 = cli.getModifiedCve20Url();
|
||||
final String cveBase12 = cli.getBaseCve12Url();
|
||||
final String cveBase20 = cli.getBaseCve20Url();
|
||||
final Integer cveValidForHours = cli.getCveValidForHours();
|
||||
final boolean experimentalEnabled = cli.isExperimentalEnabled();
|
||||
|
||||
if (propertiesFile != null) {
|
||||
try {
|
||||
@@ -296,63 +310,42 @@ 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_PYTHON_DISTRIBUTION_ENABLED, !pyDistDisabled);
|
||||
Settings.setBoolean(Settings.KEYS.ANALYZER_PYTHON_PACKAGE_ENABLED, !pyPkgDisabled);
|
||||
Settings.setBoolean(Settings.KEYS.ANALYZER_AUTOCONF_ENABLED, !autoconfDisabled);
|
||||
Settings.setBoolean(Settings.KEYS.ANALYZER_CMAKE_ENABLED, !cMakeDisabled);
|
||||
Settings.setBoolean(Settings.KEYS.ANALYZER_NUSPEC_ENABLED, !nuspecDisabled);
|
||||
Settings.setBoolean(Settings.KEYS.ANALYZER_ASSEMBLY_ENABLED, !assemblyDisabled);
|
||||
Settings.setBoolean(Settings.KEYS.ANALYZER_EXPERIMENTAL_ENABLED, experimentalEnabled);
|
||||
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.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 (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);
|
||||
}
|
||||
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);
|
||||
@@ -392,7 +385,7 @@ public class App {
|
||||
}
|
||||
|
||||
/**
|
||||
* Takes a path and resolves it to be a canonical & absolute path. The caveats are that this method will take an Ant style
|
||||
* 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 ?).
|
||||
*
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -22,7 +22,12 @@ package org.owasp.dependencycheck;
|
||||
*
|
||||
* @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.
|
||||
|
||||
@@ -5,7 +5,7 @@ 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
|
||||
| \-\-symLink | \<depth\> | The depth that symbolic links will be followed; the default is 0 meaning symbolic links will not be followed. | Optional
|
||||
@@ -13,29 +13,35 @@ Short | Argument Name | Parameter | Description | Requir
|
||||
\-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
|
||||
| \-\-experimental | | Enable the [experimental analyzers](../analyzers/index.html). If not set the analyzers marked as experimental below will not be loaded or used. | Optional
|
||||
|
||||
Advanced Options
|
||||
================
|
||||
Short | Argument Name | Parameter | Description | Default Value
|
||||
-------|-----------------------|-----------------|----------------------------------------------------------------------------------|-------------------
|
||||
| \-\-cveUrl12Modified | \<url\> | URL for the modified CVE 1.2 | http://nvd.nist.gov/download/nvdcve-modified.xml
|
||||
| \-\-cveUrl20Modified | \<url\> | URL for the modified CVE 2.0 | http://static.nvd.nist.gov/feeds/xml/cve/nvdcve-2.0-modified.xml
|
||||
| \-\-cveUrl12Base | \<url\> | Base URL for each year's CVE 1.2, the %d will be replaced with the year | http://nvd.nist.gov/download/nvdcve-%d.xml
|
||||
| \-\-cveUrl20Base | \<url\> | Base URL for each year's CVE 2.0, the %d will be replaced with the year | http://static.nvd.nist.gov/feeds/xml/cve/nvdcve-2.0-%d.xml
|
||||
| \-\-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. |
|
||||
| \-\-updateonly | | If set only the update phase of dependency-check will be executed; no scan will be executed and no report will be generated. |
|
||||
| \-\-disablePyDist | | Sets whether the Python Distribution Analyzer will be used. | false
|
||||
| \-\-disablePyPkg | | Sets whether the Python Package Analyzer will be used. | false
|
||||
| \-\-disableAutoconf | | Sets whether the Autoconf Analyzer will be used. | false
|
||||
| \-\-disablePyDist | | Sets whether the [experimental](../analyzers/index.html) Python Distribution Analyzer will be used. | false
|
||||
| \-\-disablePyPkg | | Sets whether the [experimental](../analyzers/index.html) Python Package Analyzer will be used. | false
|
||||
| \-\-disableNodeJS | | Sets whether the [experimental](../analyzers/index.html) Node.js Package Analyzer will be used. | false
|
||||
| \-\-disableRubygems | | Sets whether the [experimental](../analyzers/index.html) Ruby Gemspec Analyzer will be used. | false
|
||||
| \-\-disableBundleAudit | | Sets whether the [experimental](../analyzers/index.html) Ruby Bundler Audit Analyzer will be used. | false
|
||||
| \-\-disableAutoconf | | Sets whether the [experimental](../analyzers/index.html) Autoconf Analyzer will be used. | false
|
||||
| \-\-disableOpenSSL | | Sets whether the OpenSSL Analyzer will be used. | false
|
||||
| \-\-disableCmake | | Sets whether the Cmake Analyzer will be used. | false
|
||||
| \-\-disableArchive | | Sets whether the Archive Analyzer will be used. | false
|
||||
| \-\-disableCmake | | Sets whether the [experimental](../analyzers/index.html) 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 [experimental](../analyzers/index.html) 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 Server's web service end point (example: http://domain.enterprise/nexus/service/local/). If not set the Nexus Analyzer will be disabled. |
|
||||
@@ -43,7 +49,8 @@ Short | Argument Name | Paramete
|
||||
| \-\-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. |
|
||||
| \-\-proxyserver | \<server\> | The proxy server to use when downloading resources. |
|
||||
| \-\-bundleAudit | | The path to the bundle-audit executable. |
|
||||
| \-\-proxyserver | \<server\> | The proxy server to use when downloading resources; see the [proxy configuration](../data/proxy.html) page for more information. |
|
||||
| \-\-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. |
|
||||
@@ -54,3 +61,4 @@ Short | Argument Name | Paramete
|
||||
| \-\-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. |
|
||||
@@ -14,14 +14,21 @@ script executable:
|
||||
|
||||
$ chmod +777 dependency-check.sh
|
||||
|
||||
To scan a folder on the system you can run:
|
||||
#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 --app "My App Name" --scan "c:\java\application\lib"
|
||||
dependency-check.bat --project "My App Name" --scan "c:\java\application\lib"
|
||||
|
||||
$H$H$H *nix
|
||||
dependency-check.sh --app "My App Name" --scan "/java/application/lib"
|
||||
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:
|
||||
|
||||
@@ -29,4 +36,4 @@ $H$H$H Windows
|
||||
dependency-check.bat --help
|
||||
|
||||
$H$H$H *nix
|
||||
dependency-check.sh --help
|
||||
dependency-check.sh --help
|
||||
|
||||
@@ -1,17 +1,19 @@
|
||||
/*
|
||||
* Copyright 2015 OWASP.
|
||||
* 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
|
||||
* 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;
|
||||
|
||||
|
||||
@@ -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.3.0</version>
|
||||
<version>1.4.0</version>
|
||||
</parent>
|
||||
|
||||
<artifactId>dependency-check-core</artifactId>
|
||||
@@ -83,9 +83,6 @@ Copyright (c) 2012 Jeremy Long. All Rights Reserved.
|
||||
</testResource>
|
||||
<testResource>
|
||||
<directory>${basedir}/src/test/resources</directory>
|
||||
<excludes>
|
||||
<exclude>**/mysql-connector-java-5.1.27-bin.jar</exclude>
|
||||
</excludes>
|
||||
<filtering>false</filtering>
|
||||
</testResource>
|
||||
</testResources>
|
||||
@@ -110,19 +107,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>
|
||||
@@ -180,6 +175,7 @@ Copyright (c) 2012 Jeremy Long. All Rights Reserved.
|
||||
<groupId>org.apache.maven.plugins</groupId>
|
||||
<artifactId>maven-surefire-plugin</artifactId>
|
||||
<configuration>
|
||||
<argLine>-Dfile.encoding=UTF-8</argLine>
|
||||
<systemProperties>
|
||||
<property>
|
||||
<name>data.directory</name>
|
||||
@@ -212,81 +208,14 @@ Copyright (c) 2012 Jeremy Long. All Rights Reserved.
|
||||
</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-project-info-reports-plugin</artifactId>
|
||||
<version>${reporting.project-info-reports-plugin.version}</version>
|
||||
<reportSets>
|
||||
<reportSet>
|
||||
<reports>
|
||||
<report>summary</report>
|
||||
<report>license</report>
|
||||
<report>help</report>
|
||||
</reports>
|
||||
</reportSet>
|
||||
</reportSets>
|
||||
</plugin>
|
||||
<plugin>
|
||||
<groupId>org.apache.maven.plugins</groupId>
|
||||
<artifactId>maven-javadoc-plugin</artifactId>
|
||||
<version>${reporting.javadoc-plugin.version}</version>
|
||||
<configuration>
|
||||
<failOnError>false</failOnError>
|
||||
<bottom>Copyright© 2012-15 Jeremy Long. All Rights Reserved.</bottom>
|
||||
</configuration>
|
||||
<reportSets>
|
||||
<reportSet>
|
||||
<id>default</id>
|
||||
<reports>
|
||||
<report>javadoc</report>
|
||||
</reports>
|
||||
</reportSet>
|
||||
</reportSets>
|
||||
</plugin>
|
||||
<plugin>
|
||||
<groupId>org.codehaus.mojo</groupId>
|
||||
<artifactId>versions-maven-plugin</artifactId>
|
||||
<version>${reporting.versions-plugin.version}</version>
|
||||
<reportSets>
|
||||
<reportSet>
|
||||
<reports>
|
||||
<report>dependency-updates-report</report>
|
||||
<report>plugin-updates-report</report>
|
||||
</reports>
|
||||
</reportSet>
|
||||
</reportSets>
|
||||
</plugin>
|
||||
<plugin>
|
||||
<groupId>org.apache.maven.plugins</groupId>
|
||||
<artifactId>maven-jxr-plugin</artifactId>
|
||||
<version>${reporting.jxr-plugin.version}</version>
|
||||
</plugin>
|
||||
<plugin>
|
||||
<groupId>org.codehaus.mojo</groupId>
|
||||
<artifactId>cobertura-maven-plugin</artifactId>
|
||||
<version>${reporting.cobertura-plugin.version}</version>
|
||||
</plugin>
|
||||
<plugin>
|
||||
<groupId>org.apache.maven.plugins</groupId>
|
||||
<artifactId>maven-surefire-report-plugin</artifactId>
|
||||
<version>${reporting.surefire-report-plugin.version}</version>
|
||||
<reportSets>
|
||||
<reportSet>
|
||||
<reports>
|
||||
<report>report-only</report>
|
||||
</reports>
|
||||
</reportSet>
|
||||
<reportSet>
|
||||
<id>integration-tests</id>
|
||||
<reports>
|
||||
@@ -296,30 +225,6 @@ Copyright (c) 2012 Jeremy Long. All Rights Reserved.
|
||||
</reportSet>
|
||||
</reportSets>
|
||||
</plugin>
|
||||
<plugin>
|
||||
<groupId>org.codehaus.mojo</groupId>
|
||||
<artifactId>taglist-maven-plugin</artifactId>
|
||||
<version>${reporting.taglist-plugin.version}</version>
|
||||
<configuration>
|
||||
<tagListOptions>
|
||||
<tagClasses>
|
||||
<tagClass>
|
||||
<displayName>Todo Work</displayName>
|
||||
<tags>
|
||||
<tag>
|
||||
<matchString>todo</matchString>
|
||||
<matchType>ignoreCase</matchType>
|
||||
</tag>
|
||||
<tag>
|
||||
<matchString>FIXME</matchString>
|
||||
<matchType>exact</matchType>
|
||||
</tag>
|
||||
</tags>
|
||||
</tagClass>
|
||||
</tagClasses>
|
||||
</tagListOptions>
|
||||
</configuration>
|
||||
</plugin>
|
||||
<plugin>
|
||||
<groupId>org.apache.maven.plugins</groupId>
|
||||
<artifactId>maven-checkstyle-plugin</artifactId>
|
||||
@@ -352,11 +257,6 @@ Copyright (c) 2012 Jeremy Long. All Rights Reserved.
|
||||
</rulesets>
|
||||
</configuration>
|
||||
</plugin>
|
||||
<plugin>
|
||||
<groupId>org.codehaus.mojo</groupId>
|
||||
<artifactId>findbugs-maven-plugin</artifactId>
|
||||
<version>${reporting.findbugs-plugin.version}</version>
|
||||
</plugin>
|
||||
</plugins>
|
||||
</reporting>
|
||||
<dependencies>
|
||||
@@ -371,22 +271,11 @@ Copyright (c) 2012 Jeremy Long. All Rights Reserved.
|
||||
<artifactId>slf4j-api</artifactId>
|
||||
</dependency>
|
||||
<!-- Set this to test so that each project that uses this has to have its own implementation of SLF4J -->
|
||||
<dependency>
|
||||
<groupId>ch.qos.logback</groupId>
|
||||
<artifactId>logback-core</artifactId>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>ch.qos.logback</groupId>
|
||||
<artifactId>logback-classic</artifactId>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
<!-- For the CAL10N support -->
|
||||
<dependency>
|
||||
<groupId>org.slf4j</groupId>
|
||||
<artifactId>slf4j-ext</artifactId>
|
||||
<scope>compile</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.owasp</groupId>
|
||||
<artifactId>dependency-check-utils</artifactId>
|
||||
@@ -411,8 +300,8 @@ Copyright (c) 2012 Jeremy Long. All Rights Reserved.
|
||||
<artifactId>commons-io</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>commons-lang</groupId>
|
||||
<artifactId>commons-lang</artifactId>
|
||||
<groupId>org.apache.commons</groupId>
|
||||
<artifactId>commons-lang3</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.apache.lucene</groupId>
|
||||
@@ -433,11 +322,15 @@ Copyright (c) 2012 Jeremy Long. All Rights Reserved.
|
||||
<dependency>
|
||||
<groupId>com.h2database</groupId>
|
||||
<artifactId>h2</artifactId>
|
||||
<scope>runtime</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.glassfish</groupId>
|
||||
<artifactId>javax.json</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.jsoup</groupId>
|
||||
<artifactId>jsoup</artifactId>
|
||||
<type>jar</type>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>com.sun.mail</groupId>
|
||||
@@ -559,6 +452,13 @@ Copyright (c) 2012 Jeremy Long. All Rights Reserved.
|
||||
<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>
|
||||
<profiles>
|
||||
<profile>
|
||||
@@ -573,7 +473,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>
|
||||
@@ -581,12 +480,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>
|
||||
|
||||
@@ -38,10 +38,12 @@ 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;
|
||||
|
||||
/**
|
||||
@@ -59,7 +61,7 @@ public class Engine implements FileFilter {
|
||||
/**
|
||||
* 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.
|
||||
@@ -124,9 +126,8 @@ public class Engine implements FileFilter {
|
||||
}
|
||||
|
||||
final AnalyzerService service = new AnalyzerService(serviceClassLoader);
|
||||
final Iterator<Analyzer> iterator = service.getAnalyzers();
|
||||
while (iterator.hasNext()) {
|
||||
final Analyzer a = iterator.next();
|
||||
final List<Analyzer> iterator = service.getAnalyzers();
|
||||
for (Analyzer a : iterator) {
|
||||
analyzers.get(a.getAnalysisPhase()).add(a);
|
||||
if (a instanceof FileTypeAnalyzer) {
|
||||
this.fileTypeAnalyzers.add((FileTypeAnalyzer) a);
|
||||
@@ -173,8 +174,7 @@ public class Engine implements FileFilter {
|
||||
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);
|
||||
}
|
||||
@@ -214,33 +214,14 @@ public class Engine implements FileFilter {
|
||||
}
|
||||
|
||||
/**
|
||||
* Scans a list of files or directories. 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(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) {
|
||||
public List<Dependency> scan(Collection<File> files) {
|
||||
final List<Dependency> deps = new ArrayList<Dependency>();
|
||||
for (File file : files) {
|
||||
final List<Dependency> d = scan(file);
|
||||
@@ -352,6 +333,7 @@ public class Engine implements FileFilter {
|
||||
|
||||
LOGGER.debug("\n----------------------------------------------------\nBEGIN ANALYSIS\n----------------------------------------------------");
|
||||
LOGGER.info("Analysis Starting");
|
||||
final long analysisStart = System.currentTimeMillis();
|
||||
|
||||
// analysis phases
|
||||
for (AnalysisPhase phase : AnalysisPhase.values()) {
|
||||
@@ -365,8 +347,7 @@ public class Engine implements FileFilter {
|
||||
* This is okay for adds/deletes because it happens per analyzer.
|
||||
*/
|
||||
LOGGER.debug("Begin Analyzer '{}'", a.getName());
|
||||
final Set<Dependency> dependencySet = new HashSet<Dependency>();
|
||||
dependencySet.addAll(dependencies);
|
||||
final Set<Dependency> dependencySet = new HashSet<Dependency>(dependencies);
|
||||
for (Dependency d : dependencySet) {
|
||||
boolean shouldAnalyze = true;
|
||||
if (a instanceof FileTypeAnalyzer) {
|
||||
@@ -398,7 +379,7 @@ public class Engine implements FileFilter {
|
||||
}
|
||||
|
||||
LOGGER.debug("\n----------------------------------------------------\nEND ANALYSIS\n----------------------------------------------------");
|
||||
LOGGER.info("Analysis Complete");
|
||||
LOGGER.info("Analysis Complete ({} ms)", System.currentTimeMillis() - analysisStart);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -442,6 +423,7 @@ public class Engine implements FileFilter {
|
||||
*/
|
||||
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()) {
|
||||
@@ -454,7 +436,7 @@ public class Engine implements FileFilter {
|
||||
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);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -477,6 +459,7 @@ public class Engine implements FileFilter {
|
||||
* @param file a file extension
|
||||
* @return true or false depending on whether or not the file extension is supported
|
||||
*/
|
||||
@Override
|
||||
public boolean accept(File file) {
|
||||
if (file == null) {
|
||||
return false;
|
||||
|
||||
@@ -41,7 +41,7 @@ import org.slf4j.LoggerFactory;
|
||||
*
|
||||
* <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.slf4j.LoggerFactory;
|
||||
* scan.execute();
|
||||
* </pre>
|
||||
*
|
||||
* @author Steve Springett <steve.springett@owasp.org>
|
||||
* @author Steve Springett
|
||||
*/
|
||||
@SuppressWarnings("unused")
|
||||
public class DependencyCheckScanAgent {
|
||||
@@ -840,8 +840,7 @@ public class DependencyCheckScanAgent {
|
||||
*/
|
||||
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;
|
||||
@@ -898,67 +897,28 @@ 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);
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -104,12 +104,11 @@ public abstract class AbstractFileTypeAnalyzer extends AbstractAnalyzer implemen
|
||||
* <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>
|
||||
*
|
||||
* @return the file filter used to determine which files are to be analyzed
|
||||
* <p/>
|
||||
* <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 FileFilter getFileFilter();
|
||||
|
||||
@@ -205,7 +204,6 @@ public abstract class AbstractFileTypeAnalyzer extends AbstractAnalyzer implemen
|
||||
* <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/>
|
||||
* <p>
|
||||
* This implementation was copied from
|
||||
* http://stackoverflow.com/questions/2041778/initialize-java-hashset-values-by-construction</p>
|
||||
@@ -214,7 +212,7 @@ 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;
|
||||
}
|
||||
|
||||
@@ -34,9 +34,11 @@ import org.owasp.dependencycheck.utils.FileUtils;
|
||||
import org.owasp.dependencycheck.utils.Settings;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import org.xml.sax.SAXException;
|
||||
|
||||
/**
|
||||
* Abstract base suppression analyzer that contains methods for parsing the suppression xml file.
|
||||
* Abstract base suppression analyzer that contains methods for parsing the
|
||||
* suppression xml file.
|
||||
*
|
||||
* @author Jeremy Long
|
||||
*/
|
||||
@@ -103,6 +105,10 @@ public abstract class AbstractSuppressionAnalyzer extends AbstractAnalyzer {
|
||||
try {
|
||||
rules = parser.parseSuppressionRules(this.getClass().getClassLoader().getResourceAsStream("dependencycheck-base-suppression.xml"));
|
||||
} catch (SuppressionParseException ex) {
|
||||
LOGGER.error("Unable to parse the base suppression data file");
|
||||
LOGGER.debug("Unable to parse the base suppression data file", ex);
|
||||
} catch (SAXException ex) {
|
||||
LOGGER.error("Unable to parse the base suppression data file");
|
||||
LOGGER.debug("Unable to parse the base suppression data file", ex);
|
||||
}
|
||||
final String suppressionFilePath = Settings.getString(Settings.KEYS.SUPPRESSION_FILE);
|
||||
@@ -167,7 +173,8 @@ public abstract class AbstractSuppressionAnalyzer extends AbstractAnalyzer {
|
||||
*
|
||||
* @param message the exception message
|
||||
* @param exception the cause of the exception
|
||||
* @throws SuppressionParseException throws the generated SuppressionParseException
|
||||
* @throws SuppressionParseException throws the generated
|
||||
* SuppressionParseException
|
||||
*/
|
||||
private void throwSuppressionParseException(String message, Exception exception) throws SuppressionParseException {
|
||||
LOGGER.warn(message);
|
||||
|
||||
@@ -28,6 +28,10 @@ public enum AnalysisPhase {
|
||||
* Initialization phase.
|
||||
*/
|
||||
INITIAL,
|
||||
/**
|
||||
* Pre information collection phase.
|
||||
*/
|
||||
PRE_INFORMATION_COLLECTION,
|
||||
/**
|
||||
* Information collection phase.
|
||||
*/
|
||||
|
||||
@@ -17,8 +17,13 @@
|
||||
*/
|
||||
package org.owasp.dependencycheck.analyzer;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Iterator;
|
||||
import java.util.List;
|
||||
import java.util.ServiceLoader;
|
||||
import org.owasp.dependencycheck.utils.InvalidSettingException;
|
||||
import org.owasp.dependencycheck.utils.Settings;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
/**
|
||||
* The Analyzer Service Loader. This class loads all services that implement
|
||||
@@ -27,11 +32,15 @@ import java.util.ServiceLoader;
|
||||
* @author Jeremy Long
|
||||
*/
|
||||
public class AnalyzerService {
|
||||
/**
|
||||
* The Logger for use throughout the class.
|
||||
*/
|
||||
private static final org.slf4j.Logger LOGGER = LoggerFactory.getLogger(AnalyzerService.class);
|
||||
|
||||
/**
|
||||
* The service loader for analyzers.
|
||||
*/
|
||||
private final ServiceLoader<Analyzer> loader;
|
||||
private final ServiceLoader<Analyzer> service;
|
||||
|
||||
/**
|
||||
* Creates a new instance of AnalyzerService.
|
||||
@@ -39,15 +48,31 @@ public class AnalyzerService {
|
||||
* @param classLoader the ClassLoader to use when dynamically loading Analyzer and Update services
|
||||
*/
|
||||
public AnalyzerService(ClassLoader classLoader) {
|
||||
loader = ServiceLoader.load(Analyzer.class, classLoader);
|
||||
service = ServiceLoader.load(Analyzer.class, classLoader);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns an Iterator for all instances of the Analyzer interface.
|
||||
* Returns a list of all instances of the Analyzer interface.
|
||||
*
|
||||
* @return an iterator of Analyzers.
|
||||
* @return a list of Analyzers.
|
||||
*/
|
||||
public Iterator<Analyzer> getAnalyzers() {
|
||||
return loader.iterator();
|
||||
public List<Analyzer> getAnalyzers() {
|
||||
final List<Analyzer> analyzers = new ArrayList<Analyzer>();
|
||||
final Iterator<Analyzer> iterator = service.iterator();
|
||||
boolean experimentalEnabled = false;
|
||||
try {
|
||||
experimentalEnabled = Settings.getBoolean(Settings.KEYS.ANALYZER_EXPERIMENTAL_ENABLED, false);
|
||||
} catch (InvalidSettingException ex) {
|
||||
LOGGER.error("invalide experimental setting", ex);
|
||||
}
|
||||
while (iterator.hasNext()) {
|
||||
final Analyzer a = iterator.next();
|
||||
if (!experimentalEnabled && a.getClass().isAnnotationPresent(Experimental.class)) {
|
||||
continue;
|
||||
}
|
||||
LOGGER.debug("Loaded Analyzer {}", a.getName());
|
||||
analyzers.add(a);
|
||||
}
|
||||
return analyzers;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -18,7 +18,7 @@
|
||||
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;
|
||||
@@ -26,7 +26,6 @@ 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;
|
||||
@@ -40,8 +39,12 @@ 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;
|
||||
@@ -49,6 +52,7 @@ 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;
|
||||
|
||||
@@ -65,10 +69,6 @@ public class ArchiveAnalyzer extends AbstractFileTypeAnalyzer {
|
||||
* The logger.
|
||||
*/
|
||||
private static final Logger LOGGER = LoggerFactory.getLogger(ArchiveAnalyzer.class);
|
||||
/**
|
||||
* The buffer size to use when extracting files from the archive.
|
||||
*/
|
||||
private static final int BUFFER_SIZE = 4096;
|
||||
/**
|
||||
* The count of directories created during analysis. This is used for creating temporary directories.
|
||||
*/
|
||||
@@ -101,20 +101,21 @@ 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().
|
||||
* 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");
|
||||
|
||||
/**
|
||||
* Detects files with extensions to remove from the engine's collection of dependencies.
|
||||
*/
|
||||
private static final FileFilter REMOVE_FROM_ANALYSIS = FileFilterBuilder.newInstance().addExtensions("zip", "tar", "gz", "tgz").build();
|
||||
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);
|
||||
}
|
||||
@@ -194,8 +195,11 @@ public class ArchiveAnalyzer extends AbstractFileTypeAnalyzer {
|
||||
if (tempFileLocation != null && tempFileLocation.exists()) {
|
||||
LOGGER.debug("Attempting to delete temporary files");
|
||||
final boolean success = FileUtils.delete(tempFileLocation);
|
||||
if (!success && tempFileLocation != null && tempFileLocation.exists() && tempFileLocation.list().length > 0) {
|
||||
LOGGER.warn("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");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -215,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",
|
||||
@@ -245,41 +242,73 @@ public class ArchiveAnalyzer extends AbstractFileTypeAnalyzer {
|
||||
}
|
||||
}
|
||||
if (REMOVE_FROM_ANALYSIS.accept(dependency.getActualFile())) {
|
||||
if (ZIP_FILTER.accept(dependency.getActualFile()) && 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) {
|
||||
LOGGER.debug("Unable to perform deep copy on '{}'", dependency.getActualFile().getPath(), ex);
|
||||
}
|
||||
}
|
||||
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.
|
||||
*
|
||||
@@ -309,41 +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.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);
|
||||
}
|
||||
}
|
||||
} catch (ArchiveExtractionException ex) {
|
||||
LOGGER.warn("Exception extracting archive '{}'.", archive.getName());
|
||||
LOGGER.debug("", ex);
|
||||
} catch (IOException ex) {
|
||||
LOGGER.warn("Exception reading archive '{}'.", archive.getName());
|
||||
LOGGER.debug("", ex);
|
||||
} finally {
|
||||
if (archive != null && destination != null) {
|
||||
FileInputStream fis;
|
||||
try {
|
||||
fis.close();
|
||||
} catch (IOException ex) {
|
||||
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.warn("Exception reading archive '{}'.", archive.getName());
|
||||
LOGGER.debug("", ex);
|
||||
} finally {
|
||||
close(fis);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -360,75 +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());
|
||||
if (engine.accept(file)) {
|
||||
LOGGER.debug("Extracting '{}'", file.getPath());
|
||||
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.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 {
|
||||
if (bos != null) {
|
||||
try {
|
||||
bos.close();
|
||||
} catch (IOException ex) {
|
||||
LOGGER.trace("", ex);
|
||||
}
|
||||
}
|
||||
if (fos != null) {
|
||||
try {
|
||||
fos.close();
|
||||
} catch (IOException ex) {
|
||||
LOGGER.trace("", 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.trace("", 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);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -444,11 +449,7 @@ public class ArchiveAnalyzer extends AbstractFileTypeAnalyzer {
|
||||
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.debug("", ex);
|
||||
throw new ArchiveExtractionException(ex);
|
||||
@@ -456,12 +457,21 @@ public class ArchiveAnalyzer extends AbstractFileTypeAnalyzer {
|
||||
LOGGER.debug("", ex);
|
||||
throw new ArchiveExtractionException(ex);
|
||||
} finally {
|
||||
if (out != null) {
|
||||
try {
|
||||
out.close();
|
||||
} catch (IOException ex) {
|
||||
LOGGER.trace("", 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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -17,15 +17,13 @@
|
||||
*/
|
||||
package org.owasp.dependencycheck.analyzer;
|
||||
|
||||
import ch.qos.cal10n.IMessageConveyor;
|
||||
import ch.qos.cal10n.MessageConveyor;
|
||||
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 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;
|
||||
@@ -45,7 +43,6 @@ import javax.xml.xpath.XPathExpressionException;
|
||||
import javax.xml.xpath.XPathFactory;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.Locale;
|
||||
|
||||
/**
|
||||
* Analyzer for getting company, product, and version information from a .NET assembly.
|
||||
@@ -75,10 +72,6 @@ public class AssemblyAnalyzer extends AbstractFileTypeAnalyzer {
|
||||
* The DocumentBuilder for parsing the XML
|
||||
*/
|
||||
private DocumentBuilder builder;
|
||||
/**
|
||||
* Message Conveyer
|
||||
*/
|
||||
private static final IMessageConveyor MESSAGE_CONVERYOR = new MessageConveyor(Locale.getDefault());
|
||||
/**
|
||||
* Logger
|
||||
*/
|
||||
@@ -122,21 +115,19 @@ public class AssemblyAnalyzer extends AbstractFileTypeAnalyzer {
|
||||
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.warn("Error from GrokAssembly: {}", 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) {
|
||||
@@ -154,7 +145,7 @@ public class AssemblyAnalyzer extends AbstractFileTypeAnalyzer {
|
||||
|
||||
// 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);
|
||||
}
|
||||
|
||||
@@ -183,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.debug("ignore", ex);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -207,11 +190,8 @@ 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();
|
||||
@@ -239,45 +219,30 @@ public class AssemblyAnalyzer extends AbstractFileTypeAnalyzer {
|
||||
|
||||
// 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)) {
|
||||
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.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 occured with the .NET AssemblyAnalyzer", e);
|
||||
}
|
||||
} finally {
|
||||
if (rdr != null) {
|
||||
try {
|
||||
rdr.close();
|
||||
} catch (IOException ex) {
|
||||
LOGGER.trace("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();
|
||||
}
|
||||
|
||||
@@ -30,6 +30,7 @@ import org.owasp.dependencycheck.utils.UrlStringUtils;
|
||||
import java.io.File;
|
||||
import java.io.FileFilter;
|
||||
import java.io.IOException;
|
||||
import java.nio.charset.Charset;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.regex.Matcher;
|
||||
@@ -39,9 +40,10 @@ import java.util.regex.Pattern;
|
||||
* Used to analyze Autoconf input files named configure.ac or configure.in. Files simply named "configure" are also analyzed,
|
||||
* assuming they are generated by Autoconf, and contain certain special package descriptor variables.
|
||||
*
|
||||
* @author Dale Visser <dvisser@ida.org>
|
||||
* @author Dale Visser
|
||||
* @see <a href="https://www.gnu.org/software/autoconf/">Autoconf - GNU Project - Free Software Foundation (FSF)</a>
|
||||
*/
|
||||
@Experimental
|
||||
public class AutoconfAnalyzer extends AbstractFileTypeAnalyzer {
|
||||
|
||||
/**
|
||||
@@ -173,10 +175,10 @@ public class AutoconfAnalyzer extends AbstractFileTypeAnalyzer {
|
||||
}
|
||||
} else {
|
||||
// copy, alter and set in case some other thread is iterating over
|
||||
final List<Dependency> deps = new ArrayList<Dependency>(
|
||||
final List<Dependency> dependencies = new ArrayList<Dependency>(
|
||||
engine.getDependencies());
|
||||
deps.remove(dependency);
|
||||
engine.setDependencies(deps);
|
||||
dependencies.remove(dependency);
|
||||
engine.setDependencies(dependencies);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -220,14 +222,12 @@ public class AutoconfAnalyzer extends AbstractFileTypeAnalyzer {
|
||||
*/
|
||||
private String getFileContents(final File actualFile)
|
||||
throws AnalysisException {
|
||||
String contents = "";
|
||||
try {
|
||||
contents = FileUtils.readFileToString(actualFile).trim();
|
||||
return FileUtils.readFileToString(actualFile, Charset.defaultCharset()).trim();
|
||||
} catch (IOException e) {
|
||||
throw new AnalysisException(
|
||||
"Problem occured while reading dependency file.", e);
|
||||
"Problem occurred while reading dependency file.", e);
|
||||
}
|
||||
return contents;
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -18,7 +18,7 @@
|
||||
package org.owasp.dependencycheck.analyzer;
|
||||
|
||||
import org.apache.commons.io.FileUtils;
|
||||
import org.apache.commons.lang.StringUtils;
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
import org.owasp.dependencycheck.Engine;
|
||||
import org.owasp.dependencycheck.analyzer.exception.AnalysisException;
|
||||
import org.owasp.dependencycheck.dependency.Confidence;
|
||||
@@ -32,6 +32,8 @@ import org.slf4j.LoggerFactory;
|
||||
import java.io.File;
|
||||
import java.io.FileFilter;
|
||||
import java.io.IOException;
|
||||
import java.io.UnsupportedEncodingException;
|
||||
import java.nio.charset.Charset;
|
||||
import java.security.MessageDigest;
|
||||
import java.security.NoSuchAlgorithmException;
|
||||
import java.util.regex.Matcher;
|
||||
@@ -40,15 +42,15 @@ import java.util.regex.Pattern;
|
||||
/**
|
||||
* <p>
|
||||
* Used to analyze CMake build files, and collect information that can be used to determine the associated CPE.</p>
|
||||
* <p/>
|
||||
* <p>
|
||||
* Note: This analyzer catches straightforward invocations of the project command, plus some other observed patterns of version
|
||||
* inclusion in real CMake projects. Many projects make use of older versions of CMake and/or use custom "homebrew" ways to insert
|
||||
* version information. Hopefully as the newer CMake call pattern grows in usage, this analyzer allow more CPEs to be
|
||||
* identified.</p>
|
||||
*
|
||||
* @author Dale Visser <dvisser@ida.org>
|
||||
* @author Dale Visser
|
||||
*/
|
||||
@Experimental
|
||||
public class CMakeAnalyzer extends AbstractFileTypeAnalyzer {
|
||||
|
||||
/**
|
||||
@@ -62,11 +64,19 @@ public class CMakeAnalyzer extends AbstractFileTypeAnalyzer {
|
||||
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);
|
||||
|
||||
// Group 1: Product
|
||||
// Group 2: Version
|
||||
/**
|
||||
* 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\"]?\\)",
|
||||
@@ -148,7 +158,7 @@ public class CMakeAnalyzer extends AbstractFileTypeAnalyzer {
|
||||
dependency.setDisplayFileName(String.format("%s%c%s", parentName, File.separatorChar, name));
|
||||
String contents;
|
||||
try {
|
||||
contents = FileUtils.readFileToString(file).trim();
|
||||
contents = FileUtils.readFileToString(file, Charset.defaultCharset()).trim();
|
||||
} catch (IOException e) {
|
||||
throw new AnalysisException(
|
||||
"Problem occurred while reading dependency file.", e);
|
||||
@@ -167,20 +177,28 @@ public class CMakeAnalyzer extends AbstractFileTypeAnalyzer {
|
||||
dependency.getProductEvidence().addEvidence(name, "Project",
|
||||
group, Confidence.HIGH);
|
||||
}
|
||||
LOGGER.debug(String.format("Found %d matches.", count));
|
||||
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) {
|
||||
final Dependency orig = dependency;
|
||||
Dependency currentDep = dependency;
|
||||
|
||||
final Matcher m = SET_VERSION.matcher(contents);
|
||||
int count = 0;
|
||||
while (m.find()) {
|
||||
count++;
|
||||
LOGGER.debug(String.format(
|
||||
"Found project command match with %d groups: %s",
|
||||
m.groupCount(), m.group(0)));
|
||||
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);
|
||||
@@ -191,19 +209,24 @@ public class CMakeAnalyzer extends AbstractFileTypeAnalyzer {
|
||||
}
|
||||
if (count > 1) {
|
||||
//TODO - refactor so we do not assign to the parameter (checkstyle)
|
||||
dependency = new Dependency(orig.getActualFile());
|
||||
dependency.setDisplayFileName(String.format("%s:%s", orig.getDisplayFileName(), product));
|
||||
final String filePath = String.format("%s:%s", orig.getFilePath(), product);
|
||||
dependency.setFilePath(filePath);
|
||||
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);
|
||||
|
||||
// prevents coalescing into the dependency provided by engine
|
||||
dependency.setSha1sum(Checksum.getHex(sha1.digest(filePath.getBytes())));
|
||||
engine.getDependencies().add(dependency);
|
||||
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 = dependency.getDisplayFileName();
|
||||
dependency.getProductEvidence().addEvidence(source, "Product",
|
||||
final String source = currentDep.getDisplayFileName();
|
||||
currentDep.getProductEvidence().addEvidence(source, "Product",
|
||||
product, Confidence.MEDIUM);
|
||||
dependency.getVersionEvidence().addEvidence(source, "Version",
|
||||
currentDep.getVersionEvidence().addEvidence(source, "Version",
|
||||
version, Confidence.MEDIUM);
|
||||
}
|
||||
LOGGER.debug(String.format("Found %d matches.", count));
|
||||
|
||||
@@ -51,8 +51,9 @@ 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.
|
||||
* 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
|
||||
*/
|
||||
@@ -71,15 +72,18 @@ public class CPEAnalyzer implements Analyzer {
|
||||
*/
|
||||
static final String WEIGHTING_BOOST = "^5";
|
||||
/**
|
||||
* A string representation of a regular expression defining characters utilized within the CPE Names.
|
||||
* A string representation of a regular expression defining characters
|
||||
* utilized within the CPE Names.
|
||||
*/
|
||||
static final String CLEANSE_CHARACTER_RX = "[^A-Za-z0-9 ._-]";
|
||||
/**
|
||||
* A string representation of a regular expression used to remove all but alpha characters.
|
||||
* A string representation of a regular expression used to remove all but
|
||||
* alpha characters.
|
||||
*/
|
||||
static final String CLEANSE_NONALPHA_RX = "[^A-Za-z]*";
|
||||
/**
|
||||
* The additional size to add to a new StringBuilder to account for extra data that will be written into the string.
|
||||
* The additional size to add to a new StringBuilder to account for extra
|
||||
* data that will be written into the string.
|
||||
*/
|
||||
static final int STRING_BUILDER_BUFFER = 20;
|
||||
/**
|
||||
@@ -129,21 +133,25 @@ public class CPEAnalyzer implements Analyzer {
|
||||
/**
|
||||
* Opens the data source.
|
||||
*
|
||||
* @throws IOException when the Lucene directory to be queried does not exist or is corrupt.
|
||||
* @throws DatabaseException when the database throws an exception. This usually occurs when the database is in use by another
|
||||
* process.
|
||||
* @throws IOException when the Lucene directory to be queried does not
|
||||
* exist or is corrupt.
|
||||
* @throws DatabaseException when the database throws an exception. This
|
||||
* usually occurs when the database is in use by another process.
|
||||
*/
|
||||
public void open() throws IOException, DatabaseException {
|
||||
LOGGER.debug("Opening the CVE Database");
|
||||
cve = new CveDB();
|
||||
cve.open();
|
||||
LOGGER.debug("Creating the Lucene CPE Index");
|
||||
cpe = CpeMemoryIndex.getInstance();
|
||||
try {
|
||||
cpe.open(cve);
|
||||
} catch (IndexException ex) {
|
||||
LOGGER.debug("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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -167,8 +175,9 @@ public class CPEAnalyzer implements Analyzer {
|
||||
}
|
||||
|
||||
/**
|
||||
* Searches the data store of CPE entries, trying to identify the CPE for the given dependency based on the evidence contained
|
||||
* within. The dependency passed in is updated with any identified CPE values.
|
||||
* Searches the data store of CPE entries, trying to identify the CPE for
|
||||
* the given dependency based on the evidence contained within. The
|
||||
* dependency passed in is updated with any identified CPE values.
|
||||
*
|
||||
* @param dependency the dependency to search for CPE entries on.
|
||||
* @throws CorruptIndexException is thrown when the Lucene index is corrupt.
|
||||
@@ -189,8 +198,8 @@ public class CPEAnalyzer implements Analyzer {
|
||||
LOGGER.debug("product search: {}", products);
|
||||
}
|
||||
if (!vendors.isEmpty() && !products.isEmpty()) {
|
||||
final List<IndexEntry> entries = searchCPE(vendors, products, dependency.getProductEvidence().getWeighting(),
|
||||
dependency.getVendorEvidence().getWeighting());
|
||||
final List<IndexEntry> entries = searchCPE(vendors, products, dependency.getVendorEvidence().getWeighting(),
|
||||
dependency.getProductEvidence().getWeighting());
|
||||
if (entries == null) {
|
||||
continue;
|
||||
}
|
||||
@@ -212,9 +221,10 @@ public class CPEAnalyzer implements Analyzer {
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the text created by concatenating the text and the values from the EvidenceCollection (filtered for a specific
|
||||
* confidence). This attempts to prevent duplicate terms from being added.<br/<br/> Note, if the evidence is longer then 200
|
||||
* characters it will be truncated.
|
||||
* Returns the text created by concatenating the text and the values from
|
||||
* the EvidenceCollection (filtered for a specific confidence). This
|
||||
* attempts to prevent duplicate terms from being added.<br/<br/> Note, if
|
||||
* the evidence is longer then 200 characters it will be truncated.
|
||||
*
|
||||
* @param text the base text.
|
||||
* @param ec an EvidenceCollection
|
||||
@@ -245,17 +255,19 @@ public class CPEAnalyzer implements Analyzer {
|
||||
|
||||
/**
|
||||
* <p>
|
||||
* Searches the Lucene CPE index to identify possible CPE entries associated with the supplied vendor, product, and
|
||||
* version.</p>
|
||||
* Searches the Lucene CPE index to identify possible CPE entries associated
|
||||
* with the supplied vendor, product, and version.</p>
|
||||
*
|
||||
* <p>
|
||||
* If either the vendorWeightings or productWeightings lists have been populated this data is used to add weighting factors to
|
||||
* the search.</p>
|
||||
* If either the vendorWeightings or productWeightings lists have been
|
||||
* populated this data is used to add weighting factors to the search.</p>
|
||||
*
|
||||
* @param vendor the text used to search the vendor field
|
||||
* @param product the text used to search the product field
|
||||
* @param vendorWeightings a list of strings to use to add weighting factors to the vendor field
|
||||
* @param productWeightings Adds a list of strings that will be used to add weighting factors to the product search
|
||||
* @param vendorWeightings a list of strings to use to add weighting factors
|
||||
* to the vendor field
|
||||
* @param productWeightings Adds a list of strings that will be used to add
|
||||
* weighting factors to the product search
|
||||
* @return a list of possible CPE values
|
||||
*/
|
||||
protected List<IndexEntry> searchCPE(String vendor, String product,
|
||||
@@ -283,10 +295,10 @@ public class CPEAnalyzer implements Analyzer {
|
||||
}
|
||||
return ret;
|
||||
} catch (ParseException ex) {
|
||||
LOGGER.warn("An error occured querying the CPE data. See the log for more details.");
|
||||
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) {
|
||||
LOGGER.warn("An error occured reading CPE data. See the log for more details.");
|
||||
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;
|
||||
@@ -294,16 +306,20 @@ public class CPEAnalyzer implements Analyzer {
|
||||
|
||||
/**
|
||||
* <p>
|
||||
* Builds a Lucene search string by properly escaping data and constructing a valid search query.</p>
|
||||
* Builds a Lucene search string by properly escaping data and constructing
|
||||
* a valid search query.</p>
|
||||
*
|
||||
* <p>
|
||||
* If either the possibleVendor or possibleProducts lists have been populated this data is used to add weighting factors to
|
||||
* the search string generated.</p>
|
||||
* If either the possibleVendor or possibleProducts lists have been
|
||||
* populated this data is used to add weighting factors to the search string
|
||||
* generated.</p>
|
||||
*
|
||||
* @param vendor text to search the vendor field
|
||||
* @param product text to search the product field
|
||||
* @param vendorWeighting a list of strings to apply to the vendor to boost the terms weight
|
||||
* @param productWeightings a list of strings to apply to the product to boost the terms weight
|
||||
* @param vendorWeighting a list of strings to apply to the vendor to boost
|
||||
* the terms weight
|
||||
* @param productWeightings a list of strings to apply to the product to
|
||||
* boost the terms weight
|
||||
* @return the Lucene query
|
||||
*/
|
||||
protected String buildSearch(String vendor, String product,
|
||||
@@ -324,21 +340,25 @@ public class CPEAnalyzer implements Analyzer {
|
||||
}
|
||||
|
||||
/**
|
||||
* This method constructs a Lucene query for a given field. The searchText is split into separate words and if the word is
|
||||
* within the list of weighted words then an additional weighting is applied to the term as it is appended into the query.
|
||||
* This method constructs a Lucene query for a given field. The searchText
|
||||
* is split into separate words and if the word is within the list of
|
||||
* weighted words then an additional weighting is applied to the term as it
|
||||
* is appended into the query.
|
||||
*
|
||||
* @param sb a StringBuilder that the query text will be appended to.
|
||||
* @param field the field within the Lucene index that the query is searching.
|
||||
* @param field the field within the Lucene index that the query is
|
||||
* searching.
|
||||
* @param searchText text used to construct the query.
|
||||
* @param weightedText a list of terms that will be considered higher importance when searching.
|
||||
* @param weightedText a list of terms that will be considered higher
|
||||
* importance when searching.
|
||||
* @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;
|
||||
}
|
||||
|
||||
@@ -348,20 +368,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(" ) ");
|
||||
@@ -369,7 +396,8 @@ public class CPEAnalyzer implements Analyzer {
|
||||
}
|
||||
|
||||
/**
|
||||
* Removes characters from the input text that are not used within the CPE index.
|
||||
* Removes characters from the input text that are not used within the CPE
|
||||
* index.
|
||||
*
|
||||
* @param text is the text to remove the characters from.
|
||||
* @return the text having removed some characters.
|
||||
@@ -379,7 +407,8 @@ public class CPEAnalyzer implements Analyzer {
|
||||
}
|
||||
|
||||
/**
|
||||
* Compares two strings after lower casing them and removing the non-alpha characters.
|
||||
* Compares two strings after lower casing them and removing the non-alpha
|
||||
* characters.
|
||||
*
|
||||
* @param l string one to compare.
|
||||
* @param r string two to compare.
|
||||
@@ -396,8 +425,9 @@ public class CPEAnalyzer implements Analyzer {
|
||||
}
|
||||
|
||||
/**
|
||||
* Ensures that the CPE Identified matches the dependency. This validates that the product, vendor, and version information
|
||||
* for the CPE are contained within the dependencies evidence.
|
||||
* Ensures that the CPE Identified matches the dependency. This validates
|
||||
* that the product, vendor, and version information for the CPE are
|
||||
* contained within the dependencies evidence.
|
||||
*
|
||||
* @param entry a CPE entry.
|
||||
* @param dependency the dependency that the CPE entries could be for.
|
||||
@@ -464,14 +494,16 @@ public class CPEAnalyzer implements Analyzer {
|
||||
}
|
||||
|
||||
/**
|
||||
* Analyzes a dependency and attempts to determine if there are any CPE identifiers for this dependency.
|
||||
* Analyzes a dependency and attempts to determine if there are any CPE
|
||||
* identifiers for this dependency.
|
||||
*
|
||||
* @param dependency The Dependency to analyze.
|
||||
* @param engine The analysis engine
|
||||
* @throws AnalysisException is thrown if there is an issue analyzing the dependency.
|
||||
* @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) {
|
||||
@@ -484,15 +516,19 @@ public class CPEAnalyzer implements Analyzer {
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieves a list of CPE values from the CveDB based on the vendor and product passed in. The list is then validated to find
|
||||
* only CPEs that are valid for the given dependency. It is possible that the CPE identified is a best effort "guess" based on
|
||||
* the vendor, product, and version information.
|
||||
* Retrieves a list of CPE values from the CveDB based on the vendor and
|
||||
* product passed in. The list is then validated to find only CPEs that are
|
||||
* valid for the given dependency. It is possible that the CPE identified is
|
||||
* a best effort "guess" based on the vendor, product, and version
|
||||
* information.
|
||||
*
|
||||
* @param dependency the Dependency being analyzed
|
||||
* @param vendor the vendor for the CPE being analyzed
|
||||
* @param product the product for the CPE being analyzed
|
||||
* @param currentConfidence the current confidence being used during analysis
|
||||
* @return <code>true</code> if an identifier was added to the dependency; otherwise <code>false</code>
|
||||
* @param currentConfidence the current confidence being used during
|
||||
* analysis
|
||||
* @return <code>true</code> if an identifier was added to the dependency;
|
||||
* otherwise <code>false</code>
|
||||
* @throws UnsupportedEncodingException is thrown if UTF-8 is not supported
|
||||
*/
|
||||
protected boolean determineIdentifiers(Dependency dependency, String vendor, String product,
|
||||
@@ -502,10 +538,11 @@ public class CPEAnalyzer implements Analyzer {
|
||||
Confidence bestGuessConf = null;
|
||||
boolean hasBroadMatch = false;
|
||||
final List<IdentifierMatch> collected = new ArrayList<IdentifierMatch>();
|
||||
|
||||
//TODO the following algorithm incorrectly identifies things as a lower version
|
||||
// if there lower confidence evidence when the current (highest) version number
|
||||
// is newer then anything in the NVD.
|
||||
for (Confidence conf : Confidence.values()) {
|
||||
// if (conf.compareTo(currentConfidence) > 0) {
|
||||
// break;
|
||||
// }
|
||||
for (Evidence evidence : dependency.getVersionEvidence().iterator(conf)) {
|
||||
final DependencyVersion evVer = DependencyVersionUtil.parseVersion(evidence.getValue());
|
||||
if (evVer == null) {
|
||||
@@ -514,7 +551,7 @@ public class CPEAnalyzer implements Analyzer {
|
||||
for (VulnerableSoftware vs : cpes) {
|
||||
DependencyVersion dbVer;
|
||||
if (vs.getUpdate() != null && !vs.getUpdate().isEmpty()) {
|
||||
dbVer = DependencyVersionUtil.parseVersion(vs.getVersion() + "." + vs.getUpdate());
|
||||
dbVer = DependencyVersionUtil.parseVersion(vs.getVersion() + '.' + vs.getUpdate());
|
||||
} else {
|
||||
dbVer = DependencyVersionUtil.parseVersion(vs.getVersion());
|
||||
}
|
||||
@@ -527,15 +564,13 @@ public class CPEAnalyzer implements Analyzer {
|
||||
final String url = String.format(NVD_SEARCH_URL, URLEncoder.encode(vs.getName(), "UTF-8"));
|
||||
final IdentifierMatch match = new IdentifierMatch("cpe", vs.getName(), url, IdentifierConfidence.EXACT_MATCH, conf);
|
||||
collected.add(match);
|
||||
} else {
|
||||
//TODO the following isn't quite right is it? need to think about this guessing game a bit more.
|
||||
if (evVer.getVersionParts().size() <= dbVer.getVersionParts().size()
|
||||
&& evVer.matchesAtLeastThreeLevels(dbVer)) {
|
||||
if (bestGuessConf == null || bestGuessConf.compareTo(conf) > 0) {
|
||||
if (bestGuess.getVersionParts().size() < dbVer.getVersionParts().size()) {
|
||||
bestGuess = dbVer;
|
||||
bestGuessConf = conf;
|
||||
}
|
||||
} else //TODO the following isn't quite right is it? need to think about this guessing game a bit more.
|
||||
if (evVer.getVersionParts().size() <= dbVer.getVersionParts().size()
|
||||
&& evVer.matchesAtLeastThreeLevels(dbVer)) {
|
||||
if (bestGuessConf == null || bestGuessConf.compareTo(conf) > 0) {
|
||||
if (bestGuess.getVersionParts().size() < dbVer.getVersionParts().size()) {
|
||||
bestGuess = dbVer;
|
||||
bestGuessConf = conf;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -594,14 +629,16 @@ public class CPEAnalyzer implements Analyzer {
|
||||
*/
|
||||
BEST_GUESS,
|
||||
/**
|
||||
* The entire vendor/product group must be added (without a guess at version) because there is a CVE with a VS that only
|
||||
* specifies vendor/product.
|
||||
* The entire vendor/product group must be added (without a guess at
|
||||
* version) because there is a CVE with a VS that only specifies
|
||||
* vendor/product.
|
||||
*/
|
||||
BROAD_MATCH
|
||||
}
|
||||
|
||||
/**
|
||||
* A simple object to hold an identifier and carry information about the confidence in the identifier.
|
||||
* A simple object to hold an identifier and carry information about the
|
||||
* confidence in the identifier.
|
||||
*/
|
||||
private static class IdentifierMatch implements Comparable<IdentifierMatch> {
|
||||
|
||||
@@ -611,8 +648,10 @@ public class CPEAnalyzer implements Analyzer {
|
||||
* @param type the type of identifier (such as CPE)
|
||||
* @param value the value of the identifier
|
||||
* @param url the URL of the identifier
|
||||
* @param identifierConfidence the confidence in the identifier: best guess or exact match
|
||||
* @param evidenceConfidence the confidence of the evidence used to find the identifier
|
||||
* @param identifierConfidence the confidence in the identifier: best
|
||||
* guess or exact match
|
||||
* @param evidenceConfidence the confidence of the evidence used to find
|
||||
* the identifier
|
||||
*/
|
||||
IdentifierMatch(String type, String value, String url, IdentifierConfidence identifierConfidence, Confidence evidenceConfidence) {
|
||||
this.identifier = new Identifier(type, value, url);
|
||||
@@ -743,7 +782,8 @@ public class CPEAnalyzer implements Analyzer {
|
||||
//</editor-fold>
|
||||
|
||||
/**
|
||||
* Standard implementation of compareTo that compares identifier confidence, evidence confidence, and then the identifier.
|
||||
* Standard implementation of compareTo that compares identifier
|
||||
* confidence, evidence confidence, and then the identifier.
|
||||
*
|
||||
* @param o the IdentifierMatch to compare to
|
||||
* @return the natural ordering of IdentifierMatch
|
||||
|
||||
@@ -192,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.debug("Central analyzer found artifact ({}) for dependency ({})", 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()) {
|
||||
|
||||
@@ -0,0 +1,163 @@
|
||||
/*
|
||||
* 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
|
||||
*/
|
||||
@Experimental
|
||||
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;
|
||||
}
|
||||
}
|
||||
@@ -35,11 +35,14 @@ import org.slf4j.LoggerFactory;
|
||||
|
||||
/**
|
||||
* <p>
|
||||
* This analyzer ensures dependencies that should be grouped together, to remove excess noise from the report, are grouped. An
|
||||
* example would be Spring, Spring Beans, Spring MVC, etc. If they are all for the same version and have the same relative path
|
||||
* then these should be grouped into a single dependency under the core/main library.</p>
|
||||
* This analyzer ensures dependencies that should be grouped together, to remove
|
||||
* excess noise from the report, are grouped. An example would be Spring, Spring
|
||||
* Beans, Spring MVC, etc. If they are all for the same version and have the
|
||||
* same relative path then these should be grouped into a single dependency
|
||||
* under the core/main library.</p>
|
||||
* <p>
|
||||
* Note, this grouping only works on dependencies with identified CVE entries</p>
|
||||
* Note, this grouping only works on dependencies with identified CVE
|
||||
* entries</p>
|
||||
*
|
||||
* @author Jeremy Long
|
||||
*/
|
||||
@@ -75,6 +78,7 @@ public class DependencyBundlingAnalyzer extends AbstractAnalyzer implements Anal
|
||||
*
|
||||
* @return the name of the analyzer.
|
||||
*/
|
||||
@Override
|
||||
public String getName() {
|
||||
return ANALYZER_NAME;
|
||||
}
|
||||
@@ -84,18 +88,21 @@ 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;
|
||||
}
|
||||
//</editor-fold>
|
||||
|
||||
/**
|
||||
* Analyzes a set of dependencies. If they have been found to have the same base path and the same set of identifiers they are
|
||||
* likely related. The related dependencies are bundled into a single reportable item.
|
||||
* Analyzes a set of dependencies. If they have been found to have the same
|
||||
* base path and the same set of identifiers they are likely related. The
|
||||
* related dependencies are bundled into a single reportable item.
|
||||
*
|
||||
* @param ignore this analyzer ignores the dependency being analyzed
|
||||
* @param engine the engine that is scanning the dependencies
|
||||
* @throws AnalysisException is thrown if there is an error reading the JAR file.
|
||||
* @throws AnalysisException is thrown if there is an error reading the JAR
|
||||
* file.
|
||||
*/
|
||||
@Override
|
||||
public void analyze(Dependency ignore, Engine engine) throws AnalysisException {
|
||||
@@ -136,6 +143,14 @@ public class DependencyBundlingAnalyzer extends AbstractAnalyzer implements Anal
|
||||
mergeDependencies(nextDependency, dependency, dependenciesToRemove);
|
||||
break; //since we merged into the next dependency - skip forward to the next in mainIterator
|
||||
}
|
||||
} else if (isSameRubyGem(dependency, nextDependency)) {
|
||||
final Dependency main = getMainGemspecDependency(dependency, nextDependency);
|
||||
if (main == dependency) {
|
||||
mergeDependencies(dependency, nextDependency, dependenciesToRemove);
|
||||
} else {
|
||||
mergeDependencies(nextDependency, dependency, dependenciesToRemove);
|
||||
break; //since we merged into the next dependency - skip forward to the next in mainIterator
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -150,10 +165,11 @@ public class DependencyBundlingAnalyzer extends AbstractAnalyzer implements Anal
|
||||
* Adds the relatedDependency to the dependency's related dependencies.
|
||||
*
|
||||
* @param dependency the main dependency
|
||||
* @param relatedDependency a collection of dependencies to be removed from the main analysis loop, this is the source of
|
||||
* dependencies to remove
|
||||
* @param dependenciesToRemove a collection of dependencies that will be removed from the main analysis loop, this function
|
||||
* adds to this collection
|
||||
* @param relatedDependency a collection of dependencies to be removed from
|
||||
* the main analysis loop, this is the source of dependencies to remove
|
||||
* @param dependenciesToRemove a collection of dependencies that will be
|
||||
* removed from the main analysis loop, this function adds to this
|
||||
* collection
|
||||
*/
|
||||
private void mergeDependencies(final Dependency dependency, final Dependency relatedDependency, final Set<Dependency> dependenciesToRemove) {
|
||||
dependency.addRelatedDependency(relatedDependency);
|
||||
@@ -169,7 +185,8 @@ public class DependencyBundlingAnalyzer extends AbstractAnalyzer implements Anal
|
||||
}
|
||||
|
||||
/**
|
||||
* Attempts to trim a maven repo to a common base path. This is typically [drive]\[repo_location]\repository\[path1]\[path2].
|
||||
* Attempts to trim a maven repo to a common base path. This is typically
|
||||
* [drive]\[repo_location]\repository\[path1]\[path2].
|
||||
*
|
||||
* @param path the path to trim
|
||||
* @return a string representing the base path.
|
||||
@@ -194,11 +211,13 @@ public class DependencyBundlingAnalyzer extends AbstractAnalyzer implements Anal
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns true if the file names (and version if it exists) of the two dependencies are sufficiently similar.
|
||||
* Returns true if the file names (and version if it exists) of the two
|
||||
* dependencies are sufficiently similar.
|
||||
*
|
||||
* @param dependency1 a dependency2 to compare
|
||||
* @param dependency2 a dependency2 to compare
|
||||
* @return true if the identifiers in the two supplied dependencies are equal
|
||||
* @return true if the identifiers in the two supplied dependencies are
|
||||
* equal
|
||||
*/
|
||||
private boolean fileNameMatch(Dependency dependency1, Dependency dependency2) {
|
||||
if (dependency1 == null || dependency1.getFileName() == null
|
||||
@@ -211,10 +230,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
|
||||
@@ -228,11 +245,13 @@ public class DependencyBundlingAnalyzer extends AbstractAnalyzer implements Anal
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns true if the CPE identifiers in the two supplied dependencies are equal.
|
||||
* Returns true if the CPE identifiers in the two supplied dependencies are
|
||||
* equal.
|
||||
*
|
||||
* @param dependency1 a dependency2 to compare
|
||||
* @param dependency2 a dependency2 to compare
|
||||
* @return true if the identifiers in the two supplied dependencies are equal
|
||||
* @return true if the identifiers in the two supplied dependencies are
|
||||
* equal
|
||||
*/
|
||||
private boolean cpeIdentifiersMatch(Dependency dependency1, Dependency dependency2) {
|
||||
if (dependency1 == null || dependency1.getIdentifiers() == null
|
||||
@@ -304,12 +323,67 @@ public class DependencyBundlingAnalyzer extends AbstractAnalyzer implements Anal
|
||||
}
|
||||
|
||||
/**
|
||||
* This is likely a very broken attempt at determining if the 'left' dependency is the 'core' library in comparison to the
|
||||
* 'right' library.
|
||||
* Bundling Ruby gems that are identified from different .gemspec files but
|
||||
* denote the same package path. This happens when Ruby bundler installs an
|
||||
* application's dependencies by running "bundle install".
|
||||
*
|
||||
* @param dependency1 dependency to compare
|
||||
* @param dependency2 dependency to compare
|
||||
* @return true if the the dependencies being analyzed appear to be the
|
||||
* same; otherwise false
|
||||
*/
|
||||
private boolean isSameRubyGem(Dependency dependency1, Dependency dependency2) {
|
||||
if (dependency1 == null || dependency2 == null
|
||||
|| !dependency1.getFileName().endsWith(".gemspec")
|
||||
|| !dependency2.getFileName().endsWith(".gemspec")
|
||||
|| dependency1.getPackagePath() == null
|
||||
|| dependency2.getPackagePath() == null) {
|
||||
return false;
|
||||
}
|
||||
if (dependency1.getPackagePath().equalsIgnoreCase(dependency2.getPackagePath())) {
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Ruby gems installed by "bundle install" can have zero or more *.gemspec
|
||||
* files, all of which have the same packagePath and should be grouped. If
|
||||
* one of these gemspec is from <parent>/specifications/*.gemspec, because
|
||||
* it is a stub with fully resolved gem meta-data created by Ruby bundler,
|
||||
* this dependency should be the main one. Otherwise, use dependency2 as
|
||||
* main.
|
||||
*
|
||||
* This method returns null if any dependency is not from *.gemspec, or the
|
||||
* two do not have the same packagePath. In this case, they should not be
|
||||
* grouped.
|
||||
*
|
||||
* @param dependency1 dependency to compare
|
||||
* @param dependency2 dependency to compare
|
||||
* @return the main dependency; or null if a gemspec is not included in the
|
||||
* analysis
|
||||
*/
|
||||
private Dependency getMainGemspecDependency(Dependency dependency1, Dependency dependency2) {
|
||||
if (isSameRubyGem(dependency1, dependency2)) {
|
||||
final File lFile = dependency1.getActualFile();
|
||||
final File left = lFile.getParentFile();
|
||||
if (left != null && left.getName().equalsIgnoreCase("specifications")) {
|
||||
return dependency1;
|
||||
}
|
||||
return dependency2;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* This is likely a very broken attempt at determining if the 'left'
|
||||
* dependency is the 'core' library in comparison to the 'right' library.
|
||||
*
|
||||
* @param left the dependency to test
|
||||
* @param right the dependency to test against
|
||||
* @return a boolean indicating whether or not the left dependency should be considered the "core" version.
|
||||
* @return a boolean indicating whether or not the left dependency should be
|
||||
* considered the "core" version.
|
||||
*/
|
||||
boolean isCore(Dependency left, Dependency right) {
|
||||
final String leftName = left.getFileName().toLowerCase();
|
||||
@@ -345,11 +419,13 @@ public class DependencyBundlingAnalyzer extends AbstractAnalyzer implements Anal
|
||||
}
|
||||
|
||||
/**
|
||||
* Compares the SHA1 hashes of two dependencies to determine if they are equal.
|
||||
* Compares the SHA1 hashes of two dependencies to determine if they are
|
||||
* equal.
|
||||
*
|
||||
* @param dependency1 a dependency object to compare
|
||||
* @param dependency2 a dependency object to compare
|
||||
* @return true if the sha1 hashes of the two dependencies match; otherwise false
|
||||
* @return true if the sha1 hashes of the two dependencies match; otherwise
|
||||
* false
|
||||
*/
|
||||
private boolean hashesMatch(Dependency dependency1, Dependency dependency2) {
|
||||
if (dependency1 == null || dependency2 == null || dependency1.getSha1sum() == null || dependency2.getSha1sum() == null) {
|
||||
@@ -359,12 +435,13 @@ public class DependencyBundlingAnalyzer extends AbstractAnalyzer implements Anal
|
||||
}
|
||||
|
||||
/**
|
||||
* Determines if the jar is shaded and the created pom.xml identified the same CPE as the jar - if so, the pom.xml dependency
|
||||
* should be removed.
|
||||
* Determines if the jar is shaded and the created pom.xml identified the
|
||||
* same CPE as the jar - if so, the pom.xml dependency should be removed.
|
||||
*
|
||||
* @param dependency a dependency to check
|
||||
* @param nextDependency another dependency to check
|
||||
* @return true if on of the dependencies is a pom.xml and the identifiers between the two collections match; otherwise false
|
||||
* @return true if on of the dependencies is a pom.xml and the identifiers
|
||||
* between the two collections match; otherwise false
|
||||
*/
|
||||
private boolean isShadedJar(Dependency dependency, Dependency nextDependency) {
|
||||
final String mainName = dependency.getFileName().toLowerCase();
|
||||
@@ -378,12 +455,13 @@ public class DependencyBundlingAnalyzer extends AbstractAnalyzer implements Anal
|
||||
}
|
||||
|
||||
/**
|
||||
* Determines which path is shortest; if path lengths are equal then we use compareTo of the string method to determine if the
|
||||
* first path is smaller.
|
||||
* Determines which path is shortest; if path lengths are equal then we use
|
||||
* compareTo of the string method to determine if the first path is smaller.
|
||||
*
|
||||
* @param left the first path to compare
|
||||
* @param right the second path to compare
|
||||
* @return <code>true</code> if the leftPath is the shortest; otherwise <code>false</code>
|
||||
* @return <code>true</code> if the leftPath is the shortest; otherwise
|
||||
* <code>false</code>
|
||||
*/
|
||||
protected boolean firstPathIsShortest(String left, String right) {
|
||||
final String leftPath = left.replace('\\', '/');
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* This file is part of dependency-check-gradle.
|
||||
* 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.
|
||||
@@ -13,7 +13,22 @@
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*
|
||||
* Copyright (c) 2015 Wei Ma. All Rights Reserved.
|
||||
* Copyright (c) 2016 Jeremy Long. All Rights Reserved.
|
||||
*/
|
||||
package org.owasp.dependencycheck.analyzer;
|
||||
|
||||
rootProject.name = 'dependency-check'
|
||||
import java.lang.annotation.ElementType;
|
||||
import java.lang.annotation.Retention;
|
||||
import java.lang.annotation.RetentionPolicy;
|
||||
import java.lang.annotation.Target;
|
||||
|
||||
/**
|
||||
* Annotation used to flag an analyzer as experimental.
|
||||
*
|
||||
* @author jeremy long
|
||||
*/
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
@Target(ElementType.TYPE)
|
||||
public @interface Experimental {
|
||||
|
||||
}
|
||||
@@ -69,6 +69,7 @@ public class FalsePositiveAnalyzer extends AbstractAnalyzer {
|
||||
*
|
||||
* @return the name of the analyzer.
|
||||
*/
|
||||
@Override
|
||||
public String getName() {
|
||||
return ANALYZER_NAME;
|
||||
}
|
||||
@@ -78,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;
|
||||
}
|
||||
@@ -111,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;
|
||||
@@ -154,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()) {
|
||||
@@ -379,18 +380,16 @@ public class FalsePositiveAnalyzer extends AbstractAnalyzer {
|
||||
*/
|
||||
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,
|
||||
@@ -473,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,9 @@
|
||||
package org.owasp.dependencycheck.analyzer;
|
||||
|
||||
import java.io.File;
|
||||
|
||||
import org.apache.commons.io.FilenameUtils;
|
||||
import org.apache.commons.io.filefilter.NameFileFilter;
|
||||
import org.owasp.dependencycheck.Engine;
|
||||
import org.owasp.dependencycheck.analyzer.exception.AnalysisException;
|
||||
import org.owasp.dependencycheck.dependency.Confidence;
|
||||
@@ -48,6 +51,7 @@ public class FileNameAnalyzer extends AbstractAnalyzer implements Analyzer {
|
||||
*
|
||||
* @return the name of the analyzer.
|
||||
*/
|
||||
@Override
|
||||
public String getName() {
|
||||
return ANALYZER_NAME;
|
||||
}
|
||||
@@ -57,30 +61,35 @@ 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;
|
||||
}
|
||||
//</editor-fold>
|
||||
|
||||
/**
|
||||
* Python init files
|
||||
*/
|
||||
private static final NameFileFilter IGNORED_FILES = new NameFileFilter(new String[]{
|
||||
"__init__.py",
|
||||
"__init__.pyc",
|
||||
"__init__.pyo",
|
||||
});
|
||||
|
||||
/**
|
||||
* Collects information about the file name.
|
||||
*
|
||||
* @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 JAR file.
|
||||
* @throws AnalysisException is thrown if there is an error reading the JAR
|
||||
* file.
|
||||
*/
|
||||
@Override
|
||||
public void analyze(Dependency dependency, Engine engine) throws AnalysisException {
|
||||
|
||||
//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);
|
||||
@@ -92,20 +101,14 @@ public class FileNameAnalyzer extends AbstractAnalyzer implements Analyzer {
|
||||
dependency.getVersionEvidence().addEvidence("file", "name",
|
||||
version.toString(), Confidence.MEDIUM);
|
||||
} else {
|
||||
dependency.getVersionEvidence().addEvidence("file", "name",
|
||||
dependency.getVersionEvidence().addEvidence("file", "version",
|
||||
version.toString(), Confidence.HIGHEST);
|
||||
}
|
||||
dependency.getVersionEvidence().addEvidence("file", "name",
|
||||
fileName, Confidence.MEDIUM);
|
||||
}
|
||||
|
||||
//add as vendor and product evidence
|
||||
if (fileName.contains("-")) {
|
||||
dependency.getProductEvidence().addEvidence("file", "name",
|
||||
fileName, Confidence.HIGHEST);
|
||||
dependency.getVendorEvidence().addEvidence("file", "name",
|
||||
fileName, Confidence.HIGHEST);
|
||||
} else {
|
||||
if (!IGNORED_FILES.accept(f)) {
|
||||
dependency.getProductEvidence().addEvidence("file", "name",
|
||||
fileName, Confidence.HIGH);
|
||||
dependency.getVendorEvidence().addEvidence("file", "name",
|
||||
|
||||
@@ -104,6 +104,21 @@ public class HintAnalyzer extends AbstractAnalyzer implements Analyzer {
|
||||
"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();
|
||||
@@ -128,6 +143,18 @@ public class HintAnalyzer extends AbstractAnalyzer implements Analyzer {
|
||||
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
|
||||
final Iterator<Evidence> itr = dependency.getVendorEvidence().iterator();
|
||||
final List<Evidence> newEntries = new ArrayList<Evidence>();
|
||||
|
||||
@@ -17,7 +17,6 @@
|
||||
*/
|
||||
package org.owasp.dependencycheck.analyzer;
|
||||
|
||||
import java.io.BufferedOutputStream;
|
||||
import java.io.File;
|
||||
import java.io.FileFilter;
|
||||
import java.io.FileOutputStream;
|
||||
@@ -42,6 +41,8 @@ import java.util.jar.JarFile;
|
||||
import java.util.jar.Manifest;
|
||||
import java.util.regex.Pattern;
|
||||
import java.util.zip.ZipEntry;
|
||||
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;
|
||||
@@ -58,7 +59,8 @@ 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.
|
||||
* Used to load a JAR file and collect information that can be used to determine
|
||||
* the associated CPE.
|
||||
*
|
||||
* @author Jeremy Long
|
||||
*/
|
||||
@@ -70,11 +72,8 @@ public class JarAnalyzer extends AbstractFileTypeAnalyzer {
|
||||
*/
|
||||
private static final Logger LOGGER = LoggerFactory.getLogger(JarAnalyzer.class);
|
||||
/**
|
||||
* The buffer size to use when extracting files from the archive.
|
||||
*/
|
||||
private static final int BUFFER_SIZE = 4096;
|
||||
/**
|
||||
* The count of directories created during analysis. This is used for creating temporary directories.
|
||||
* The count of directories created during analysis. This is used for
|
||||
* creating temporary directories.
|
||||
*/
|
||||
private static int dirCount = 0;
|
||||
/**
|
||||
@@ -82,7 +81,8 @@ public class JarAnalyzer extends AbstractFileTypeAnalyzer {
|
||||
*/
|
||||
private static final String NEWLINE = System.getProperty("line.separator");
|
||||
/**
|
||||
* A list of values in the manifest to ignore as they only result in false positives.
|
||||
* A list of values in the manifest to ignore as they only result in false
|
||||
* positives.
|
||||
*/
|
||||
private static final Set<String> IGNORE_VALUES = newHashSet(
|
||||
"Sun Java System Application Server");
|
||||
@@ -125,7 +125,8 @@ public class JarAnalyzer extends AbstractFileTypeAnalyzer {
|
||||
"ipojo-extension",
|
||||
"eclipse-sourcereferences");
|
||||
/**
|
||||
* Deprecated Jar manifest attribute, that is, nonetheless, useful for analysis.
|
||||
* Deprecated Jar manifest attribute, that is, nonetheless, useful for
|
||||
* analysis.
|
||||
*/
|
||||
@SuppressWarnings("deprecation")
|
||||
private static final String IMPLEMENTATION_VENDOR_ID = Attributes.Name.IMPLEMENTATION_VENDOR_ID
|
||||
@@ -198,13 +199,15 @@ public class JarAnalyzer extends AbstractFileTypeAnalyzer {
|
||||
*
|
||||
* @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.
|
||||
* Returns the key used in the properties file to reference the analyzer's
|
||||
* enabled property.
|
||||
*
|
||||
* @return the analyzer's enabled property setting key
|
||||
*/
|
||||
@@ -214,12 +217,13 @@ public class JarAnalyzer extends AbstractFileTypeAnalyzer {
|
||||
}
|
||||
|
||||
/**
|
||||
* Loads a specified JAR file and collects information from the manifest and checksums to identify the correct CPE
|
||||
* information.
|
||||
* Loads a specified JAR file and collects information from the manifest and
|
||||
* checksums to identify the correct CPE information.
|
||||
*
|
||||
* @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 JAR file.
|
||||
* @throws AnalysisException is thrown if there is an error reading the JAR
|
||||
* file.
|
||||
*/
|
||||
@Override
|
||||
public void analyzeFileType(Dependency dependency, Engine engine) throws AnalysisException {
|
||||
@@ -243,13 +247,15 @@ public class JarAnalyzer extends AbstractFileTypeAnalyzer {
|
||||
}
|
||||
|
||||
/**
|
||||
* Attempts to find a pom.xml within the JAR file. If found it extracts information and adds it to the evidence. This will
|
||||
* attempt to interpolate the strings contained within the pom.properties if one exists.
|
||||
* Attempts to find a pom.xml within the JAR file. If found it extracts
|
||||
* information and adds it to the evidence. This will attempt to interpolate
|
||||
* the strings contained within the pom.properties if one exists.
|
||||
*
|
||||
* @param dependency the dependency being analyzed
|
||||
* @param classes a collection of class name information
|
||||
* @param engine the analysis engine, used to add additional dependencies
|
||||
* @throws AnalysisException is thrown if there is an exception parsing the pom
|
||||
* @throws AnalysisException is thrown if there is an exception parsing the
|
||||
* pom
|
||||
* @return whether or not evidence was added to the dependency
|
||||
*/
|
||||
protected boolean analyzePOM(Dependency dependency, List<ClassNameInformation> classes, Engine engine) throws AnalysisException {
|
||||
@@ -272,8 +278,7 @@ public class JarAnalyzer extends AbstractFileTypeAnalyzer {
|
||||
}
|
||||
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);
|
||||
@@ -323,7 +328,7 @@ public class JarAnalyzer extends AbstractFileTypeAnalyzer {
|
||||
foundSomething |= setPomEvidence(dependency, pom, classes);
|
||||
}
|
||||
} catch (AnalysisException ex) {
|
||||
LOGGER.warn("An error occured while analyzing '{}'.", dependency.getActualFilePath());
|
||||
LOGGER.warn("An error occurred while analyzing '{}'.", dependency.getActualFilePath());
|
||||
LOGGER.trace("", ex);
|
||||
}
|
||||
}
|
||||
@@ -331,12 +336,14 @@ public class JarAnalyzer extends AbstractFileTypeAnalyzer {
|
||||
}
|
||||
|
||||
/**
|
||||
* Given a path to a pom.xml within a JarFile, this method attempts to load a sibling pom.properties if one exists.
|
||||
* Given a path to a pom.xml within a JarFile, this method attempts to load
|
||||
* a sibling pom.properties if one exists.
|
||||
*
|
||||
* @param path the path to the pom.xml within the JarFile
|
||||
* @param jar the JarFile to load the pom.properties from
|
||||
* @return a Properties object or null if no pom.properties was found
|
||||
* @throws IOException thrown if there is an exception reading the pom.properties
|
||||
* @throws IOException thrown if there is an exception reading the
|
||||
* pom.properties
|
||||
*/
|
||||
private Properties retrievePomProperties(String path, final JarFile jar) throws IOException {
|
||||
Properties pomProperties = null;
|
||||
@@ -363,7 +370,8 @@ public class JarAnalyzer extends AbstractFileTypeAnalyzer {
|
||||
}
|
||||
|
||||
/**
|
||||
* Searches a JarFile for pom.xml entries and returns a listing of these entries.
|
||||
* Searches a JarFile for pom.xml entries and returns a listing of these
|
||||
* entries.
|
||||
*
|
||||
* @param jar the JarFile to search
|
||||
* @return a list of pom.xml entries
|
||||
@@ -390,32 +398,24 @@ public class JarAnalyzer extends AbstractFileTypeAnalyzer {
|
||||
* @param jar the jar file to extract the pom from
|
||||
* @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.xml.pom.Model} object
|
||||
* @throws AnalysisException is thrown if there is an exception extracting
|
||||
* or parsing the POM {@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) {
|
||||
LOGGER.warn("An error occurred reading '{}' from '{}'.", path, dependency.getFilePath());
|
||||
LOGGER.error("", ex);
|
||||
} finally {
|
||||
closeStream(bos);
|
||||
closeStream(fos);
|
||||
closeStream(input);
|
||||
}
|
||||
@@ -457,9 +457,10 @@ public class JarAnalyzer extends AbstractFileTypeAnalyzer {
|
||||
*
|
||||
* @param dependency the dependency to set data on
|
||||
* @param pom the information from the pom
|
||||
* @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
|
||||
* @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
|
||||
*/
|
||||
public static boolean setPomEvidence(Dependency dependency, Model pom, List<ClassNameInformation> classes) {
|
||||
boolean foundSomething = false;
|
||||
@@ -576,17 +577,25 @@ public class JarAnalyzer extends AbstractFileTypeAnalyzer {
|
||||
addMatchingValues(classes, trimmedDescription, dependency.getProductEvidence());
|
||||
}
|
||||
|
||||
final String projectURL = pom.getProjectURL();
|
||||
if (projectURL != null && !projectURL.trim().isEmpty()) {
|
||||
dependency.getVendorEvidence().addEvidence("pom", "url", projectURL, Confidence.HIGHEST);
|
||||
}
|
||||
|
||||
extractLicense(pom, dependency);
|
||||
return foundSomething;
|
||||
}
|
||||
|
||||
/**
|
||||
* Analyzes the path information of the classes contained within the JarAnalyzer to try and determine possible vendor or
|
||||
* product names. If any are found they are stored in the packageVendor and packageProduct hashSets.
|
||||
* Analyzes the path information of the classes contained within the
|
||||
* JarAnalyzer to try and determine possible vendor or product names. If any
|
||||
* are found they are stored in the packageVendor and packageProduct
|
||||
* hashSets.
|
||||
*
|
||||
* @param classNames a list of class names
|
||||
* @param dependency a dependency to analyze
|
||||
* @param addPackagesAsEvidence a flag indicating whether or not package names should be added as evidence.
|
||||
* @param addPackagesAsEvidence a flag indicating whether or not package
|
||||
* names should be added as evidence.
|
||||
*/
|
||||
protected void analyzePackageNames(List<ClassNameInformation> classNames,
|
||||
Dependency dependency, boolean addPackagesAsEvidence) {
|
||||
@@ -621,11 +630,13 @@ public class JarAnalyzer extends AbstractFileTypeAnalyzer {
|
||||
|
||||
/**
|
||||
* <p>
|
||||
* Reads the manifest from the JAR file and collects the entries. Some vendorKey entries are:</p>
|
||||
* Reads the manifest from the JAR file and collects the entries. Some
|
||||
* vendorKey entries are:</p>
|
||||
* <ul><li>Implementation Title</li>
|
||||
* <li>Implementation Version</li> <li>Implementation Vendor</li>
|
||||
* <li>Implementation VendorId</li> <li>Bundle Name</li> <li>Bundle Version</li> <li>Bundle Vendor</li> <li>Bundle
|
||||
* Description</li> <li>Main Class</li> </ul>
|
||||
* <li>Implementation VendorId</li> <li>Bundle Name</li> <li>Bundle
|
||||
* Version</li> <li>Bundle Vendor</li> <li>Bundle Description</li> <li>Main
|
||||
* Class</li> </ul>
|
||||
* However, all but a handful of specific entries are read in.
|
||||
*
|
||||
* @param dependency A reference to the dependency
|
||||
@@ -633,16 +644,15 @@ public class JarAnalyzer extends AbstractFileTypeAnalyzer {
|
||||
* @return whether evidence was identified parsing the manifest
|
||||
* @throws IOException if there is an issue reading the JAR file
|
||||
*/
|
||||
protected boolean parseManifest(Dependency dependency, List<ClassNameInformation> classInformation) throws IOException {
|
||||
protected boolean parseManifest(Dependency dependency,
|
||||
List<ClassNameInformation> classInformation)
|
||||
throws IOException {
|
||||
boolean foundSomething = false;
|
||||
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")
|
||||
@@ -652,17 +662,14 @@ public class JarAnalyzer extends AbstractFileTypeAnalyzer {
|
||||
}
|
||||
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);
|
||||
@@ -692,7 +699,6 @@ public class JarAnalyzer extends AbstractFileTypeAnalyzer {
|
||||
} else if (key.equalsIgnoreCase(BUNDLE_DESCRIPTION)) {
|
||||
foundSomething = true;
|
||||
addDescription(dependency, value, "manifest", key);
|
||||
//productEvidence.addEvidence(source, key, value, Confidence.MEDIUM);
|
||||
addMatchingValues(classInformation, value, productEvidence);
|
||||
} else if (key.equalsIgnoreCase(BUNDLE_NAME)) {
|
||||
foundSomething = true;
|
||||
@@ -711,14 +717,8 @@ public class JarAnalyzer extends AbstractFileTypeAnalyzer {
|
||||
//skipping main class as if this has important information to add
|
||||
// it will be added during class name analysis... if other fields
|
||||
// have the information from the class name then they will get added...
|
||||
// foundSomething = true;
|
||||
// productEvidence.addEvidence(source, key, value, Confidence.MEDIUM);
|
||||
// vendorEvidence.addEvidence(source, key, value, Confidence.MEDIUM);
|
||||
// addMatchingValues(classInformation, value, vendorEvidence);
|
||||
// addMatchingValues(classInformation, value, productEvidence);
|
||||
} else {
|
||||
key = key.toLowerCase();
|
||||
|
||||
if (!IGNORE_KEYS.contains(key)
|
||||
&& !key.endsWith("jdk")
|
||||
&& !key.contains("lastmodified")
|
||||
@@ -730,12 +730,9 @@ public class JarAnalyzer extends AbstractFileTypeAnalyzer {
|
||||
&& !value.trim().startsWith("scm:")
|
||||
&& !isImportPackage(key, value)
|
||||
&& !isPackage(key, value)) {
|
||||
|
||||
foundSomething = true;
|
||||
if (key.contains("version")) {
|
||||
if (!key.contains("specification")) {
|
||||
//versionEvidence.addEvidence(source, key, value, Confidence.LOW);
|
||||
//} else {
|
||||
versionEvidence.addEvidence(source, key, value, Confidence.MEDIUM);
|
||||
}
|
||||
} else if ("build-id".equals(key)) {
|
||||
@@ -765,21 +762,19 @@ public class JarAnalyzer extends AbstractFileTypeAnalyzer {
|
||||
addMatchingValues(classInformation, value, productEvidence);
|
||||
} else if (key.contains("license")) {
|
||||
addLicense(dependency, value);
|
||||
} else if (key.contains("description")) {
|
||||
addDescription(dependency, value, "manifest", key);
|
||||
} else {
|
||||
if (key.contains("description")) {
|
||||
addDescription(dependency, value, "manifest", key);
|
||||
} else {
|
||||
productEvidence.addEvidence(source, key, value, Confidence.LOW);
|
||||
vendorEvidence.addEvidence(source, key, value, Confidence.LOW);
|
||||
addMatchingValues(classInformation, value, vendorEvidence);
|
||||
addMatchingValues(classInformation, value, productEvidence);
|
||||
if (value.matches(".*\\d.*")) {
|
||||
final StringTokenizer tokenizer = new StringTokenizer(value, " ");
|
||||
while (tokenizer.hasMoreElements()) {
|
||||
final String s = tokenizer.nextToken();
|
||||
if (s.matches("^[0-9.]+$")) {
|
||||
versionEvidence.addEvidence(source, key, s, Confidence.LOW);
|
||||
}
|
||||
productEvidence.addEvidence(source, key, value, Confidence.LOW);
|
||||
vendorEvidence.addEvidence(source, key, value, Confidence.LOW);
|
||||
addMatchingValues(classInformation, value, vendorEvidence);
|
||||
addMatchingValues(classInformation, value, productEvidence);
|
||||
if (value.matches(".*\\d.*")) {
|
||||
final StringTokenizer tokenizer = new StringTokenizer(value, " ");
|
||||
while (tokenizer.hasMoreElements()) {
|
||||
final String s = tokenizer.nextToken();
|
||||
if (s.matches("^[0-9.]+$")) {
|
||||
versionEvidence.addEvidence(source, key, s, Confidence.LOW);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -787,9 +782,35 @@ public class JarAnalyzer extends AbstractFileTypeAnalyzer {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for (Map.Entry<String, Attributes> item : manifest.getEntries().entrySet()) {
|
||||
final String name = item.getKey();
|
||||
source = "manifest: " + name;
|
||||
atts = item.getValue();
|
||||
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, "specificationn-version", specificationVersion, Confidence.HIGH);
|
||||
versionEvidence.addEvidence(source, "specification-version", specificationVersion, Confidence.HIGH);
|
||||
}
|
||||
} finally {
|
||||
if (jar != null) {
|
||||
@@ -800,15 +821,18 @@ public class JarAnalyzer extends AbstractFileTypeAnalyzer {
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds a description to the given dependency. If the description contains one of the following strings beyond 100 characters,
|
||||
* then the description used will be trimmed to that position:
|
||||
* <ul><li>"such as"</li><li>"like "</li><li>"will use "</li><li>"* uses "</li></ul>
|
||||
* Adds a description to the given dependency. If the description contains
|
||||
* one of the following strings beyond 100 characters, then the description
|
||||
* used will be trimmed to that position:
|
||||
* <ul><li>"such as"</li><li>"like "</li><li>"will use "</li><li>"* uses
|
||||
* "</li></ul>
|
||||
*
|
||||
* @param dependency a dependency
|
||||
* @param description the description
|
||||
* @param source the source of the evidence
|
||||
* @param key the "name" of the evidence
|
||||
* @return if the description is trimmed, the trimmed version is returned; otherwise the original description is returned
|
||||
* @return if the description is trimmed, the trimmed version is returned;
|
||||
* otherwise the original description is returned
|
||||
*/
|
||||
public static String addDescription(Dependency dependency, String description, String source, String key) {
|
||||
if (dependency.getDescription() == null) {
|
||||
@@ -846,10 +870,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);
|
||||
@@ -882,7 +903,8 @@ public class JarAnalyzer extends AbstractFileTypeAnalyzer {
|
||||
/**
|
||||
* Initializes the JarAnalyzer.
|
||||
*
|
||||
* @throws Exception is thrown if there is an exception creating a temporary directory
|
||||
* @throws Exception is thrown if there is an exception creating a temporary
|
||||
* directory
|
||||
*/
|
||||
@Override
|
||||
public void initializeFileTypeAnalyzer() throws Exception {
|
||||
@@ -913,11 +935,13 @@ public class JarAnalyzer extends AbstractFileTypeAnalyzer {
|
||||
}
|
||||
|
||||
/**
|
||||
* Determines if the key value pair from the manifest is for an "import" type entry for package names.
|
||||
* Determines if the key value pair from the manifest is for an "import"
|
||||
* type entry for package names.
|
||||
*
|
||||
* @param key the key from the manifest
|
||||
* @param value the value from the manifest
|
||||
* @return true or false depending on if it is believed the entry is an "import" entry
|
||||
* @return true or false depending on if it is believed the entry is an
|
||||
* "import" entry
|
||||
*/
|
||||
private boolean isImportPackage(String key, String value) {
|
||||
final Pattern packageRx = Pattern.compile("^([a-zA-Z0-9_#\\$\\*\\.]+\\s*[,;]\\s*)+([a-zA-Z0-9_#\\$\\*\\.]+\\s*)?$");
|
||||
@@ -926,8 +950,9 @@ public class JarAnalyzer extends AbstractFileTypeAnalyzer {
|
||||
}
|
||||
|
||||
/**
|
||||
* Cycles through an enumeration of JarEntries, contained within the dependency, and returns a list of the class names. This
|
||||
* does not include core Java package names (i.e. java.* or javax.*).
|
||||
* Cycles through an enumeration of JarEntries, contained within the
|
||||
* dependency, and returns a list of the class names. This does not include
|
||||
* core Java package names (i.e. java.* or javax.*).
|
||||
*
|
||||
* @param dependency the dependency being analyzed
|
||||
* @return an list of fully qualified class names
|
||||
@@ -963,12 +988,16 @@ public class JarAnalyzer extends AbstractFileTypeAnalyzer {
|
||||
}
|
||||
|
||||
/**
|
||||
* Cycles through the list of class names and places the package levels 0-3 into the provided maps for vendor and product.
|
||||
* This is helpful when analyzing vendor/product as many times this is included in the package name.
|
||||
* Cycles through the list of class names and places the package levels 0-3
|
||||
* into the provided maps for vendor and product. This is helpful when
|
||||
* analyzing vendor/product as many times this is included in the package
|
||||
* name.
|
||||
*
|
||||
* @param classNames a list of class names
|
||||
* @param vendor HashMap of possible vendor names from package names (e.g. owasp)
|
||||
* @param product HashMap of possible product names from package names (e.g. dependencycheck)
|
||||
* @param vendor HashMap of possible vendor names from package names (e.g.
|
||||
* owasp)
|
||||
* @param product HashMap of possible product names from package names (e.g.
|
||||
* dependencycheck)
|
||||
*/
|
||||
private void analyzeFullyQualifiedClassNames(List<ClassNameInformation> classNames,
|
||||
Map<String, Integer> vendor, Map<String, Integer> product) {
|
||||
@@ -995,8 +1024,9 @@ public class JarAnalyzer extends AbstractFileTypeAnalyzer {
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds an entry to the specified collection and sets the Integer (e.g. the count) to 1. If the entry already exists in the
|
||||
* collection then the Integer is incremented by 1.
|
||||
* Adds an entry to the specified collection and sets the Integer (e.g. the
|
||||
* count) to 1. If the entry already exists in the collection then the
|
||||
* Integer is incremented by 1.
|
||||
*
|
||||
* @param collection a collection of strings and their occurrence count
|
||||
* @param key the key to add to the collection
|
||||
@@ -1010,9 +1040,10 @@ public class JarAnalyzer extends AbstractFileTypeAnalyzer {
|
||||
}
|
||||
|
||||
/**
|
||||
* Cycles through the collection of class name information to see if parts of the package names are contained in the provided
|
||||
* value. If found, it will be added as the HIGHEST confidence evidence because we have more then one source corroborating the
|
||||
* value.
|
||||
* Cycles through the collection of class name information to see if parts
|
||||
* of the package names are contained in the provided value. If found, it
|
||||
* will be added as the HIGHEST confidence evidence because we have more
|
||||
* then one source corroborating the value.
|
||||
*
|
||||
* @param classes a collection of class name information
|
||||
* @param value the value to check to see if it contains a package name
|
||||
@@ -1025,7 +1056,9 @@ public class JarAnalyzer extends AbstractFileTypeAnalyzer {
|
||||
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);
|
||||
}
|
||||
}
|
||||
@@ -1033,7 +1066,8 @@ public class JarAnalyzer extends AbstractFileTypeAnalyzer {
|
||||
}
|
||||
|
||||
/**
|
||||
* Simple check to see if the attribute from a manifest is just a package name.
|
||||
* Simple check to see if the attribute from a manifest is just a package
|
||||
* name.
|
||||
*
|
||||
* @param key the key of the value to check
|
||||
* @param value the value to check
|
||||
@@ -1047,7 +1081,8 @@ public class JarAnalyzer extends AbstractFileTypeAnalyzer {
|
||||
}
|
||||
|
||||
/**
|
||||
* Extracts the license information from the pom and adds it to the dependency.
|
||||
* Extracts the license information from the pom and adds it to the
|
||||
* dependency.
|
||||
*
|
||||
* @param pom the pom object
|
||||
* @param dependency the dependency to add license information too
|
||||
@@ -1094,9 +1129,11 @@ public class JarAnalyzer extends AbstractFileTypeAnalyzer {
|
||||
|
||||
/**
|
||||
* <p>
|
||||
* Stores information about a given class name. This class will keep the fully qualified class name and a list of the
|
||||
* important parts of the package structure. Up to the first four levels of the package structure are stored, excluding a
|
||||
* leading "org" or "com". Example:</p>
|
||||
* Stores information about a given class name. This class will keep the
|
||||
* fully qualified class name and a list of the important parts of the
|
||||
* package structure. Up to the first four levels of the package
|
||||
* structure are stored, excluding a leading "org" or "com".
|
||||
* Example:</p>
|
||||
* <code>ClassNameInformation obj = new ClassNameInformation("org.owasp.dependencycheck.analyzer.JarAnalyzer");
|
||||
* System.out.println(obj.getName());
|
||||
* for (String p : obj.getPackageStructure())
|
||||
@@ -1155,7 +1192,8 @@ public class JarAnalyzer extends AbstractFileTypeAnalyzer {
|
||||
this.name = name;
|
||||
}
|
||||
/**
|
||||
* Up to the first four levels of the package structure, excluding a leading "org" or "com".
|
||||
* Up to the first four levels of the package structure, excluding a
|
||||
* leading "org" or "com".
|
||||
*/
|
||||
private final ArrayList<String> packageStructure = new ArrayList<String>();
|
||||
|
||||
|
||||
@@ -104,7 +104,7 @@ 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;
|
||||
@@ -247,7 +247,7 @@ 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.debug("Artifact not found in repository '{}'", dependency.getFileName());
|
||||
|
||||
@@ -0,0 +1,188 @@
|
||||
/*
|
||||
* 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
|
||||
*/
|
||||
@Experimental
|
||||
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);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -126,7 +126,7 @@ public class NuspecAnalyzer extends AbstractFileTypeAnalyzer {
|
||||
*/
|
||||
@Override
|
||||
public void analyzeFileType(Dependency dependency, Engine engine) throws AnalysisException {
|
||||
LOGGER.debug("Checking Nuspec file {}", dependency.toString());
|
||||
LOGGER.debug("Checking Nuspec file {}", dependency);
|
||||
try {
|
||||
final NuspecParser parser = new XPathNuspecParser();
|
||||
NugetPackage np = null;
|
||||
|
||||
@@ -73,7 +73,7 @@ public class NvdCveAnalyzer implements Analyzer {
|
||||
* @return true or false.
|
||||
*/
|
||||
public boolean isOpen() {
|
||||
return (cveDB != null);
|
||||
return cveDB != null;
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -28,16 +28,20 @@ import org.owasp.dependencycheck.utils.Settings;
|
||||
import java.io.File;
|
||||
import java.io.FileFilter;
|
||||
import java.io.IOException;
|
||||
import java.nio.charset.Charset;
|
||||
import java.util.regex.Matcher;
|
||||
import java.util.regex.Pattern;
|
||||
|
||||
/**
|
||||
* Used to analyze OpenSSL source code present in the file system.
|
||||
*
|
||||
* @author Dale Visser <dvisser@ida.org>
|
||||
* @author Dale Visser
|
||||
*/
|
||||
public class OpenSSLAnalyzer extends AbstractFileTypeAnalyzer {
|
||||
|
||||
/**
|
||||
* Hexadecimal.
|
||||
*/
|
||||
private static final int HEXADECIMAL = 16;
|
||||
/**
|
||||
* Filename to analyze. All other .h files get removed from consideration.
|
||||
@@ -48,17 +52,47 @@ public class OpenSSLAnalyzer extends AbstractFileTypeAnalyzer {
|
||||
* Filter that detects files named "__init__.py".
|
||||
*/
|
||||
private static final FileFilter OPENSSLV_FILTER = FileFilterBuilder.newInstance().addFilenames(OPENSSLV_H).build();
|
||||
/**
|
||||
* Open SSL Version number pattern.
|
||||
*/
|
||||
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);
|
||||
/**
|
||||
* The offset of the major version number.
|
||||
*/
|
||||
private static final int MAJOR_OFFSET = 28;
|
||||
/**
|
||||
* The mask for the minor version number.
|
||||
*/
|
||||
private static final long MINOR_MASK = 0x0ff00000L;
|
||||
/**
|
||||
* The offset of the minor version number.
|
||||
*/
|
||||
private static final int MINOR_OFFSET = 20;
|
||||
/**
|
||||
* The max for the fix version.
|
||||
*/
|
||||
private static final long FIX_MASK = 0x000ff000L;
|
||||
/**
|
||||
* The offset for the fix version.
|
||||
*/
|
||||
private static final int FIX_OFFSET = 12;
|
||||
/**
|
||||
* The mask for the patch version.
|
||||
*/
|
||||
private static final long PATCH_MASK = 0x00000ff0L;
|
||||
/**
|
||||
* The offset for the patch version.
|
||||
*/
|
||||
private static final int PATCH_OFFSET = 4;
|
||||
/**
|
||||
* Number of letters.
|
||||
*/
|
||||
private static final int NUM_LETTERS = 26;
|
||||
/**
|
||||
* The status mask.
|
||||
*/
|
||||
private static final int STATUS_MASK = 0x0000000f;
|
||||
|
||||
/**
|
||||
@@ -123,7 +157,8 @@ public class OpenSSLAnalyzer extends AbstractFileTypeAnalyzer {
|
||||
*
|
||||
* @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
|
||||
* @throws AnalysisException thrown if there is an unrecoverable error
|
||||
* analyzing the dependency
|
||||
*/
|
||||
@Override
|
||||
protected void analyzeFileType(Dependency dependency, Engine engine)
|
||||
@@ -158,16 +193,19 @@ public class OpenSSLAnalyzer extends AbstractFileTypeAnalyzer {
|
||||
*/
|
||||
private String getFileContents(final File actualFile)
|
||||
throws AnalysisException {
|
||||
String contents;
|
||||
try {
|
||||
contents = FileUtils.readFileToString(actualFile).trim();
|
||||
return FileUtils.readFileToString(actualFile, Charset.defaultCharset()).trim();
|
||||
} catch (IOException e) {
|
||||
throw new AnalysisException(
|
||||
"Problem occurred while reading dependency file.", e);
|
||||
}
|
||||
return contents;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the setting for the analyzer enabled setting key.
|
||||
*
|
||||
* @return the setting for the analyzer enabled setting key
|
||||
*/
|
||||
@Override
|
||||
protected String getAnalyzerEnabledSettingKey() {
|
||||
return Settings.KEYS.ANALYZER_OPENSSL_ENABLED;
|
||||
|
||||
@@ -26,7 +26,7 @@ import java.io.FilenameFilter;
|
||||
import org.apache.commons.io.filefilter.NameFileFilter;
|
||||
import org.apache.commons.io.filefilter.SuffixFileFilter;
|
||||
import org.apache.commons.io.input.AutoCloseInputStream;
|
||||
import org.apache.commons.lang.StringUtils;
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
import org.owasp.dependencycheck.Engine;
|
||||
import org.owasp.dependencycheck.analyzer.exception.AnalysisException;
|
||||
import org.owasp.dependencycheck.dependency.Confidence;
|
||||
@@ -48,12 +48,13 @@ import org.owasp.dependencycheck.utils.UrlStringUtils;
|
||||
* Used to analyze a Wheel or egg distribution files, or their contents in unzipped form, and collect information that can be used
|
||||
* to determine the associated CPE.
|
||||
*
|
||||
* @author Dale Visser <dvisser@ida.org>
|
||||
* @author Dale Visser
|
||||
*/
|
||||
@Experimental
|
||||
public class PythonDistributionAnalyzer extends AbstractFileTypeAnalyzer {
|
||||
|
||||
/**
|
||||
* Name of egg metatdata files to analyze.
|
||||
* Name of egg metadata files to analyze.
|
||||
*/
|
||||
private static final String PKG_INFO = "PKG-INFO";
|
||||
|
||||
@@ -269,10 +270,8 @@ public class PythonDistributionAnalyzer extends AbstractFileTypeAnalyzer {
|
||||
*
|
||||
* @param dependency the dependency being analyzed
|
||||
* @param file a reference to the manifest/properties file
|
||||
* @throws AnalysisException thrown when there is an error
|
||||
*/
|
||||
private static void collectWheelMetadata(Dependency dependency, File file)
|
||||
throws AnalysisException {
|
||||
private static void collectWheelMetadata(Dependency dependency, File file) {
|
||||
final InternetHeaders headers = getManifestProperties(file);
|
||||
addPropertyToEvidence(headers, dependency.getVersionEvidence(),
|
||||
"Version", Confidence.HIGHEST);
|
||||
@@ -352,7 +351,7 @@ public class PythonDistributionAnalyzer extends AbstractFileTypeAnalyzer {
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieves the next temporary destingation directory for extracting an archive.
|
||||
* Retrieves the next temporary destination directory for extracting an archive.
|
||||
*
|
||||
* @return a directory
|
||||
* @throws AnalysisException thrown if unable to create temporary directory
|
||||
|
||||
@@ -28,23 +28,23 @@ import org.owasp.dependencycheck.dependency.EvidenceCollection;
|
||||
import org.owasp.dependencycheck.utils.FileFilterBuilder;
|
||||
import org.owasp.dependencycheck.utils.Settings;
|
||||
import org.owasp.dependencycheck.utils.UrlStringUtils;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.FileFilter;
|
||||
import java.io.IOException;
|
||||
import java.net.MalformedURLException;
|
||||
import java.nio.charset.Charset;
|
||||
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.
|
||||
* Used to analyze a Python package, and collect information that can be used to
|
||||
* determine the associated CPE.
|
||||
*
|
||||
* @author Dale Visser <dvisser@ida.org>
|
||||
* @author Dale Visser
|
||||
*/
|
||||
@Experimental
|
||||
public class PythonPackageAnalyzer extends AbstractFileTypeAnalyzer {
|
||||
|
||||
/**
|
||||
@@ -53,12 +53,6 @@ public class PythonPackageAnalyzer extends AbstractFileTypeAnalyzer {
|
||||
private static final int REGEX_OPTIONS = Pattern.DOTALL
|
||||
| Pattern.CASE_INSENSITIVE;
|
||||
|
||||
/**
|
||||
* The logger.
|
||||
*/
|
||||
private static final Logger LOGGER = LoggerFactory
|
||||
.getLogger(PythonPackageAnalyzer.class);
|
||||
|
||||
/**
|
||||
* Filename extensions for files to be analyzed.
|
||||
*/
|
||||
@@ -174,7 +168,8 @@ public class PythonPackageAnalyzer extends AbstractFileTypeAnalyzer {
|
||||
*
|
||||
* @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
|
||||
* @throws AnalysisException thrown if there is an unrecoverable error
|
||||
* analyzing the dependency
|
||||
*/
|
||||
@Override
|
||||
protected void analyzeFileType(Dependency dependency, Engine engine)
|
||||
@@ -182,28 +177,33 @@ public class PythonPackageAnalyzer extends AbstractFileTypeAnalyzer {
|
||||
final File file = dependency.getActualFile();
|
||||
final File parent = file.getParentFile();
|
||||
final String parentName = parent.getName();
|
||||
boolean found = false;
|
||||
if (INIT_PY_FILTER.accept(file)) {
|
||||
for (final File sourcefile : parent.listFiles(PY_FILTER)) {
|
||||
found |= analyzeFileContents(dependency, sourcefile);
|
||||
}
|
||||
}
|
||||
if (found) {
|
||||
//by definition, the containing folder of __init__.py is considered the package, even the file is empty:
|
||||
//"The __init__.py files are required to make Python treat the directories as containing packages"
|
||||
//see section "6.4 Packages" from https://docs.python.org/2/tutorial/modules.html;
|
||||
dependency.setDisplayFileName(parentName + "/__init__.py");
|
||||
dependency.getProductEvidence().addEvidence(file.getName(),
|
||||
"PackageName", parentName, Confidence.MEDIUM);
|
||||
"PackageName", parentName, Confidence.HIGHEST);
|
||||
|
||||
final File[] fileList = parent.listFiles(PY_FILTER);
|
||||
if (fileList != null) {
|
||||
for (final File sourceFile : fileList) {
|
||||
analyzeFileContents(dependency, sourceFile);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
// copy, alter and set in case some other thread is iterating over
|
||||
final List<Dependency> deps = new ArrayList<Dependency>(
|
||||
final List<Dependency> dependencies = new ArrayList<Dependency>(
|
||||
engine.getDependencies());
|
||||
deps.remove(dependency);
|
||||
engine.setDependencies(deps);
|
||||
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.
|
||||
* 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
|
||||
@@ -214,7 +214,7 @@ public class PythonPackageAnalyzer extends AbstractFileTypeAnalyzer {
|
||||
throws AnalysisException {
|
||||
String contents;
|
||||
try {
|
||||
contents = FileUtils.readFileToString(file).trim();
|
||||
contents = FileUtils.readFileToString(file, Charset.defaultCharset()).trim();
|
||||
} catch (IOException e) {
|
||||
throw new AnalysisException(
|
||||
"Problem occurred while reading dependency file.", e);
|
||||
@@ -238,14 +238,10 @@ public class PythonPackageAnalyzer extends AbstractFileTypeAnalyzer {
|
||||
.getVendorEvidence();
|
||||
found |= gatherEvidence(AUTHOR_PATTERN, contents, source,
|
||||
vendorEvidence, "SourceAuthor", Confidence.MEDIUM);
|
||||
try {
|
||||
found |= gatherHomePageEvidence(URI_PATTERN, vendorEvidence,
|
||||
source, "URL", contents);
|
||||
found |= gatherHomePageEvidence(HOMEPAGE_PATTERN,
|
||||
vendorEvidence, source, "HomePage", contents);
|
||||
} catch (MalformedURLException e) {
|
||||
LOGGER.warn(e.getMessage());
|
||||
}
|
||||
found |= gatherHomePageEvidence(URI_PATTERN, vendorEvidence,
|
||||
source, "URL", contents);
|
||||
found |= gatherHomePageEvidence(HOMEPAGE_PATTERN,
|
||||
vendorEvidence, source, "HomePage", contents);
|
||||
}
|
||||
return found;
|
||||
}
|
||||
@@ -281,11 +277,10 @@ public class PythonPackageAnalyzer extends AbstractFileTypeAnalyzer {
|
||||
* @param name the name of the evidence
|
||||
* @param contents the home page URL
|
||||
* @return true if evidence was collected; otherwise false
|
||||
* @throws MalformedURLException thrown if the URL is malformed
|
||||
*/
|
||||
private boolean gatherHomePageEvidence(Pattern pattern,
|
||||
EvidenceCollection evidence, String source, String name,
|
||||
String contents) throws MalformedURLException {
|
||||
String contents) {
|
||||
final Matcher matcher = pattern.matcher(contents);
|
||||
boolean found = false;
|
||||
if (matcher.find()) {
|
||||
@@ -299,7 +294,8 @@ public class PythonPackageAnalyzer extends AbstractFileTypeAnalyzer {
|
||||
}
|
||||
|
||||
/**
|
||||
* Gather evidence from a Python source file usin the given string assignment regex pattern.
|
||||
* 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
|
||||
|
||||
@@ -0,0 +1,471 @@
|
||||
/*
|
||||
* 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.BufferedReader;
|
||||
import java.io.File;
|
||||
import java.io.FileFilter;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStreamReader;
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.nio.charset.Charset;
|
||||
import org.apache.commons.io.FileUtils;
|
||||
import org.owasp.dependencycheck.Engine;
|
||||
import org.owasp.dependencycheck.analyzer.exception.AnalysisException;
|
||||
import org.owasp.dependencycheck.data.nvdcve.CveDB;
|
||||
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 org.owasp.dependencycheck.data.nvdcve.DatabaseException;
|
||||
|
||||
/**
|
||||
* Used to analyze Ruby Bundler Gemspec.lock files utilizing the 3rd party
|
||||
* bundle-audit tool.
|
||||
*
|
||||
* @author Dale Visser
|
||||
*/
|
||||
@Experimental
|
||||
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;
|
||||
/**
|
||||
* The filter defining which files will be analyzed.
|
||||
*/
|
||||
private static final FileFilter FILTER = FileFilterBuilder.newInstance().addFilenames("Gemfile.lock").build();
|
||||
/**
|
||||
* Name.
|
||||
*/
|
||||
public static final String NAME = "Name: ";
|
||||
/**
|
||||
* Version.
|
||||
*/
|
||||
public static final String VERSION = "Version: ";
|
||||
/**
|
||||
* Advisory.
|
||||
*/
|
||||
public static final String ADVISORY = "Advisory: ";
|
||||
/**
|
||||
* Criticality.
|
||||
*/
|
||||
public static final String CRITICALITY = "Criticality: ";
|
||||
|
||||
/**
|
||||
* The DAL.
|
||||
*/
|
||||
private CveDB cvedb;
|
||||
|
||||
/**
|
||||
* @return a filter that accepts files named Gemfile.lock
|
||||
*/
|
||||
@Override
|
||||
protected FileFilter getFileFilter() {
|
||||
return FILTER;
|
||||
}
|
||||
|
||||
/**
|
||||
* Launch bundle-audit.
|
||||
*
|
||||
* @param folder directory that contains bundle audit
|
||||
* @return a handle to the process
|
||||
* @throws AnalysisException thrown when there is an issue launching bundle
|
||||
* audit
|
||||
*/
|
||||
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 {
|
||||
LOGGER.info("Launching: " + args + " from " + folder);
|
||||
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 {
|
||||
try {
|
||||
cvedb = new CveDB();
|
||||
cvedb.open();
|
||||
} catch (DatabaseException ex) {
|
||||
LOGGER.warn("Exception opening the database");
|
||||
LOGGER.debug("error", ex);
|
||||
setEnabled(false);
|
||||
throw ex;
|
||||
}
|
||||
// Now, need to see if bundle-audit actually runs from this location.
|
||||
Process process = null;
|
||||
try {
|
||||
process = launchBundleAudit(Settings.getTempDirectory());
|
||||
} catch (AnalysisException ae) {
|
||||
LOGGER.warn("Exception from bundle-audit process: {}. Disabling {}", ae.getCause(), ANALYZER_NAME);
|
||||
setEnabled(false);
|
||||
cvedb.close();
|
||||
cvedb = null;
|
||||
throw ae;
|
||||
}
|
||||
|
||||
final 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;
|
||||
|
||||
/**
|
||||
* Determines if the analyzer can analyze the given file type.
|
||||
*
|
||||
* @param dependency the dependency to determine if it can analyze
|
||||
* @param engine the dependency-check engine
|
||||
* @throws AnalysisException thrown if there is an analysis exception.
|
||||
*/
|
||||
@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 RubyBundlerAnalyzer) {
|
||||
((RubyBundlerAnalyzer) analyzer).setEnabled(false);
|
||||
LOGGER.info("Disabled " + RubyBundlerAnalyzer.class.getName() + " to avoid noisy duplicate results.");
|
||||
} else 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;
|
||||
BufferedReader errReader = null;
|
||||
try {
|
||||
errReader = new BufferedReader(new InputStreamReader(process.getErrorStream(), "UTF-8"));
|
||||
while (errReader.ready()) {
|
||||
final String error = errReader.readLine();
|
||||
LOGGER.warn(error);
|
||||
}
|
||||
rdr = new BufferedReader(new InputStreamReader(process.getInputStream(), "UTF-8"));
|
||||
processBundlerAuditOutput(dependency, engine, rdr);
|
||||
} catch (IOException ioe) {
|
||||
LOGGER.warn("bundle-audit failure", ioe);
|
||||
} finally {
|
||||
if (errReader != null) {
|
||||
try {
|
||||
errReader.close();
|
||||
} catch (IOException ioe) {
|
||||
LOGGER.warn("bundle-audit close failure", ioe);
|
||||
}
|
||||
}
|
||||
if (null != rdr) {
|
||||
try {
|
||||
rdr.close();
|
||||
} catch (IOException ioe) {
|
||||
LOGGER.warn("bundle-audit close failure", ioe);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Processes the bundler audit output.
|
||||
*
|
||||
* @param original the dependency
|
||||
* @param engine the dependency-check engine
|
||||
* @param rdr the reader of the report
|
||||
* @throws IOException thrown if the report cannot be read.
|
||||
*/
|
||||
private void processBundlerAuditOutput(Dependency original, Engine engine, BufferedReader rdr) throws IOException {
|
||||
final String parentName = original.getActualFile().getParentFile().getName();
|
||||
final String fileName = original.getFileName();
|
||||
final String filePath = original.getFilePath();
|
||||
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, filePath, gem));
|
||||
}
|
||||
dependency = map.get(gem);
|
||||
LOGGER.debug(String.format("bundle-audit (%s): %s", parentName, nextLine));
|
||||
} else if (nextLine.startsWith(VERSION)) {
|
||||
vulnerability = createVulnerability(parentName, dependency, 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");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the vulnerability name.
|
||||
*
|
||||
* @param parentName the parent name
|
||||
* @param dependency the dependency
|
||||
* @param vulnerability the vulnerability
|
||||
* @param nextLine the line to parse
|
||||
*/
|
||||
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));
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds a reference to the vulnerability.
|
||||
*
|
||||
* @param parentName the parent name
|
||||
* @param vulnerability the vulnerability
|
||||
* @param nextLine the line to parse
|
||||
*/
|
||||
private void addReferenceToVulnerability(String parentName, Vulnerability vulnerability, String nextLine) {
|
||||
final String url = nextLine.substring(("URL: ").length());
|
||||
if (null != vulnerability) {
|
||||
final 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));
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds the criticality to the vulnerability
|
||||
*
|
||||
* @param parentName the parent name
|
||||
* @param vulnerability the vulnerability
|
||||
* @param nextLine the line to parse
|
||||
*/
|
||||
private void addCriticalityToVulnerability(String parentName, Vulnerability vulnerability, String nextLine) {
|
||||
if (null != vulnerability) {
|
||||
final String criticality = nextLine.substring(CRITICALITY.length()).trim();
|
||||
float score = -1.0f;
|
||||
Vulnerability v = null;
|
||||
try {
|
||||
v = cvedb.getVulnerability(vulnerability.getName());
|
||||
} catch (DatabaseException ex) {
|
||||
LOGGER.debug("Unable to look up vulnerability {}", vulnerability.getName());
|
||||
}
|
||||
if (v != null) {
|
||||
score = v.getCvssScore();
|
||||
} else if ("High".equalsIgnoreCase(criticality)) {
|
||||
score = 8.5f;
|
||||
} else if ("Medium".equalsIgnoreCase(criticality)) {
|
||||
score = 5.5f;
|
||||
} else if ("Low".equalsIgnoreCase(criticality)) {
|
||||
score = 2.0f;
|
||||
}
|
||||
vulnerability.setCvssScore(score);
|
||||
}
|
||||
LOGGER.debug(String.format("bundle-audit (%s): %s", parentName, nextLine));
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a vulnerability.
|
||||
*
|
||||
* @param parentName the parent name
|
||||
* @param dependency the dependency
|
||||
* @param gem the gem name
|
||||
* @param nextLine the line to parse
|
||||
* @return the vulnerability
|
||||
*/
|
||||
private Vulnerability createVulnerability(String parentName, Dependency dependency, String gem, String nextLine) {
|
||||
Vulnerability vulnerability = null;
|
||||
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;
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates the dependency based off of the gem.
|
||||
*
|
||||
* @param engine the engine used for scanning
|
||||
* @param parentName the gem parent
|
||||
* @param fileName the file name
|
||||
* @param filePath the file path
|
||||
* @param gem the gem name
|
||||
* @return the dependency to add
|
||||
* @throws IOException thrown if a temporary gem file could not be written
|
||||
*/
|
||||
private Dependency createDependencyForGem(Engine engine, String parentName, String fileName, String filePath, String gem) throws IOException {
|
||||
final File gemFile = new File(Settings.getTempDirectory(), gem + "_Gemfile.lock");
|
||||
gemFile.createNewFile();
|
||||
final String displayFileName = String.format("%s%c%s:%s", parentName, File.separatorChar, fileName, gem);
|
||||
|
||||
FileUtils.write(gemFile, displayFileName, Charset.defaultCharset()); // unique contents to avoid dependency bundling
|
||||
final Dependency dependency = new Dependency(gemFile);
|
||||
dependency.getProductEvidence().addEvidence("bundler-audit", "Name", gem, Confidence.HIGHEST);
|
||||
dependency.setDisplayFileName(displayFileName);
|
||||
dependency.setFileName(fileName);
|
||||
dependency.setFilePath(filePath);
|
||||
engine.getDependencies().add(dependency);
|
||||
return dependency;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,139 @@
|
||||
/*
|
||||
* 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) 2016 Bianca Jiang. All Rights Reserved.
|
||||
*/
|
||||
package org.owasp.dependencycheck.analyzer;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.FilenameFilter;
|
||||
|
||||
import org.owasp.dependencycheck.Engine;
|
||||
import org.owasp.dependencycheck.analyzer.exception.AnalysisException;
|
||||
import org.owasp.dependencycheck.dependency.Dependency;
|
||||
|
||||
/**
|
||||
* This analyzer accepts the fully resolved .gemspec created by the Ruby bundler
|
||||
* (http://bundler.io) for better evidence results. It also tries to resolve the
|
||||
* dependency packagePath to where the gem is actually installed. Then during {@link org.owasp.dependencycheck.analyzer.AnalysisPhase#PRE_FINDING_ANALYSIS}
|
||||
* {@link DependencyBundlingAnalyzer} will merge two .gemspec dependencies
|
||||
* together if <code>Dependency.getPackagePath()</code> are the same.
|
||||
*
|
||||
* Ruby bundler creates new .gemspec files under a folder called
|
||||
* "specifications" at deploy time, in addition to the original .gemspec files
|
||||
* from source. The bundler generated .gemspec files always contain fully
|
||||
* resolved attributes thus provide more accurate evidences, whereas the
|
||||
* original .gemspec from source often contain variables for attributes that
|
||||
* can't be used for evidences.
|
||||
*
|
||||
* Note this analyzer share the same
|
||||
* {@link org.owasp.dependencycheck.utils.Settings.KEYS#ANALYZER_RUBY_GEMSPEC_ENABLED} as
|
||||
* {@link RubyGemspecAnalyzer}, so it will enabled/disabled with
|
||||
* {@link RubyGemspecAnalyzer}.
|
||||
*
|
||||
* @author Bianca Jiang (biancajiang@gmail.com)
|
||||
*/
|
||||
@Experimental
|
||||
public class RubyBundlerAnalyzer extends RubyGemspecAnalyzer {
|
||||
|
||||
/**
|
||||
* The name of the analyzer.
|
||||
*/
|
||||
private static final String ANALYZER_NAME = "Ruby Bundler Analyzer";
|
||||
|
||||
/**
|
||||
* Folder name that contains .gemspec files created by "bundle install"
|
||||
*/
|
||||
private static final String SPECIFICATIONS = "specifications";
|
||||
|
||||
/**
|
||||
* Folder name that contains the gems by "bundle install"
|
||||
*/
|
||||
private static final String GEMS = "gems";
|
||||
|
||||
/**
|
||||
* Returns the name of the analyzer.
|
||||
*
|
||||
* @return the name of the analyzer.
|
||||
*/
|
||||
@Override
|
||||
public String getName() {
|
||||
return ANALYZER_NAME;
|
||||
}
|
||||
|
||||
/**
|
||||
* Only accept *.gemspec files generated by "bundle install --deployment"
|
||||
* under "specifications" folder.
|
||||
*
|
||||
* @param pathname the path name to test
|
||||
* @return true if the analyzer can process the given file; otherwise false
|
||||
*/
|
||||
@Override
|
||||
public boolean accept(File pathname) {
|
||||
|
||||
boolean accepted = super.accept(pathname);
|
||||
if (accepted) {
|
||||
final File parentDir = pathname.getParentFile();
|
||||
accepted = parentDir != null && parentDir.getName().equals(SPECIFICATIONS);
|
||||
}
|
||||
|
||||
return accepted;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void analyzeFileType(Dependency dependency, Engine engine)
|
||||
throws AnalysisException {
|
||||
super.analyzeFileType(dependency, engine);
|
||||
|
||||
//find the corresponding gem folder for this .gemspec stub by "bundle install --deployment"
|
||||
final File gemspecFile = dependency.getActualFile();
|
||||
final String gemFileName = gemspecFile.getName();
|
||||
final String gemName = gemFileName.substring(0, gemFileName.lastIndexOf(".gemspec"));
|
||||
final File specificationsDir = gemspecFile.getParentFile();
|
||||
if (specificationsDir != null && specificationsDir.getName().equals(SPECIFICATIONS) && specificationsDir.exists()) {
|
||||
final File parentDir = specificationsDir.getParentFile();
|
||||
if (parentDir != null && parentDir.exists()) {
|
||||
final File gemsDir = new File(parentDir, GEMS);
|
||||
if (gemsDir.exists()) {
|
||||
final File[] matchingFiles = gemsDir.listFiles(new FilenameFilter() {
|
||||
public boolean accept(File dir, String name) {
|
||||
return name.equals(gemName);
|
||||
}
|
||||
});
|
||||
|
||||
if (matchingFiles != null && matchingFiles.length > 0) {
|
||||
final String gemPath = matchingFiles[0].getAbsolutePath();
|
||||
if (dependency.getActualFilePath().equals(dependency.getFilePath())) {
|
||||
if (gemPath != null) {
|
||||
dependency.setPackagePath(gemPath);
|
||||
}
|
||||
} else {
|
||||
//.gemspec's actualFilePath and filePath are different when it's from a compressed file
|
||||
//in which case actualFilePath is the temp directory used by decompression.
|
||||
//packagePath should use the filePath of the identified gem file in "gems" folder
|
||||
final File gemspecStub = new File(dependency.getFilePath());
|
||||
final File specDir = gemspecStub.getParentFile();
|
||||
if (specDir != null && specDir.getName().equals(SPECIFICATIONS)) {
|
||||
final File gemsDir2 = new File(specDir.getParentFile(), GEMS);
|
||||
final File packageDir = new File(gemsDir2, gemName);
|
||||
dependency.setPackagePath(packageDir.getAbsolutePath());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,244 @@
|
||||
/*
|
||||
* 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.File;
|
||||
import java.io.FileFilter;
|
||||
import java.io.FilenameFilter;
|
||||
import java.io.IOException;
|
||||
import java.nio.charset.Charset;
|
||||
import java.util.List;
|
||||
import java.util.regex.Matcher;
|
||||
import java.util.regex.Pattern;
|
||||
|
||||
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;
|
||||
|
||||
/**
|
||||
* 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
|
||||
*/
|
||||
@Experimental
|
||||
public class RubyGemspecAnalyzer extends AbstractFileTypeAnalyzer {
|
||||
|
||||
/**
|
||||
* The logger.
|
||||
*/
|
||||
private static final Logger LOGGER = LoggerFactory.getLogger(RubyGemspecAnalyzer.class);
|
||||
/**
|
||||
* 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;
|
||||
|
||||
/**
|
||||
* The gemspec file extension.
|
||||
*/
|
||||
private static final String GEMSPEC = "gemspec";
|
||||
|
||||
/**
|
||||
* The file filter containing the list of file extensions that can be
|
||||
* analyzed.
|
||||
*/
|
||||
private static final FileFilter FILTER = FileFilterBuilder.newInstance().addExtensions(GEMSPEC).build();
|
||||
//TODO: support Rakefile
|
||||
//= FileFilterBuilder.newInstance().addExtensions(GEMSPEC).addFilenames("Rakefile").build();
|
||||
|
||||
/**
|
||||
* The name of the version file.
|
||||
*/
|
||||
private static final String VERSION_FILE_NAME = "VERSION";
|
||||
|
||||
/**
|
||||
* @return a filter that accepts files 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(), Charset.defaultCharset());
|
||||
} 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();
|
||||
final EvidenceCollection product = dependency.getProductEvidence();
|
||||
final String name = addStringEvidence(product, contents, blockVariable, "name", "name", Confidence.HIGHEST);
|
||||
if (!name.isEmpty()) {
|
||||
vendor.addEvidence(GEMSPEC, "name_project", name + "_project", Confidence.LOW);
|
||||
}
|
||||
addStringEvidence(product, contents, blockVariable, "summary", "summary", Confidence.LOW);
|
||||
|
||||
addStringEvidence(vendor, contents, blockVariable, "author", "authors?", Confidence.HIGHEST);
|
||||
addStringEvidence(vendor, contents, blockVariable, "email", "emails?", Confidence.MEDIUM);
|
||||
addStringEvidence(vendor, contents, blockVariable, "homepage", "homepage", Confidence.HIGHEST);
|
||||
addStringEvidence(vendor, contents, blockVariable, "license", "licen[cs]es?", Confidence.HIGHEST);
|
||||
|
||||
final String value = addStringEvidence(dependency.getVersionEvidence(), contents,
|
||||
blockVariable, "version", "version", Confidence.HIGHEST);
|
||||
if (value.length() < 1) {
|
||||
addEvidenceFromVersionFile(dependency.getActualFile(), dependency.getVersionEvidence());
|
||||
}
|
||||
}
|
||||
|
||||
setPackagePath(dependency);
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds the specified evidence to the given evidence collection.
|
||||
*
|
||||
* @param evidences the collection to add the evidence to
|
||||
* @param contents the evidence contents
|
||||
* @param blockVariable the variable
|
||||
* @param field the field
|
||||
* @param fieldPattern the field pattern
|
||||
* @param confidence the confidence of the evidence
|
||||
* @return the evidence string value added
|
||||
*/
|
||||
private String addStringEvidence(EvidenceCollection evidences, String contents,
|
||||
String blockVariable, String field, String fieldPattern, Confidence confidence) {
|
||||
String value = "";
|
||||
|
||||
//capture array value between [ ]
|
||||
final Matcher arrayMatcher = Pattern.compile(
|
||||
String.format("\\s*?%s\\.%s\\s*?=\\s*?\\[(.*?)\\]", blockVariable, fieldPattern), Pattern.CASE_INSENSITIVE).matcher(contents);
|
||||
if (arrayMatcher.find()) {
|
||||
final String arrayValue = arrayMatcher.group(1);
|
||||
value = arrayValue.replaceAll("['\"]", "").trim(); //strip quotes
|
||||
} else { //capture single value between quotes
|
||||
final Matcher matcher = Pattern.compile(
|
||||
String.format("\\s*?%s\\.%s\\s*?=\\s*?(['\"])(.*?)\\1", blockVariable, fieldPattern), Pattern.CASE_INSENSITIVE).matcher(contents);
|
||||
if (matcher.find()) {
|
||||
value = matcher.group(2);
|
||||
}
|
||||
}
|
||||
if (value.length() > 0) {
|
||||
evidences.addEvidence(GEMSPEC, field, value, confidence);
|
||||
}
|
||||
|
||||
return value;
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds evidence from the version file.
|
||||
*
|
||||
* @param dependencyFile the dependency being analyzed
|
||||
* @param versionEvidences the version evidence
|
||||
*/
|
||||
private void addEvidenceFromVersionFile(File dependencyFile, EvidenceCollection versionEvidences) {
|
||||
final File parentDir = dependencyFile.getParentFile();
|
||||
if (parentDir != null) {
|
||||
final File[] matchingFiles = parentDir.listFiles(new FilenameFilter() {
|
||||
public boolean accept(File dir, String name) {
|
||||
return name.contains(VERSION_FILE_NAME);
|
||||
}
|
||||
});
|
||||
for (File f : matchingFiles) {
|
||||
try {
|
||||
final List<String> lines = FileUtils.readLines(f, Charset.defaultCharset());
|
||||
if (lines.size() == 1) { //TODO other checking?
|
||||
final String value = lines.get(0).trim();
|
||||
versionEvidences.addEvidence(GEMSPEC, "version", value, Confidence.HIGH);
|
||||
}
|
||||
} catch (IOException e) {
|
||||
LOGGER.debug("Error reading gemspec", e);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the package path on the dependency.
|
||||
*
|
||||
* @param dep the dependency to alter
|
||||
*/
|
||||
private void setPackagePath(Dependency dep) {
|
||||
final File file = new File(dep.getFilePath());
|
||||
final String parent = file.getParent();
|
||||
if (parent != null) {
|
||||
dep.setPackagePath(parent);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -90,7 +90,7 @@ public class CentralSearch {
|
||||
|
||||
final URL url = new URL(rootURL + String.format("?q=1:\"%s\"&wt=xml", sha1));
|
||||
|
||||
LOGGER.debug("Searching Central url {}", 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
|
||||
@@ -116,7 +116,7 @@ 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));
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
/**
|
||||
*
|
||||
* Contains classes related to searching Maven Central.<br/><br/>
|
||||
* 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.
|
||||
*/
|
||||
|
||||
@@ -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;
|
||||
@@ -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.
|
||||
*/
|
||||
@@ -230,9 +210,20 @@ 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.debug("", 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);
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -24,6 +24,7 @@ import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.io.ObjectInputStream;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
*
|
||||
@@ -45,21 +46,21 @@ 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.warn("Unable to load CWE data. This should not be an issue.");
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -77,6 +77,7 @@ public final class LuceneUtils {
|
||||
case '*':
|
||||
case '?':
|
||||
case ':':
|
||||
case '/':
|
||||
case '\\': //it is supposed to fall through here
|
||||
buf.append('\\');
|
||||
default:
|
||||
@@ -93,17 +94,12 @@ public final class LuceneUtils {
|
||||
* @return the escaped text.
|
||||
*/
|
||||
public static String escapeLuceneQuery(final CharSequence text) {
|
||||
|
||||
if (text == null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
int size = text.length();
|
||||
size = size >> 1;
|
||||
final int size = text.length() << 1;
|
||||
final StringBuilder buf = new StringBuilder(size);
|
||||
|
||||
appendEscapedLuceneQuery(buf, text);
|
||||
|
||||
return buf.toString();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -27,7 +27,7 @@ import org.apache.lucene.analysis.tokenattributes.CharTermAttribute;
|
||||
* <p>
|
||||
* Takes a TokenStream and adds additional tokens by concatenating pairs of words.</p>
|
||||
* <p>
|
||||
* <b>Example:</b> "Spring Framework Core" -> "Spring SpringFramework Framework FrameworkCore Core".</p>
|
||||
* <b>Example:</b> "Spring Framework Core" -> "Spring SpringFramework Framework FrameworkCore Core".</p>
|
||||
*
|
||||
* @author Jeremy Long
|
||||
*/
|
||||
@@ -75,8 +75,8 @@ public final class TokenPairConcatenatingFilter extends TokenFilter {
|
||||
}
|
||||
|
||||
/**
|
||||
* Increments the underlying TokenStream and sets CharTermAttributes to construct an expanded set of tokens by
|
||||
* concatenating tokens with the previous token.
|
||||
* Increments the underlying TokenStream and sets CharTermAttributes to construct an expanded set of tokens by concatenating
|
||||
* tokens with the previous token.
|
||||
*
|
||||
* @return whether or not we have hit the end of the TokenStream
|
||||
* @throws IOException is thrown when an IOException occurs
|
||||
@@ -112,8 +112,7 @@ public final class TokenPairConcatenatingFilter extends TokenFilter {
|
||||
|
||||
/**
|
||||
* <p>
|
||||
* Resets the Filter and clears any internal state data that may have been left-over from previous uses of the
|
||||
* Filter.</p>
|
||||
* Resets the Filter and clears any internal state data that may have been left-over from previous uses of the Filter.</p>
|
||||
* <p>
|
||||
* <b>If this Filter is re-used this method must be called between uses.</b></p>
|
||||
*/
|
||||
@@ -121,4 +120,46 @@ public final class TokenPairConcatenatingFilter extends TokenFilter {
|
||||
previousWord = null;
|
||||
words.clear();
|
||||
}
|
||||
|
||||
/**
|
||||
* Standard hash code implementation.
|
||||
*
|
||||
* @return the hash code
|
||||
*/
|
||||
@Override
|
||||
public int hashCode() {
|
||||
int hash = 3;
|
||||
hash = 31 * hash + (this.termAtt != null ? this.termAtt.hashCode() : 0);
|
||||
hash = 31 * hash + (this.previousWord != null ? this.previousWord.hashCode() : 0);
|
||||
hash = 31 * hash + (this.words != null ? this.words.hashCode() : 0);
|
||||
return hash;
|
||||
}
|
||||
|
||||
/**
|
||||
* Standard equals implementation.
|
||||
*
|
||||
* @param obj the object to compare
|
||||
* @return true if the objects are equal; otherwise false.
|
||||
*/
|
||||
@Override
|
||||
public boolean equals(Object obj) {
|
||||
if (obj == null) {
|
||||
return false;
|
||||
}
|
||||
if (getClass() != obj.getClass()) {
|
||||
return false;
|
||||
}
|
||||
final TokenPairConcatenatingFilter other = (TokenPairConcatenatingFilter) obj;
|
||||
if (this.termAtt != other.termAtt && (this.termAtt == null || !this.termAtt.equals(other.termAtt))) {
|
||||
return false;
|
||||
}
|
||||
if ((this.previousWord == null) ? (other.previousWord != null) : !this.previousWord.equals(other.previousWord)) {
|
||||
return false;
|
||||
}
|
||||
if (this.words != other.words && (this.words == null || !this.words.equals(other.words))) {
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -31,15 +31,17 @@ import org.slf4j.LoggerFactory;
|
||||
* <p>
|
||||
* Takes a TokenStream and splits or adds tokens to correctly index version numbers.</p>
|
||||
* <p>
|
||||
* <b>Example:</b> "3.0.0.RELEASE" -> "3 3.0 3.0.0 RELEASE 3.0.0.RELEASE".</p>
|
||||
* <b>Example:</b> "3.0.0.RELEASE" -> "3 3.0 3.0.0 RELEASE 3.0.0.RELEASE".</p>
|
||||
*
|
||||
* @author Jeremy Long
|
||||
*/
|
||||
public final class UrlTokenizingFilter extends AbstractTokenizingFilter {
|
||||
|
||||
/**
|
||||
* The logger.
|
||||
*/
|
||||
private static final Logger LOGGER = LoggerFactory.getLogger(UrlTokenizingFilter.class);
|
||||
|
||||
/**
|
||||
* Constructs a new VersionTokenizingFilter.
|
||||
*
|
||||
@@ -50,8 +52,8 @@ public final class UrlTokenizingFilter extends AbstractTokenizingFilter {
|
||||
}
|
||||
|
||||
/**
|
||||
* Increments the underlying TokenStream and sets CharTermAttributes to construct an expanded set of tokens by
|
||||
* concatenating tokens with the previous token.
|
||||
* Increments the underlying TokenStream and sets CharTermAttributes to construct an expanded set of tokens by concatenating
|
||||
* tokens with the previous token.
|
||||
*
|
||||
* @return whether or not we have hit the end of the TokenStream
|
||||
* @throws IOException is thrown when an IOException occurs
|
||||
|
||||
@@ -94,13 +94,13 @@ public class MavenArtifact {
|
||||
}
|
||||
if (jarAvailable) {
|
||||
//org/springframework/spring-core/3.2.0.RELEASE/spring-core-3.2.0.RELEASE.pom
|
||||
this.artifactUrl = base + groupId.replace('.', '/') + "/" + artifactId + "/"
|
||||
+ version + "/" + artifactId + "-" + version + ".jar";
|
||||
this.artifactUrl = base + groupId.replace('.', '/') + '/' + artifactId + '/'
|
||||
+ version + '/' + artifactId + '-' + version + ".jar";
|
||||
}
|
||||
if (pomAvailable) {
|
||||
//org/springframework/spring-core/3.2.0.RELEASE/spring-core-3.2.0.RELEASE.pom
|
||||
this.pomUrl = base + groupId.replace('.', '/') + "/" + artifactId + "/"
|
||||
+ version + "/" + artifactId + "-" + version + ".pom";
|
||||
this.pomUrl = base + groupId.replace('.', '/') + '/' + artifactId + '/'
|
||||
+ version + '/' + artifactId + '-' + version + ".pom";
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -63,7 +63,7 @@ public class NexusSearch {
|
||||
this.rootURL = rootURL;
|
||||
try {
|
||||
if (null != Settings.getString(Settings.KEYS.PROXY_SERVER)
|
||||
&& Settings.getBoolean(Settings.KEYS.ANALYZER_NEXUS_PROXY)) {
|
||||
&& Settings.getBoolean(Settings.KEYS.ANALYZER_NEXUS_USES_PROXY)) {
|
||||
useProxy = true;
|
||||
LOGGER.debug("Using proxy");
|
||||
} else {
|
||||
@@ -132,10 +132,10 @@ public class NexusSearch {
|
||||
"/org.sonatype.nexus.rest.model.NexusArtifact/pomLink",
|
||||
doc);
|
||||
final MavenArtifact ma = new MavenArtifact(groupId, artifactId, version);
|
||||
if (link != null && !"".equals(link)) {
|
||||
if (link != null && !link.isEmpty()) {
|
||||
ma.setArtifactUrl(link);
|
||||
}
|
||||
if (pomLink != null && !"".equals(pomLink)) {
|
||||
if (pomLink != null && !pomLink.isEmpty()) {
|
||||
ma.setPomUrl(pomLink);
|
||||
}
|
||||
return ma;
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/**
|
||||
* Contains classes related to searching a Nexus repository.<br/><br/>
|
||||
* Contains classes related to searching a Nexus repository.<br><br>
|
||||
*
|
||||
* These are used to abstract Nexus searching away from OWASP Dependency Check so they can be reused elsewhere.
|
||||
*/
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/**
|
||||
* Contains classes related to parsing Nuget related files<br/><br/>
|
||||
* Contains classes related to parsing Nuget related files<br><br>
|
||||
* These are used to abstract away Nuget-related handling from Dependency Check so they can be used elsewhere.
|
||||
*/
|
||||
package org.owasp.dependencycheck.data.nuget;
|
||||
|
||||
@@ -17,11 +17,9 @@
|
||||
*/
|
||||
package org.owasp.dependencycheck.data.nvdcve;
|
||||
|
||||
import java.io.BufferedReader;
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.io.InputStreamReader;
|
||||
import java.sql.CallableStatement;
|
||||
import java.sql.Connection;
|
||||
import java.sql.Driver;
|
||||
@@ -29,7 +27,10 @@ import java.sql.DriverManager;
|
||||
import java.sql.ResultSet;
|
||||
import java.sql.SQLException;
|
||||
import java.sql.Statement;
|
||||
import org.apache.commons.io.IOUtils;
|
||||
import org.owasp.dependencycheck.utils.DBUtils;
|
||||
import org.owasp.dependencycheck.utils.DependencyVersion;
|
||||
import org.owasp.dependencycheck.utils.DependencyVersionUtil;
|
||||
import org.owasp.dependencycheck.utils.Settings;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
@@ -58,6 +59,10 @@ public final class ConnectionFactory {
|
||||
* Resource location for SQL file used to create the database schema.
|
||||
*/
|
||||
public static final String DB_STRUCTURE_UPDATE_RESOURCE = "data/upgrade_%s.sql";
|
||||
/**
|
||||
* The URL that discusses upgrading non-H2 databases.
|
||||
*/
|
||||
public static final String UPGRADE_HELP_URL = "http://jeremylong.github.io/DependencyCheck/data/upgrade.html";
|
||||
/**
|
||||
* The database driver used to connect to the database.
|
||||
*/
|
||||
@@ -243,22 +248,15 @@ public final class ConnectionFactory {
|
||||
*/
|
||||
private static void createTables(Connection conn) throws DatabaseException {
|
||||
LOGGER.debug("Creating database structure");
|
||||
InputStream is;
|
||||
InputStreamReader reader;
|
||||
BufferedReader in = null;
|
||||
InputStream is = null;
|
||||
try {
|
||||
is = ConnectionFactory.class.getClassLoader().getResourceAsStream(DB_STRUCTURE_RESOURCE);
|
||||
reader = new InputStreamReader(is, "UTF-8");
|
||||
in = new BufferedReader(reader);
|
||||
final StringBuilder sb = new StringBuilder(2110);
|
||||
String tmp;
|
||||
while ((tmp = in.readLine()) != null) {
|
||||
sb.append(tmp);
|
||||
}
|
||||
final String dbStructure = IOUtils.toString(is, "UTF-8");
|
||||
|
||||
Statement statement = null;
|
||||
try {
|
||||
statement = conn.createStatement();
|
||||
statement.execute(sb.toString());
|
||||
statement.execute(dbStructure);
|
||||
} catch (SQLException ex) {
|
||||
LOGGER.debug("", ex);
|
||||
throw new DatabaseException("Unable to create database statement", ex);
|
||||
@@ -268,13 +266,7 @@ public final class ConnectionFactory {
|
||||
} catch (IOException ex) {
|
||||
throw new DatabaseException("Unable to create database schema", ex);
|
||||
} finally {
|
||||
if (in != null) {
|
||||
try {
|
||||
in.close();
|
||||
} catch (IOException ex) {
|
||||
LOGGER.trace("", ex);
|
||||
}
|
||||
}
|
||||
IOUtils.closeQuietly(is);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -284,52 +276,74 @@ public final class ConnectionFactory {
|
||||
* execute it against the database. The upgrade script must update the 'version' in the properties table.
|
||||
*
|
||||
* @param conn the database connection object
|
||||
* @param schema the current schema version that is being upgraded
|
||||
* @param appExpectedVersion the schema version that the application expects
|
||||
* @param currentDbVersion the current schema version of the database
|
||||
* @throws DatabaseException thrown if there is an exception upgrading the database schema
|
||||
*/
|
||||
private static void updateSchema(Connection conn, String schema) throws DatabaseException {
|
||||
LOGGER.debug("Updating database structure");
|
||||
InputStream is;
|
||||
InputStreamReader reader;
|
||||
BufferedReader in = null;
|
||||
String updateFile = null;
|
||||
private static void updateSchema(Connection conn, DependencyVersion appExpectedVersion, DependencyVersion currentDbVersion)
|
||||
throws DatabaseException {
|
||||
|
||||
final String databaseProductName;
|
||||
try {
|
||||
updateFile = String.format(DB_STRUCTURE_UPDATE_RESOURCE, schema);
|
||||
is = ConnectionFactory.class.getClassLoader().getResourceAsStream(updateFile);
|
||||
if (is == null) {
|
||||
throw new DatabaseException(String.format("Unable to load update file '%s'", updateFile));
|
||||
}
|
||||
reader = new InputStreamReader(is, "UTF-8");
|
||||
in = new BufferedReader(reader);
|
||||
final StringBuilder sb = new StringBuilder(2110);
|
||||
String tmp;
|
||||
while ((tmp = in.readLine()) != null) {
|
||||
sb.append(tmp);
|
||||
}
|
||||
Statement statement = null;
|
||||
databaseProductName = conn.getMetaData().getDatabaseProductName();
|
||||
} catch (SQLException ex) {
|
||||
throw new DatabaseException("Unable to get the database product name");
|
||||
}
|
||||
if ("h2".equalsIgnoreCase(databaseProductName)) {
|
||||
LOGGER.debug("Updating database structure");
|
||||
InputStream is = null;
|
||||
String updateFile = null;
|
||||
try {
|
||||
statement = conn.createStatement();
|
||||
statement.execute(sb.toString());
|
||||
} catch (SQLException ex) {
|
||||
LOGGER.debug("", ex);
|
||||
throw new DatabaseException("Unable to update database schema", ex);
|
||||
} finally {
|
||||
DBUtils.closeStatement(statement);
|
||||
}
|
||||
} catch (IOException ex) {
|
||||
final String msg = String.format("Upgrade SQL file does not exist: %s", updateFile);
|
||||
throw new DatabaseException(msg, ex);
|
||||
} finally {
|
||||
if (in != null) {
|
||||
try {
|
||||
in.close();
|
||||
} catch (IOException ex) {
|
||||
LOGGER.trace("", ex);
|
||||
updateFile = String.format(DB_STRUCTURE_UPDATE_RESOURCE, currentDbVersion.toString());
|
||||
is = ConnectionFactory.class.getClassLoader().getResourceAsStream(updateFile);
|
||||
if (is == null) {
|
||||
throw new DatabaseException(String.format("Unable to load update file '%s'", updateFile));
|
||||
}
|
||||
final String dbStructureUpdate = IOUtils.toString(is, "UTF-8");
|
||||
|
||||
Statement statement = null;
|
||||
try {
|
||||
statement = conn.createStatement();
|
||||
final boolean success = statement.execute(dbStructureUpdate);
|
||||
if (!success && statement.getUpdateCount() <= 0) {
|
||||
throw new DatabaseException(String.format("Unable to upgrade the database schema to %s",
|
||||
currentDbVersion.toString()));
|
||||
}
|
||||
} catch (SQLException ex) {
|
||||
LOGGER.debug("", ex);
|
||||
throw new DatabaseException("Unable to update database schema", ex);
|
||||
} finally {
|
||||
DBUtils.closeStatement(statement);
|
||||
}
|
||||
} catch (IOException ex) {
|
||||
final String msg = String.format("Upgrade SQL file does not exist: %s", updateFile);
|
||||
throw new DatabaseException(msg, ex);
|
||||
} finally {
|
||||
IOUtils.closeQuietly(is);
|
||||
}
|
||||
} else {
|
||||
final int e0 = Integer.parseInt(appExpectedVersion.getVersionParts().get(0));
|
||||
final int c0 = Integer.parseInt(currentDbVersion.getVersionParts().get(0));
|
||||
final int e1 = Integer.parseInt(appExpectedVersion.getVersionParts().get(1));
|
||||
final int c1 = Integer.parseInt(currentDbVersion.getVersionParts().get(1));
|
||||
if (e0 == c0 && e1 < c1) {
|
||||
LOGGER.warn("A new version of dependency-check is available; consider upgrading");
|
||||
Settings.setBoolean(Settings.KEYS.AUTO_UPDATE, false);
|
||||
} else if (e0 == c0 && e1 == c1) {
|
||||
//do nothing - not sure how we got here, but just incase...
|
||||
} else {
|
||||
LOGGER.error("The database schema must be upgraded to use this version of dependency-check. Please see {} for more information.",
|
||||
UPGRADE_HELP_URL);
|
||||
throw new DatabaseException("Database schema is out of date");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Counter to ensure that calls to ensureSchemaVersion does not end up in an endless loop.
|
||||
*/
|
||||
private static int callDepth = 0;
|
||||
|
||||
/**
|
||||
* Uses the provided connection to check the specified schema version within the database.
|
||||
*
|
||||
@@ -344,10 +358,15 @@ public final class ConnectionFactory {
|
||||
cs = conn.prepareCall("SELECT value FROM properties WHERE id = 'version'");
|
||||
rs = cs.executeQuery();
|
||||
if (rs.next()) {
|
||||
if (!DB_SCHEMA_VERSION.equals(rs.getString(1))) {
|
||||
LOGGER.debug("Current Schema: " + DB_SCHEMA_VERSION);
|
||||
LOGGER.debug("DB Schema: " + rs.getString(1));
|
||||
updateSchema(conn, rs.getString(1));
|
||||
final DependencyVersion appDbVersion = DependencyVersionUtil.parseVersion(DB_SCHEMA_VERSION);
|
||||
final DependencyVersion db = DependencyVersionUtil.parseVersion(rs.getString(1));
|
||||
if (appDbVersion.compareTo(db) > 0) {
|
||||
LOGGER.debug("Current Schema: {}", DB_SCHEMA_VERSION);
|
||||
LOGGER.debug("DB Schema: {}", rs.getString(1));
|
||||
updateSchema(conn, appDbVersion, db);
|
||||
if (++callDepth < 10) {
|
||||
ensureSchemaVersion(conn);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
throw new DatabaseException("Database schema is missing");
|
||||
|
||||
@@ -18,12 +18,11 @@
|
||||
package org.owasp.dependencycheck.data.nvdcve;
|
||||
|
||||
/**
|
||||
* An exception used to indicate the db4o database is corrupt. This could be due to invalid data or a complete failure
|
||||
* of the db.
|
||||
* An exception used to indicate the db4o database is corrupt. This could be due to invalid data or a complete failure of the db.
|
||||
*
|
||||
* @author Jeremy Long
|
||||
*/
|
||||
class CorruptDatabaseException extends DatabaseException {
|
||||
public class CorruptDatabaseException extends DatabaseException {
|
||||
|
||||
/**
|
||||
* the serial version uid.
|
||||
@@ -31,7 +30,7 @@ class CorruptDatabaseException extends DatabaseException {
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
/**
|
||||
* Creates an CorruptDatabaseException
|
||||
* Creates an CorruptDatabaseException.
|
||||
*
|
||||
* @param msg the exception message
|
||||
*/
|
||||
@@ -40,7 +39,7 @@ class CorruptDatabaseException extends DatabaseException {
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates an CorruptDatabaseException
|
||||
* Creates an CorruptDatabaseException.
|
||||
*
|
||||
* @param msg the exception message
|
||||
* @param ex the cause of the exception
|
||||
|
||||
@@ -29,8 +29,10 @@ import java.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
import java.util.Locale;
|
||||
import java.util.Map;
|
||||
import java.util.Map.Entry;
|
||||
import java.util.MissingResourceException;
|
||||
import java.util.Properties;
|
||||
import java.util.ResourceBundle;
|
||||
import java.util.Set;
|
||||
@@ -67,16 +69,34 @@ public class CveDB {
|
||||
private ResourceBundle statementBundle = null;
|
||||
|
||||
/**
|
||||
* Creates a new CveDB object and opens the database connection. Note, the connection must be closed by the caller by calling
|
||||
* the close method.
|
||||
*
|
||||
* @throws DatabaseException thrown if there is an exception opening the database.
|
||||
* Creates a new CveDB object and opens the database
|
||||
* connection. Note, the connection must be closed by the caller by calling
|
||||
* the close method. ======= Does the underlying connection support batch
|
||||
* operations?
|
||||
*/
|
||||
private boolean batchSupported;
|
||||
|
||||
/**
|
||||
* Creates a new CveDB object and opens the database connection. Note, the
|
||||
* connection must be closed by the caller by calling the close method.
|
||||
*
|
||||
* @throws DatabaseException thrown if there is an exception opening the
|
||||
* database.
|
||||
*/
|
||||
public CveDB() throws DatabaseException {
|
||||
super();
|
||||
statementBundle = ResourceBundle.getBundle("data/dbStatements");
|
||||
try {
|
||||
open();
|
||||
try {
|
||||
final String databaseProductName = conn.getMetaData().getDatabaseProductName();
|
||||
batchSupported = conn.getMetaData().supportsBatchUpdates();
|
||||
LOGGER.debug("Database dialect: {}", databaseProductName);
|
||||
final Locale dbDialect = new Locale(databaseProductName);
|
||||
statementBundle = ResourceBundle.getBundle("data/dbStatements", dbDialect);
|
||||
} catch (SQLException se) {
|
||||
LOGGER.warn("Problem loading database specific dialect!", se);
|
||||
statementBundle = ResourceBundle.getBundle("data/dbStatements");
|
||||
}
|
||||
databaseProperties = new DatabaseProperties(this);
|
||||
} catch (DatabaseException ex) {
|
||||
throw ex;
|
||||
@@ -93,9 +113,11 @@ public class CveDB {
|
||||
}
|
||||
|
||||
/**
|
||||
* Opens the database connection. If the database does not exist, it will create a new one.
|
||||
* Opens the database connection. If the database does not exist, it will
|
||||
* create a new one.
|
||||
*
|
||||
* @throws DatabaseException thrown if there is an error opening the database connection
|
||||
* @throws DatabaseException thrown if there is an error opening the
|
||||
* database connection
|
||||
*/
|
||||
public final void open() throws DatabaseException {
|
||||
if (!isOpen()) {
|
||||
@@ -104,7 +126,8 @@ public class CveDB {
|
||||
}
|
||||
|
||||
/**
|
||||
* Closes the DB4O database. Close should be called on this object when it is done being used.
|
||||
* Closes the DB4O database. Close should be called on this object when it
|
||||
* is done being used.
|
||||
*/
|
||||
public void close() {
|
||||
if (conn != null) {
|
||||
@@ -155,7 +178,8 @@ public class CveDB {
|
||||
super.finalize();
|
||||
}
|
||||
/**
|
||||
* Database properties object containing the 'properties' from the database table.
|
||||
* Database properties object containing the 'properties' from the database
|
||||
* table.
|
||||
*/
|
||||
private DatabaseProperties databaseProperties;
|
||||
|
||||
@@ -169,11 +193,13 @@ public class CveDB {
|
||||
}
|
||||
|
||||
/**
|
||||
* Searches the CPE entries in the database and retrieves all entries for a given vendor and product combination. The returned
|
||||
* list will include all versions of the product that are registered in the NVD CVE data.
|
||||
* Searches the CPE entries in the database and retrieves all entries for a
|
||||
* given vendor and product combination. The returned list will include all
|
||||
* versions of the product that are registered in the NVD CVE data.
|
||||
*
|
||||
* @param vendor the identified vendor name of the dependency being analyzed
|
||||
* @param product the identified name of the product of the dependency being analyzed
|
||||
* @param product the identified name of the product of the dependency being
|
||||
* analyzed
|
||||
* @return a set of vulnerable software
|
||||
*/
|
||||
public Set<VulnerableSoftware> getCPEs(String vendor, String product) {
|
||||
@@ -205,7 +231,8 @@ public class CveDB {
|
||||
* Returns the entire list of vendor/product combinations.
|
||||
*
|
||||
* @return the entire list of vendor/product combinations
|
||||
* @throws DatabaseException thrown when there is an error retrieving the data from the DB
|
||||
* @throws DatabaseException thrown when there is an error retrieving the
|
||||
* data from the DB
|
||||
*/
|
||||
public Set<Pair<String, String>> getVendorProductList() throws DatabaseException {
|
||||
final Set<Pair<String, String>> data = new HashSet<Pair<String, String>>();
|
||||
@@ -252,44 +279,6 @@ public class CveDB {
|
||||
return prop;
|
||||
}
|
||||
|
||||
/**
|
||||
* Saves a set of properties to the database.
|
||||
*
|
||||
* @param props a collection of properties
|
||||
*/
|
||||
void saveProperties(Properties props) {
|
||||
PreparedStatement updateProperty = null;
|
||||
PreparedStatement insertProperty = null;
|
||||
try {
|
||||
try {
|
||||
updateProperty = getConnection().prepareStatement(statementBundle.getString("UPDATE_PROPERTY"));
|
||||
insertProperty = getConnection().prepareStatement(statementBundle.getString("INSERT_PROPERTY"));
|
||||
} catch (SQLException ex) {
|
||||
LOGGER.warn("Unable to save properties to the database");
|
||||
LOGGER.debug("Unable to save properties to the database", ex);
|
||||
return;
|
||||
}
|
||||
for (Entry<Object, Object> entry : props.entrySet()) {
|
||||
final String key = entry.getKey().toString();
|
||||
final String value = entry.getValue().toString();
|
||||
try {
|
||||
updateProperty.setString(1, value);
|
||||
updateProperty.setString(2, key);
|
||||
if (updateProperty.executeUpdate() == 0) {
|
||||
insertProperty.setString(1, key);
|
||||
insertProperty.setString(2, value);
|
||||
}
|
||||
} catch (SQLException ex) {
|
||||
LOGGER.warn("Unable to save property '{}' with a value of '{}' to the database", key, value);
|
||||
LOGGER.debug("", ex);
|
||||
}
|
||||
}
|
||||
} finally {
|
||||
DBUtils.closeStatement(updateProperty);
|
||||
DBUtils.closeStatement(insertProperty);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Saves a property to the database.
|
||||
*
|
||||
@@ -297,38 +286,38 @@ public class CveDB {
|
||||
* @param value the property value
|
||||
*/
|
||||
void saveProperty(String key, String value) {
|
||||
PreparedStatement updateProperty = null;
|
||||
PreparedStatement insertProperty = null;
|
||||
try {
|
||||
try {
|
||||
updateProperty = getConnection().prepareStatement(statementBundle.getString("UPDATE_PROPERTY"));
|
||||
} catch (SQLException ex) {
|
||||
LOGGER.warn("Unable to save properties to the database");
|
||||
LOGGER.debug("Unable to save properties to the database", ex);
|
||||
return;
|
||||
}
|
||||
try {
|
||||
updateProperty.setString(1, value);
|
||||
updateProperty.setString(2, key);
|
||||
if (updateProperty.executeUpdate() == 0) {
|
||||
try {
|
||||
insertProperty = getConnection().prepareStatement(statementBundle.getString("INSERT_PROPERTY"));
|
||||
} catch (SQLException ex) {
|
||||
LOGGER.warn("Unable to save properties to the database");
|
||||
LOGGER.debug("Unable to save properties to the database", ex);
|
||||
return;
|
||||
}
|
||||
insertProperty.setString(1, key);
|
||||
insertProperty.setString(2, value);
|
||||
insertProperty.execute();
|
||||
final PreparedStatement mergeProperty = getConnection().prepareStatement(statementBundle.getString("MERGE_PROPERTY"));
|
||||
try {
|
||||
mergeProperty.setString(1, key);
|
||||
mergeProperty.setString(2, value);
|
||||
mergeProperty.executeUpdate();
|
||||
} finally {
|
||||
DBUtils.closeStatement(mergeProperty);
|
||||
}
|
||||
} catch (MissingResourceException mre) {
|
||||
// No Merge statement, so doing an Update/Insert...
|
||||
PreparedStatement updateProperty = null;
|
||||
PreparedStatement insertProperty = null;
|
||||
try {
|
||||
updateProperty = getConnection().prepareStatement(statementBundle.getString("UPDATE_PROPERTY"));
|
||||
updateProperty.setString(1, value);
|
||||
updateProperty.setString(2, key);
|
||||
if (updateProperty.executeUpdate() == 0) {
|
||||
insertProperty = getConnection().prepareStatement(statementBundle.getString("INSERT_PROPERTY"));
|
||||
insertProperty.setString(1, key);
|
||||
insertProperty.setString(2, value);
|
||||
insertProperty.executeUpdate();
|
||||
}
|
||||
} finally {
|
||||
DBUtils.closeStatement(updateProperty);
|
||||
DBUtils.closeStatement(insertProperty);
|
||||
}
|
||||
} catch (SQLException ex) {
|
||||
LOGGER.warn("Unable to save property '{}' with a value of '{}' to the database", key, value);
|
||||
LOGGER.debug("", ex);
|
||||
}
|
||||
} finally {
|
||||
DBUtils.closeStatement(updateProperty);
|
||||
DBUtils.closeStatement(insertProperty);
|
||||
} catch (SQLException ex) {
|
||||
LOGGER.warn("Unable to save property '{}' with a value of '{}' to the database", key, value);
|
||||
LOGGER.debug("", ex);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -340,7 +329,6 @@ public class CveDB {
|
||||
* @throws DatabaseException thrown if there is an exception retrieving data
|
||||
*/
|
||||
public List<Vulnerability> getVulnerabilities(String cpeStr) throws DatabaseException {
|
||||
ResultSet rs = null;
|
||||
final VulnerableSoftware cpe = new VulnerableSoftware();
|
||||
try {
|
||||
cpe.parseName(cpeStr);
|
||||
@@ -350,7 +338,8 @@ public class CveDB {
|
||||
final DependencyVersion detectedVersion = parseDependencyVersion(cpe);
|
||||
final List<Vulnerability> vulnerabilities = new ArrayList<Vulnerability>();
|
||||
|
||||
PreparedStatement ps;
|
||||
PreparedStatement ps = null;
|
||||
ResultSet rs = null;
|
||||
try {
|
||||
ps = getConnection().prepareStatement(statementBundle.getString("SELECT_CVE_FROM_SOFTWARE"));
|
||||
ps.setString(1, cpe.getVendor());
|
||||
@@ -384,12 +373,11 @@ public class CveDB {
|
||||
v.setMatchedCPE(matchedCPE.getKey(), matchedCPE.getValue() ? "Y" : null);
|
||||
vulnerabilities.add(v);
|
||||
}
|
||||
DBUtils.closeResultSet(rs);
|
||||
DBUtils.closeStatement(ps);
|
||||
} catch (SQLException ex) {
|
||||
throw new DatabaseException("Exception retrieving vulnerability for " + cpeStr, ex);
|
||||
} finally {
|
||||
DBUtils.closeResultSet(rs);
|
||||
DBUtils.closeStatement(ps);
|
||||
}
|
||||
return vulnerabilities;
|
||||
}
|
||||
@@ -401,7 +389,7 @@ public class CveDB {
|
||||
* @return a vulnerability object
|
||||
* @throws DatabaseException if an exception occurs
|
||||
*/
|
||||
private Vulnerability getVulnerability(String cve) throws DatabaseException {
|
||||
public Vulnerability getVulnerability(String cve) throws DatabaseException {
|
||||
PreparedStatement psV = null;
|
||||
PreparedStatement psR = null;
|
||||
PreparedStatement psS = null;
|
||||
@@ -409,6 +397,7 @@ public class CveDB {
|
||||
ResultSet rsR = null;
|
||||
ResultSet rsS = null;
|
||||
Vulnerability vuln = null;
|
||||
|
||||
try {
|
||||
psV = getConnection().prepareStatement(statementBundle.getString("SELECT_VULNERABILITY"));
|
||||
psV.setString(1, cve);
|
||||
@@ -421,7 +410,7 @@ public class CveDB {
|
||||
if (cwe != null) {
|
||||
final String name = CweDB.getCweName(cwe);
|
||||
if (name != null) {
|
||||
cwe += " " + name;
|
||||
cwe += ' ' + name;
|
||||
}
|
||||
}
|
||||
final int cveId = rsV.getInt(1);
|
||||
@@ -467,7 +456,8 @@ public class CveDB {
|
||||
}
|
||||
|
||||
/**
|
||||
* Updates the vulnerability within the database. If the vulnerability does not exist it will be added.
|
||||
* Updates the vulnerability within the database. If the vulnerability does
|
||||
* not exist it will be added.
|
||||
*
|
||||
* @param vuln the vulnerability to add to the database
|
||||
* @throws DatabaseException is thrown if the database
|
||||
@@ -490,7 +480,7 @@ public class CveDB {
|
||||
deleteReferences = getConnection().prepareStatement(statementBundle.getString("DELETE_REFERENCE"));
|
||||
deleteSoftware = getConnection().prepareStatement(statementBundle.getString("DELETE_SOFTWARE"));
|
||||
updateVulnerability = getConnection().prepareStatement(statementBundle.getString("UPDATE_VULNERABILITY"));
|
||||
String ids[] = {"id"};
|
||||
final String[] ids = {"id"};
|
||||
insertVulnerability = getConnection().prepareStatement(statementBundle.getString("INSERT_VULNERABILITY"),
|
||||
//Statement.RETURN_GENERATED_KEYS);
|
||||
ids);
|
||||
@@ -513,6 +503,7 @@ public class CveDB {
|
||||
}
|
||||
DBUtils.closeResultSet(rs);
|
||||
rs = null;
|
||||
|
||||
if (vulnerabilityId != 0) {
|
||||
if (vuln.getDescription().contains("** REJECT **")) {
|
||||
deleteVulnerability.setInt(1, vulnerabilityId);
|
||||
@@ -554,13 +545,24 @@ public class CveDB {
|
||||
rs = null;
|
||||
}
|
||||
}
|
||||
insertReference.setInt(1, vulnerabilityId);
|
||||
|
||||
for (Reference r : vuln.getReferences()) {
|
||||
insertReference.setInt(1, vulnerabilityId);
|
||||
insertReference.setString(2, r.getName());
|
||||
insertReference.setString(3, r.getUrl());
|
||||
insertReference.setString(4, r.getSource());
|
||||
insertReference.execute();
|
||||
|
||||
if (batchSupported) {
|
||||
insertReference.addBatch();
|
||||
} else {
|
||||
insertReference.execute();
|
||||
}
|
||||
}
|
||||
|
||||
if (batchSupported) {
|
||||
insertReference.executeBatch();
|
||||
}
|
||||
|
||||
for (VulnerableSoftware s : vuln.getVulnerableSoftware()) {
|
||||
int cpeProductId = 0;
|
||||
selectCpeId.setString(1, s.getName());
|
||||
@@ -589,17 +591,33 @@ public class CveDB {
|
||||
|
||||
insertSoftware.setInt(1, vulnerabilityId);
|
||||
insertSoftware.setInt(2, cpeProductId);
|
||||
|
||||
if (s.getPreviousVersion() == null) {
|
||||
insertSoftware.setNull(3, java.sql.Types.VARCHAR);
|
||||
} else {
|
||||
insertSoftware.setString(3, s.getPreviousVersion());
|
||||
}
|
||||
insertSoftware.execute();
|
||||
if (batchSupported) {
|
||||
insertSoftware.addBatch();
|
||||
} else {
|
||||
try {
|
||||
insertSoftware.execute();
|
||||
} catch (SQLException ex) {
|
||||
if (ex.getMessage().contains("Duplicate entry")) {
|
||||
final String msg = String.format("Duplicate software key identified in '%s:%s'", vuln.getName(), s.getName());
|
||||
LOGGER.debug(msg, ex);
|
||||
} else {
|
||||
throw ex;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
if (batchSupported) {
|
||||
insertSoftware.executeBatch();
|
||||
}
|
||||
|
||||
} catch (SQLException ex) {
|
||||
final String msg = String.format("Error updating '%s'", vuln.getName());
|
||||
LOGGER.debug("", ex);
|
||||
LOGGER.debug(msg, ex);
|
||||
throw new DatabaseException(msg, ex);
|
||||
} finally {
|
||||
DBUtils.closeStatement(selectVulnerabilityId);
|
||||
@@ -652,8 +670,9 @@ public class CveDB {
|
||||
}
|
||||
|
||||
/**
|
||||
* It is possible that orphaned rows may be generated during database updates. This should be called after all updates have
|
||||
* been completed to ensure orphan entries are removed.
|
||||
* It is possible that orphaned rows may be generated during database
|
||||
* updates. This should be called after all updates have been completed to
|
||||
* ensure orphan entries are removed.
|
||||
*/
|
||||
public void cleanupDatabase() {
|
||||
PreparedStatement ps = null;
|
||||
@@ -671,13 +690,17 @@ public class CveDB {
|
||||
}
|
||||
|
||||
/**
|
||||
* Determines if the given identifiedVersion is affected by the given cpeId and previous version flag. A non-null, non-empty
|
||||
* string passed to the previous version argument indicates that all previous versions are affected.
|
||||
* Determines if the given identifiedVersion is affected by the given cpeId
|
||||
* and previous version flag. A non-null, non-empty string passed to the
|
||||
* previous version argument indicates that all previous versions are
|
||||
* affected.
|
||||
*
|
||||
* @param vendor the vendor of the dependency being analyzed
|
||||
* @param product the product name of the dependency being analyzed
|
||||
* @param vulnerableSoftware a map of the vulnerable software with a boolean indicating if all previous versions are affected
|
||||
* @param identifiedVersion the identified version of the dependency being analyzed
|
||||
* @param vulnerableSoftware a map of the vulnerable software with a boolean
|
||||
* indicating if all previous versions are affected
|
||||
* @param identifiedVersion the identified version of the dependency being
|
||||
* analyzed
|
||||
* @return true if the identified version is affected, otherwise false
|
||||
*/
|
||||
Entry<String, Boolean> getMatchingSoftware(Map<String, Boolean> vulnerableSoftware, String vendor, String product,
|
||||
@@ -744,7 +767,8 @@ public class CveDB {
|
||||
}
|
||||
|
||||
/**
|
||||
* Parses the version (including revision) from a CPE identifier. If no version is identified then a '-' is returned.
|
||||
* Parses the version (including revision) from a CPE identifier. If no
|
||||
* version is identified then a '-' is returned.
|
||||
*
|
||||
* @param cpeStr a cpe identifier
|
||||
* @return a dependency version
|
||||
@@ -761,15 +785,16 @@ public class CveDB {
|
||||
}
|
||||
|
||||
/**
|
||||
* Takes a CPE and parses out the version number. If no version is identified then a '-' is returned.
|
||||
* Takes a CPE and parses out the version number. If no version is
|
||||
* identified then a '-' is returned.
|
||||
*
|
||||
* @param cpe a cpe object
|
||||
* @return a dependency version
|
||||
*/
|
||||
private DependencyVersion parseDependencyVersion(VulnerableSoftware cpe) {
|
||||
DependencyVersion cpeVersion;
|
||||
final DependencyVersion cpeVersion;
|
||||
if (cpe.getVersion() != null && !cpe.getVersion().isEmpty()) {
|
||||
String versionText;
|
||||
final String versionText;
|
||||
if (cpe.getUpdate() != null && !cpe.getUpdate().isEmpty()) {
|
||||
versionText = String.format("%s.%s", cpe.getVersion(), cpe.getUpdate());
|
||||
} else {
|
||||
@@ -783,6 +808,8 @@ public class CveDB {
|
||||
}
|
||||
|
||||
/**
|
||||
* This method is only referenced in unused code.
|
||||
*
|
||||
* Deletes unused dictionary entries from the database.
|
||||
*/
|
||||
public void deleteUnusedCpe() {
|
||||
@@ -798,6 +825,9 @@ public class CveDB {
|
||||
}
|
||||
|
||||
/**
|
||||
* This method is only referenced in unused code and will likely break on
|
||||
* MySQL if ever used due to the MERGE statement.
|
||||
*
|
||||
* Merges CPE entries into the database.
|
||||
*
|
||||
* @param cpe the CPE identifier
|
||||
|
||||
@@ -45,6 +45,10 @@ public class DatabaseProperties {
|
||||
* updates)..
|
||||
*/
|
||||
public static final String MODIFIED = "Modified";
|
||||
/**
|
||||
* The properties file key for the last checked field - used to store the last check time of the Modified NVD CVE xml file.
|
||||
*/
|
||||
public static final String LAST_CHECKED = "NVD CVE Checked";
|
||||
/**
|
||||
* The properties file key for the last updated field - used to store the last updated time of the Modified NVD CVE xml file.
|
||||
*/
|
||||
@@ -66,11 +70,11 @@ public class DatabaseProperties {
|
||||
/**
|
||||
* A collection of properties about the data.
|
||||
*/
|
||||
private Properties properties;
|
||||
private final Properties properties;
|
||||
/**
|
||||
* A reference to the database.
|
||||
*/
|
||||
private CveDB cveDB;
|
||||
private final CveDB cveDB;
|
||||
|
||||
/**
|
||||
* Constructs a new data properties object.
|
||||
@@ -79,13 +83,6 @@ public class DatabaseProperties {
|
||||
*/
|
||||
DatabaseProperties(CveDB cveDB) {
|
||||
this.cveDB = cveDB;
|
||||
loadProperties();
|
||||
}
|
||||
|
||||
/**
|
||||
* Loads the properties from the database.
|
||||
*/
|
||||
private void loadProperties() {
|
||||
this.properties = cveDB.getProperties();
|
||||
}
|
||||
|
||||
|
||||
@@ -63,15 +63,13 @@ public final class DriverLoader {
|
||||
}
|
||||
|
||||
/**
|
||||
* Loads the specified class by registering the supplied paths to the class loader and then registers the driver
|
||||
* with the driver manager. The pathToDriver argument is added to the class loader so that an external driver can be
|
||||
* loaded. Note, the pathToDriver can contain a semi-colon separated list of paths so any dependencies can be added
|
||||
* as needed. If a path in the pathToDriver argument is a directory all files in the directory are added to the
|
||||
* class path.
|
||||
* Loads the specified class by registering the supplied paths to the class loader and then registers the driver with the
|
||||
* driver manager. The pathToDriver argument is added to the class loader so that an external driver can be loaded. Note, the
|
||||
* pathToDriver can contain a semi-colon separated list of paths so any dependencies can be added as needed. If a path in the
|
||||
* pathToDriver argument is a directory all files in the directory are added to the class path.
|
||||
*
|
||||
* @param className the fully qualified name of the desired class
|
||||
* @param pathToDriver the path to the JAR file containing the driver; note, this can be a semi-colon separated list
|
||||
* of paths
|
||||
* @param pathToDriver the path to the JAR file containing the driver; note, this can be a semi-colon separated list of paths
|
||||
* @return the loaded Driver
|
||||
* @throws DriverLoadException thrown if the driver cannot be loaded
|
||||
*/
|
||||
@@ -83,14 +81,15 @@ public final class DriverLoader {
|
||||
final File file = new File(path);
|
||||
if (file.isDirectory()) {
|
||||
final File[] files = file.listFiles();
|
||||
|
||||
for (File f : files) {
|
||||
try {
|
||||
urls.add(f.toURI().toURL());
|
||||
} catch (MalformedURLException ex) {
|
||||
LOGGER.debug("Unable to load database driver '{}'; invalid path provided '{}'",
|
||||
className, f.getAbsoluteFile(), ex);
|
||||
throw new DriverLoadException("Unable to load database driver. Invalid path provided", ex);
|
||||
if (files != null) {
|
||||
for (File f : files) {
|
||||
try {
|
||||
urls.add(f.toURI().toURL());
|
||||
} catch (MalformedURLException ex) {
|
||||
LOGGER.debug("Unable to load database driver '{}'; invalid path provided '{}'",
|
||||
className, f.getAbsoluteFile(), ex);
|
||||
throw new DriverLoadException("Unable to load database driver. Invalid path provided", ex);
|
||||
}
|
||||
}
|
||||
}
|
||||
} else if (file.exists()) {
|
||||
@@ -98,7 +97,7 @@ public final class DriverLoader {
|
||||
urls.add(file.toURI().toURL());
|
||||
} catch (MalformedURLException ex) {
|
||||
LOGGER.debug("Unable to load database driver '{}'; invalid path provided '{}'",
|
||||
className, file.getAbsoluteFile(), ex);
|
||||
className, file.getAbsoluteFile(), ex);
|
||||
throw new DriverLoadException("Unable to load database driver. Invalid path provided", ex);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -115,7 +115,7 @@ class DriverShim implements Driver {
|
||||
* @throws SQLFeatureNotSupportedException thrown if the feature is not supported
|
||||
* @see java.sql.Driver#getParentLogger()
|
||||
*/
|
||||
//@Override
|
||||
@Override
|
||||
public java.util.logging.Logger getParentLogger() throws SQLFeatureNotSupportedException {
|
||||
//return driver.getParentLogger();
|
||||
Method m = null;
|
||||
|
||||
@@ -24,7 +24,6 @@ import java.io.FileOutputStream;
|
||||
import java.io.IOException;
|
||||
import java.net.MalformedURLException;
|
||||
import java.net.URL;
|
||||
import java.util.Date;
|
||||
import java.util.List;
|
||||
import java.util.zip.GZIPInputStream;
|
||||
import javax.xml.parsers.ParserConfigurationException;
|
||||
@@ -44,6 +43,9 @@ import org.slf4j.LoggerFactory;
|
||||
import org.xml.sax.SAXException;
|
||||
|
||||
/**
|
||||
*
|
||||
* This class is currently unused and if enabled will likely not work on MySQL as the MERGE statement is used.
|
||||
*
|
||||
* The CpeUpdater is designed to download the CPE data file from NIST and import the data into the database. However, as this
|
||||
* currently adds no beneficial data, compared to what is in the CPE data contained in the CVE data files, this class is not
|
||||
* currently used. The code is being kept as a future update may utilize more data from the CPE xml files.
|
||||
@@ -69,8 +71,8 @@ public class CpeUpdater extends BaseUpdater implements CachedWebDataSource {
|
||||
for (Cpe cpe : cpes) {
|
||||
getCveDB().addCpe(cpe.getValue(), cpe.getVendor(), cpe.getProduct());
|
||||
}
|
||||
final Date now = new Date();
|
||||
getProperties().save(LAST_CPE_UPDATE, Long.toString(now.getTime()));
|
||||
final long now = System.currentTimeMillis();
|
||||
getProperties().save(LAST_CPE_UPDATE, Long.toString(now));
|
||||
LOGGER.info("CPE update complete");
|
||||
}
|
||||
} finally {
|
||||
@@ -134,14 +136,14 @@ public class CpeUpdater extends BaseUpdater implements CachedWebDataSource {
|
||||
* @return true if the CPE data should be refreshed
|
||||
*/
|
||||
private boolean updateNeeded() {
|
||||
final Date now = new Date();
|
||||
final int days = Settings.getInt(Settings.KEYS.CVE_MODIFIED_VALID_FOR_DAYS, 30);
|
||||
final long now = System.currentTimeMillis();
|
||||
final int days = Settings.getInt(Settings.KEYS.CPE_MODIFIED_VALID_FOR_DAYS, 30);
|
||||
long timestamp = 0;
|
||||
final String ts = getProperties().getProperty(LAST_CPE_UPDATE);
|
||||
if (ts != null && ts.matches("^[0-9]+$")) {
|
||||
timestamp = Long.parseLong(ts);
|
||||
}
|
||||
return !DateUtil.withinDateRange(timestamp, now.getTime(), days);
|
||||
return !DateUtil.withinDateRange(timestamp, now, days);
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -21,7 +21,6 @@ import java.io.IOException;
|
||||
import java.net.HttpURLConnection;
|
||||
import java.net.MalformedURLException;
|
||||
import java.net.URL;
|
||||
import java.util.Date;
|
||||
import org.apache.commons.io.IOUtils;
|
||||
import org.owasp.dependencycheck.data.nvdcve.CveDB;
|
||||
import org.owasp.dependencycheck.data.nvdcve.DatabaseException;
|
||||
@@ -29,6 +28,7 @@ import org.owasp.dependencycheck.data.nvdcve.DatabaseProperties;
|
||||
import org.owasp.dependencycheck.data.update.exception.UpdateException;
|
||||
import org.owasp.dependencycheck.utils.DateUtil;
|
||||
import org.owasp.dependencycheck.utils.DependencyVersion;
|
||||
import org.owasp.dependencycheck.utils.InvalidSettingException;
|
||||
import org.owasp.dependencycheck.utils.Settings;
|
||||
import org.owasp.dependencycheck.utils.URLConnectionFactory;
|
||||
import org.owasp.dependencycheck.utils.URLConnectionFailureException;
|
||||
@@ -83,27 +83,33 @@ public class EngineVersionCheck implements CachedWebDataSource {
|
||||
|
||||
@Override
|
||||
public void update() throws UpdateException {
|
||||
|
||||
try {
|
||||
openDatabase();
|
||||
LOGGER.debug("Begin Engine Version Check");
|
||||
final DatabaseProperties properties = cveDB.getDatabaseProperties();
|
||||
final long lastChecked = Long.parseLong(properties.getProperty(ENGINE_VERSION_CHECKED_ON, "0"));
|
||||
final long now = (new Date()).getTime();
|
||||
updateToVersion = properties.getProperty(CURRENT_ENGINE_RELEASE, "");
|
||||
final String currentVersion = Settings.getString(Settings.KEYS.APPLICATION_VERSION, "0.0.0");
|
||||
LOGGER.debug("Last checked: {}", lastChecked);
|
||||
LOGGER.debug("Now: {}", now);
|
||||
LOGGER.debug("Current version: {}", currentVersion);
|
||||
final boolean updateNeeded = shouldUpdate(lastChecked, now, properties, currentVersion);
|
||||
if (updateNeeded) {
|
||||
LOGGER.warn("A new version of dependency-check is available. Consider updating to version {}.",
|
||||
updateToVersion);
|
||||
if (Settings.getBoolean(Settings.KEYS.AUTO_UPDATE)) {
|
||||
openDatabase();
|
||||
LOGGER.debug("Begin Engine Version Check");
|
||||
final DatabaseProperties properties = cveDB.getDatabaseProperties();
|
||||
final long lastChecked = Long.parseLong(properties.getProperty(ENGINE_VERSION_CHECKED_ON, "0"));
|
||||
final long now = System.currentTimeMillis();
|
||||
updateToVersion = properties.getProperty(CURRENT_ENGINE_RELEASE, "");
|
||||
final String currentVersion = Settings.getString(Settings.KEYS.APPLICATION_VERSION, "0.0.0");
|
||||
LOGGER.debug("Last checked: {}", lastChecked);
|
||||
LOGGER.debug("Now: {}", now);
|
||||
LOGGER.debug("Current version: {}", currentVersion);
|
||||
final boolean updateNeeded = shouldUpdate(lastChecked, now, properties, currentVersion);
|
||||
if (updateNeeded) {
|
||||
LOGGER.warn("A new version of dependency-check is available. Consider updating to version {}.",
|
||||
updateToVersion);
|
||||
}
|
||||
}
|
||||
} catch (DatabaseException ex) {
|
||||
LOGGER.debug("Database Exception opening databases to retrieve properties", ex);
|
||||
throw new UpdateException("Error occured updating database properties.");
|
||||
} catch (InvalidSettingException ex) {
|
||||
LOGGER.debug("Unable to determine if autoupdate is enabled", ex);
|
||||
} finally {
|
||||
closeDatabase();
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@@ -121,10 +127,7 @@ public class EngineVersionCheck implements CachedWebDataSource {
|
||||
protected boolean shouldUpdate(final long lastChecked, final long now, final DatabaseProperties properties,
|
||||
String currentVersion) throws UpdateException {
|
||||
//check every 30 days if we know there is an update, otherwise check every 7 days
|
||||
int checkRange = 30;
|
||||
if (updateToVersion.isEmpty()) {
|
||||
checkRange = 7;
|
||||
}
|
||||
final int checkRange = 30;
|
||||
if (!DateUtil.withinDateRange(lastChecked, now, checkRange)) {
|
||||
LOGGER.debug("Checking web for new version.");
|
||||
final String currentRelease = getCurrentReleaseVersion();
|
||||
@@ -134,14 +137,16 @@ public class EngineVersionCheck implements CachedWebDataSource {
|
||||
updateToVersion = v.toString();
|
||||
if (!currentRelease.equals(updateToVersion)) {
|
||||
properties.save(CURRENT_ENGINE_RELEASE, updateToVersion);
|
||||
} else {
|
||||
properties.save(CURRENT_ENGINE_RELEASE, "");
|
||||
}
|
||||
properties.save(ENGINE_VERSION_CHECKED_ON, Long.toString(now));
|
||||
}
|
||||
}
|
||||
LOGGER.debug("Current Release: {}", updateToVersion);
|
||||
}
|
||||
if (updateToVersion == null) {
|
||||
LOGGER.debug("Unable to obtain current release");
|
||||
return false;
|
||||
}
|
||||
final DependencyVersion running = new DependencyVersion(currentVersion);
|
||||
final DependencyVersion released = new DependencyVersion(updateToVersion);
|
||||
if (running.compareTo(released) < 0) {
|
||||
|
||||
@@ -19,13 +19,14 @@ package org.owasp.dependencycheck.data.update;
|
||||
|
||||
import java.net.MalformedURLException;
|
||||
import java.util.Calendar;
|
||||
import java.util.Date;
|
||||
import java.util.HashSet;
|
||||
import java.util.Set;
|
||||
import java.util.concurrent.ExecutionException;
|
||||
import java.util.concurrent.ExecutorService;
|
||||
import java.util.concurrent.Executors;
|
||||
import java.util.concurrent.Future;
|
||||
import org.owasp.dependencycheck.data.nvdcve.CveDB;
|
||||
import org.owasp.dependencycheck.data.nvdcve.DatabaseException;
|
||||
import org.owasp.dependencycheck.data.nvdcve.DatabaseProperties;
|
||||
import static org.owasp.dependencycheck.data.nvdcve.DatabaseProperties.MODIFIED;
|
||||
import org.owasp.dependencycheck.data.update.exception.InvalidDataException;
|
||||
@@ -59,17 +60,28 @@ public class NvdCveUpdater extends BaseUpdater implements CachedWebDataSource {
|
||||
|
||||
/**
|
||||
* <p>
|
||||
* Downloads the latest NVD CVE XML file from the web and imports it into the current CVE Database.</p>
|
||||
* Downloads the latest NVD CVE XML file from the web and imports it into
|
||||
* the current CVE Database.</p>
|
||||
*
|
||||
* @throws UpdateException is thrown if there is an error updating the database
|
||||
* @throws UpdateException is thrown if there is an error updating the
|
||||
* database
|
||||
*/
|
||||
@Override
|
||||
public void update() throws UpdateException {
|
||||
try {
|
||||
openDataStores();
|
||||
final UpdateableNvdCve updateable = getUpdatesNeeded();
|
||||
if (updateable.isUpdateNeeded()) {
|
||||
performUpdate(updateable);
|
||||
boolean autoUpdate = true;
|
||||
try {
|
||||
autoUpdate = Settings.getBoolean(Settings.KEYS.AUTO_UPDATE);
|
||||
} catch (InvalidSettingException ex) {
|
||||
LOGGER.debug("Invalid setting for auto-update; using true.");
|
||||
}
|
||||
if (autoUpdate && checkUpdate()) {
|
||||
final UpdateableNvdCve updateable = getUpdatesNeeded();
|
||||
getProperties().save(DatabaseProperties.LAST_CHECKED, Long.toString(System.currentTimeMillis()));
|
||||
if (updateable.isUpdateNeeded()) {
|
||||
performUpdate(updateable);
|
||||
}
|
||||
}
|
||||
} catch (MalformedURLException ex) {
|
||||
LOGGER.warn(
|
||||
@@ -89,11 +101,63 @@ public class NvdCveUpdater extends BaseUpdater implements CachedWebDataSource {
|
||||
}
|
||||
|
||||
/**
|
||||
* Downloads the latest NVD CVE XML file from the web and imports it into the current CVE Database.
|
||||
* Checks if the NVD CVE XML files were last checked recently. As an
|
||||
* optimization, we can avoid repetitive checks against the NVD. Setting
|
||||
* CVE_CHECK_VALID_FOR_HOURS determines the duration since last check before
|
||||
* checking again. A database property stores the timestamp of the last
|
||||
* check.
|
||||
*
|
||||
* @param updateable a collection of NVD CVE data file references that need to be downloaded and processed to update the
|
||||
* @return true to proceed with the check, or false to skip.
|
||||
* @throws UpdateException thrown when there is an issue checking for
|
||||
* updates.
|
||||
*/
|
||||
private boolean checkUpdate() throws UpdateException {
|
||||
boolean proceed = true;
|
||||
// If the valid setting has not been specified, then we proceed to check...
|
||||
final int validForHours = Settings.getInt(Settings.KEYS.CVE_CHECK_VALID_FOR_HOURS, 0);
|
||||
if (dataExists() && 0 < validForHours) {
|
||||
// ms Valid = valid (hours) x 60 min/hour x 60 sec/min x 1000 ms/sec
|
||||
final long msValid = validForHours * 60L * 60L * 1000L;
|
||||
final long lastChecked = Long.parseLong(getProperties().getProperty(DatabaseProperties.LAST_CHECKED, "0"));
|
||||
final long now = System.currentTimeMillis();
|
||||
proceed = (now - lastChecked) > msValid;
|
||||
if (!proceed) {
|
||||
LOGGER.info("Skipping NVD check since last check was within {} hours.", validForHours);
|
||||
LOGGER.debug("Last NVD was at {}, and now {} is within {} ms.",
|
||||
lastChecked, now, msValid);
|
||||
}
|
||||
}
|
||||
return proceed;
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks the CVE Index to ensure data exists and analysis can continue.
|
||||
*
|
||||
* @return true if the database contains data
|
||||
*/
|
||||
private boolean dataExists() {
|
||||
CveDB cve = null;
|
||||
try {
|
||||
cve = new CveDB();
|
||||
cve.open();
|
||||
return cve.dataExists();
|
||||
} catch (DatabaseException ex) {
|
||||
return false;
|
||||
} finally {
|
||||
if (cve != null) {
|
||||
cve.close();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Downloads the latest NVD CVE XML file from the web and imports it into
|
||||
* the current CVE Database.
|
||||
*
|
||||
* @param updateable a collection of NVD CVE data file references that need
|
||||
* to be downloaded and processed to update the database
|
||||
* @throws UpdateException is thrown if there is an error updating the
|
||||
* database
|
||||
* @throws UpdateException is thrown if there is an error updating the database
|
||||
*/
|
||||
public void performUpdate(UpdateableNvdCve updateable) throws UpdateException {
|
||||
int maxUpdates = 0;
|
||||
@@ -187,13 +251,18 @@ public class NvdCveUpdater extends BaseUpdater implements CachedWebDataSource {
|
||||
}
|
||||
|
||||
/**
|
||||
* Determines if the index needs to be updated. This is done by fetching the NVD CVE meta data and checking the last update
|
||||
* date. If the data needs to be refreshed this method will return the NvdCveUrl for the files that need to be updated.
|
||||
* Determines if the index needs to be updated. This is done by fetching the
|
||||
* NVD CVE meta data and checking the last update date. If the data needs to
|
||||
* be refreshed this method will return the NvdCveUrl for the files that
|
||||
* need to be updated.
|
||||
*
|
||||
* @return the collection of files that need to be updated
|
||||
* @throws MalformedURLException is thrown if the URL for the NVD CVE Meta data is incorrect
|
||||
* @throws DownloadFailedException is thrown if there is an error. downloading the NVD CVE download data file
|
||||
* @throws UpdateException Is thrown if there is an issue with the last updated properties file
|
||||
* @throws MalformedURLException is thrown if the URL for the NVD CVE Meta
|
||||
* data is incorrect
|
||||
* @throws DownloadFailedException is thrown if there is an error.
|
||||
* downloading the NVD CVE download data file
|
||||
* @throws UpdateException Is thrown if there is an issue with the last
|
||||
* updated properties file
|
||||
*/
|
||||
protected final UpdateableNvdCve getUpdatesNeeded() throws MalformedURLException, DownloadFailedException, UpdateException {
|
||||
UpdateableNvdCve updates = null;
|
||||
@@ -214,11 +283,11 @@ public class NvdCveUpdater extends BaseUpdater implements CachedWebDataSource {
|
||||
if (!getProperties().isEmpty()) {
|
||||
try {
|
||||
final long lastUpdated = Long.parseLong(getProperties().getProperty(DatabaseProperties.LAST_UPDATED, "0"));
|
||||
final Date now = new Date();
|
||||
final long now = System.currentTimeMillis();
|
||||
final int days = Settings.getInt(Settings.KEYS.CVE_MODIFIED_VALID_FOR_DAYS, 7);
|
||||
if (lastUpdated == updates.getTimeStamp(MODIFIED)) {
|
||||
updates.clear(); //we don't need to update anything.
|
||||
} else if (DateUtil.withinDateRange(lastUpdated, now.getTime(), days)) {
|
||||
} else if (DateUtil.withinDateRange(lastUpdated, now, days)) {
|
||||
for (NvdCveInfo entry : updates) {
|
||||
if (MODIFIED.equals(entry.getId())) {
|
||||
entry.setNeedsUpdate(true);
|
||||
@@ -257,9 +326,12 @@ public class NvdCveUpdater extends BaseUpdater implements CachedWebDataSource {
|
||||
* Retrieves the timestamps from the NVD CVE meta data file.
|
||||
*
|
||||
* @return the timestamp from the currently published nvdcve downloads page
|
||||
* @throws MalformedURLException thrown if the URL for the NVD CCE Meta data is incorrect.
|
||||
* @throws DownloadFailedException thrown if there is an error downloading the nvd cve meta data file
|
||||
* @throws InvalidDataException thrown if there is an exception parsing the timestamps
|
||||
* @throws MalformedURLException thrown if the URL for the NVD CCE Meta data
|
||||
* is incorrect.
|
||||
* @throws DownloadFailedException thrown if there is an error downloading
|
||||
* the nvd cve meta data file
|
||||
* @throws InvalidDataException thrown if there is an exception parsing the
|
||||
* timestamps
|
||||
* @throws InvalidSettingException thrown if the settings are invalid
|
||||
*/
|
||||
private UpdateableNvdCve retrieveCurrentTimestampsFromWeb()
|
||||
@@ -281,5 +353,4 @@ public class NvdCveUpdater extends BaseUpdater implements CachedWebDataSource {
|
||||
}
|
||||
return updates;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -46,7 +46,7 @@ public class CPEHandler extends DefaultHandler {
|
||||
/**
|
||||
* A reference to the current element.
|
||||
*/
|
||||
private Element current = new Element();
|
||||
private final Element current = new Element();
|
||||
/**
|
||||
* The logger.
|
||||
*/
|
||||
@@ -54,7 +54,7 @@ public class CPEHandler extends DefaultHandler {
|
||||
/**
|
||||
* The list of CPE values.
|
||||
*/
|
||||
private List<Cpe> data = new ArrayList<Cpe>();
|
||||
private final List<Cpe> data = new ArrayList<Cpe>();
|
||||
|
||||
/**
|
||||
* Returns the list of CPE values.
|
||||
@@ -179,7 +179,7 @@ public class CPEHandler extends DefaultHandler {
|
||||
/**
|
||||
* A simple class to maintain information about the current element while parsing the CPE XML.
|
||||
*/
|
||||
protected class Element {
|
||||
protected static final class Element {
|
||||
|
||||
/**
|
||||
* A node type in the CPE Schema 2.2
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/**
|
||||
* Contains classes used to parse the CPE XML file from NIST.<br/><br/>
|
||||
* Contains classes used to parse the CPE XML file from NIST.<br><br>
|
||||
*
|
||||
* These classes are not used as they add no value over the existing CPE data contained within the CVE data from the NVD. However,
|
||||
* we may consider pulling the more descriptive data from the CPE data in the future.
|
||||
|
||||
@@ -22,6 +22,7 @@ import java.io.FileInputStream;
|
||||
import java.io.FileNotFoundException;
|
||||
import java.io.FileOutputStream;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.net.URL;
|
||||
import java.util.concurrent.Callable;
|
||||
import java.util.concurrent.ExecutorService;
|
||||
@@ -68,8 +69,8 @@ public class DownloadTask implements Callable<Future<ProcessTask>> {
|
||||
final File file2;
|
||||
|
||||
try {
|
||||
file1 = File.createTempFile("cve" + nvdCveInfo.getId() + "_", ".xml", Settings.getTempDirectory());
|
||||
file2 = File.createTempFile("cve_1_2_" + nvdCveInfo.getId() + "_", ".xml", Settings.getTempDirectory());
|
||||
file1 = File.createTempFile("cve" + nvdCveInfo.getId() + '_', ".xml", Settings.getTempDirectory());
|
||||
file2 = File.createTempFile("cve_1_2_" + nvdCveInfo.getId() + '_', ".xml", Settings.getTempDirectory());
|
||||
} catch (IOException ex) {
|
||||
throw new UpdateException("Unable to create temporary files", ex);
|
||||
}
|
||||
@@ -80,11 +81,11 @@ public class DownloadTask implements Callable<Future<ProcessTask>> {
|
||||
/**
|
||||
* The CVE DB to use when processing the files.
|
||||
*/
|
||||
private CveDB cveDB;
|
||||
private final CveDB cveDB;
|
||||
/**
|
||||
* The processor service to pass the results of the download to.
|
||||
*/
|
||||
private ExecutorService processorService;
|
||||
private final ExecutorService processorService;
|
||||
/**
|
||||
* The NVD CVE Meta Data.
|
||||
*/
|
||||
@@ -92,7 +93,7 @@ public class DownloadTask implements Callable<Future<ProcessTask>> {
|
||||
/**
|
||||
* A reference to the global settings object.
|
||||
*/
|
||||
private Settings settings;
|
||||
private final Settings settings;
|
||||
|
||||
/**
|
||||
* Get the value of nvdCveInfo.
|
||||
@@ -155,28 +156,6 @@ public class DownloadTask implements Callable<Future<ProcessTask>> {
|
||||
public void setSecond(File second) {
|
||||
this.second = second;
|
||||
}
|
||||
/**
|
||||
* A placeholder for an exception.
|
||||
*/
|
||||
private Exception exception = null;
|
||||
|
||||
/**
|
||||
* Get the value of exception.
|
||||
*
|
||||
* @return the value of exception
|
||||
*/
|
||||
public Exception getException() {
|
||||
return exception;
|
||||
}
|
||||
|
||||
/**
|
||||
* returns whether or not an exception occurred during download.
|
||||
*
|
||||
* @return whether or not an exception occurred during download
|
||||
*/
|
||||
public boolean hasException() {
|
||||
return exception != null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Future<ProcessTask> call() throws Exception {
|
||||
@@ -185,6 +164,7 @@ public class DownloadTask implements Callable<Future<ProcessTask>> {
|
||||
final URL url1 = new URL(nvdCveInfo.getUrl());
|
||||
final URL url2 = new URL(nvdCveInfo.getOldSchemaVersionUrl());
|
||||
LOGGER.info("Download Started for NVD CVE - {}", nvdCveInfo.getId());
|
||||
final long startDownload = System.currentTimeMillis();
|
||||
try {
|
||||
Downloader.fetchFile(url1, first);
|
||||
Downloader.fetchFile(url2, second);
|
||||
@@ -197,14 +177,15 @@ public class DownloadTask implements Callable<Future<ProcessTask>> {
|
||||
LOGGER.debug("", ex);
|
||||
return null;
|
||||
}
|
||||
if (url1.toExternalForm().endsWith(".xml.gz")) {
|
||||
if (url1.toExternalForm().endsWith(".xml.gz") && !isXml(first)) {
|
||||
extractGzip(first);
|
||||
}
|
||||
if (url2.toExternalForm().endsWith(".xml.gz")) {
|
||||
if (url2.toExternalForm().endsWith(".xml.gz") && !isXml(second)) {
|
||||
extractGzip(second);
|
||||
}
|
||||
|
||||
LOGGER.info("Download Complete for NVD CVE - {}", nvdCveInfo.getId());
|
||||
LOGGER.info("Download Complete for NVD CVE - {} ({} ms)", nvdCveInfo.getId(),
|
||||
System.currentTimeMillis() - startDownload);
|
||||
if (this.processorService == null) {
|
||||
return null;
|
||||
}
|
||||
@@ -246,6 +227,46 @@ public class DownloadTask implements Callable<Future<ProcessTask>> {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks the file header to see if it is an XML file.
|
||||
*
|
||||
* @param file the file to check
|
||||
* @return true if the file is XML
|
||||
*/
|
||||
public static boolean isXml(File file) {
|
||||
if (file == null || !file.isFile()) {
|
||||
return false;
|
||||
}
|
||||
InputStream is = null;
|
||||
try {
|
||||
is = new FileInputStream(file);
|
||||
|
||||
final byte[] buf = new byte[5];
|
||||
int read = 0;
|
||||
try {
|
||||
read = is.read(buf);
|
||||
} catch (IOException ex) {
|
||||
return false;
|
||||
}
|
||||
return read == 5
|
||||
&& buf[0] == '<'
|
||||
&& (buf[1] == '?')
|
||||
&& (buf[2] == 'x' || buf[2] == 'X')
|
||||
&& (buf[3] == 'm' || buf[3] == 'M')
|
||||
&& (buf[4] == 'l' || buf[4] == 'L');
|
||||
} catch (FileNotFoundException ex) {
|
||||
return false;
|
||||
} finally {
|
||||
if (is != null) {
|
||||
try {
|
||||
is.close();
|
||||
} catch (IOException ex) {
|
||||
LOGGER.debug("Error closing stream", ex);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Extracts the file contained in a gzip archive. The extracted file is placed in the exact same path as the file specified.
|
||||
*
|
||||
|
||||
@@ -99,7 +99,6 @@ public class NvdCve12Handler extends DefaultHandler {
|
||||
software = null;
|
||||
}
|
||||
} else if (!skip && current.isProdNode()) {
|
||||
|
||||
vendor = attributes.getValue("vendor");
|
||||
product = attributes.getValue("name");
|
||||
} else if (!skip && current.isVersNode()) {
|
||||
@@ -112,15 +111,19 @@ public class NvdCve12Handler extends DefaultHandler {
|
||||
/*yes yes, this may not actually be an "a" - it could be an OS, etc. but for our
|
||||
purposes this is good enough as we won't use this if we don't find a corresponding "a"
|
||||
in the nvd cve 2.0. */
|
||||
String cpe = "cpe:/a:" + vendor + ":" + product;
|
||||
final int cpeLen = 8 + vendor.length() + product.length()
|
||||
+ (null != num ? (1 + num.length()) : 0)
|
||||
+ (null != edition ? (1 + edition.length()) : 0);
|
||||
final StringBuilder cpe = new StringBuilder(cpeLen);
|
||||
cpe.append("cpe:/a:").append(vendor).append(':').append(product);
|
||||
if (num != null) {
|
||||
cpe += ":" + num;
|
||||
cpe.append(':').append(num);
|
||||
}
|
||||
if (edition != null) {
|
||||
cpe += ":" + edition;
|
||||
cpe.append(':').append(edition);
|
||||
}
|
||||
final VulnerableSoftware vs = new VulnerableSoftware();
|
||||
vs.setCpe(cpe);
|
||||
vs.setCpe(cpe.toString());
|
||||
vs.setPreviousVersion(prev);
|
||||
software.add(vs);
|
||||
}
|
||||
|
||||
@@ -254,17 +254,16 @@ public class NvdCve20Handler extends DefaultHandler {
|
||||
* @throws IOException thrown if there is an IOException with the CPE Index
|
||||
*/
|
||||
private void saveEntry(Vulnerability vuln) throws DatabaseException, CorruptIndexException, IOException {
|
||||
if (cveDB == null) {
|
||||
return;
|
||||
}
|
||||
final String cveName = vuln.getName();
|
||||
if (prevVersionVulnMap.containsKey(cveName)) {
|
||||
if (prevVersionVulnMap != null && prevVersionVulnMap.containsKey(cveName)) {
|
||||
final List<VulnerableSoftware> vulnSoftware = prevVersionVulnMap.get(cveName);
|
||||
for (VulnerableSoftware vs : vulnSoftware) {
|
||||
vuln.updateVulnerableSoftware(vs);
|
||||
}
|
||||
}
|
||||
cveDB.updateVulnerability(vuln);
|
||||
if (cveDB != null) {
|
||||
cveDB.updateVulnerability(vuln);
|
||||
}
|
||||
}
|
||||
|
||||
// <editor-fold defaultstate="collapsed" desc="The Element Class that maintains state information about the current node">
|
||||
|
||||
@@ -85,7 +85,7 @@ public class ProcessTask implements Callable<ProcessTask> {
|
||||
/**
|
||||
* A reference to the global settings object.
|
||||
*/
|
||||
private Settings settings;
|
||||
private final Settings settings;
|
||||
|
||||
/**
|
||||
* Constructs a new ProcessTask used to process an NVD CVE update.
|
||||
@@ -157,6 +157,7 @@ public class ProcessTask implements Callable<ProcessTask> {
|
||||
*/
|
||||
private void processFiles() throws UpdateException {
|
||||
LOGGER.info("Processing Started for NVD CVE - {}", filePair.getNvdCveInfo().getId());
|
||||
final long startProcessing = System.currentTimeMillis();
|
||||
try {
|
||||
importXML(filePair.getFirst(), filePair.getSecond());
|
||||
cveDB.commit();
|
||||
@@ -178,6 +179,7 @@ public class ProcessTask implements Callable<ProcessTask> {
|
||||
} finally {
|
||||
filePair.cleanup();
|
||||
}
|
||||
LOGGER.info("Processing Complete for NVD CVE - {}", filePair.getNvdCveInfo().getId());
|
||||
LOGGER.info("Processing Complete for NVD CVE - {} ({} ms)", filePair.getNvdCveInfo().getId(),
|
||||
System.currentTimeMillis() - startProcessing);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -32,12 +32,12 @@ import org.owasp.dependencycheck.utils.Downloader;
|
||||
*
|
||||
* @author Jeremy Long
|
||||
*/
|
||||
public class UpdateableNvdCve implements java.lang.Iterable<NvdCveInfo>, Iterator<NvdCveInfo> {
|
||||
public class UpdateableNvdCve implements Iterable<NvdCveInfo>, Iterator<NvdCveInfo> {
|
||||
|
||||
/**
|
||||
* A collection of sources of data.
|
||||
*/
|
||||
private Map<String, NvdCveInfo> collection = new TreeMap<String, NvdCveInfo>();
|
||||
private final Map<String, NvdCveInfo> collection = new TreeMap<String, NvdCveInfo>();
|
||||
|
||||
/**
|
||||
* Returns the collection of NvdCveInfo objects. This method is mainly used for testing.
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
/**
|
||||
* Contains classes used to download, parse, and load the NVD CVE data from NIST into the local database.<br/><br/>
|
||||
* Contains classes used to download, parse, and load the NVD CVE data from NIST into the local database.<br><br>
|
||||
*/
|
||||
package org.owasp.dependencycheck.data.update.nvd;
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
/**
|
||||
*
|
||||
* Contains classes used to update the data stores.<br/><br/>
|
||||
* Contains classes used to update the data stores.<br><br>
|
||||
*
|
||||
* The UpdateService will load, any correctly defined CachedWebDataSource(s) and call update() on them. The Cached Data Source
|
||||
* must determine if it needs to be updated and if so perform the update. The sub packages contain classes used to perform the
|
||||
|
||||
@@ -28,21 +28,27 @@ import java.util.Set;
|
||||
import java.util.SortedSet;
|
||||
import java.util.TreeSet;
|
||||
|
||||
import org.apache.commons.lang.ObjectUtils;
|
||||
import org.apache.commons.lang3.builder.EqualsBuilder;
|
||||
import org.apache.commons.lang3.builder.HashCodeBuilder;
|
||||
import org.owasp.dependencycheck.data.nexus.MavenArtifact;
|
||||
import org.owasp.dependencycheck.utils.Checksum;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
/**
|
||||
* A program dependency. This object is one of the core components within DependencyCheck. It is used to collect information about
|
||||
* the dependency in the form of evidence. The Evidence is then used to determine if there are any known, published,
|
||||
* vulnerabilities associated with the program dependency.
|
||||
* A program dependency. This object is one of the core components within
|
||||
* DependencyCheck. It is used to collect information about the dependency in
|
||||
* the form of evidence. The Evidence is then used to determine if there are any
|
||||
* known, published, vulnerabilities associated with the program dependency.
|
||||
*
|
||||
* @author Jeremy Long
|
||||
*/
|
||||
public class Dependency implements Serializable, Comparable<Dependency> {
|
||||
|
||||
/**
|
||||
* The serial version UID for serialization.
|
||||
*/
|
||||
private static final long serialVersionUID = 1L;
|
||||
/**
|
||||
* The logger.
|
||||
*/
|
||||
@@ -67,6 +73,30 @@ public class Dependency implements Serializable, Comparable<Dependency> {
|
||||
* The file name of the dependency.
|
||||
*/
|
||||
private String fileName;
|
||||
|
||||
/**
|
||||
* The package path.
|
||||
*/
|
||||
private String packagePath;
|
||||
|
||||
/**
|
||||
* Returns the package path.
|
||||
*
|
||||
* @return the package path
|
||||
*/
|
||||
public String getPackagePath() {
|
||||
return packagePath;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the package path.
|
||||
*
|
||||
* @param packagePath the package path
|
||||
*/
|
||||
public void setPackagePath(String packagePath) {
|
||||
this.packagePath = packagePath;
|
||||
}
|
||||
|
||||
/**
|
||||
* The md5 hash of the dependency.
|
||||
*/
|
||||
@@ -115,6 +145,7 @@ public class Dependency implements Serializable, Comparable<Dependency> {
|
||||
this.actualFilePath = file.getAbsolutePath();
|
||||
this.filePath = this.actualFilePath;
|
||||
this.fileName = file.getName();
|
||||
this.packagePath = filePath;
|
||||
determineHashes(file);
|
||||
}
|
||||
|
||||
@@ -128,10 +159,12 @@ public class Dependency implements Serializable, Comparable<Dependency> {
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the file name of the dependency with the backslash escaped for use in JavaScript. This is a complete hack as I
|
||||
* could not get the replace to work in the template itself.
|
||||
* Returns the file name of the dependency with the backslash escaped for
|
||||
* use in JavaScript. This is a complete hack as I could not get the replace
|
||||
* to work in the template itself.
|
||||
*
|
||||
* @return the file name of the dependency with the backslash escaped for use in JavaScript
|
||||
* @return the file name of the dependency with the backslash escaped for
|
||||
* use in JavaScript
|
||||
*/
|
||||
public String getFileNameForJavaScript() {
|
||||
return this.fileName.replace("\\", "\\\\");
|
||||
@@ -183,6 +216,9 @@ public class Dependency implements Serializable, Comparable<Dependency> {
|
||||
* @param filePath the file path of the dependency
|
||||
*/
|
||||
public void setFilePath(String filePath) {
|
||||
if (this.packagePath == null || this.packagePath.equals(this.filePath)) {
|
||||
this.packagePath = filePath;
|
||||
}
|
||||
this.filePath = filePath;
|
||||
}
|
||||
|
||||
@@ -201,7 +237,8 @@ public class Dependency implements Serializable, Comparable<Dependency> {
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the file name to display in reports; if no display file name has been set it will default to the actual file name.
|
||||
* Returns the file name to display in reports; if no display file name has
|
||||
* been set it will default to the actual file name.
|
||||
*
|
||||
* @return the file name to display
|
||||
*/
|
||||
@@ -216,8 +253,9 @@ public class Dependency implements Serializable, Comparable<Dependency> {
|
||||
* <p>
|
||||
* Gets the file path of the dependency.</p>
|
||||
* <p>
|
||||
* <b>NOTE:</b> This may not be the actual path of the file on disk. The actual path of the file on disk can be obtained via
|
||||
* the getActualFilePath().</p>
|
||||
* <b>NOTE:</b> This may not be the actual path of the file on disk. The
|
||||
* actual path of the file on disk can be obtained via the
|
||||
* getActualFilePath().</p>
|
||||
*
|
||||
* @return the file path of the dependency
|
||||
*/
|
||||
@@ -280,7 +318,8 @@ public class Dependency implements Serializable, Comparable<Dependency> {
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds an entry to the list of detected Identifiers for the dependency file.
|
||||
* Adds an entry to the list of detected Identifiers for the dependency
|
||||
* file.
|
||||
*
|
||||
* @param type the type of identifier (such as CPE)
|
||||
* @param value the value of the identifier
|
||||
@@ -292,7 +331,8 @@ public class Dependency implements Serializable, Comparable<Dependency> {
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds an entry to the list of detected Identifiers for the dependency file.
|
||||
* Adds an entry to the list of detected Identifiers for the dependency
|
||||
* file.
|
||||
*
|
||||
* @param type the type of identifier (such as CPE)
|
||||
* @param value the value of the identifier
|
||||
@@ -336,14 +376,15 @@ public class Dependency implements Serializable, Comparable<Dependency> {
|
||||
}
|
||||
}
|
||||
if (!found) {
|
||||
LOGGER.debug("Adding new maven identifier {}", mavenArtifact.toString());
|
||||
LOGGER.debug("Adding new maven identifier {}", mavenArtifact);
|
||||
this.addIdentifier("maven", mavenArtifact.toString(), mavenArtifact.getArtifactUrl(), Confidence.HIGHEST);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds an entry to the list of detected Identifiers for the dependency file.
|
||||
* Adds an entry to the list of detected Identifiers for the dependency
|
||||
* file.
|
||||
*
|
||||
* @param identifier the identifier to add
|
||||
*/
|
||||
@@ -575,8 +616,9 @@ public class Dependency implements Serializable, Comparable<Dependency> {
|
||||
private Set<Dependency> relatedDependencies = new TreeSet<Dependency>();
|
||||
|
||||
/**
|
||||
* Get the value of {@link #relatedDependencies}. This field is used to collect other dependencies which really represent the
|
||||
* same dependency, and may be presented as one item in reports.
|
||||
* Get the value of {@link #relatedDependencies}. This field is used to
|
||||
* collect other dependencies which really represent the same dependency,
|
||||
* and may be presented as one item in reports.
|
||||
*
|
||||
* @return the value of relatedDependencies
|
||||
*/
|
||||
@@ -635,9 +677,11 @@ public class Dependency implements Serializable, Comparable<Dependency> {
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds a related dependency. The internal collection is normally a {@link java.util.TreeSet}, which relies on
|
||||
* {@link #compareTo(Dependency)}. A consequence of this is that if you attempt to add a dependency with the same file path
|
||||
* (modulo character case) as one that is already in the collection, it won't get added.
|
||||
* Adds a related dependency. The internal collection is normally a
|
||||
* {@link java.util.TreeSet}, which relies on
|
||||
* {@link #compareTo(Dependency)}. A consequence of this is that if you
|
||||
* attempt to add a dependency with the same file path (modulo character
|
||||
* case) as one that is already in the collection, it won't get added.
|
||||
*
|
||||
* @param dependency a reference to the related dependency
|
||||
*/
|
||||
@@ -687,11 +731,13 @@ public class Dependency implements Serializable, Comparable<Dependency> {
|
||||
}
|
||||
|
||||
/**
|
||||
* Implementation of the Comparable<Dependency> interface. The comparison is solely based on the file path.
|
||||
* Implementation of the Comparable<Dependency> interface. The
|
||||
* comparison is solely based on the file path.
|
||||
*
|
||||
* @param o a dependency to compare
|
||||
* @return an integer representing the natural ordering
|
||||
*/
|
||||
@Override
|
||||
public int compareTo(Dependency o) {
|
||||
return this.getFilePath().compareToIgnoreCase(o.getFilePath());
|
||||
}
|
||||
@@ -708,21 +754,25 @@ public class Dependency implements Serializable, Comparable<Dependency> {
|
||||
return false;
|
||||
}
|
||||
final Dependency other = (Dependency) obj;
|
||||
return ObjectUtils.equals(this.actualFilePath, other.actualFilePath)
|
||||
&& ObjectUtils.equals(this.filePath, other.filePath)
|
||||
&& ObjectUtils.equals(this.fileName, other.fileName)
|
||||
&& ObjectUtils.equals(this.md5sum, other.md5sum)
|
||||
&& ObjectUtils.equals(this.sha1sum, other.sha1sum)
|
||||
&& ObjectUtils.equals(this.identifiers, other.identifiers)
|
||||
&& ObjectUtils.equals(this.vendorEvidence, other.vendorEvidence)
|
||||
&& ObjectUtils.equals(this.productEvidence, other.productEvidence)
|
||||
&& ObjectUtils.equals(this.versionEvidence, other.versionEvidence)
|
||||
&& ObjectUtils.equals(this.description, other.description)
|
||||
&& ObjectUtils.equals(this.license, other.license)
|
||||
&& ObjectUtils.equals(this.vulnerabilities, other.vulnerabilities)
|
||||
&& ObjectUtils.equals(this.relatedDependencies, other.relatedDependencies)
|
||||
&& ObjectUtils.equals(this.projectReferences, other.projectReferences)
|
||||
&& ObjectUtils.equals(this.availableVersions, other.availableVersions);
|
||||
return new EqualsBuilder()
|
||||
.appendSuper(super.equals(obj))
|
||||
.append(this.actualFilePath, other.actualFilePath)
|
||||
.append(this.filePath, other.filePath)
|
||||
.append(this.fileName, other.fileName)
|
||||
.append(this.packagePath, other.packagePath)
|
||||
.append(this.md5sum, other.md5sum)
|
||||
.append(this.sha1sum, other.sha1sum)
|
||||
.append(this.identifiers, other.identifiers)
|
||||
.append(this.vendorEvidence, other.vendorEvidence)
|
||||
.append(this.productEvidence, other.productEvidence)
|
||||
.append(this.versionEvidence, other.versionEvidence)
|
||||
.append(this.description, other.description)
|
||||
.append(this.license, other.license)
|
||||
.append(this.vulnerabilities, other.vulnerabilities)
|
||||
//.append(this.relatedDependencies, other.relatedDependencies)
|
||||
.append(this.projectReferences, other.projectReferences)
|
||||
.append(this.availableVersions, other.availableVersions)
|
||||
.isEquals();
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -732,23 +782,34 @@ public class Dependency implements Serializable, Comparable<Dependency> {
|
||||
*/
|
||||
@Override
|
||||
public int hashCode() {
|
||||
int hash = MAGIC_HASH_INIT_VALUE;
|
||||
for (Object field : new Object[]{this.actualFilePath, this.filePath, this.fileName, this.md5sum,
|
||||
this.sha1sum, this.identifiers, this.vendorEvidence, this.productEvidence, this.versionEvidence,
|
||||
this.description, this.license, this.vulnerabilities, this.relatedDependencies, this.projectReferences,
|
||||
this.availableVersions}) {
|
||||
hash = MAGIC_HASH_MULTIPLIER * hash + ObjectUtils.hashCode(field);
|
||||
}
|
||||
return hash;
|
||||
return new HashCodeBuilder(MAGIC_HASH_INIT_VALUE, MAGIC_HASH_MULTIPLIER)
|
||||
.append(actualFilePath)
|
||||
.append(filePath)
|
||||
.append(fileName)
|
||||
.append(md5sum)
|
||||
.append(sha1sum)
|
||||
.append(identifiers)
|
||||
.append(vendorEvidence)
|
||||
.append(productEvidence)
|
||||
.append(versionEvidence)
|
||||
.append(description)
|
||||
.append(license)
|
||||
.append(vulnerabilities)
|
||||
//.append(relatedDependencies)
|
||||
.append(projectReferences)
|
||||
.append(availableVersions)
|
||||
.toHashCode();
|
||||
}
|
||||
|
||||
/**
|
||||
* Standard toString() implementation showing the filename, actualFilePath, and filePath.
|
||||
* Standard toString() implementation showing the filename, actualFilePath,
|
||||
* and filePath.
|
||||
*
|
||||
* @return the string representation of the file
|
||||
*/
|
||||
@Override
|
||||
public String toString() {
|
||||
return "Dependency{ fileName='" + fileName + "', actualFilePath='" + actualFilePath + "', filePath='" + filePath + "'}";
|
||||
return "Dependency{ fileName='" + fileName + "', actualFilePath='" + actualFilePath
|
||||
+ "', filePath='" + filePath + "', packagePath='" + packagePath + "'}";
|
||||
}
|
||||
}
|
||||
|
||||
@@ -17,8 +17,9 @@
|
||||
*/
|
||||
package org.owasp.dependencycheck.dependency;
|
||||
|
||||
import org.apache.commons.lang.ObjectUtils;
|
||||
import org.apache.commons.lang.StringUtils;
|
||||
import org.apache.commons.lang3.ObjectUtils;
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
import org.apache.commons.lang3.builder.HashCodeBuilder;
|
||||
|
||||
import java.io.Serializable;
|
||||
|
||||
@@ -29,6 +30,10 @@ import java.io.Serializable;
|
||||
*/
|
||||
public class Evidence implements Serializable, Comparable<Evidence> {
|
||||
|
||||
/**
|
||||
* The serial version UID for serialization.
|
||||
*/
|
||||
private static final long serialVersionUID = 1L;
|
||||
/**
|
||||
* Used as starting point for generating the value in {@link #hashCode()}.
|
||||
*/
|
||||
@@ -194,12 +199,12 @@ public class Evidence implements Serializable, Comparable<Evidence> {
|
||||
*/
|
||||
@Override
|
||||
public int hashCode() {
|
||||
int hash = MAGIC_HASH_INIT_VALUE;
|
||||
hash = MAGIC_HASH_MULTIPLIER * hash + ObjectUtils.hashCode(StringUtils.lowerCase(this.name));
|
||||
hash = MAGIC_HASH_MULTIPLIER * hash + ObjectUtils.hashCode(StringUtils.lowerCase(this.source));
|
||||
hash = MAGIC_HASH_MULTIPLIER * hash + ObjectUtils.hashCode(StringUtils.lowerCase(this.value));
|
||||
hash = MAGIC_HASH_MULTIPLIER * hash + ObjectUtils.hashCode(this.confidence);
|
||||
return hash;
|
||||
return new HashCodeBuilder(MAGIC_HASH_INIT_VALUE, MAGIC_HASH_MULTIPLIER)
|
||||
.append(StringUtils.lowerCase(name))
|
||||
.append(StringUtils.lowerCase(source))
|
||||
.append(StringUtils.lowerCase(value))
|
||||
.append(confidence)
|
||||
.toHashCode();
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -230,6 +235,7 @@ public class Evidence implements Serializable, Comparable<Evidence> {
|
||||
* @param o the evidence being compared
|
||||
* @return an integer indicating the ordering of the two objects
|
||||
*/
|
||||
@Override
|
||||
public int compareTo(Evidence o) {
|
||||
if (o == null) {
|
||||
return 1;
|
||||
|
||||
@@ -24,7 +24,7 @@ import java.util.Iterator;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
import java.util.TreeSet;
|
||||
import org.apache.commons.lang.StringUtils;
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
import org.owasp.dependencycheck.utils.DependencyVersion;
|
||||
import org.owasp.dependencycheck.utils.DependencyVersionUtil;
|
||||
import org.owasp.dependencycheck.utils.Filter;
|
||||
@@ -39,6 +39,10 @@ import org.slf4j.LoggerFactory;
|
||||
*/
|
||||
public class EvidenceCollection implements Serializable, Iterable<Evidence> {
|
||||
|
||||
/**
|
||||
* The serial version UID for serialization.
|
||||
*/
|
||||
private static final long serialVersionUID = 1L;
|
||||
/**
|
||||
* The logger.
|
||||
*/
|
||||
@@ -47,6 +51,7 @@ public class EvidenceCollection implements Serializable, Iterable<Evidence> {
|
||||
* Used to iterate over highest confidence evidence contained in the collection.
|
||||
*/
|
||||
private static final Filter<Evidence> HIGHEST_CONFIDENCE = new Filter<Evidence>() {
|
||||
@Override
|
||||
public boolean passes(Evidence evidence) {
|
||||
return evidence.getConfidence() == Confidence.HIGHEST;
|
||||
}
|
||||
@@ -55,6 +60,7 @@ public class EvidenceCollection implements Serializable, Iterable<Evidence> {
|
||||
* Used to iterate over high confidence evidence contained in the collection.
|
||||
*/
|
||||
private static final Filter<Evidence> HIGH_CONFIDENCE = new Filter<Evidence>() {
|
||||
@Override
|
||||
public boolean passes(Evidence evidence) {
|
||||
return evidence.getConfidence() == Confidence.HIGH;
|
||||
}
|
||||
@@ -63,6 +69,7 @@ public class EvidenceCollection implements Serializable, Iterable<Evidence> {
|
||||
* Used to iterate over medium confidence evidence contained in the collection.
|
||||
*/
|
||||
private static final Filter<Evidence> MEDIUM_CONFIDENCE = new Filter<Evidence>() {
|
||||
@Override
|
||||
public boolean passes(Evidence evidence) {
|
||||
return evidence.getConfidence() == Confidence.MEDIUM;
|
||||
}
|
||||
@@ -71,6 +78,7 @@ public class EvidenceCollection implements Serializable, Iterable<Evidence> {
|
||||
* Used to iterate over low confidence evidence contained in the collection.
|
||||
*/
|
||||
private static final Filter<Evidence> LOW_CONFIDENCE = new Filter<Evidence>() {
|
||||
@Override
|
||||
public boolean passes(Evidence evidence) {
|
||||
return evidence.getConfidence() == Confidence.LOW;
|
||||
}
|
||||
@@ -79,6 +87,7 @@ public class EvidenceCollection implements Serializable, Iterable<Evidence> {
|
||||
* Used to iterate over evidence that has was used (aka read) from the collection.
|
||||
*/
|
||||
private static final Filter<Evidence> EVIDENCE_USED = new Filter<Evidence>() {
|
||||
@Override
|
||||
public boolean passes(Evidence evidence) {
|
||||
return evidence.isUsed();
|
||||
}
|
||||
@@ -88,7 +97,7 @@ public class EvidenceCollection implements Serializable, Iterable<Evidence> {
|
||||
* Used to iterate over evidence of the specified confidence.
|
||||
*
|
||||
* @param confidence the confidence level for the evidence to be iterated over.
|
||||
* @return Iterable<Evidence> an iterable collection of evidence
|
||||
* @return Iterable<Evidence> an iterable collection of evidence
|
||||
*/
|
||||
public final Iterable<Evidence> iterator(Confidence confidence) {
|
||||
if (confidence == Confidence.HIGHEST) {
|
||||
@@ -159,7 +168,7 @@ public class EvidenceCollection implements Serializable, Iterable<Evidence> {
|
||||
* Returns a set of Weightings - a list of terms that are believed to be of higher confidence when also found in another
|
||||
* location.
|
||||
*
|
||||
* @return Set<String>
|
||||
* @return Set<String>
|
||||
*/
|
||||
public Set<String> getWeighting() {
|
||||
return weightedStrings;
|
||||
@@ -216,8 +225,9 @@ public class EvidenceCollection implements Serializable, Iterable<Evidence> {
|
||||
/**
|
||||
* Implements the iterator interface for the Evidence Collection.
|
||||
*
|
||||
* @return an Iterator<Evidence>.
|
||||
* @return an Iterator<Evidence>
|
||||
*/
|
||||
@Override
|
||||
public Iterator<Evidence> iterator() {
|
||||
return list.iterator();
|
||||
}
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user