mirror of
https://github.com/ysoftdevs/DependencyCheck.git
synced 2026-01-14 15:53:36 +01:00
Compare commits
3339 Commits
v1.2.3
...
issue690_t
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
d2a8645dd4 | ||
|
|
4543835a0d | ||
|
|
c0f41c461b | ||
|
|
116ef264e1 | ||
|
|
1371dacdaa | ||
|
|
d252d0f29f | ||
|
|
3786f6ebc7 | ||
|
|
6813427867 | ||
|
|
f94cf106a6 | ||
|
|
a67e421a5d | ||
|
|
865db1b6c3 | ||
|
|
31d7379a39 | ||
|
|
f473e63a61 | ||
|
|
238a96184a | ||
|
|
44ddad8101 | ||
|
|
afa47f7dfc | ||
|
|
f289bcd285 | ||
|
|
c7adb1bb65 | ||
|
|
4bbc5e27b5 | ||
|
|
c877ade004 | ||
|
|
ebd8996ad5 | ||
|
|
f31313d021 | ||
|
|
6936dac9b4 | ||
|
|
4b2f6832fe | ||
|
|
35d0f21c47 | ||
|
|
3066d286c5 | ||
|
|
18564e8e86 | ||
|
|
832cbabc7d | ||
|
|
8b764d5e17 | ||
|
|
e2a1a59543 | ||
|
|
cedb8d3db1 | ||
|
|
539bd754df | ||
|
|
109f5c22e9 | ||
|
|
a23d127c62 | ||
|
|
6825304100 | ||
|
|
947499726a | ||
|
|
97b2e1a4da | ||
|
|
3bb6553111 | ||
|
|
371dba948d | ||
|
|
675349c06f | ||
|
|
7a88981aa4 | ||
|
|
626f6c3de2 | ||
|
|
5540397456 | ||
|
|
69c6dd40a1 | ||
|
|
5ed6e838fc | ||
|
|
1d32a6012a | ||
|
|
b157049a7e | ||
|
|
8ea6b08a0a | ||
|
|
8856ff04ec | ||
|
|
8bfbd11a51 | ||
|
|
abd843d281 | ||
|
|
c54f9b1144 | ||
|
|
318f3e14dd | ||
|
|
46f227e92e | ||
|
|
a7b6f37503 | ||
|
|
a61bba2f72 | ||
|
|
dfc6d952bd | ||
|
|
046f4605f9 | ||
|
|
32590ab7ff | ||
|
|
efeb084e57 | ||
|
|
03ec3142c3 | ||
|
|
679df936e7 | ||
|
|
5ed5764ab5 | ||
|
|
d588092727 | ||
|
|
295ba0679d | ||
|
|
bcdf26c88d | ||
|
|
d6e092bfa2 | ||
|
|
388c1b5af1 | ||
|
|
717aea9a03 | ||
|
|
4951ee5a62 | ||
|
|
666150cf7f | ||
|
|
d8290c0c45 | ||
|
|
e363e8109b | ||
|
|
b228d08843 | ||
|
|
3e08437808 | ||
|
|
e0d5651b75 | ||
|
|
59e29b7afe | ||
|
|
d180208e34 | ||
|
|
0ce1ef596c | ||
|
|
5f7486f851 | ||
|
|
03559fd106 | ||
|
|
d08357a1c2 | ||
|
|
c1cb87ebde | ||
|
|
82fd1cf4d7 | ||
|
|
a87391e609 | ||
|
|
3071cfd7be | ||
|
|
583c2d34d3 | ||
|
|
c9640fbf04 | ||
|
|
192d1de944 | ||
|
|
aa0314c840 | ||
|
|
0171b859c6 | ||
|
|
d267e14b73 | ||
|
|
79e63f4067 | ||
|
|
72d7af5291 | ||
|
|
0e313d1910 | ||
|
|
6841f9a009 | ||
|
|
caeec68999 | ||
|
|
541915a5a7 | ||
|
|
cb75ab8cca | ||
|
|
0f3845b16d | ||
|
|
dd7128095e | ||
|
|
1367be510c | ||
|
|
2ea0eb3c64 | ||
|
|
a5990ea6f3 | ||
|
|
67921f5f3d | ||
|
|
d31e0453bd | ||
|
|
ae21424a30 | ||
|
|
3577949425 | ||
|
|
0d72471502 | ||
|
|
17590a6d38 | ||
|
|
d9dcc8cc2d | ||
|
|
df1ee5e8c6 | ||
|
|
3c68ebece7 | ||
|
|
c9e8e6cf0e | ||
|
|
36945fb84d | ||
|
|
960a2e27ab | ||
|
|
71724461a9 | ||
|
|
ae5a95bfb3 | ||
|
|
d6c9fea354 | ||
|
|
d6f1351f6b | ||
|
|
373488adb4 | ||
|
|
59401cc9f8 | ||
|
|
eca0e7a852 | ||
|
|
563dc24854 | ||
|
|
3a70e25983 | ||
|
|
a9fc6bf02c | ||
|
|
cd4f09dc86 | ||
|
|
4193718571 | ||
|
|
0464626e2b | ||
|
|
a0198e34e7 | ||
|
|
0b329bd40e | ||
|
|
3d33f24f09 | ||
|
|
886c02fad2 | ||
|
|
3a11504153 | ||
|
|
3a082ae00a | ||
|
|
780201845b | ||
|
|
0e0a4bb0b4 | ||
|
|
5333083a78 | ||
|
|
b8c6c86330 | ||
|
|
e246757f47 | ||
|
|
4172300799 | ||
|
|
f39f754b7b | ||
|
|
c59615f452 | ||
|
|
847bed2fa0 | ||
|
|
a9af15f6f8 | ||
|
|
92519ae955 | ||
|
|
2d90aca1f2 | ||
|
|
f29ed38c34 | ||
|
|
df8d4fd77c | ||
|
|
baa2e2c6ff | ||
|
|
9d5769bb69 | ||
|
|
4cdfa804ee | ||
|
|
523cd23b6b | ||
|
|
61866e9e76 | ||
|
|
ff7fbdc98d | ||
|
|
b625d642ea | ||
|
|
8733a85ebb | ||
|
|
5ab5a7b72b | ||
|
|
3cb8b9fa9e | ||
|
|
429039bf1c | ||
|
|
29d28c3408 | ||
|
|
372d484440 | ||
|
|
eac47800a3 | ||
|
|
86a85db12b | ||
|
|
4ab6cd278c | ||
|
|
233a068c8b | ||
|
|
d9f0ffa742 | ||
|
|
8d63ee19ed | ||
|
|
1fb74e1a27 | ||
|
|
c94ab6108c | ||
|
|
bf285e19ab | ||
|
|
b1ceca73e4 | ||
|
|
f3aca63b61 | ||
|
|
fca107d287 | ||
|
|
64b6964fff | ||
|
|
6af0842838 | ||
|
|
4c49adf1ba | ||
|
|
5f4e4fab56 | ||
|
|
146d7e3fbf | ||
|
|
4d22800747 | ||
|
|
541a7f8180 | ||
|
|
f205cf79c9 | ||
|
|
d8bb6488b7 | ||
|
|
4324563c0a | ||
|
|
bad03660b1 | ||
|
|
20b1ff38f9 | ||
|
|
def78a3cfd | ||
|
|
a41158a716 | ||
|
|
63ad13ff7a | ||
|
|
dd92ec675f | ||
|
|
6e1512f7d9 | ||
|
|
287b1df3fd | ||
|
|
38bf9b4ddb | ||
|
|
f9d3a9d8d8 | ||
|
|
309a5d9bcb | ||
|
|
60e661d3a4 | ||
|
|
c33257d266 | ||
|
|
1dbc183567 | ||
|
|
bf258146da | ||
|
|
bb927b447e | ||
|
|
d91b4c3151 | ||
|
|
91dbb39f18 | ||
|
|
35ae8fd660 | ||
|
|
d854917090 | ||
|
|
32ebf6c8ed | ||
|
|
edd4191d47 | ||
|
|
0cce49506a | ||
|
|
1c053469e9 | ||
|
|
610e97ef7f | ||
|
|
5a678d2ccb | ||
|
|
8db61a4d1e | ||
|
|
f47c6b07f4 | ||
|
|
bd3af45db9 | ||
|
|
a271d422f6 | ||
|
|
4dd6dedaa4 | ||
|
|
10ee569096 | ||
|
|
1474855305 | ||
|
|
0202bc11d4 | ||
|
|
e7072ea04c | ||
|
|
8f2c755f21 | ||
|
|
e513a79bd2 | ||
|
|
dd17f7393f | ||
|
|
32f38bf892 | ||
|
|
d5c3eeaf28 | ||
|
|
bfa67fcba7 | ||
|
|
37a556dcc0 | ||
|
|
fe61f298f0 | ||
|
|
9786c9bf82 | ||
|
|
668161081a | ||
|
|
4978f9dcba | ||
|
|
a6ca2e3895 | ||
|
|
6ecf55be91 | ||
|
|
13bd63dac8 | ||
|
|
db5ff1bfca | ||
|
|
42f2385bb2 | ||
|
|
e9556bbbf0 | ||
|
|
316b936326 | ||
|
|
6838b9b950 | ||
|
|
cdfe5d0c9a | ||
|
|
1610f14c47 | ||
|
|
85ab894b94 | ||
|
|
ddbca24f33 | ||
|
|
6b9acac8c4 | ||
|
|
2333bee5fd | ||
|
|
2ad08d2367 | ||
|
|
1337686013 | ||
|
|
41041bfd18 | ||
|
|
e693e53630 | ||
|
|
b99e13a337 | ||
|
|
3bbc485968 | ||
|
|
e0b549e427 | ||
|
|
75207169e3 | ||
|
|
e07f568237 | ||
|
|
e2cd99d40d | ||
|
|
27f2682a98 | ||
|
|
34a2110e9a | ||
|
|
96ba51db4f | ||
|
|
9c6053a60a | ||
|
|
358367ef9e | ||
|
|
a12bc44ecd | ||
|
|
773ac019f8 | ||
|
|
e751b7b814 | ||
|
|
824aa23b9b | ||
|
|
b7b97960a6 | ||
|
|
40f0e907e1 | ||
|
|
5ff0dc885d | ||
|
|
e70a0ee238 | ||
|
|
9338697079 | ||
|
|
4018a4e1de | ||
|
|
e8788dd2a4 | ||
|
|
e70c2f2b05 | ||
|
|
5ed0583039 | ||
|
|
f76d7295f9 | ||
|
|
6e280c4958 | ||
|
|
48b4ef1944 | ||
|
|
9150df964f | ||
|
|
b2237394e1 | ||
|
|
b3a0f7ad26 | ||
|
|
782ba42abc | ||
|
|
74b93ce602 | ||
|
|
e907c40f17 | ||
|
|
13a9dedb1e | ||
|
|
b37698f245 | ||
|
|
d30d000346 | ||
|
|
446239a5bd | ||
|
|
ac25aa795b | ||
|
|
f117a9ded0 | ||
|
|
947d38ccd2 | ||
|
|
23f7996db8 | ||
|
|
9fdff51f26 | ||
|
|
9b43bf004a | ||
|
|
5d73faa1f0 | ||
|
|
9e70279b31 | ||
|
|
9e671d1065 | ||
|
|
7e2c4af0b3 | ||
|
|
11f9092a65 | ||
|
|
6017e5c217 | ||
|
|
b2149ff4b9 | ||
|
|
1a5177c576 | ||
|
|
7020c9931a | ||
|
|
9bc43e2e8e | ||
|
|
26a4e7451e | ||
|
|
3470d33bdc | ||
|
|
51c96894b4 | ||
|
|
7fc2be6a0a | ||
|
|
110c97bc15 | ||
|
|
8d51d8fa1f | ||
|
|
4b02a567e0 | ||
|
|
5a939ec108 | ||
|
|
d9c4480627 | ||
|
|
9388340e23 | ||
|
|
2285d2ef4b | ||
|
|
f84aea0040 | ||
|
|
452969cc92 | ||
|
|
128a600f18 | ||
|
|
7dd9a52e78 | ||
|
|
ff341b7228 | ||
|
|
92a8b4ca85 | ||
|
|
384199b28d | ||
|
|
44edcabe15 | ||
|
|
1a5e9884fc | ||
|
|
cda81315d2 | ||
|
|
d7100e54d1 | ||
|
|
989caead9c | ||
|
|
a9d3b627f1 | ||
|
|
99a1606df1 | ||
|
|
6326513c63 | ||
|
|
f6cfae595a | ||
|
|
0794efcf41 | ||
|
|
b9ea82f2c1 | ||
|
|
8b705b3370 | ||
|
|
c684607a4d | ||
|
|
b00833c2de | ||
|
|
0ca6bc6ab6 | ||
|
|
60faddff9b | ||
|
|
b35da8ad4b | ||
|
|
79887c148a | ||
|
|
1ae3457ee6 | ||
|
|
d2154c9d29 | ||
|
|
40ede24a99 | ||
|
|
5960ba919d | ||
|
|
f6aaaa8815 | ||
|
|
6f1b20c936 | ||
|
|
7734a50427 | ||
|
|
aef118d375 | ||
|
|
22cae71999 | ||
|
|
29d127303c | ||
|
|
5574f1c24f | ||
|
|
9457744571 | ||
|
|
19243c479c | ||
|
|
e868ce8328 | ||
|
|
ffa846c05a | ||
|
|
dde1791476 | ||
|
|
45438a7f06 | ||
|
|
c980e77ea3 | ||
|
|
176d3ddefa | ||
|
|
98d783d448 | ||
|
|
bcd6634d8a | ||
|
|
0b260cef2a | ||
|
|
6a68abbd67 | ||
|
|
9fcf23c802 | ||
|
|
5c2c08e051 | ||
|
|
1f254997e1 | ||
|
|
4f95af0864 | ||
|
|
6ff39be9d2 | ||
|
|
6cf5a47971 | ||
|
|
56da53c700 | ||
|
|
7091e10795 | ||
|
|
34765c5741 | ||
|
|
36c139872a | ||
|
|
1e77cec677 | ||
|
|
e95e3fb2d0 | ||
|
|
39c2234e38 | ||
|
|
f4fff5d9cb | ||
|
|
659785f972 | ||
|
|
85c04f6e3e | ||
|
|
bef117cbe8 | ||
|
|
46dd7cf86e | ||
|
|
9ed5a97267 | ||
|
|
cc2da70db2 | ||
|
|
cedd93e774 | ||
|
|
632e1692eb | ||
|
|
4861592d2a | ||
|
|
22e6d4edf3 | ||
|
|
e9bd7ff72f | ||
|
|
e7228fb489 | ||
|
|
96c03a68f2 | ||
|
|
4f6f248421 | ||
|
|
a8f14c86fd | ||
|
|
36de3d1e25 | ||
|
|
48bc4570e1 | ||
|
|
94b272dbae | ||
|
|
c093edf459 | ||
|
|
0164feffcc | ||
|
|
8cd377b99f | ||
|
|
74282c8ac5 | ||
|
|
d2158e5e44 | ||
|
|
9ea16ad1d1 | ||
|
|
45941adb71 | ||
|
|
c4d662fd2b | ||
|
|
d9ce3cda66 | ||
|
|
6bd7d6b078 | ||
|
|
84c6dd5dfa | ||
|
|
71e7412f15 | ||
|
|
d22c920b35 | ||
|
|
f7a0982ca0 | ||
|
|
bed04150e1 | ||
|
|
ba15de2218 | ||
|
|
e9ec89dc9c | ||
|
|
d09f75658c | ||
|
|
62f92db181 | ||
|
|
27a98f4244 | ||
|
|
f0a3482eda | ||
|
|
5f76843c4a | ||
|
|
c6ea92cff9 | ||
|
|
c253308284 | ||
|
|
9ae9c111e3 | ||
|
|
4894372eee | ||
|
|
7cf040653f | ||
|
|
034bd4dba0 | ||
|
|
af12a2161c | ||
|
|
57fcf6fde3 | ||
|
|
c5757dc5f4 | ||
|
|
6d5d5ceb7b | ||
|
|
2fa8507d69 | ||
|
|
f23003ead3 | ||
|
|
c996f6b436 | ||
|
|
d2ee66a1c4 | ||
|
|
26b0dd5ef5 | ||
|
|
ad4149a259 | ||
|
|
9611c3b478 | ||
|
|
cead88d221 | ||
|
|
c1e1a6bb4f | ||
|
|
6212a5f740 | ||
|
|
b3d9ea3c47 | ||
|
|
cd51989354 | ||
|
|
b705ae5f0c | ||
|
|
13b53537fa | ||
|
|
7d05aa6073 | ||
|
|
85de173086 | ||
|
|
d264d804c8 | ||
|
|
8272da615e | ||
|
|
857b993d51 | ||
|
|
a71edf584e | ||
|
|
461d7fec0e | ||
|
|
5e3da035dd | ||
|
|
ebb52995a5 | ||
|
|
519b82c620 | ||
|
|
84682d07c6 | ||
|
|
960eeb19af | ||
|
|
ab3920f8f1 | ||
|
|
f5f5857897 | ||
|
|
1c400b410e | ||
|
|
cc751aa224 | ||
|
|
c20892ee3e | ||
|
|
32ab53c9e1 | ||
|
|
d0a7d9eb42 | ||
|
|
a1a9602509 | ||
|
|
cf97c89fe0 | ||
|
|
8895bc85ea | ||
|
|
1a9976c6ca | ||
|
|
f47ebf6145 | ||
|
|
0380715311 | ||
|
|
80ad16c7fa | ||
|
|
e56e9035b6 | ||
|
|
73f22d32d2 | ||
|
|
c3bc56eebc | ||
|
|
35cc14815e | ||
|
|
9be91474f6 | ||
|
|
adf949bf08 | ||
|
|
c6bf41b8ba | ||
|
|
bc656c6218 | ||
|
|
f46226d055 | ||
|
|
00d4ee47de | ||
|
|
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 | ||
|
|
413c71eb0a | ||
|
|
9d1408be20 | ||
|
|
f21f371751 | ||
|
|
2b761279e4 | ||
|
|
d5e8f54214 | ||
|
|
83f83d4eee | ||
|
|
b0f4ab9ba5 | ||
|
|
06dad8f79c | ||
|
|
83ab122ddf | ||
|
|
8a42fe4ae1 | ||
|
|
94c6778b89 | ||
|
|
c0e5973517 | ||
|
|
1e7bbfa7c1 | ||
|
|
dc7245ff6e | ||
|
|
ffaf7b40e9 | ||
|
|
4de3fb1f2a | ||
|
|
99355d993a | ||
|
|
d25f6e813c | ||
|
|
043f8e0523 | ||
|
|
5fcf2a2623 | ||
|
|
ee77fccffd | ||
|
|
f1422adf75 | ||
|
|
189da08885 | ||
|
|
c2b1742582 | ||
|
|
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 | ||
|
|
d529e88242 | ||
|
|
5d6ad8bc6c | ||
|
|
01769a6f38 | ||
|
|
a43cc38739 | ||
|
|
085069c2c7 | ||
|
|
816a6d057a | ||
|
|
19ab099f98 | ||
|
|
99a1097953 | ||
|
|
673cf7018b | ||
|
|
624f52882e | ||
|
|
654ab4a289 | ||
|
|
ec86dc5734 | ||
|
|
44f37c12c3 | ||
|
|
d0b704d7f4 | ||
|
|
7452942091 | ||
|
|
ea4ea680a2 | ||
|
|
ac7ae3d8df | ||
|
|
4fa5f2ac72 | ||
|
|
8b1a44fe42 | ||
|
|
c4d26f9194 | ||
|
|
79b59f2aae | ||
|
|
1eecd13ea7 | ||
|
|
1ae3a63f5c | ||
|
|
561694a991 | ||
|
|
096af016ef | ||
|
|
498835015a | ||
|
|
cafa0d6578 | ||
|
|
5444253ed6 | ||
|
|
d0ae12a167 | ||
|
|
e323c7f810 | ||
|
|
dd3758af43 | ||
|
|
94ae6e76f1 | ||
|
|
ee969a5ed9 | ||
|
|
a547a219a4 | ||
|
|
d4eba634ea | ||
|
|
0927897451 | ||
|
|
63e5a2c5ba | ||
|
|
a7f3f1d806 | ||
|
|
97d3a2986c | ||
|
|
d3b20757ef | ||
|
|
d99804f14e | ||
|
|
1b8dc71980 | ||
|
|
dc466f1480 | ||
|
|
ba6a783834 | ||
|
|
b2edf5683c | ||
|
|
dacb91b9a8 | ||
|
|
7ac71a7b2a | ||
|
|
4b44bb5426 | ||
|
|
8cd68c7c16 | ||
|
|
0ae228d6f8 | ||
|
|
6a2ed23822 | ||
|
|
fe0035fe0e | ||
|
|
aeabaf8513 | ||
|
|
43907e07c2 | ||
|
|
2413dc9a41 | ||
|
|
2d92c9d240 | ||
|
|
a24813b678 | ||
|
|
dffb2887d6 | ||
|
|
68f1c1a54c | ||
|
|
726aa7b894 | ||
|
|
44c795cd4f | ||
|
|
4d5d46d08a | ||
|
|
52cdff14bd | ||
|
|
0372167f25 | ||
|
|
005e401c7f | ||
|
|
479212dd60 | ||
|
|
0af9239906 | ||
|
|
13d871ab21 | ||
|
|
136830ce22 | ||
|
|
afe8e343b1 | ||
|
|
f7c2cdff9b | ||
|
|
a7abe97ca0 | ||
|
|
5354137c76 | ||
|
|
433c2e5916 | ||
|
|
e5fdda60fc | ||
|
|
b227cf890b | ||
|
|
0a4c3102dd | ||
|
|
54094ebc21 | ||
|
|
bf3fe6404a | ||
|
|
58888ac389 | ||
|
|
07df8ecc02 | ||
|
|
c86becb169 | ||
|
|
98a43606ce | ||
|
|
5b2353e612 | ||
|
|
a3ad598004 | ||
|
|
c02d1d73b8 | ||
|
|
77c99e1d7c | ||
|
|
055d34818a | ||
|
|
3a06503b74 | ||
|
|
cae15a8d7a | ||
|
|
70554d1158 | ||
|
|
db42da14d1 | ||
|
|
9daa9b6cca | ||
|
|
30087b5e79 | ||
|
|
c214b70459 | ||
|
|
ad0b6c28ba | ||
|
|
8127dc2620 | ||
|
|
fed5d3efc0 | ||
|
|
ed3c806869 | ||
|
|
b8a32eb086 | ||
|
|
e537ce155e | ||
|
|
be506964b0 | ||
|
|
df39b490f5 | ||
|
|
e3256e4bb9 | ||
|
|
4d01d636cc | ||
|
|
1bf07036e8 | ||
|
|
da058fcaf5 | ||
|
|
7203c91c70 | ||
|
|
44893a2a2c | ||
|
|
bdf2ca6e1d | ||
|
|
621ac3b6ec | ||
|
|
9fbf8b58a1 | ||
|
|
70ac55f983 | ||
|
|
890bb4a2c3 | ||
|
|
888f2aed97 | ||
|
|
e6707c65a5 | ||
|
|
414912de67 | ||
|
|
723ba740e0 | ||
|
|
e2389b4992 | ||
|
|
39e587085f | ||
|
|
42e77c77a9 | ||
|
|
e8353089f3 | ||
|
|
d76799cfd0 | ||
|
|
4907c20ba6 | ||
|
|
fa16a960a5 | ||
|
|
aa66e5ab15 | ||
|
|
802e4fc238 | ||
|
|
2494fec2a7 | ||
|
|
13db27854b | ||
|
|
190e17e6b9 | ||
|
|
02acd3162e | ||
|
|
47fa6e67d9 | ||
|
|
aba7b47fa8 | ||
|
|
c1ae4f8cc2 | ||
|
|
4f43793e17 | ||
|
|
8fd32ebd5e | ||
|
|
0b2059462b | ||
|
|
b0df41213a | ||
|
|
f421f30122 | ||
|
|
358ac46393 | ||
|
|
ebd98b9094 | ||
|
|
c713bb0353 | ||
|
|
d61a7b090d | ||
|
|
9f1a894b86 | ||
|
|
cc86d73719 | ||
|
|
86b1802d16 | ||
|
|
3cdf66a0a4 | ||
|
|
faeee200d3 | ||
|
|
4b34734919 | ||
|
|
765c1b8875 | ||
|
|
f89cefd9ae | ||
|
|
23dfa8645c | ||
|
|
9556e7bf51 | ||
|
|
7fa306dd9a | ||
|
|
d9a322b533 | ||
|
|
fde1b21d1f | ||
|
|
124249a35d | ||
|
|
6d6e9a6df7 | ||
|
|
77ae9dfbef | ||
|
|
4ed642ed5d | ||
|
|
556be02696 | ||
|
|
572418a2f5 | ||
|
|
fce742910e | ||
|
|
370b0cb049 | ||
|
|
76333b8647 | ||
|
|
ce7d12e850 | ||
|
|
63d92c62a5 | ||
|
|
7e2720e673 | ||
|
|
a7c0ea3602 | ||
|
|
374829ecd5 | ||
|
|
6a67c04ca2 | ||
|
|
f4ce087649 | ||
|
|
4566ce7de8 | ||
|
|
a898e61a7a | ||
|
|
6d524bdc99 | ||
|
|
1ba21f7f71 | ||
|
|
7f710e0782 | ||
|
|
acb78c18bf | ||
|
|
5b1f632035 | ||
|
|
8aca739f54 | ||
|
|
efdfcee7fc | ||
|
|
1b4cb1379a | ||
|
|
820d7f18c4 | ||
|
|
7a5a5e0211 | ||
|
|
07dda233ec | ||
|
|
02209fc039 | ||
|
|
a372882c18 | ||
|
|
91c05598b2 | ||
|
|
0130ab6356 | ||
|
|
581a3f8388 | ||
|
|
2587ad21c0 | ||
|
|
8b56349daa | ||
|
|
25f2eb69b9 | ||
|
|
46b4761f1a | ||
|
|
4d3f96f979 | ||
|
|
084371a1e3 | ||
|
|
f5aaaf1c63 | ||
|
|
316bab6fff | ||
|
|
65a5d38fc6 | ||
|
|
aa927e9168 | ||
|
|
7b0a120e66 | ||
|
|
143ce58cb3 | ||
|
|
9244b44ce6 | ||
|
|
4720312b26 | ||
|
|
d43610701b | ||
|
|
243b0b2c21 | ||
|
|
930894ced5 | ||
|
|
63ce7850e1 | ||
|
|
984a38ce91 | ||
|
|
12ce2275e0 | ||
|
|
214b88ea1c | ||
|
|
980e00e824 | ||
|
|
80276d5e4d | ||
|
|
28c2db9edc | ||
|
|
5e66f70cf0 | ||
|
|
4e41187bf3 | ||
|
|
0a09760aec | ||
|
|
500ad62470 | ||
|
|
1204d98e8d | ||
|
|
ae3596ac99 | ||
|
|
d662c693f1 | ||
|
|
1820cd0ae8 | ||
|
|
c5e144d211 | ||
|
|
e1c041a250 | ||
|
|
82dff86802 | ||
|
|
b2019d7633 | ||
|
|
f6afea0004 | ||
|
|
309eb502cd | ||
|
|
712252eb6b | ||
|
|
c3baf36eb5 | ||
|
|
771fd77088 | ||
|
|
7d3ac21e42 | ||
|
|
cc3a72f4fd | ||
|
|
d87fa374ec | ||
|
|
154a576388 | ||
|
|
29fe71b82c | ||
|
|
e960fd31fa | ||
|
|
132fb87c2c | ||
|
|
6e281e0b66 | ||
|
|
a86ff9dfd1 | ||
|
|
3ea33f1dd6 | ||
|
|
b645fd495f | ||
|
|
5e635224e2 | ||
|
|
54d8becd74 | ||
|
|
87243537e7 | ||
|
|
0604361d4e | ||
|
|
399c052129 | ||
|
|
362c7e9c04 | ||
|
|
c4843253c0 | ||
|
|
928d8dbb15 | ||
|
|
7f528d8d4a | ||
|
|
8ddf4a0e72 | ||
|
|
5c589136e5 | ||
|
|
00f10771d9 | ||
|
|
583a5cda61 | ||
|
|
f9e5ebccfd | ||
|
|
77eebb6c1b | ||
|
|
53d01e5fe1 | ||
|
|
3d08e8db06 | ||
|
|
50a3ce2036 | ||
|
|
a127948c4c | ||
|
|
36b406f7ec | ||
|
|
3c50e9f784 | ||
|
|
51e2af148e | ||
|
|
d7351f97fe | ||
|
|
1a042fab4b | ||
|
|
c3f000c5ef | ||
|
|
e848dd5bee | ||
|
|
566e11f755 | ||
|
|
13aa00e465 | ||
|
|
e9df060e0c | ||
|
|
c4724e8020 | ||
|
|
9c36087dae | ||
|
|
51c3ebcdb8 | ||
|
|
f29e4a5d36 | ||
|
|
99dd04a1c1 | ||
|
|
29c47e3e96 | ||
|
|
659248ff22 | ||
|
|
71a7e8d2dc | ||
|
|
caabdc6584 | ||
|
|
0b92d2ec17 | ||
|
|
db8bcd8fd6 | ||
|
|
17cb96ef41 | ||
|
|
2248380c90 | ||
|
|
ffe64d2f8f | ||
|
|
a0c624fca6 | ||
|
|
31022ea8de | ||
|
|
0d0de4d5b3 | ||
|
|
1fdb4c4627 | ||
|
|
76665c54e2 | ||
|
|
04166766da | ||
|
|
aa7f903210 | ||
|
|
c4ca53cdf9 | ||
|
|
d5885acd6e | ||
|
|
550b3332a3 | ||
|
|
93b98576b8 | ||
|
|
e6f2c25167 | ||
|
|
0b207c6141 | ||
|
|
3ed5e85646 | ||
|
|
4068da33c8 | ||
|
|
d1d53ee65b | ||
|
|
38413c4f64 | ||
|
|
a6bb6cd170 | ||
|
|
145bf70420 | ||
|
|
e2c92c57e6 | ||
|
|
1fa59270c1 | ||
|
|
d5c1fda958 | ||
|
|
b0e34fd062 | ||
|
|
8fbf8df0bd | ||
|
|
bcc2173768 | ||
|
|
aa1df53ab0 | ||
|
|
fb6a2a2c37 | ||
|
|
f403fc732c | ||
|
|
03aa7c56a2 | ||
|
|
547d6d4bcc | ||
|
|
2cba8f906d | ||
|
|
bb5ee6a347 | ||
|
|
34604efde4 | ||
|
|
c232a4fbad | ||
|
|
0c5dfdbe24 | ||
|
|
c0f9a382b3 | ||
|
|
8ca32fcace | ||
|
|
0461a9fc89 | ||
|
|
2b600290ae | ||
|
|
56fd3f2566 | ||
|
|
142e06e752 | ||
|
|
cbf2a047be | ||
|
|
1880e22d22 | ||
|
|
963b1eae1c | ||
|
|
d173573e6c | ||
|
|
b6c0426c1c | ||
|
|
4f18e9ee7f | ||
|
|
e227b90370 | ||
|
|
360b112bd2 | ||
|
|
ff7027439d | ||
|
|
a5ed91611a | ||
|
|
168b1c3684 | ||
|
|
7e1141ff16 | ||
|
|
168d55c54c | ||
|
|
d5ed2bc765 | ||
|
|
940a4613ee | ||
|
|
4f6d96e16b | ||
|
|
707d9925a8 | ||
|
|
657340c912 | ||
|
|
3e220704a1 | ||
|
|
4a2309a3f8 | ||
|
|
09122be7be | ||
|
|
e26ec47ad7 | ||
|
|
05ae73eea2 | ||
|
|
511d2b9457 | ||
|
|
bf96c24ec3 | ||
|
|
e328ec990c | ||
|
|
a5dee0cb27 | ||
|
|
7fb5d5bde5 | ||
|
|
5a329b4a6d | ||
|
|
500f6c5b6f | ||
|
|
29f76ba62a | ||
|
|
70e0c84a20 | ||
|
|
3dd95180e0 | ||
|
|
dcd8fc0320 | ||
|
|
bcd9fb0be9 | ||
|
|
a088d20612 | ||
|
|
29fb347bbb | ||
|
|
b2a436b3bc | ||
|
|
d288912df1 | ||
|
|
7bde6baaac | ||
|
|
26ca6d9b77 | ||
|
|
961626a136 | ||
|
|
641a311537 | ||
|
|
995ba02357 | ||
|
|
fb3e6e4208 | ||
|
|
e5363f7c8f | ||
|
|
d1a128b897 | ||
|
|
2b5fb4d75a | ||
|
|
6439ddde23 | ||
|
|
f2994ed4ff | ||
|
|
019bf67f93 | ||
|
|
78c1dcd0d0 | ||
|
|
e07b30df85 | ||
|
|
96cd517c36 | ||
|
|
2cb8e00c99 | ||
|
|
92f093009e | ||
|
|
27256a1854 | ||
|
|
ba782ca56f | ||
|
|
3f3e33a366 | ||
|
|
343fd75477 | ||
|
|
7bcfb6ff49 | ||
|
|
78ec08792f | ||
|
|
461b41f300 | ||
|
|
5b246424fb | ||
|
|
6af4b4cd5e | ||
|
|
6d348eb5a7 | ||
|
|
b26f6b697a | ||
|
|
554510bb78 | ||
|
|
3f2e5b7c69 | ||
|
|
3c4989f5ca | ||
|
|
d33c649be6 | ||
|
|
c55954e5e8 | ||
|
|
678311e65b | ||
|
|
ab1d3075e8 | ||
|
|
0a6f8b7ac1 | ||
|
|
422a1f78fc | ||
|
|
f21af8bd1e | ||
|
|
924278e387 | ||
|
|
c6ea4466fb | ||
|
|
318cc7a8fb | ||
|
|
9554a30286 | ||
|
|
5336da52d9 | ||
|
|
bd0c2e4ee4 | ||
|
|
64aad66adc | ||
|
|
587bf131db | ||
|
|
fc96c727ec | ||
|
|
d17bd5bd9e | ||
|
|
b22a935a6c | ||
|
|
a7c1d594dc | ||
|
|
dd20a9c7cc | ||
|
|
e0994e0e54 | ||
|
|
0f8ce09646 | ||
|
|
871e27d19f | ||
|
|
c429df3280 | ||
|
|
13f355c385 | ||
|
|
d33ddefb2d | ||
|
|
75b3f4b3c8 | ||
|
|
03ce1d2ea8 | ||
|
|
08eae2b09c | ||
|
|
c94f9e2d2b | ||
|
|
520370688c | ||
|
|
725949db2f | ||
|
|
5d647155b6 | ||
|
|
c152bd0517 | ||
|
|
f35146d93d | ||
|
|
e8e58555d0 | ||
|
|
7190dcc04e | ||
|
|
b623e3b3c8 | ||
|
|
d78e82bd56 | ||
|
|
ff478253e3 | ||
|
|
85c3368cda | ||
|
|
a4095cec8d | ||
|
|
c840ce249f | ||
|
|
b70812fc3d | ||
|
|
3ccf06321d | ||
|
|
1d5dd5ea11 | ||
|
|
0cadd88769 | ||
|
|
75499a3321 | ||
|
|
5096027523 | ||
|
|
5c8c07794d | ||
|
|
18a72bbb59 | ||
|
|
7b3c4475da | ||
|
|
419c446f01 | ||
|
|
735c16cc11 | ||
|
|
ed41abcf9d | ||
|
|
b750a8c802 | ||
|
|
1ee75dd8cb | ||
|
|
396efad518 | ||
|
|
8f33be262a | ||
|
|
9daa111f9c | ||
|
|
889bf22840 | ||
|
|
f46e96c7de | ||
|
|
9be6dc2935 | ||
|
|
6188f6d74a | ||
|
|
8837fab9fa | ||
|
|
316339011b | ||
|
|
fe7121e057 | ||
|
|
bc09bfd3ba | ||
|
|
26f19cead1 | ||
|
|
777b35f412 | ||
|
|
9e94ffb422 | ||
|
|
b6a38bf4d1 | ||
|
|
92d12ec68e | ||
|
|
93dd5e4b31 | ||
|
|
79e325e2ab | ||
|
|
0e095018a4 | ||
|
|
7040071ab9 | ||
|
|
e157350d03 | ||
|
|
28f6ef5eec | ||
|
|
15bcee3d10 | ||
|
|
67dbf70f5b | ||
|
|
c75b99837f | ||
|
|
cbc951be62 | ||
|
|
f5b38852a7 | ||
|
|
45b5fd3762 | ||
|
|
04c14f3a27 | ||
|
|
a55d89cc93 | ||
|
|
888801ab0c | ||
|
|
731528ef6e | ||
|
|
d7fbd0df47 | ||
|
|
6f95e6d499 | ||
|
|
79e6a13b29 | ||
|
|
b9a53775b6 | ||
|
|
1b15603227 | ||
|
|
a7ffeb7016 | ||
|
|
13b1c0fe0c | ||
|
|
1d259c510f | ||
|
|
56783bbf4d | ||
|
|
e63c296b16 | ||
|
|
57450a65cf | ||
|
|
716b52ef90 | ||
|
|
6ab8552f44 | ||
|
|
9880483690 | ||
|
|
7b9b459b74 | ||
|
|
0723606120 | ||
|
|
4261e9eb29 | ||
|
|
a322556c66 | ||
|
|
b6d3efa042 | ||
|
|
4019a0615c | ||
|
|
376e486c47 | ||
|
|
5b7c47682b | ||
|
|
741a803ea7 | ||
|
|
8a886f5434 | ||
|
|
01514af188 | ||
|
|
c5d5dccc57 | ||
|
|
5e58304448 | ||
|
|
dd9c4bfa42 | ||
|
|
e6a559f0d1 | ||
|
|
f1c860f68c | ||
|
|
cd175816e2 | ||
|
|
1d74d2e241 | ||
|
|
c4479a36a9 | ||
|
|
cc2c18243e | ||
|
|
211d34fcef | ||
|
|
dc60c24d89 | ||
|
|
922e6437cf | ||
|
|
1058157827 | ||
|
|
33b38e686a | ||
|
|
a6014f30dd | ||
|
|
3fc75df55d | ||
|
|
2bcd9d78e8 | ||
|
|
723b9e9cea | ||
|
|
efb7088cd8 | ||
|
|
f2131102f5 | ||
|
|
eae04bb156 | ||
|
|
11716128df | ||
|
|
5122808189 | ||
|
|
3c1905f941 | ||
|
|
3348086c00 | ||
|
|
919efc5037 | ||
|
|
04ab0e09d5 | ||
|
|
c8862cb927 | ||
|
|
ac135ec2b6 | ||
|
|
0257000d1a | ||
|
|
608b95e941 | ||
|
|
e6a2c5b5b4 | ||
|
|
a546aadba1 | ||
|
|
5934588b2c | ||
|
|
3ad5482a30 | ||
|
|
c3902447af | ||
|
|
764aa466f4 | ||
|
|
9ffda6cd17 | ||
|
|
8281fb09fc | ||
|
|
b6988f96fb | ||
|
|
4597c13d9a | ||
|
|
acf7297c8d | ||
|
|
bbdc8298d9 | ||
|
|
4d9f102033 | ||
|
|
0056e1052c | ||
|
|
7b729e078b | ||
|
|
6a0623f1e7 | ||
|
|
542c871152 | ||
|
|
77189eeeb1 | ||
|
|
340172ab56 | ||
|
|
afcfed1c67 | ||
|
|
59ce3bb64d | ||
|
|
81c5aa73d2 | ||
|
|
12ff05208c | ||
|
|
dc0ef70699 | ||
|
|
6ce735dcc7 | ||
|
|
faf3298f7a | ||
|
|
4f1b6b4bf1 | ||
|
|
99702fdb67 | ||
|
|
7bce7691e4 | ||
|
|
7f90160936 | ||
|
|
f367ad7185 | ||
|
|
29a31476b1 | ||
|
|
b844b66614 | ||
|
|
3e6fa1ed1f | ||
|
|
e141b4eb9f | ||
|
|
c794194bb5 | ||
|
|
3a31902e78 | ||
|
|
fedafe55c3 | ||
|
|
1c0b885267 | ||
|
|
8e4791048b | ||
|
|
e28be6f2b7 | ||
|
|
55271b8e83 | ||
|
|
8b5d8679f7 | ||
|
|
51d8ced8ce | ||
|
|
1cc94dd60b | ||
|
|
6d107e79b6 | ||
|
|
6f44b4dce1 | ||
|
|
1600492780 | ||
|
|
5f396cc647 | ||
|
|
49bd45d88c | ||
|
|
c41e673346 | ||
|
|
cf8d1a490c | ||
|
|
962f20296c | ||
|
|
e9c1ae1893 | ||
|
|
5db51a2abf | ||
|
|
63be1efed9 | ||
|
|
7fe3c659e0 | ||
|
|
4d76c7685c | ||
|
|
b50bcde028 | ||
|
|
9a8b61ae47 | ||
|
|
c31880d8de | ||
|
|
1496dc8e7d | ||
|
|
cdbd513e42 | ||
|
|
653bf1764e | ||
|
|
df08acfe9e | ||
|
|
e7a5287bb4 | ||
|
|
656f26cc9d | ||
|
|
52385ddac4 | ||
|
|
50c58667ba | ||
|
|
9cc6ca5ebe | ||
|
|
34b82a3f84 | ||
|
|
d0401f3f8d | ||
|
|
f247978d12 | ||
|
|
999116c75e | ||
|
|
04e9f5b15b | ||
|
|
78b0f7798f | ||
|
|
b0727ef3cf | ||
|
|
01fb31fc15 | ||
|
|
a1187acc31 | ||
|
|
fe4a24a651 | ||
|
|
3dcce572d3 | ||
|
|
ece69014ce | ||
|
|
fc6bb67e56 | ||
|
|
968de2947b | ||
|
|
6f9ba0033f | ||
|
|
4d4672fc4d | ||
|
|
70859eb719 | ||
|
|
ae9daf7f33 | ||
|
|
ff0daa8d66 | ||
|
|
09f1a0ac92 | ||
|
|
e562be77f6 | ||
|
|
af7c6bc2a0 | ||
|
|
e49cbcf345 | ||
|
|
b4218ff0e8 | ||
|
|
4af174d27b | ||
|
|
203a7da23a | ||
|
|
9833ff20d1 | ||
|
|
638b3c0695 | ||
|
|
01ef2e1061 | ||
|
|
56aea8ad24 | ||
|
|
d530eddc57 | ||
|
|
1eab76aab8 | ||
|
|
167dbd7368 | ||
|
|
2594fb1c5f | ||
|
|
c57d21e9bc | ||
|
|
9c15bdfe41 | ||
|
|
64dedf892d | ||
|
|
d6fc456039 | ||
|
|
df606674db | ||
|
|
1e3a7ff4ba | ||
|
|
b53de8c69b | ||
|
|
0f3ffaf270 | ||
|
|
25238d5fb5 | ||
|
|
cf677bd70e | ||
|
|
42939e4922 | ||
|
|
7c4cc1334b | ||
|
|
ff4a1e0ac6 | ||
|
|
069e22049d | ||
|
|
135ed5c614 | ||
|
|
13d7d29630 | ||
|
|
889f315c0a | ||
|
|
5a0e280899 | ||
|
|
ccb5e234b3 | ||
|
|
2caccab85f | ||
|
|
085ab48f3f | ||
|
|
a28c2819fa | ||
|
|
40beec2e40 | ||
|
|
d136aeda84 | ||
|
|
fdd6c47cd5 | ||
|
|
c5a2b5b3d8 | ||
|
|
babe4739c5 | ||
|
|
49e8ee443c | ||
|
|
a5d8ce07d8 | ||
|
|
babc016b48 | ||
|
|
a5f378d755 | ||
|
|
ebf995537e | ||
|
|
49edb6c2e1 | ||
|
|
423f26852f | ||
|
|
f931412bee | ||
|
|
bef0657801 | ||
|
|
d79d5b5f33 | ||
|
|
4c5489efd3 | ||
|
|
d5753b9589 | ||
|
|
a841027d48 | ||
|
|
73bea8e63f | ||
|
|
bbc8bab4da | ||
|
|
019f6dfb8b | ||
|
|
3b6a2a2908 | ||
|
|
c2b757ad6f | ||
|
|
efeba40f2b | ||
|
|
018e4bc382 | ||
|
|
88924ea520 | ||
|
|
4461c2e4a4 | ||
|
|
1c4aceb0fb | ||
|
|
a5b396a60d | ||
|
|
efd96ed892 | ||
|
|
fe88785846 | ||
|
|
0dcb0fb325 | ||
|
|
0825843d0f | ||
|
|
8c4df134e4 | ||
|
|
dfed5067f3 | ||
|
|
2b78e8fdc1 | ||
|
|
63c7a9d926 | ||
|
|
6609481cc1 | ||
|
|
a37853def6 | ||
|
|
9f348cfa16 | ||
|
|
52293f2596 | ||
|
|
54d3a73282 | ||
|
|
ab2d3b70cb | ||
|
|
451df460f6 | ||
|
|
b4afa01887 | ||
|
|
2ea95f5bf9 | ||
|
|
22602f42f2 | ||
|
|
b2c5183043 | ||
|
|
9f6559c7fb | ||
|
|
ef04c16237 | ||
|
|
dd85bfd2ab | ||
|
|
7152a05bfd | ||
|
|
754c2fc9bf | ||
|
|
85ad0b881f | ||
|
|
db6c471cc6 | ||
|
|
300d990276 | ||
|
|
9c55b889cb | ||
|
|
735f76cc0b | ||
|
|
d1c27a4298 | ||
|
|
650f09bbc5 | ||
|
|
08bf16971a | ||
|
|
ccb149240e | ||
|
|
ae22719985 | ||
|
|
55c4d729bb | ||
|
|
429f0966f0 | ||
|
|
7a246b90b9 | ||
|
|
d2e7de5505 | ||
|
|
a9eab16502 | ||
|
|
d59cce8080 | ||
|
|
9390e71dd9 | ||
|
|
65992243fa | ||
|
|
c81b8b0171 | ||
|
|
0671d12628 | ||
|
|
a892c5e7b7 | ||
|
|
b5c21ffbf0 | ||
|
|
bb2b25cca5 | ||
|
|
b3867244ba | ||
|
|
6bf8d396e0 | ||
|
|
6394c1a7b4 | ||
|
|
ccd656845d | ||
|
|
2931e8454c | ||
|
|
112b158795 | ||
|
|
921001000f | ||
|
|
3e3a8e9f98 | ||
|
|
7440a039fd | ||
|
|
e73f9ab02f | ||
|
|
59815b858e | ||
|
|
7df7f59d93 | ||
|
|
e971bc1991 | ||
|
|
a3f0f12779 | ||
|
|
2a9c214593 | ||
|
|
3fc37f3e5e | ||
|
|
ebe4423e25 | ||
|
|
cfafb4a101 | ||
|
|
8d538a9977 | ||
|
|
cc2953d6a3 | ||
|
|
c888019068 | ||
|
|
56639d3965 | ||
|
|
09ff99823e | ||
|
|
5078e32dc7 | ||
|
|
ecaadff0d8 | ||
|
|
f2ad8cc7d1 | ||
|
|
c8d77eb213 | ||
|
|
fe3d9e8bf6 | ||
|
|
6c4171be75 | ||
|
|
4bbb466e43 | ||
|
|
c478415667 | ||
|
|
fc832b67c5 | ||
|
|
943a9ea97e | ||
|
|
2c7ab297d7 | ||
|
|
d8299f7db1 | ||
|
|
4deeb33f08 | ||
|
|
3bf4cf8c85 | ||
|
|
e0217fc6c3 | ||
|
|
62a3efa23a | ||
|
|
cc7ebe6d52 | ||
|
|
5d920e4b44 | ||
|
|
1264ea54a1 | ||
|
|
caa1d77d23 | ||
|
|
20a55b3342 | ||
|
|
8bfe67fc60 | ||
|
|
d42a1c6ab1 | ||
|
|
80a89ef6d1 | ||
|
|
1a0e605f0c | ||
|
|
573c8eb509 | ||
|
|
e676e3a14b | ||
|
|
af8c807ee0 | ||
|
|
dfaa5df965 | ||
|
|
32055ecdcc | ||
|
|
9db71c5f0c | ||
|
|
99856bf285 | ||
|
|
4d006b3e05 | ||
|
|
4e37165ba6 | ||
|
|
38a5834785 | ||
|
|
d6e1352869 | ||
|
|
bf1b7bd7a2 | ||
|
|
2306327057 | ||
|
|
2d389ba73f | ||
|
|
ce8d5bc635 | ||
|
|
8fdc2007e0 | ||
|
|
88a97769de | ||
|
|
589c761cb0 | ||
|
|
3e6787fd61 | ||
|
|
aff52ee3f5 | ||
|
|
4555b02592 | ||
|
|
e1d4599a93 | ||
|
|
1a1e141cb8 | ||
|
|
33218f41e8 | ||
|
|
8772cda47a | ||
|
|
512eb713e4 | ||
|
|
0f90d48c62 | ||
|
|
658860e396 | ||
|
|
7522dae557 | ||
|
|
e34e65a3ba | ||
|
|
5a001a2c32 | ||
|
|
13a03eb250 | ||
|
|
cd863b6cca | ||
|
|
83b182dda5 | ||
|
|
3b90d1a564 | ||
|
|
d724855dfc | ||
|
|
78008330fe | ||
|
|
e716aad224 | ||
|
|
aa0d7cb4e9 | ||
|
|
0cd43ce35c | ||
|
|
ac98c8e395 | ||
|
|
70a8fc09c6 | ||
|
|
5b00d05e2e | ||
|
|
28c1730a02 | ||
|
|
c54483d36f | ||
|
|
2dd02ff8cb | ||
|
|
46c5501b7a | ||
|
|
f154826749 | ||
|
|
96383ef985 | ||
|
|
ab4b19dbab | ||
|
|
cdc53ac570 | ||
|
|
143cc1912e | ||
|
|
0d90b676bc | ||
|
|
5fadbb3d25 | ||
|
|
0ec99a3e12 | ||
|
|
1efbc44cc4 | ||
|
|
735fcfeee2 | ||
|
|
4a77150566 | ||
|
|
180a420219 | ||
|
|
d12ba8f3ef | ||
|
|
f333ef76d9 | ||
|
|
af5ba6854e | ||
|
|
8b7ce06793 | ||
|
|
297a5e516f | ||
|
|
92b11526be | ||
|
|
299350f655 | ||
|
|
127eafc9b3 | ||
|
|
ad1ad3a997 | ||
|
|
82151c5b3f | ||
|
|
90457c89ff | ||
|
|
3f3ac86d38 | ||
|
|
aa126039e5 | ||
|
|
662815b1ee | ||
|
|
243c36849c | ||
|
|
52d5baaf3f | ||
|
|
89217f778e | ||
|
|
9bc9bc9169 | ||
|
|
6b73430473 | ||
|
|
5ca5bca3df | ||
|
|
89ab382a18 | ||
|
|
bad425c0d7 | ||
|
|
cdbbb1b94c | ||
|
|
0a9d8a9b22 | ||
|
|
e662041d06 | ||
|
|
155464bc87 | ||
|
|
06cd811ae4 | ||
|
|
1b2cd354db | ||
|
|
1b31268f59 | ||
|
|
b57ef7291f | ||
|
|
c3bf6aa3f8 | ||
|
|
d2fa14bbe2 | ||
|
|
9b6e55e90c | ||
|
|
afb07b651f | ||
|
|
e6806fdf2b | ||
|
|
e5ff2cff4e | ||
|
|
17d7d47b9a | ||
|
|
64e32061ab | ||
|
|
931110ba6c | ||
|
|
d90e7820cd | ||
|
|
824898dba5 | ||
|
|
761dd61ed4 | ||
|
|
89c63e6d87 | ||
|
|
a2361f9327 | ||
|
|
ea15205be8 | ||
|
|
0a45048535 | ||
|
|
1c51655ce3 | ||
|
|
7749f0da7c | ||
|
|
5695238f95 | ||
|
|
e1feeb7e21 | ||
|
|
84fecaf040 | ||
|
|
da77727673 | ||
|
|
f8c913a3e8 | ||
|
|
2024881ee1 | ||
|
|
35ed3a51e5 | ||
|
|
24b1c4d0a4 | ||
|
|
7ec2458fb5 | ||
|
|
175feaea23 | ||
|
|
dda6cf728b | ||
|
|
a7fd410b01 | ||
|
|
d281c36733 | ||
|
|
dc91e44c0a | ||
|
|
7967a858f4 | ||
|
|
2081407e38 | ||
|
|
976eabd527 | ||
|
|
b6d6a5de2b | ||
|
|
2d58cfe0ce | ||
|
|
9df8bdff5f | ||
|
|
c86b821951 | ||
|
|
4def086bf9 | ||
|
|
885c890d7d | ||
|
|
06060a6694 | ||
|
|
70667814f6 | ||
|
|
766b7a940c | ||
|
|
0c37586357 | ||
|
|
b4aa55ce1f | ||
|
|
109443ce77 | ||
|
|
5f38741831 | ||
|
|
c6f391501d | ||
|
|
d1f3105fbd | ||
|
|
8f88ca9d3d | ||
|
|
f9e4ca0cc2 | ||
|
|
5caf023677 | ||
|
|
35c2f4873c | ||
|
|
1ed7bab375 | ||
|
|
f0d1bfb777 | ||
|
|
42519ac843 | ||
|
|
8869e13385 | ||
|
|
8f9cbfe806 | ||
|
|
6481938626 | ||
|
|
9c7cc2acbf | ||
|
|
89a57d4ed3 | ||
|
|
732378592b | ||
|
|
19dc46660b | ||
|
|
4aad3471af | ||
|
|
533b455356 | ||
|
|
92bd305b00 | ||
|
|
f71eb09f74 | ||
|
|
83d4a7bc18 | ||
|
|
58807d9021 | ||
|
|
29595324c4 | ||
|
|
f9064e526f | ||
|
|
93ec2e8639 | ||
|
|
0e2a31709a | ||
|
|
c785b39eda | ||
|
|
8fab2f58da | ||
|
|
e44ee3bfe1 | ||
|
|
62065c9d28 | ||
|
|
c76275275f | ||
|
|
257f78879d | ||
|
|
894263809c | ||
|
|
bc9458101c | ||
|
|
c503935d6a | ||
|
|
d4756c9eb8 | ||
|
|
0004767775 | ||
|
|
74908642c7 | ||
|
|
aadfb71c98 | ||
|
|
1244af649d | ||
|
|
7bd48cc811 | ||
|
|
8f3ce38418 | ||
|
|
1b2d9b4245 | ||
|
|
c6b2b34fde | ||
|
|
e58fc13fdb | ||
|
|
922d53d2e4 | ||
|
|
fec53b3951 | ||
|
|
e72e2c6a02 | ||
|
|
08d001ee05 | ||
|
|
99d8a07f4a | ||
|
|
eef565134b | ||
|
|
9d78293437 | ||
|
|
fc0a556e5f | ||
|
|
b6b070584f | ||
|
|
e13225eee6 | ||
|
|
da20fb2922 | ||
|
|
459c2beb12 | ||
|
|
f1cc44dead | ||
|
|
d24cfdc382 | ||
|
|
ae4cc543f6 | ||
|
|
abdb3d17f9 | ||
|
|
4095c5da38 | ||
|
|
78fab728e4 | ||
|
|
52097a6867 | ||
|
|
cb990b55b5 | ||
|
|
5070fe303a | ||
|
|
b4405ebf3e | ||
|
|
d9e6bf5068 | ||
|
|
6822188f52 | ||
|
|
15858d03ff | ||
|
|
814a733258 | ||
|
|
3ce85d8ca9 | ||
|
|
d3bff2f39d | ||
|
|
f2272730ac | ||
|
|
fe19c97d86 | ||
|
|
d49556bf3d | ||
|
|
56b447493e | ||
|
|
e45b68eda7 | ||
|
|
8df1ef5986 | ||
|
|
dac34cda82 | ||
|
|
9925e30c8b | ||
|
|
dc5566b5ae | ||
|
|
8132ee651a | ||
|
|
f49a134a3d | ||
|
|
bd955cda06 | ||
|
|
c6dbc01912 | ||
|
|
fabe1aa940 | ||
|
|
ba5dbb94b8 | ||
|
|
6ccc053d7e | ||
|
|
cf21dfaa3a | ||
|
|
54ceb630de | ||
|
|
0a0c302cb2 | ||
|
|
f6eef54566 | ||
|
|
a69804f84d | ||
|
|
0b06b194b0 | ||
|
|
73f6ce304c | ||
|
|
195818a432 | ||
|
|
47c817de1c | ||
|
|
8b3894f213 | ||
|
|
a411252f07 | ||
|
|
d7626aeb3f | ||
|
|
3565098650 | ||
|
|
803fcf146b | ||
|
|
d9d646c5fb | ||
|
|
034a274b07 | ||
|
|
718d7af8bc | ||
|
|
860d3d9c8b | ||
|
|
f28b566992 | ||
|
|
1c261c7463 | ||
|
|
226b2482b1 | ||
|
|
ff346dc429 | ||
|
|
2dcef25175 | ||
|
|
46702bbb5c | ||
|
|
5600c9bc69 | ||
|
|
d7e46b1693 | ||
|
|
fe8c60ade1 | ||
|
|
288892441f | ||
|
|
e1179a8e22 | ||
|
|
4b06d0fd87 | ||
|
|
464d91f45a | ||
|
|
5cc7aa25cc | ||
|
|
20ec224070 | ||
|
|
9cbcc29ddb | ||
|
|
b9003a2f02 | ||
|
|
6b303410d1 | ||
|
|
8cae2f24b1 | ||
|
|
0a04d753ea | ||
|
|
35402c7bd3 | ||
|
|
847a97f61c | ||
|
|
fac27a6120 | ||
|
|
2e24eda00d | ||
|
|
7a653abf22 | ||
|
|
ae09229107 | ||
|
|
be35f48bdd | ||
|
|
846173844e | ||
|
|
59c28d8e51 | ||
|
|
abdfa3ccf6 | ||
|
|
99ad6634c4 | ||
|
|
84556fb055 | ||
|
|
26e14e0151 | ||
|
|
3df2daa5cb | ||
|
|
c55efddc81 | ||
|
|
a59c8908f0 | ||
|
|
a421c5f952 | ||
|
|
37b0612d45 | ||
|
|
07bc94f9f6 | ||
|
|
82511880ac | ||
|
|
2f5cc6a8a4 | ||
|
|
f9a0f5e7a1 | ||
|
|
47b083eaca | ||
|
|
8fcf5ee760 | ||
|
|
f2006206d3 | ||
|
|
c32361a428 | ||
|
|
ac83c2bc3c | ||
|
|
32808c16e7 | ||
|
|
e4e2433396 | ||
|
|
8196b6e69e | ||
|
|
8dd49b6156 | ||
|
|
c4ab83a801 | ||
|
|
2c51b7b835 | ||
|
|
bab49d04b7 | ||
|
|
6963d66240 | ||
|
|
8cbf3ffc6b | ||
|
|
2a4693f6ed | ||
|
|
217256746c | ||
|
|
6c90225024 | ||
|
|
92d8a894e3 | ||
|
|
c89d619808 | ||
|
|
31dd4f6305 | ||
|
|
ff9715ede7 | ||
|
|
ffd1e383c2 | ||
|
|
2cc4f8c2fe | ||
|
|
6f513eb359 | ||
|
|
b235a5bb49 | ||
|
|
25f1912573 | ||
|
|
d24d6f6b52 | ||
|
|
afdb156c84 | ||
|
|
643d3600b8 | ||
|
|
9c51bff55b | ||
|
|
81c91b3877 | ||
|
|
3d365eb258 | ||
|
|
6857f6d8f8 | ||
|
|
81bd9991bb | ||
|
|
056fa9ded2 | ||
|
|
a3792c474b | ||
|
|
ec233dbb46 | ||
|
|
d89cd789ac | ||
|
|
69088e162d | ||
|
|
ec53bd4125 | ||
|
|
35a264d21c | ||
|
|
0372c2eccc | ||
|
|
08c7ffc6d9 | ||
|
|
e386f6ac20 | ||
|
|
60ab893888 | ||
|
|
f2d960c3eb | ||
|
|
fb88aeaeb9 | ||
|
|
94561de719 | ||
|
|
89ed18cea3 | ||
|
|
b996fa234b | ||
|
|
f6cd5cb4b2 | ||
|
|
6ac8caaf5f | ||
|
|
e5a4145e37 | ||
|
|
2c8b408bfb | ||
|
|
58c5c04feb | ||
|
|
b0d6070d28 | ||
|
|
3728594f73 | ||
|
|
dc2f1eabb2 | ||
|
|
eda08e7454 | ||
|
|
1bf4b6daa9 | ||
|
|
f757266282 | ||
|
|
0321823125 | ||
|
|
33d190afaa | ||
|
|
ff16c4f127 | ||
|
|
134728438e | ||
|
|
754bd68a87 | ||
|
|
bd32eeeaa2 | ||
|
|
1b9a3bd4bd | ||
|
|
584d369b0b | ||
|
|
0ebe052752 | ||
|
|
535863bc52 | ||
|
|
dd925cd92b | ||
|
|
5529de3d95 | ||
|
|
ce6b65adb8 | ||
|
|
9897109332 | ||
|
|
cfc851a99b | ||
|
|
380178ccc8 | ||
|
|
3227ddd9f9 | ||
|
|
336be63237 | ||
|
|
37c9b9e1f5 | ||
|
|
ebb3e02dcc | ||
|
|
352505c54f | ||
|
|
0c7998712e | ||
|
|
b9a20e7ac5 | ||
|
|
7ab89b900c | ||
|
|
9620956727 | ||
|
|
9b85768b7e | ||
|
|
5276e1863d | ||
|
|
0fc1a30a2c | ||
|
|
8609b98b1c | ||
|
|
c85514a17a | ||
|
|
d00bef5546 | ||
|
|
b905f46f98 | ||
|
|
cdd4765d38 | ||
|
|
d62793f4ad | ||
|
|
d83d325a49 | ||
|
|
e5baf99814 | ||
|
|
b4aeab3501 | ||
|
|
039bfd372d | ||
|
|
1a92de71d1 | ||
|
|
d8279e11aa | ||
|
|
b1b8584641 | ||
|
|
11e75df1a9 | ||
|
|
25fc2bfbea | ||
|
|
a93c84ff64 | ||
|
|
986a4182d9 | ||
|
|
d38a8b109b | ||
|
|
711d8c8c6b | ||
|
|
0d1d22aeff | ||
|
|
ac2231f0f3 | ||
|
|
21344dacfc | ||
|
|
ca22ba5bbc | ||
|
|
fc64c34214 | ||
|
|
c35bc2476d | ||
|
|
222826af95 | ||
|
|
db28db0bc7 | ||
|
|
931f7d47ea | ||
|
|
987ed1cefc | ||
|
|
3e9a77abfa | ||
|
|
3879eb6b3a | ||
|
|
5e5a2040fc | ||
|
|
eea44d7de2 | ||
|
|
3fcbf075fb | ||
|
|
b2641494cc | ||
|
|
c48a794aee | ||
|
|
e53906aea8 | ||
|
|
05a4a1670f | ||
|
|
4bd35852a5 | ||
|
|
be4d56f8d2 | ||
|
|
dfbcd616f2 | ||
|
|
dc0106348d | ||
|
|
f2666d4a30 | ||
|
|
4220e58d26 | ||
|
|
07de43981a | ||
|
|
fa352c1a8f | ||
|
|
e5d582b30b | ||
|
|
8fb14ffdf3 | ||
|
|
c16e85e7db | ||
|
|
25a72e3508 | ||
|
|
20411da67b | ||
|
|
81bfdc69dd | ||
|
|
5e2829fe49 | ||
|
|
2aba09f090 | ||
|
|
38e27309fb | ||
|
|
6b586684e6 | ||
|
|
773e280339 | ||
|
|
297a67cd00 | ||
|
|
ceb61ebe74 | ||
|
|
6c85e3502e | ||
|
|
690192300f | ||
|
|
3ba963f474 | ||
|
|
9b2cacc3a0 | ||
|
|
315a616293 | ||
|
|
3c56cd6738 | ||
|
|
a48ac013e8 | ||
|
|
258602ce1a | ||
|
|
c85b547502 | ||
|
|
d6266c36bf | ||
|
|
fdd7f30e9a | ||
|
|
3994ef3619 | ||
|
|
633028a63f | ||
|
|
013374e9db | ||
|
|
4358b47e91 | ||
|
|
6decc1ce30 | ||
|
|
8a3dba3064 | ||
|
|
27bcead1bc | ||
|
|
acb9c01776 | ||
|
|
79fd23d51b | ||
|
|
776614d211 | ||
|
|
b03a498cd7 | ||
|
|
b612926fb6 | ||
|
|
b67377f505 | ||
|
|
2033acbe2a | ||
|
|
e435cfc489 | ||
|
|
a3199a52af | ||
|
|
99be870ab9 | ||
|
|
9b2ecb4701 | ||
|
|
be7443a0a0 | ||
|
|
0de6557872 | ||
|
|
258e890056 | ||
|
|
d84bbad79a | ||
|
|
07e6477686 | ||
|
|
acde161412 | ||
|
|
8d8f9c6d26 | ||
|
|
c7507d9743 | ||
|
|
ff970fde56 | ||
|
|
2c4a997c64 | ||
|
|
5c787e0b69 | ||
|
|
41da8435cc | ||
|
|
84ecc4c664 | ||
|
|
d18a36af22 | ||
|
|
b3e766aa50 | ||
|
|
0cee54c51b | ||
|
|
41e436a183 | ||
|
|
743fc19fa3 | ||
|
|
76e8c66b1b | ||
|
|
4379ea63f0 | ||
|
|
00ae54b4b2 | ||
|
|
3a7fd7d271 | ||
|
|
94a0c98bfe | ||
|
|
c2b2b2698d | ||
|
|
9bb630bae6 | ||
|
|
c47b2f5b18 | ||
|
|
ecdc9a968d | ||
|
|
c041ff66e2 | ||
|
|
fe0e2d5c2d | ||
|
|
2cf3bca8de | ||
|
|
b2a817e17b | ||
|
|
d1ca951ffa | ||
|
|
b3932ae8c5 | ||
|
|
35223d5737 | ||
|
|
9d263f11e5 | ||
|
|
3f28b30e95 | ||
|
|
d797abdb1f | ||
|
|
3b3a940ee4 | ||
|
|
1b5b61b25e | ||
|
|
00d29b88df | ||
|
|
ab9bc9da74 | ||
|
|
b79f7b7ab8 | ||
|
|
9b34b5ca89 | ||
|
|
b486788993 | ||
|
|
563e9c51e1 | ||
|
|
6ab5e3ed4f | ||
|
|
43a6c81151 | ||
|
|
887a5d50a4 | ||
|
|
be68f8c3f7 | ||
|
|
86a4923157 | ||
|
|
f80ff31412 | ||
|
|
94acc82bf5 | ||
|
|
3c1a1fcca1 | ||
|
|
b3d08e4cb8 | ||
|
|
ab766ce85b | ||
|
|
bcb8245c61 | ||
|
|
c9e60d5c3a | ||
|
|
eb7c74eea7 | ||
|
|
40f5911ceb | ||
|
|
2a8809adbb | ||
|
|
39524c4064 | ||
|
|
c1cc2d6350 | ||
|
|
acb857f433 | ||
|
|
d343d92b17 | ||
|
|
43cb4716a9 | ||
|
|
6222561431 | ||
|
|
07b10e9e23 | ||
|
|
dffe8cef7a | ||
|
|
bb26626fd5 | ||
|
|
2f207de1a0 | ||
|
|
a69419ed04 | ||
|
|
be7c1ba914 | ||
|
|
461f6ad2c1 | ||
|
|
aff85cbfb8 | ||
|
|
c0ce4523fa | ||
|
|
65f8b3978d | ||
|
|
80ca3e114e | ||
|
|
330e803675 | ||
|
|
337e9ac3ef | ||
|
|
dfb78788f9 | ||
|
|
2dc560f583 | ||
|
|
7355400548 | ||
|
|
50b4630436 | ||
|
|
132d43f999 | ||
|
|
0627f20f5e | ||
|
|
40f329512b | ||
|
|
c196c08ada | ||
|
|
8f1e0d57bf | ||
|
|
c30c455a9f | ||
|
|
cd0e8e1c6b | ||
|
|
cbeb91f9a9 | ||
|
|
a3830989ba | ||
|
|
86427e2042 | ||
|
|
8f079de0aa | ||
|
|
651727c697 | ||
|
|
5c55f4d4bb | ||
|
|
c8502d3b7b | ||
|
|
22e3b9b544 | ||
|
|
f16db8298b | ||
|
|
cf4a32b260 | ||
|
|
b8d83c37d9 | ||
|
|
617f6bb8ef | ||
|
|
0c9f2bf5d2 | ||
|
|
eb9afecd66 | ||
|
|
2c1f2ae589 | ||
|
|
9387b09a19 | ||
|
|
f17f04f00a | ||
|
|
07f0192088 | ||
|
|
0fd19f0de8 | ||
|
|
e954fa6478 | ||
|
|
a0fdfc0f39 | ||
|
|
57a4372b65 | ||
|
|
c11cb38269 | ||
|
|
e4fd446946 | ||
|
|
714d8ac3ba | ||
|
|
f09293e077 | ||
|
|
389e8bc325 | ||
|
|
367f763ce5 | ||
|
|
3febed82f1 | ||
|
|
8a6371fe68 | ||
|
|
93937feb13 | ||
|
|
21e62d8597 | ||
|
|
88e8019858 | ||
|
|
cbe562a204 | ||
|
|
4dc40389a3 | ||
|
|
0552f10c38 | ||
|
|
c9ac7401e8 | ||
|
|
60625b9978 | ||
|
|
b4b53cfa4c | ||
|
|
f1e1d67f4e | ||
|
|
982641752f | ||
|
|
ba66cbbc95 | ||
|
|
750d13a300 | ||
|
|
3c69a87fc2 | ||
|
|
dbaddab07b | ||
|
|
1d58811680 | ||
|
|
4d78fe9ca4 | ||
|
|
56d3082696 | ||
|
|
8f573aba2f | ||
|
|
96633360d0 | ||
|
|
8ae7935cee | ||
|
|
68e860baad | ||
|
|
38ead3133f | ||
|
|
553d1f85c4 | ||
|
|
d9a985ff38 | ||
|
|
d3a2d2b248 | ||
|
|
575b8e5f62 | ||
|
|
37ff924c74 | ||
|
|
7ccbc4c77c | ||
|
|
27b7a60a8d | ||
|
|
dca731ffb8 | ||
|
|
0d56de99a7 | ||
|
|
ac5e11d327 | ||
|
|
9d315b0ff9 | ||
|
|
038fe84498 | ||
|
|
4fd59f2a19 | ||
|
|
f77c3bfdf7 | ||
|
|
dc7d941316 | ||
|
|
433cc1e32c | ||
|
|
c066a03683 | ||
|
|
562a8036bc | ||
|
|
53ac703f09 | ||
|
|
a2891d97d0 | ||
|
|
2bd5169f20 | ||
|
|
b3fd6d8c92 | ||
|
|
cea281b1d3 | ||
|
|
e85b2a8961 | ||
|
|
77b879d6bb | ||
|
|
9de3ae5cf2 | ||
|
|
b3a0dc3506 | ||
|
|
383731da4d | ||
|
|
67abb42652 | ||
|
|
edcc24bc12 | ||
|
|
a6836cab15 | ||
|
|
8f985737b0 | ||
|
|
6e2f102177 | ||
|
|
46a768339a | ||
|
|
f1dbbd62e9 | ||
|
|
8bb94889e0 | ||
|
|
da38e4e00c | ||
|
|
d8e8156b1c | ||
|
|
77a1b18673 | ||
|
|
9abd51f318 | ||
|
|
c7d51a29ac | ||
|
|
ac453ef32a | ||
|
|
db25493c04 | ||
|
|
8d4b4d3cd9 | ||
|
|
b05f13d82b | ||
|
|
438622d450 | ||
|
|
4f79efedc9 | ||
|
|
845fa89d0f | ||
|
|
29768576c8 | ||
|
|
4e659d799d | ||
|
|
10596bcb54 | ||
|
|
5ac6f4f7b3 | ||
|
|
957bb46e5c | ||
|
|
1042a537c1 | ||
|
|
2159b4b691 | ||
|
|
ce48e07e18 | ||
|
|
48dded02c6 | ||
|
|
b7d77042bf | ||
|
|
b4ea2569e3 | ||
|
|
42a9f864eb | ||
|
|
22e6de19c4 | ||
|
|
572a65d661 | ||
|
|
108ecb7e12 | ||
|
|
9c87d61528 | ||
|
|
dd903dd7e5 | ||
|
|
ae13cb2513 | ||
|
|
40f47ccd4e | ||
|
|
c344cd2a2b | ||
|
|
7601af24f0 | ||
|
|
0197eb0d08 | ||
|
|
a248967ae8 | ||
|
|
a4beb58b54 | ||
|
|
922cc942a4 | ||
|
|
f11b086381 | ||
|
|
e5eab69f65 | ||
|
|
961884ef12 | ||
|
|
5dbbf643a4 | ||
|
|
f937458c25 | ||
|
|
c617e62a16 | ||
|
|
343c886d54 | ||
|
|
824d85b2a0 | ||
|
|
0289fc5ce2 | ||
|
|
914a886bfe | ||
|
|
f65c30e975 | ||
|
|
48ac0049aa | ||
|
|
fea1117eae | ||
|
|
ace1a060db | ||
|
|
be6ad9c5e3 | ||
|
|
b2d51a2a9b | ||
|
|
74411d8656 | ||
|
|
332392b7ba | ||
|
|
e441414854 | ||
|
|
4b1d79e7f7 | ||
|
|
d7889e27e5 | ||
|
|
e65a68ce78 | ||
|
|
990f6d3730 | ||
|
|
84a62b3707 | ||
|
|
e18789b8d3 | ||
|
|
cb7be0e460 | ||
|
|
df825d0109 | ||
|
|
ce4baecb4b | ||
|
|
48907517e9 | ||
|
|
dde1d96058 | ||
|
|
b2f688a032 | ||
|
|
b4664f85f0 | ||
|
|
2725d32c33 | ||
|
|
c9f80db3c6 | ||
|
|
cb53ddf8a8 | ||
|
|
fdca41a71b | ||
|
|
d59ceee0f7 | ||
|
|
38b08835c2 | ||
|
|
dbbdb1bcbe | ||
|
|
b408e5d0d3 | ||
|
|
30f00508f5 | ||
|
|
75bb6aa966 | ||
|
|
eff206fb2b | ||
|
|
98da419c96 | ||
|
|
efe226045d | ||
|
|
35ba1532f4 | ||
|
|
476d732a3c | ||
|
|
21efc0c4a5 | ||
|
|
c20c6665fd | ||
|
|
cd497bfe9b | ||
|
|
25c42bee6d | ||
|
|
6d639385da | ||
|
|
fd1c0efedf | ||
|
|
5d2010aa73 | ||
|
|
d9333b2e93 | ||
|
|
3034306fcc | ||
|
|
0c7bae6fd7 | ||
|
|
855233f498 | ||
|
|
6b859a0478 | ||
|
|
2f37b658f1 | ||
|
|
3bd952e5c5 | ||
|
|
ae58c1fa99 | ||
|
|
dfb411cb6a | ||
|
|
449e3f5cc6 | ||
|
|
1b1fe17fca | ||
|
|
f3c457745e | ||
|
|
26f2e2b223 | ||
|
|
fcdd399eea | ||
|
|
c1d16782ab | ||
|
|
860434a1d5 | ||
|
|
38b493ee9d | ||
|
|
19dc560d56 | ||
|
|
bb10214db0 | ||
|
|
6a871c51a1 | ||
|
|
d7ff3050c2 | ||
|
|
8e0a0379d5 | ||
|
|
b7ceb90e61 | ||
|
|
c1935c83f6 | ||
|
|
62f08a2105 | ||
|
|
38d7f6e671 | ||
|
|
3c2c99c236 | ||
|
|
7694402ae4 | ||
|
|
7ed1d13221 | ||
|
|
47e89e35b2 | ||
|
|
3633759295 | ||
|
|
98bdb0479b | ||
|
|
1e40df227d | ||
|
|
caf0a709b8 | ||
|
|
daef951e59 | ||
|
|
73eab87dd9 | ||
|
|
1a2720649b | ||
|
|
1083cdb743 | ||
|
|
06eb8f9c10 | ||
|
|
31af15d267 | ||
|
|
12938df375 | ||
|
|
24d8dbcf64 | ||
|
|
2b7585357f | ||
|
|
5b659966c8 | ||
|
|
2834d6cac7 | ||
|
|
65dd4c873f | ||
|
|
8c834e634b | ||
|
|
f92430d092 | ||
|
|
b110e944c3 | ||
|
|
77eb5b5147 | ||
|
|
1fabdb9e2d | ||
|
|
e8682ac058 | ||
|
|
08603ad905 | ||
|
|
224b867737 | ||
|
|
0eb4ac5bcc | ||
|
|
876ca5927d | ||
|
|
98b4509014 | ||
|
|
c0013a0ba5 | ||
|
|
cc915e39c5 | ||
|
|
b569ad4ef5 | ||
|
|
6ab5388075 | ||
|
|
ded3079390 | ||
|
|
44fe358766 | ||
|
|
cee4b089c6 | ||
|
|
ba8bd4f95c | ||
|
|
c602072e5b | ||
|
|
76061c84aa | ||
|
|
cd01d3e923 | ||
|
|
ff23e7aba7 | ||
|
|
e61fb6f206 | ||
|
|
a6cab8fddc | ||
|
|
ec16d9abfc | ||
|
|
b5c67a47d1 | ||
|
|
a4c1e3b0bc | ||
|
|
b160d58d1b | ||
|
|
b6a4dfb424 | ||
|
|
5837718cf4 | ||
|
|
962e579434 | ||
|
|
63a249ecb0 | ||
|
|
3f40ca65f5 | ||
|
|
57668fc618 | ||
|
|
e82d14c973 | ||
|
|
8e9aa23c3c | ||
|
|
4687c7dcda | ||
|
|
5d857c731f | ||
|
|
eaec1205a1 | ||
|
|
e3d03c3d78 | ||
|
|
927fb013ff | ||
|
|
4deb14ccfb | ||
|
|
e04dba610b | ||
|
|
99a5dfee31 | ||
|
|
66842fca8e | ||
|
|
a47280f47b | ||
|
|
2808ca139c | ||
|
|
d87467aa88 | ||
|
|
382aad5119 | ||
|
|
93f94b65f1 | ||
|
|
bc66d4b0e7 | ||
|
|
ff044c831f | ||
|
|
cb85292f99 | ||
|
|
7c7722e8fc | ||
|
|
78cc6764bf | ||
|
|
0b540d6406 | ||
|
|
f1e0b7a94f | ||
|
|
611635a9a2 | ||
|
|
26c30b013b | ||
|
|
899f5231b5 | ||
|
|
0cfeee18c9 | ||
|
|
3e44835687 | ||
|
|
d5ac67071f | ||
|
|
6aee9ce92e | ||
|
|
6a268bfb68 | ||
|
|
63848e815f | ||
|
|
6640df18ac | ||
|
|
b9436c0cab | ||
|
|
c730f7931f | ||
|
|
ef6035b5be | ||
|
|
8502c0f048 | ||
|
|
acc4d5201a | ||
|
|
8248f31b20 | ||
|
|
39c1624d42 | ||
|
|
7eb82f2e84 | ||
|
|
df0d0d820a | ||
|
|
e0c0d8bc04 | ||
|
|
97619d8ba1 | ||
|
|
80df96fd0d | ||
|
|
579e76430d | ||
|
|
36dd7269e2 | ||
|
|
6596cb014f | ||
|
|
62ac63fd77 | ||
|
|
e6e8d96f12 | ||
|
|
f80464ea31 | ||
|
|
75b0c6f7a3 | ||
|
|
f95ce8c7b5 | ||
|
|
c991a3ccfd | ||
|
|
a1d612b1f6 | ||
|
|
d3cbd20c5e | ||
|
|
cff4f29ba4 | ||
|
|
dc08363360 | ||
|
|
a2aa8d9336 | ||
|
|
ab2bfa951c | ||
|
|
e871d37044 | ||
|
|
e32ee71bea | ||
|
|
3bc8823e54 | ||
|
|
a4b9dfaf1c | ||
|
|
c7c85ac676 | ||
|
|
1af445a390 | ||
|
|
4236a2e6f7 | ||
|
|
47e58942f8 | ||
|
|
f854ed50d6 | ||
|
|
2933a173a2 | ||
|
|
39c45cd329 | ||
|
|
93e6473828 | ||
|
|
2cf96bef52 | ||
|
|
3850ef4355 | ||
|
|
d29f989c22 | ||
|
|
0e31d503d0 | ||
|
|
8c2d552238 | ||
|
|
1b6cb61f8a | ||
|
|
b6e0fa9085 | ||
|
|
1f983d502e | ||
|
|
13637be1aa | ||
|
|
8f22740e07 | ||
|
|
03d5cc7521 | ||
|
|
c9f9e2b97d | ||
|
|
8ca4ede403 | ||
|
|
b50be86615 | ||
|
|
fe1a8f4425 | ||
|
|
dd472c1322 | ||
|
|
a636adec10 | ||
|
|
e3960445ae | ||
|
|
c631b7cd8a | ||
|
|
bb2bf12808 | ||
|
|
db95dfe208 | ||
|
|
86d052e51e | ||
|
|
fb55b9db17 | ||
|
|
ad3ad81c1e | ||
|
|
dccb84ded8 | ||
|
|
510c693871 | ||
|
|
8696df12ac | ||
|
|
d56e0b0eba | ||
|
|
29d77b2f2c | ||
|
|
4e131cd059 | ||
|
|
4c1f3948a3 | ||
|
|
c40ff67704 | ||
|
|
af6ac8bd4f | ||
|
|
70211a8407 | ||
|
|
4d6b83425b | ||
|
|
985396aaf9 | ||
|
|
d86c14d3a6 | ||
|
|
3bdb3a6b87 | ||
|
|
8dac57d4cf | ||
|
|
a91e7b9ed0 | ||
|
|
220b2c9a2a | ||
|
|
06bc8ed4a4 | ||
|
|
648863d21b | ||
|
|
3232e60467 | ||
|
|
da81ea4e57 | ||
|
|
42baec7c72 | ||
|
|
1accdfe2e6 | ||
|
|
f625653b30 | ||
|
|
2682187fa3 | ||
|
|
090f3fafa9 | ||
|
|
de81ed0c61 | ||
|
|
49465888b2 | ||
|
|
1555185d60 | ||
|
|
e5235bd714 | ||
|
|
1b4fe6135f | ||
|
|
9481b29d6b | ||
|
|
20115e6557 | ||
|
|
ee47136fb4 | ||
|
|
83dece68fc | ||
|
|
fce7083e28 | ||
|
|
5268375153 | ||
|
|
3598f59123 | ||
|
|
557f491a7e | ||
|
|
5aa876da72 | ||
|
|
7e7a66595b | ||
|
|
c429bdf139 | ||
|
|
22d22f3afa | ||
|
|
f5845908b9 | ||
|
|
138ce1c69a | ||
|
|
8366ec5831 | ||
|
|
383f0a7f43 | ||
|
|
22e5a5cafd | ||
|
|
8d6255aa55 | ||
|
|
8fd6f7add9 | ||
|
|
623c2cb9f1 | ||
|
|
259e87442d | ||
|
|
8655e025a2 | ||
|
|
aba2a9f504 | ||
|
|
9aa76bd088 | ||
|
|
10faef62fa | ||
|
|
6b291a5ce5 | ||
|
|
164f1dcfd4 | ||
|
|
b7d6d027d3 | ||
|
|
c4869f1917 | ||
|
|
79c31b5f54 | ||
|
|
89e99219d7 | ||
|
|
a9b6c68ce3 | ||
|
|
0563077fb9 | ||
|
|
e2f174e92e | ||
|
|
861bdb47ed | ||
|
|
9f9e2d12c4 | ||
|
|
03f504cadc | ||
|
|
182c7e827b | ||
|
|
61e0cfc979 | ||
|
|
3ea3f01394 | ||
|
|
fc5b8ca1e5 | ||
|
|
5d67b2f9dc | ||
|
|
bcf4fd9e93 | ||
|
|
5b5faad553 | ||
|
|
5299261d18 | ||
|
|
f852851886 | ||
|
|
20a4d9adb8 | ||
|
|
13997cd282 | ||
|
|
965429296b | ||
|
|
d9750ce4dc | ||
|
|
d0fb41e582 | ||
|
|
f7a83d5a60 | ||
|
|
fc52462df4 | ||
|
|
119804794f | ||
|
|
f23bd0b268 | ||
|
|
d6f61b4faf | ||
|
|
4e4b7a1c39 | ||
|
|
376bfb6799 | ||
|
|
12bdba9a9c | ||
|
|
33fa1e1350 | ||
|
|
94e1a4f793 | ||
|
|
2603d960b7 | ||
|
|
b8433c4ea7 | ||
|
|
fc30aeea61 | ||
|
|
01d6e1f14d | ||
|
|
3b4a65deaa | ||
|
|
2ec5ec78a9 | ||
|
|
6b416b8494 | ||
|
|
eac470e081 | ||
|
|
34ce50b7b5 | ||
|
|
6d85e7cdf7 | ||
|
|
23a47a6f63 | ||
|
|
d2bfcc6f0e | ||
|
|
7495392aa2 | ||
|
|
c4ddf84ba8 | ||
|
|
aad6c28e4d | ||
|
|
2bd03dada4 | ||
|
|
5fab16ad06 | ||
|
|
6a4d1ed44d | ||
|
|
db22159a89 | ||
|
|
029e0e5044 | ||
|
|
3f1ee0b1b8 | ||
|
|
8009794cca | ||
|
|
12ce96d802 | ||
|
|
53bd62b236 | ||
|
|
cd7362c654 | ||
|
|
788b5633cb | ||
|
|
46d106e6e2 | ||
|
|
8ffb91022e | ||
|
|
57c09d1772 | ||
|
|
0731ed2c7a | ||
|
|
19ecb67f2d | ||
|
|
d16123c276 | ||
|
|
f90b168fdd | ||
|
|
09f416efdf | ||
|
|
05f40f3451 | ||
|
|
d81206fe2e | ||
|
|
f166ef9313 | ||
|
|
14704f9b4d | ||
|
|
8381daeeb7 | ||
|
|
164ed75af2 | ||
|
|
1f7c64e279 | ||
|
|
a76bf03bc9 | ||
|
|
e50d7f7b95 | ||
|
|
45b1327c58 | ||
|
|
fe60421731 | ||
|
|
0404fe9044 | ||
|
|
8cf6c59ec7 | ||
|
|
7b817ff866 | ||
|
|
f087f70a2c | ||
|
|
b05752f430 | ||
|
|
c4cde366e8 | ||
|
|
33249fad21 | ||
|
|
f0dd28d4db | ||
|
|
c0e35aa9fa | ||
|
|
1fd633a23b | ||
|
|
9a65e26e71 | ||
|
|
f22cabc32a | ||
|
|
b97d57f00b | ||
|
|
5db3544683 | ||
|
|
96eee95596 | ||
|
|
ffb3243bb6 | ||
|
|
09f07902ef | ||
|
|
43583bbc2e | ||
|
|
2ebc713cbb | ||
|
|
65ecc0f3bb | ||
|
|
ebabc1117e | ||
|
|
672e59e657 | ||
|
|
882e11f558 | ||
|
|
1cd5acb972 | ||
|
|
464a6efd28 | ||
|
|
18c3c1f475 | ||
|
|
52de46aeb3 | ||
|
|
b80d088254 | ||
|
|
7d0d85aeb7 | ||
|
|
d19ef8322e | ||
|
|
840b4d7619 | ||
|
|
e4a36545d7 | ||
|
|
31fbc7389b | ||
|
|
19ec936d38 | ||
|
|
939c67d41c | ||
|
|
9614e4f115 | ||
|
|
c48150a792 | ||
|
|
60687502d1 | ||
|
|
2fab58759e | ||
|
|
a42c586bb2 | ||
|
|
a6b76b3494 | ||
|
|
a6eaf7fc84 | ||
|
|
97ba9b42eb | ||
|
|
e0a71f0373 | ||
|
|
b8875d7f1c | ||
|
|
67dfd9a942 | ||
|
|
db46b03d0c | ||
|
|
5672c86905 | ||
|
|
d5406270a5 | ||
|
|
0b3f5e408b | ||
|
|
2ce432ac77 | ||
|
|
6cb26b3fbb | ||
|
|
a9b5949191 | ||
|
|
6016370515 | ||
|
|
f3c026f278 | ||
|
|
8f218bd6d6 | ||
|
|
59fd89bf68 | ||
|
|
d27a6235f0 | ||
|
|
c23febbcf0 | ||
|
|
81e85a4d0d | ||
|
|
44ba1bc85b | ||
|
|
6244fe5a93 | ||
|
|
973335db56 | ||
|
|
4b2c4f88d3 | ||
|
|
bbd2ca0d68 | ||
|
|
a82c225841 | ||
|
|
f9a6852aaa | ||
|
|
fad704b692 | ||
|
|
e362632477 | ||
|
|
4558b49c1b | ||
|
|
4357d8788a | ||
|
|
78b7c24c15 | ||
|
|
127e9e9f74 | ||
|
|
1951ae1cce | ||
|
|
79e2fd4b52 | ||
|
|
2265a2c43d | ||
|
|
1e7e543ab0 | ||
|
|
9671a73bd6 | ||
|
|
5bbee94d68 | ||
|
|
9d7122d69c | ||
|
|
6b1270a4f9 | ||
|
|
3c8de2be3f | ||
|
|
5afb5f0e83 | ||
|
|
7f42d0df40 | ||
|
|
0df54c9021 | ||
|
|
41bc33f4ba | ||
|
|
dcc883fa27 | ||
|
|
492c5d01bf | ||
|
|
49eaca1290 | ||
|
|
ce43b586ad | ||
|
|
ae49cd6a26 | ||
|
|
6ad3897af8 | ||
|
|
53ddb067ea | ||
|
|
a9762170bc | ||
|
|
4d91403fd2 | ||
|
|
e1cd4a63d0 | ||
|
|
18f3874dab | ||
|
|
6efcee500d | ||
|
|
8c0532f363 | ||
|
|
fdb0d07ab8 | ||
|
|
58e30649a3 | ||
|
|
85feef3a60 | ||
|
|
fccd913a8a | ||
|
|
dd119edafe | ||
|
|
f6633fb16c | ||
|
|
d243bf4f48 | ||
|
|
92d306f777 | ||
|
|
0ea29b3d7c | ||
|
|
c8e6e8eb32 | ||
|
|
a6aae6292e | ||
|
|
e33100b075 | ||
|
|
84a229d286 | ||
|
|
ab32c42487 | ||
|
|
0dc3744859 | ||
|
|
d22eab4155 | ||
|
|
ea9bfec3c9 | ||
|
|
02b43a5d66 | ||
|
|
e0fc7952f4 | ||
|
|
66ec2c5d27 | ||
|
|
f5a78402a6 | ||
|
|
29bfd7325d | ||
|
|
318962c01f | ||
|
|
8ca49fafa1 | ||
|
|
656e783894 | ||
|
|
18c6d60a85 | ||
|
|
b202121c21 | ||
|
|
ea3672dd08 | ||
|
|
88037af7ef | ||
|
|
4bda5b619d | ||
|
|
a0645ea30f | ||
|
|
a3e4adb0af | ||
|
|
e18aedfabf | ||
|
|
44529a78d2 | ||
|
|
bb9025364b | ||
|
|
7c78283b46 | ||
|
|
f7d6ca5c11 | ||
|
|
172a341b40 | ||
|
|
09aef67808 | ||
|
|
a400312d3a | ||
|
|
1b01b35b03 | ||
|
|
2d0acaa8ae | ||
|
|
a31a73320b | ||
|
|
75da352806 | ||
|
|
61b0c9b1c1 | ||
|
|
2185fe0f4c | ||
|
|
4ee0977aa1 | ||
|
|
1ba44771bb | ||
|
|
9966eec1df | ||
|
|
dd444f5f76 | ||
|
|
a0a6089057 | ||
|
|
4be72fc989 | ||
|
|
033cbf696a | ||
|
|
805bc85ea9 | ||
|
|
0d057d500e | ||
|
|
7462500e20 | ||
|
|
3e06a4a7c5 | ||
|
|
e0684ab086 | ||
|
|
e7be883e2e | ||
|
|
8fe80a4507 | ||
|
|
68084c4567 | ||
|
|
9c27545f5f | ||
|
|
6da8af7680 | ||
|
|
1b7ce93623 | ||
|
|
5f6480527e | ||
|
|
4d7b4ce877 | ||
|
|
fd61f7d363 | ||
|
|
47cc3d7358 | ||
|
|
d180618634 | ||
|
|
b2b96426d7 | ||
|
|
5796d4b969 | ||
|
|
37957613df | ||
|
|
cb82f02eb4 | ||
|
|
3feccefee8 | ||
|
|
910b1dca85 | ||
|
|
d71c6f055b | ||
|
|
536f373b91 | ||
|
|
6987845228 | ||
|
|
2edd2bf763 | ||
|
|
2605761d76 | ||
|
|
391d261ca1 | ||
|
|
6a7531f1e6 | ||
|
|
fb294e8bea | ||
|
|
a1046488c3 | ||
|
|
8cef56265c | ||
|
|
ec30851247 | ||
|
|
7420c12b89 | ||
|
|
895c770c24 | ||
|
|
606070f449 | ||
|
|
ec41493d91 | ||
|
|
d551093199 | ||
|
|
f7f8b2da62 | ||
|
|
1378b630a6 | ||
|
|
9726d86ab0 | ||
|
|
c9364e7b94 | ||
|
|
1e6780a2e3 | ||
|
|
72855d4d7a | ||
|
|
c0359da930 | ||
|
|
b4f39b0bfc | ||
|
|
d7af145f3b | ||
|
|
b078d8477e | ||
|
|
02b64e1a4b | ||
|
|
f444825e42 | ||
|
|
9fa62ef388 | ||
|
|
e73ad07836 | ||
|
|
a680e79686 | ||
|
|
728c05262c | ||
|
|
23e08c1ca1 | ||
|
|
198d73acfa | ||
|
|
71e210b66c | ||
|
|
2f31c53fd4 | ||
|
|
9f661535e0 | ||
|
|
5b0d4bf8e6 | ||
|
|
a639264149 | ||
|
|
91ab257eb6 | ||
|
|
e24a62d621 | ||
|
|
ec9f4b2b61 | ||
|
|
b66c7da4b3 | ||
|
|
6544cc98d5 | ||
|
|
2dbef9e1fa | ||
|
|
a924e81adb | ||
|
|
1ded1b603e | ||
|
|
a3012a29c2 | ||
|
|
8fcd800aff | ||
|
|
4d414ea082 | ||
|
|
d5b2380bc2 | ||
|
|
d2853fafa9 | ||
|
|
0e5a207c44 | ||
|
|
d7744537ae | ||
|
|
9e79e9efb6 | ||
|
|
a04338d184 | ||
|
|
772b0ca2b0 | ||
|
|
13eb2b75d5 | ||
|
|
c800440e44 | ||
|
|
05f822380c | ||
|
|
7896c81e98 | ||
|
|
ea50569b2a | ||
|
|
7bce07aa0e | ||
|
|
5ef02290dd | ||
|
|
34d5ba7d35 | ||
|
|
55004e7832 | ||
|
|
4945446171 | ||
|
|
0e2d2408ca | ||
|
|
8b8707c36e | ||
|
|
3bd9caf113 | ||
|
|
f713a83abf | ||
|
|
b0e0f8c8bf | ||
|
|
c8623fd3a2 | ||
|
|
c6aad2c2d4 | ||
|
|
7ede87753b | ||
|
|
59bed5a0fa | ||
|
|
e59377d9a3 | ||
|
|
6274cfce4b | ||
|
|
9d624702f6 | ||
|
|
f9d8ff3f74 | ||
|
|
6c837f0639 | ||
|
|
03c9ce3589 | ||
|
|
1ac7cdacb0 | ||
|
|
ba93be1814 | ||
|
|
1404bbab9f | ||
|
|
a5f8ed6378 | ||
|
|
1b59212003 | ||
|
|
4142901dc6 | ||
|
|
4ba9431e6f | ||
|
|
5da83517a8 | ||
|
|
a7e95c2a4d | ||
|
|
ae7fbbb04f | ||
|
|
cc18ef9aa8 | ||
|
|
4202e8a7ba | ||
|
|
882ff8a325 | ||
|
|
1b29957731 | ||
|
|
5702543bc5 | ||
|
|
c810f0647a | ||
|
|
d366b67bee | ||
|
|
85286b3cf9 | ||
|
|
ae4b5464c7 | ||
|
|
dec2536e3e | ||
|
|
30ea512dcc | ||
|
|
f6cdf34b25 | ||
|
|
99818d038b | ||
|
|
c35ce8e195 | ||
|
|
2ae856b0dd | ||
|
|
e592598990 | ||
|
|
07af34fbd0 | ||
|
|
0b3e313260 | ||
|
|
21947de4e0 | ||
|
|
3cdd0baabb | ||
|
|
f851e62330 | ||
|
|
bea19ad8ce | ||
|
|
f5b48f5390 | ||
|
|
cc712b86d5 | ||
|
|
0cf6cfc2b0 | ||
|
|
6f19360da5 | ||
|
|
f216b4716f | ||
|
|
3bf638f7c6 | ||
|
|
5ec9a24c99 | ||
|
|
23caa1d0b5 | ||
|
|
36ecf7c7fd | ||
|
|
0027e75a45 | ||
|
|
4cd759bfa6 | ||
|
|
0f2752220a | ||
|
|
ce1ed46851 | ||
|
|
aa795ee7eb | ||
|
|
5c83671739 | ||
|
|
3fb9390040 | ||
|
|
965687186c | ||
|
|
83742437d6 | ||
|
|
a37e53769c | ||
|
|
084a389a02 | ||
|
|
7971c42814 | ||
|
|
c694461abc |
2
.gitattributes
vendored
Normal file
2
.gitattributes
vendored
Normal file
@@ -0,0 +1,2 @@
|
|||||||
|
*.html linguist-documentation
|
||||||
|
(^|/)site/) linguist-documentation
|
||||||
34
.github/contributing.md
vendored
Normal file
34
.github/contributing.md
vendored
Normal file
@@ -0,0 +1,34 @@
|
|||||||
|
# Contributing to OWASP dependency-check
|
||||||
|
|
||||||
|
## Reporting Bugs
|
||||||
|
|
||||||
|
- Ensure you're running the latest version of dependency-check.
|
||||||
|
- Ensure the bug has not [already been reported](https://github.com/jeremylong/DependencyCheck/issues).
|
||||||
|
- If you're unable to find an open issue addressing the problem, please [submit a new issue](https://github.com/jeremylong/DependencyCheck/issues/new).
|
||||||
|
- Please fill out the appropriate section of the bug report template provided. Please delete any sections not needed in the template.
|
||||||
|
|
||||||
|
## Reporting Vulnerabilities
|
||||||
|
|
||||||
|
- If you believe you have found a vulnerability in dependency-check itself (not that dependency-check found a vulnerability); please email jeremy.long@owasp.org.
|
||||||
|
|
||||||
|
## Asking Questions
|
||||||
|
|
||||||
|
- Your question may be answered by taking a look at the [documentataion](https://jeremylong.github.io/DependencyCheck/).
|
||||||
|
- If you still have a question consider:
|
||||||
|
- posting to the [Google Group](https://groups.google.com/forum/#!forum/dependency-check)
|
||||||
|
- opening a [new issue](https://github.com/jeremylong/DependencyCheck/issues/new)
|
||||||
|
|
||||||
|
## Enhancement Requests
|
||||||
|
|
||||||
|
- Suggest changes by [submitting a new issue](https://github.com/jeremylong/DependencyCheck/issues/new) and begin coding.
|
||||||
|
|
||||||
|
## Contributing Code
|
||||||
|
|
||||||
|
- If you have written a new feature or have fixed a bug please open a new pull request with the patch.
|
||||||
|
- Ensure the PR description clearly describes the problem and solution. Include any related issue number(s) if applicable.
|
||||||
|
- Please ensure the PR passes the automated checks performed (travis-ci, codacy, etc.)
|
||||||
|
- Please consider adding test cases for any new functionality
|
||||||
|
|
||||||
|
## Thank you for your contributions
|
||||||
|
|
||||||
|
OWASP dependency-check team
|
||||||
20
.github/issue_template.md
vendored
Normal file
20
.github/issue_template.md
vendored
Normal file
@@ -0,0 +1,20 @@
|
|||||||
|
Please delete any un-needed section from the following issue template:
|
||||||
|
|
||||||
|
### Reporting Bugs/Errors
|
||||||
|
When reporting errors, 99% of the time log file output is required. Please post the log file as a [gist](https://gist.github.com/) and provide a link in the new issue.
|
||||||
|
|
||||||
|
### Reporting False Positives
|
||||||
|
When reporting a false positive please include:
|
||||||
|
- The location of the dependency (Maven GAV, URL to download the dependency, etc.)
|
||||||
|
- The CPE that is believed to be false positive
|
||||||
|
- Please report the CPE not the CVE
|
||||||
|
|
||||||
|
#### Example
|
||||||
|
False positive on library foo.jar - reported as cpe:/a:apache:tomcat:7.0
|
||||||
|
```xml
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.sample</groupId>
|
||||||
|
<artifactId>foo</artifactId>
|
||||||
|
<version>1.0</version>
|
||||||
|
</dependency>
|
||||||
|
```
|
||||||
9
.github/pull_request_template.md
vendored
Normal file
9
.github/pull_request_template.md
vendored
Normal file
@@ -0,0 +1,9 @@
|
|||||||
|
## Fixes Issue #
|
||||||
|
|
||||||
|
## Description of Change
|
||||||
|
|
||||||
|
*Please add a description of the proposed change*
|
||||||
|
|
||||||
|
## Have test cases been added to cover the new functionality?
|
||||||
|
|
||||||
|
*yes/no*
|
||||||
10
.gitignore
vendored
10
.gitignore
vendored
@@ -1,4 +1,6 @@
|
|||||||
*/target/**
|
*/target/**
|
||||||
|
# IntelliJ test run side-effects
|
||||||
|
dependency-check-core/data/
|
||||||
# Intellij project files
|
# Intellij project files
|
||||||
*.iml
|
*.iml
|
||||||
*.ipr
|
*.ipr
|
||||||
@@ -7,6 +9,10 @@
|
|||||||
# Eclipse project files
|
# Eclipse project files
|
||||||
.classpath
|
.classpath
|
||||||
.project
|
.project
|
||||||
|
.settings
|
||||||
|
maven-eclipse.xml
|
||||||
|
.externalToolBuilders
|
||||||
|
.pmd
|
||||||
# Netbeans configuration
|
# Netbeans configuration
|
||||||
nb-configuration.xml
|
nb-configuration.xml
|
||||||
/target/
|
/target/
|
||||||
@@ -19,4 +25,6 @@ _site/**
|
|||||||
#unknown as to why these are showing up... but need to be ignored.
|
#unknown as to why these are showing up... but need to be ignored.
|
||||||
.LCKpom.xml~
|
.LCKpom.xml~
|
||||||
#coverity
|
#coverity
|
||||||
/cov-int/
|
/cov-int/
|
||||||
|
/dependency-check-core/nbproject/
|
||||||
|
cov-scan.bat
|
||||||
3
.travis.yml
Normal file
3
.travis.yml
Normal file
@@ -0,0 +1,3 @@
|
|||||||
|
language: java
|
||||||
|
jdk: oraclejdk7
|
||||||
|
script: mvn install -DreleaseTesting
|
||||||
14
Dockerfile
Normal file
14
Dockerfile
Normal file
@@ -0,0 +1,14 @@
|
|||||||
|
FROM java:8
|
||||||
|
|
||||||
|
MAINTAINER Timo Pagel <dependencycheckmaintainer@timo-pagel.de>
|
||||||
|
|
||||||
|
RUN wget -O /tmp/current.txt http://jeremylong.github.io/DependencyCheck/current.txt && current=$(cat /tmp/current.txt) && wget https://dl.bintray.com/jeremy-long/owasp/dependency-check-$current-release.zip && unzip dependency-check-$current-release.zip && mv dependency-check /usr/share/
|
||||||
|
|
||||||
|
RUN useradd -ms /bin/bash dockeruser && chown -R dockeruser:dockeruser /usr/share/dependency-check && mkdir /report && chown -R dockeruser:dockeruser /report
|
||||||
|
USER dockeruser
|
||||||
|
|
||||||
|
VOLUME "/src /usr/share/dependency-check/data /report"
|
||||||
|
|
||||||
|
WORKDIR /report
|
||||||
|
|
||||||
|
ENTRYPOINT ["/usr/share/dependency-check/bin/dependency-check.sh", "--scan", "/src"]
|
||||||
78
README.md
78
README.md
@@ -1,3 +1,7 @@
|
|||||||
|
[](https://travis-ci.org/jeremylong/DependencyCheck) [](https://scan.coverity.com/projects/dependencycheck) [](https://www.codacy.com/app/jeremylong/DependencyCheck?utm_source=github.com&utm_medium=referral&utm_content=jeremylong/DependencyCheck&utm_campaign=Badge_Grade) [](https://www.apache.org/licenses/LICENSE-2.0.txt)
|
||||||
|
|
||||||
|
[](https://www.toolswatch.org/2015/06/black-hat-arsenal-usa-2015-speakers-lineup/) [](https://www.toolswatch.org/2014/06/black-hat-usa-2014-arsenal-tools-speaker-list/) [](https://www.toolswatch.org/2013/06/announcement-blackhat-arsenal-usa-2013-selected-tools/)
|
||||||
|
|
||||||
Dependency-Check
|
Dependency-Check
|
||||||
================
|
================
|
||||||
|
|
||||||
@@ -9,27 +13,35 @@ Current Releases
|
|||||||
-------------
|
-------------
|
||||||
### Jenkins Plugin
|
### 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
|
### Command Line
|
||||||
|
|
||||||
More detailed instructions can be found on the [dependency-check github pages](http://jeremylong.github.io/DependencyCheck/dependency-check-cli/installation.html).
|
More detailed instructions can be found on the
|
||||||
The latest CLI can be downloaded from bintray's [dependency-check page](https://bintray.com/jeremy-long/owasp/dependency-check).
|
[dependency-check github pages](http://jeremylong.github.io/DependencyCheck/dependency-check-cli/).
|
||||||
|
The latest CLI can be downloaded from bintray's
|
||||||
|
[dependency-check page](https://bintray.com/jeremy-long/owasp/dependency-check).
|
||||||
|
|
||||||
On *nix
|
On *nix
|
||||||
```
|
```
|
||||||
$ ./bin/dependency-check.sh -h
|
$ ./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
|
On Windows
|
||||||
```
|
```
|
||||||
> bin/dependency-check.bat -h
|
> bin/dependency-check.bat -h
|
||||||
> bin/dependency-check.bat --app Testing --out . --scan [path to jar files to be scanned]
|
> bin/dependency-check.bat --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 --project Testing --out . --scan [path to jar files to be scanned]
|
||||||
```
|
```
|
||||||
|
|
||||||
### Maven Plugin
|
### 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:
|
The plugin can be configured using the following:
|
||||||
|
|
||||||
```xml
|
```xml
|
||||||
@@ -40,7 +52,6 @@ The plugin can be configured using the following:
|
|||||||
<plugin>
|
<plugin>
|
||||||
<groupId>org.owasp</groupId>
|
<groupId>org.owasp</groupId>
|
||||||
<artifactId>dependency-check-maven</artifactId>
|
<artifactId>dependency-check-maven</artifactId>
|
||||||
<version>1.0.2</version>
|
|
||||||
<executions>
|
<executions>
|
||||||
<execution>
|
<execution>
|
||||||
<goals>
|
<goals>
|
||||||
@@ -59,31 +70,66 @@ The plugin can be configured using the following:
|
|||||||
|
|
||||||
### Ant Task
|
### Ant Task
|
||||||
|
|
||||||
For instructions on the use of the Ant Task, please see the [dependency-check-ant github page](http://jeremylong.github.io/DependencyCheck/dependency-check-maven/installation.html).
|
For instructions on the use of the Ant Task, please see the [dependency-check-ant github page](http://jeremylong.github.io/DependencyCheck/dependency-check-ant).
|
||||||
|
|
||||||
Development Usage
|
Development Usage
|
||||||
-------------
|
-------------
|
||||||
The following instructions outline how to compile and use the current snapshot. While every intention is to maintain a stable snapshot it is recommended
|
The following instructions outline how to compile and use the current snapshot. While every intention is to maintain a stable snapshot it is recommended
|
||||||
that the release versions listed above be used.
|
that the release versions listed above be used.
|
||||||
|
|
||||||
Note, currently the install goal may take a long time to execute the integration tests. However, if this takes more then 30 minutes it is likely that the
|
The repository has some large files due to test resources. The team has tried to cleanup the history as much as possible.
|
||||||
download of data from the NVD is having an issue. This issue is still being researched and a solution should be published soon.
|
However, it is recommended that you perform a shallow clone to save yourself time:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
git clone --depth 1 git@github.com:jeremylong/DependencyCheck.git
|
||||||
|
```
|
||||||
|
|
||||||
On *nix
|
On *nix
|
||||||
```
|
```
|
||||||
$ mvn install
|
$ mvn install
|
||||||
$ ./dependency-check-cli/target/release/bin/dependency-check.sh -h
|
$ ./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
|
On Windows
|
||||||
```
|
```
|
||||||
> mvn install
|
> mvn install
|
||||||
> dependency-check-cli/target/release/bin/dependency-check.bat -h
|
> 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.
|
Then load the resulting 'DependencyCheck-Report.html' into your favorite browser.
|
||||||
|
|
||||||
|
### Docker
|
||||||
|
|
||||||
|
In the following example it is assumed that the source to be checked is in the actual directory. A persistent data directory and a persistent report directory is used so that the container can be destroyed after running it to make sure that you use the newest version, always.
|
||||||
|
```
|
||||||
|
# After the first run, feel free to change the owner of the directories to the owner of the created files and the permissions to 744
|
||||||
|
DATA_DIRECTORY=$HOME/OWASP-Dependency-Check/data
|
||||||
|
REPORT_DIRECTORY=/$HOME/OWASP-Dependency-Check/reports
|
||||||
|
|
||||||
|
if [ ! -d $DATA_DIRECTORY ]; then
|
||||||
|
echo "Initially creating persistent directories"
|
||||||
|
mkdir -p $DATA_DIRECTORY
|
||||||
|
chmod -R 777 $DATA_DIRECTORY
|
||||||
|
|
||||||
|
mkdir -p $REPORT_DIRECTORY
|
||||||
|
chmod -R 777 $REPORT_DIRECTORY
|
||||||
|
fi
|
||||||
|
|
||||||
|
docker pull owasp/dependency-check # Make sure it is the actual version
|
||||||
|
|
||||||
|
docker run --rm \
|
||||||
|
--volume $(pwd):/src \
|
||||||
|
--volume $DATA_DIRECTORY:/usr/share/dependency-check/data \
|
||||||
|
--volume $REPORT_DIRECTORY:/report \
|
||||||
|
--name dependency-check \
|
||||||
|
dc \
|
||||||
|
--suppression "/src/security/dependency-check-suppression.xml"\
|
||||||
|
--format "ALL" \
|
||||||
|
--project "My OWASP Dependency Check Project" \
|
||||||
|
```
|
||||||
|
|
||||||
|
|
||||||
Mailing List
|
Mailing List
|
||||||
------------
|
------------
|
||||||
|
|
||||||
@@ -96,14 +142,14 @@ Archive: [google group](https://groups.google.com/forum/#!forum/dependency-check
|
|||||||
Copyright & License
|
Copyright & License
|
||||||
-
|
-
|
||||||
|
|
||||||
Dependency-Check is Copyright (c) 2012-2014 Jeremy Long. All Rights Reserved.
|
Dependency-Check is Copyright (c) 2012-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.
|
Dependency-Check makes use of several other open source libraries. Please see the [NOTICE.txt][notices] file for more information.
|
||||||
|
|
||||||
|
|
||||||
[wiki]: https://github.com/jeremylong/DependencyCheck/wiki
|
[wiki]: https://github.com/jeremylong/DependencyCheck/wiki
|
||||||
[subscribe]: mailto:dependency-check+subscribe@googlegroups.com
|
[subscribe]: mailto:dependency-check+subscribe@googlegroups.com
|
||||||
[post]: mailto:dependency-check@googlegroups.com
|
[post]: mailto:dependency-check@googlegroups.com
|
||||||
[notices]: https://github.com/jeremylong/DependencyCheck/blob/master/NOTICES.txt
|
[notices]: https://github.com/jeremylong/DependencyCheck/blob/master/NOTICE.txt
|
||||||
|
|||||||
@@ -1,9 +1,6 @@
|
|||||||
-----------------------------
|
OWASP dependency-check
|
||||||
---begin dependency-check----
|
|
||||||
-----------------------------
|
|
||||||
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].
|
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 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
|
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
|
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).
|
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
|
Mailing List
|
||||||
------------
|
------------
|
||||||
@@ -20,6 +20,6 @@ Copyright & License
|
|||||||
|
|
||||||
Dependency-Check is Copyright (c) 2012-2014 Jeremy Long. All Rights Reserved.
|
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.
|
||||||
|
|||||||
@@ -15,20 +15,19 @@ limitations under the License.
|
|||||||
|
|
||||||
Copyright (c) 2013 - Jeremy Long. All Rights Reserved.
|
Copyright (c) 2013 - Jeremy Long. All Rights Reserved.
|
||||||
-->
|
-->
|
||||||
|
|
||||||
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
|
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
|
||||||
<modelVersion>4.0.0</modelVersion>
|
<modelVersion>4.0.0</modelVersion>
|
||||||
<parent>
|
<parent>
|
||||||
<groupId>org.owasp</groupId>
|
<groupId>org.owasp</groupId>
|
||||||
<artifactId>dependency-check-parent</artifactId>
|
<artifactId>dependency-check-parent</artifactId>
|
||||||
<version>1.2.3</version>
|
<version>1.4.6-SNAPSHOT</version>
|
||||||
</parent>
|
</parent>
|
||||||
|
|
||||||
<artifactId>dependency-check-ant</artifactId>
|
<artifactId>dependency-check-ant</artifactId>
|
||||||
<packaging>jar</packaging>
|
<packaging>jar</packaging>
|
||||||
|
|
||||||
<name>Dependency-Check Ant Task</name>
|
<name>Dependency-Check Ant Task</name>
|
||||||
<description>Dependency-check is a utility that attempts to detect publicly disclosed vulnerabilities contained within project dependencies. It does this by determining if there is a Common Platform Enumeration (CPE) identifier for a given dependency. If found, it will generate a report linking to the associated CVE entries.</description>
|
<description>dependency-check-ant is an Ant Task that uses dependency-check-core to detect publicly disclosed vulnerabilities associated with the project's dependencies. The task will generate a report listing the dependency, any identified Common Platform Enumeration (CPE) identifiers, and the associated Common Vulnerability and Exposure (CVE) entries.</description>
|
||||||
<!-- begin copy from http://minds.coremedia.com/2012/09/11/problem-solved-deploy-multi-module-maven-project-site-as-github-pages/ -->
|
<!-- begin copy from http://minds.coremedia.com/2012/09/11/problem-solved-deploy-multi-module-maven-project-site-as-github-pages/ -->
|
||||||
<distributionManagement>
|
<distributionManagement>
|
||||||
<site>
|
<site>
|
||||||
@@ -69,7 +68,6 @@ Copyright (c) 2013 - Jeremy Long. All Rights Reserved.
|
|||||||
<plugin>
|
<plugin>
|
||||||
<groupId>org.apache.maven.plugins</groupId>
|
<groupId>org.apache.maven.plugins</groupId>
|
||||||
<artifactId>maven-resources-plugin</artifactId>
|
<artifactId>maven-resources-plugin</artifactId>
|
||||||
<version>2.6</version>
|
|
||||||
<configuration>
|
<configuration>
|
||||||
<escapeWindowsPaths>false</escapeWindowsPaths>
|
<escapeWindowsPaths>false</escapeWindowsPaths>
|
||||||
</configuration>
|
</configuration>
|
||||||
@@ -194,54 +192,41 @@ Copyright (c) 2013 - Jeremy Long. All Rights Reserved.
|
|||||||
</plugin>
|
</plugin>
|
||||||
<plugin>
|
<plugin>
|
||||||
<groupId>org.apache.maven.plugins</groupId>
|
<groupId>org.apache.maven.plugins</groupId>
|
||||||
<artifactId>maven-shade-plugin</artifactId>
|
<artifactId>maven-jar-plugin</artifactId>
|
||||||
<version>2.1</version>
|
|
||||||
<configuration>
|
<configuration>
|
||||||
<transformers>
|
<archive>
|
||||||
<transformer implementation="org.apache.maven.plugins.shade.resource.ServicesResourceTransformer" />
|
<manifest>
|
||||||
<transformer implementation="org.apache.maven.plugins.shade.resource.AppendingTransformer">
|
<addClasspath>true</addClasspath>
|
||||||
<resource>META-INF/NOTICE.txt</resource>
|
<classpathPrefix>lib/</classpathPrefix>
|
||||||
</transformer>
|
</manifest>
|
||||||
<transformer implementation="org.apache.maven.plugins.shade.resource.DontIncludeResourceTransformer">
|
</archive>
|
||||||
<resource>META-INF/NOTICE</resource>
|
</configuration>
|
||||||
</transformer>
|
</plugin>
|
||||||
<transformer implementation="org.apache.maven.plugins.shade.resource.DontIncludeResourceTransformer">
|
<plugin>
|
||||||
<resource>META-INF/LICENSE</resource>
|
<groupId>org.apache.maven.plugins</groupId>
|
||||||
</transformer>
|
<artifactId>maven-assembly-plugin</artifactId>
|
||||||
</transformers>
|
<configuration>
|
||||||
|
<attach>false</attach> <!-- don't install/deploy this archive -->
|
||||||
</configuration>
|
</configuration>
|
||||||
<executions>
|
<executions>
|
||||||
<execution>
|
<execution>
|
||||||
|
<id>create-distribution</id>
|
||||||
<phase>package</phase>
|
<phase>package</phase>
|
||||||
<goals>
|
<goals>
|
||||||
<goal>shade</goal>
|
<goal>single</goal>
|
||||||
</goals>
|
</goals>
|
||||||
|
<configuration>
|
||||||
|
<descriptors>
|
||||||
|
<descriptor>src/main/assembly/release.xml</descriptor>
|
||||||
|
</descriptors>
|
||||||
|
</configuration>
|
||||||
</execution>
|
</execution>
|
||||||
</executions>
|
</executions>
|
||||||
</plugin>
|
</plugin>
|
||||||
<plugin>
|
|
||||||
<groupId>org.apache.maven.plugins</groupId>
|
|
||||||
<artifactId>maven-jar-plugin</artifactId>
|
|
||||||
<version>2.4</version>
|
|
||||||
<configuration>
|
|
||||||
<archive>
|
|
||||||
<manifest>
|
|
||||||
<addDefaultImplementationEntries>true</addDefaultImplementationEntries>
|
|
||||||
</manifest>
|
|
||||||
</archive>
|
|
||||||
<excludes>
|
|
||||||
<exclude>**/checkstyle*</exclude>
|
|
||||||
</excludes>
|
|
||||||
</configuration>
|
|
||||||
</plugin>
|
|
||||||
<plugin>
|
<plugin>
|
||||||
<groupId>org.codehaus.mojo</groupId>
|
<groupId>org.codehaus.mojo</groupId>
|
||||||
<artifactId>cobertura-maven-plugin</artifactId>
|
<artifactId>cobertura-maven-plugin</artifactId>
|
||||||
<version>2.6</version>
|
|
||||||
<configuration>
|
<configuration>
|
||||||
<instrumentation>
|
|
||||||
<ignoreTrivial>true</ignoreTrivial>
|
|
||||||
</instrumentation>
|
|
||||||
<check>
|
<check>
|
||||||
<branchRate>85</branchRate>
|
<branchRate>85</branchRate>
|
||||||
<lineRate>85</lineRate>
|
<lineRate>85</lineRate>
|
||||||
@@ -270,8 +255,8 @@ Copyright (c) 2013 - Jeremy Long. All Rights Reserved.
|
|||||||
<plugin>
|
<plugin>
|
||||||
<groupId>org.apache.maven.plugins</groupId>
|
<groupId>org.apache.maven.plugins</groupId>
|
||||||
<artifactId>maven-surefire-plugin</artifactId>
|
<artifactId>maven-surefire-plugin</artifactId>
|
||||||
<version>2.16</version>
|
|
||||||
<configuration>
|
<configuration>
|
||||||
|
<argLine>-Dfile.encoding=UTF-8</argLine>
|
||||||
<systemProperties>
|
<systemProperties>
|
||||||
<property>
|
<property>
|
||||||
<name>data.directory</name>
|
<name>data.directory</name>
|
||||||
@@ -280,159 +265,44 @@ Copyright (c) 2013 - Jeremy Long. All Rights Reserved.
|
|||||||
</systemProperties>
|
</systemProperties>
|
||||||
</configuration>
|
</configuration>
|
||||||
</plugin>
|
</plugin>
|
||||||
|
</plugins>
|
||||||
|
</build>
|
||||||
|
<reporting>
|
||||||
|
<plugins>
|
||||||
<plugin>
|
<plugin>
|
||||||
<groupId>org.apache.maven.plugins</groupId>
|
<groupId>org.apache.maven.plugins</groupId>
|
||||||
<artifactId>maven-compiler-plugin</artifactId>
|
<artifactId>maven-checkstyle-plugin</artifactId>
|
||||||
<version>3.1</version>
|
<version>${reporting.checkstyle-plugin.version}</version>
|
||||||
<configuration>
|
<configuration>
|
||||||
<showDeprecation>false</showDeprecation>
|
<enableRulesSummary>false</enableRulesSummary>
|
||||||
<source>1.6</source>
|
<enableFilesSummary>false</enableFilesSummary>
|
||||||
<target>1.6</target>
|
<configLocation>${basedir}/../src/main/config/checkstyle-checks.xml</configLocation>
|
||||||
|
<headerLocation>${basedir}/../src/main/config/checkstyle-header.txt</headerLocation>
|
||||||
|
<suppressionsLocation>${basedir}/../src/main/config/checkstyle-suppressions.xml</suppressionsLocation>
|
||||||
|
<suppressionsFileExpression>checkstyle.suppressions.file</suppressionsFileExpression>
|
||||||
</configuration>
|
</configuration>
|
||||||
</plugin>
|
</plugin>
|
||||||
|
|
||||||
<plugin>
|
<plugin>
|
||||||
<groupId>org.apache.maven.plugins</groupId>
|
<groupId>org.apache.maven.plugins</groupId>
|
||||||
<artifactId>maven-site-plugin</artifactId>
|
<artifactId>maven-pmd-plugin</artifactId>
|
||||||
<version>3.3</version>
|
<version>${reporting.pmd-plugin.version}</version>
|
||||||
<dependencies>
|
|
||||||
<dependency>
|
|
||||||
<groupId>org.apache.maven.doxia</groupId>
|
|
||||||
<artifactId>doxia-module-markdown</artifactId>
|
|
||||||
<version>1.5</version>
|
|
||||||
</dependency>
|
|
||||||
</dependencies>
|
|
||||||
<configuration>
|
<configuration>
|
||||||
<skipDeploy>true</skipDeploy>
|
<targetJdk>1.6</targetJdk>
|
||||||
<reportPlugins>
|
<linkXRef>true</linkXRef>
|
||||||
<plugin>
|
<sourceEncoding>utf-8</sourceEncoding>
|
||||||
<groupId>org.apache.maven.plugins</groupId>
|
<excludes>
|
||||||
<artifactId>maven-project-info-reports-plugin</artifactId>
|
<exclude>**/generated/*.java</exclude>
|
||||||
<version>2.7</version>
|
</excludes>
|
||||||
<reportSets>
|
<rulesets>
|
||||||
<reportSet>
|
<ruleset>../src/main/config/dcrules.xml</ruleset>
|
||||||
<reports>
|
<ruleset>/rulesets/java/basic.xml</ruleset>
|
||||||
<report>index</report>
|
<ruleset>/rulesets/java/imports.xml</ruleset>
|
||||||
<report>summary</report>
|
<ruleset>/rulesets/java/unusedcode.xml</ruleset>
|
||||||
<report>license</report>
|
</rulesets>
|
||||||
<report>help</report>
|
|
||||||
</reports>
|
|
||||||
</reportSet>
|
|
||||||
</reportSets>
|
|
||||||
</plugin>
|
|
||||||
<plugin>
|
|
||||||
<groupId>org.apache.maven.plugins</groupId>
|
|
||||||
<artifactId>maven-javadoc-plugin</artifactId>
|
|
||||||
<version>2.9.1</version>
|
|
||||||
<reportSets>
|
|
||||||
<reportSet>
|
|
||||||
<id>default</id>
|
|
||||||
<reports>
|
|
||||||
<report>javadoc</report>
|
|
||||||
</reports>
|
|
||||||
</reportSet>
|
|
||||||
</reportSets>
|
|
||||||
</plugin>
|
|
||||||
<plugin>
|
|
||||||
<groupId>org.codehaus.mojo</groupId>
|
|
||||||
<artifactId>versions-maven-plugin</artifactId>
|
|
||||||
<version>2.1</version>
|
|
||||||
<reportSets>
|
|
||||||
<reportSet>
|
|
||||||
<reports>
|
|
||||||
<report>dependency-updates-report</report>
|
|
||||||
<report>plugin-updates-report</report>
|
|
||||||
</reports>
|
|
||||||
</reportSet>
|
|
||||||
</reportSets>
|
|
||||||
</plugin>
|
|
||||||
<plugin>
|
|
||||||
<groupId>org.apache.maven.plugins</groupId>
|
|
||||||
<artifactId>maven-jxr-plugin</artifactId>
|
|
||||||
<version>2.4</version>
|
|
||||||
</plugin>
|
|
||||||
<plugin>
|
|
||||||
<groupId>org.codehaus.mojo</groupId>
|
|
||||||
<artifactId>cobertura-maven-plugin</artifactId>
|
|
||||||
<version>2.6</version>
|
|
||||||
</plugin>
|
|
||||||
<plugin>
|
|
||||||
<groupId>org.apache.maven.plugins</groupId>
|
|
||||||
<artifactId>maven-surefire-report-plugin</artifactId>
|
|
||||||
<version>2.16</version>
|
|
||||||
<reportSets>
|
|
||||||
<reportSet>
|
|
||||||
<reports>
|
|
||||||
<report>report-only</report>
|
|
||||||
</reports>
|
|
||||||
</reportSet>
|
|
||||||
</reportSets>
|
|
||||||
</plugin>
|
|
||||||
<plugin>
|
|
||||||
<groupId>org.codehaus.mojo</groupId>
|
|
||||||
<artifactId>taglist-maven-plugin</artifactId>
|
|
||||||
<version>2.4</version>
|
|
||||||
<configuration>
|
|
||||||
<tagListOptions>
|
|
||||||
<tagClasses>
|
|
||||||
<tagClass>
|
|
||||||
<displayName>Todo Work</displayName>
|
|
||||||
<tags>
|
|
||||||
<tag>
|
|
||||||
<matchString>todo</matchString>
|
|
||||||
<matchType>ignoreCase</matchType>
|
|
||||||
</tag>
|
|
||||||
<tag>
|
|
||||||
<matchString>FIXME</matchString>
|
|
||||||
<matchType>exact</matchType>
|
|
||||||
</tag>
|
|
||||||
</tags>
|
|
||||||
</tagClass>
|
|
||||||
</tagClasses>
|
|
||||||
</tagListOptions>
|
|
||||||
</configuration>
|
|
||||||
</plugin>
|
|
||||||
<plugin>
|
|
||||||
<groupId>org.apache.maven.plugins</groupId>
|
|
||||||
<artifactId>maven-checkstyle-plugin</artifactId>
|
|
||||||
<version>2.11</version>
|
|
||||||
<configuration>
|
|
||||||
<enableRulesSummary>false</enableRulesSummary>
|
|
||||||
<configLocation>${basedir}/../src/main/config/checkstyle-checks.xml</configLocation>
|
|
||||||
<headerLocation>${basedir}/../src/main/config/checkstyle-header.txt</headerLocation>
|
|
||||||
<suppressionsLocation>${basedir}/../src/main/config/checkstyle-suppressions.xml</suppressionsLocation>
|
|
||||||
<suppressionsFileExpression>checkstyle.suppressions.file</suppressionsFileExpression>
|
|
||||||
</configuration>
|
|
||||||
</plugin>
|
|
||||||
<plugin>
|
|
||||||
<groupId>org.apache.maven.plugins</groupId>
|
|
||||||
<artifactId>maven-pmd-plugin</artifactId>
|
|
||||||
<version>3.0.1</version>
|
|
||||||
<configuration>
|
|
||||||
<targetJdk>1.6</targetJdk>
|
|
||||||
<linkXref>true</linkXref>
|
|
||||||
<sourceEncoding>utf-8</sourceEncoding>
|
|
||||||
<excludes>
|
|
||||||
<exclude>**/generated/*.java</exclude>
|
|
||||||
</excludes>
|
|
||||||
<rulesets>
|
|
||||||
<ruleset>../src/main/config/dcrules.xml</ruleset>
|
|
||||||
<ruleset>/rulesets/java/basic.xml</ruleset>
|
|
||||||
<ruleset>/rulesets/java/imports.xml</ruleset>
|
|
||||||
<ruleset>/rulesets/java/unusedcode.xml</ruleset>
|
|
||||||
</rulesets>
|
|
||||||
</configuration>
|
|
||||||
</plugin>
|
|
||||||
<plugin>
|
|
||||||
<groupId>org.codehaus.mojo</groupId>
|
|
||||||
<artifactId>findbugs-maven-plugin</artifactId>
|
|
||||||
<version>2.5.3</version>
|
|
||||||
</plugin>
|
|
||||||
</reportPlugins>
|
|
||||||
</configuration>
|
</configuration>
|
||||||
</plugin>
|
</plugin>
|
||||||
</plugins>
|
</plugins>
|
||||||
</build>
|
</reporting>
|
||||||
<dependencies>
|
<dependencies>
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>org.owasp</groupId>
|
<groupId>org.owasp</groupId>
|
||||||
@@ -454,12 +324,11 @@ Copyright (c) 2013 - Jeremy Long. All Rights Reserved.
|
|||||||
<dependency>
|
<dependency>
|
||||||
<groupId>org.apache.ant</groupId>
|
<groupId>org.apache.ant</groupId>
|
||||||
<artifactId>ant</artifactId>
|
<artifactId>ant</artifactId>
|
||||||
<version>1.9.3</version>
|
<scope>provided</scope>
|
||||||
</dependency>
|
</dependency>
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>org.apache.ant</groupId>
|
<groupId>org.apache.ant</groupId>
|
||||||
<artifactId>ant-testutil</artifactId>
|
<artifactId>ant-testutil</artifactId>
|
||||||
<version>1.9.3</version>
|
|
||||||
<scope>test</scope>
|
<scope>test</scope>
|
||||||
</dependency>
|
</dependency>
|
||||||
</dependencies>
|
</dependencies>
|
||||||
|
|||||||
@@ -12,18 +12,25 @@
|
|||||||
<format>zip</format>
|
<format>zip</format>
|
||||||
</formats>
|
</formats>
|
||||||
<includeBaseDirectory>false</includeBaseDirectory>
|
<includeBaseDirectory>false</includeBaseDirectory>
|
||||||
<fileSets>
|
<!--fileSets>
|
||||||
<fileSet>
|
<fileSet>
|
||||||
<outputDirectory>/</outputDirectory>
|
<outputDirectory>dependency-check</outputDirectory>
|
||||||
<directory>${project.build.directory}</directory>
|
<directory>${project.build.directory}</directory>
|
||||||
<includes>
|
<includes>
|
||||||
<include>dependency-check*.jar</include>
|
<include>dependency-check*.jar</include>
|
||||||
</includes>
|
</includes>
|
||||||
</fileSet>
|
</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>
|
<dependencySets>
|
||||||
<dependencySet>
|
<dependencySet>
|
||||||
<outputDirectory>/lib</outputDirectory>
|
<outputDirectory>dependency-check-ant/lib</outputDirectory>
|
||||||
<scope>runtime</scope>
|
<scope>runtime</scope>
|
||||||
</dependencySet>
|
</dependencySet>
|
||||||
</dependencySets>
|
</dependencySets>
|
||||||
|
|||||||
@@ -0,0 +1,278 @@
|
|||||||
|
/*
|
||||||
|
* This file is part of dependency-check-ant.
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*
|
||||||
|
* Copyright (c) 2015 The OWASP Foundation. All Rights Reserved.
|
||||||
|
*/
|
||||||
|
package org.owasp.dependencycheck.ant.logging;
|
||||||
|
|
||||||
|
import org.apache.tools.ant.Project;
|
||||||
|
import org.apache.tools.ant.Task;
|
||||||
|
import org.slf4j.helpers.FormattingTuple;
|
||||||
|
import org.slf4j.helpers.MarkerIgnoringBase;
|
||||||
|
import org.slf4j.helpers.MessageFormatter;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* An instance of {@link org.slf4j.Logger} which simply calls the log method on
|
||||||
|
* the delegate Ant task.
|
||||||
|
*
|
||||||
|
* @author colezlaw
|
||||||
|
*/
|
||||||
|
public class AntLoggerAdapter extends MarkerIgnoringBase {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* serialization UID.
|
||||||
|
*/
|
||||||
|
private static final long serialVersionUID = -1337;
|
||||||
|
/**
|
||||||
|
* A reference to the Ant task used for logging.
|
||||||
|
*/
|
||||||
|
private transient Task task;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Constructs an Ant Logger Adapter.
|
||||||
|
*
|
||||||
|
* @param task the Ant Task to use for logging
|
||||||
|
*/
|
||||||
|
public AntLoggerAdapter(Task task) {
|
||||||
|
super();
|
||||||
|
this.task = task;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets the current Ant task to use for logging.
|
||||||
|
*
|
||||||
|
* @param task the Ant task to use for logging
|
||||||
|
*/
|
||||||
|
public void setTask(Task task) {
|
||||||
|
this.task = task;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean isTraceEnabled() {
|
||||||
|
// Might be a more efficient way to do this, but Ant doesn't enable or disable
|
||||||
|
// various levels globally - it just fires things at registered Listeners.
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void trace(String msg) {
|
||||||
|
if (task != null) {
|
||||||
|
task.log(msg, Project.MSG_VERBOSE);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void trace(String format, Object arg) {
|
||||||
|
if (task != null) {
|
||||||
|
final FormattingTuple tp = MessageFormatter.format(format, arg);
|
||||||
|
task.log(tp.getMessage(), Project.MSG_VERBOSE);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void trace(String format, Object arg1, Object arg2) {
|
||||||
|
if (task != null) {
|
||||||
|
final FormattingTuple tp = MessageFormatter.format(format, arg1, arg2);
|
||||||
|
task.log(tp.getMessage(), Project.MSG_VERBOSE);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void trace(String format, Object... arguments) {
|
||||||
|
if (task != null) {
|
||||||
|
final FormattingTuple tp = MessageFormatter.format(format, arguments);
|
||||||
|
task.log(tp.getMessage(), Project.MSG_VERBOSE);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void trace(String msg, Throwable t) {
|
||||||
|
if (task != null) {
|
||||||
|
task.log(msg, t, Project.MSG_VERBOSE);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean isDebugEnabled() {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void debug(String msg) {
|
||||||
|
if (task != null) {
|
||||||
|
task.log(msg, Project.MSG_DEBUG);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void debug(String format, Object arg) {
|
||||||
|
if (task != null) {
|
||||||
|
final FormattingTuple tp = MessageFormatter.format(format, arg);
|
||||||
|
task.log(tp.getMessage(), Project.MSG_DEBUG);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void debug(String format, Object arg1, Object arg2) {
|
||||||
|
if (task != null) {
|
||||||
|
final FormattingTuple tp = MessageFormatter.format(format, arg1, arg2);
|
||||||
|
task.log(tp.getMessage(), Project.MSG_DEBUG);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void debug(String format, Object... arguments) {
|
||||||
|
if (task != null) {
|
||||||
|
final FormattingTuple tp = MessageFormatter.format(format, arguments);
|
||||||
|
task.log(tp.getMessage(), Project.MSG_DEBUG);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void debug(String msg, Throwable t) {
|
||||||
|
if (task != null) {
|
||||||
|
task.log(msg, t, Project.MSG_DEBUG);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean isInfoEnabled() {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void info(String msg) {
|
||||||
|
if (task != null) {
|
||||||
|
task.log(msg, Project.MSG_INFO);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void info(String format, Object arg) {
|
||||||
|
if (task != null) {
|
||||||
|
final FormattingTuple tp = MessageFormatter.format(format, arg);
|
||||||
|
task.log(tp.getMessage(), Project.MSG_INFO);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void info(String format, Object arg1, Object arg2) {
|
||||||
|
if (task != null) {
|
||||||
|
final FormattingTuple tp = MessageFormatter.format(format, arg1, arg2);
|
||||||
|
task.log(tp.getMessage(), Project.MSG_INFO);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void info(String format, Object... arguments) {
|
||||||
|
if (task != null) {
|
||||||
|
final FormattingTuple tp = MessageFormatter.format(format, arguments);
|
||||||
|
task.log(tp.getMessage(), Project.MSG_INFO);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void info(String msg, Throwable t) {
|
||||||
|
if (task != null) {
|
||||||
|
task.log(msg, t, Project.MSG_INFO);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean isWarnEnabled() {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void warn(String msg) {
|
||||||
|
if (task != null) {
|
||||||
|
task.log(msg, Project.MSG_WARN);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void warn(String format, Object arg) {
|
||||||
|
if (task != null) {
|
||||||
|
final FormattingTuple tp = MessageFormatter.format(format, arg);
|
||||||
|
task.log(tp.getMessage(), Project.MSG_WARN);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void warn(String format, Object... arguments) {
|
||||||
|
if (task != null) {
|
||||||
|
final FormattingTuple tp = MessageFormatter.format(format, arguments);
|
||||||
|
task.log(tp.getMessage(), Project.MSG_WARN);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void warn(String format, Object arg1, Object arg2) {
|
||||||
|
if (task != null) {
|
||||||
|
final FormattingTuple tp = MessageFormatter.format(format, arg1, arg2);
|
||||||
|
task.log(tp.getMessage(), Project.MSG_WARN);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void warn(String msg, Throwable t) {
|
||||||
|
if (task != null) {
|
||||||
|
task.log(msg, t, Project.MSG_WARN);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean isErrorEnabled() {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void error(String msg) {
|
||||||
|
if (task != null) {
|
||||||
|
task.log(msg, Project.MSG_ERR);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void error(String format, Object arg) {
|
||||||
|
if (task != null) {
|
||||||
|
final FormattingTuple tp = MessageFormatter.format(format, arg);
|
||||||
|
task.log(tp.getMessage(), Project.MSG_ERR);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void error(String format, Object arg1, Object arg2) {
|
||||||
|
if (task != null) {
|
||||||
|
final FormattingTuple tp = MessageFormatter.format(format, arg1, arg2);
|
||||||
|
task.log(tp.getMessage(), Project.MSG_ERR);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void error(String format, Object... arguments) {
|
||||||
|
if (task != null) {
|
||||||
|
final FormattingTuple tp = MessageFormatter.format(format, arguments);
|
||||||
|
task.log(tp.getMessage(), Project.MSG_ERR);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void error(String msg, Throwable t) {
|
||||||
|
if (task != null) {
|
||||||
|
task.log(msg, t, Project.MSG_ERR);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,56 @@
|
|||||||
|
/*
|
||||||
|
* This file is part of dependency-check-ant.
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*
|
||||||
|
* Copyright (c) 2015 The OWASP Foundation. All Rights Reserved.
|
||||||
|
*/
|
||||||
|
package org.owasp.dependencycheck.ant.logging;
|
||||||
|
|
||||||
|
import org.apache.tools.ant.Task;
|
||||||
|
import org.slf4j.ILoggerFactory;
|
||||||
|
import org.slf4j.Logger;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* An implementation of {@link org.slf4j.ILoggerFactory} which always returns {@link AntLoggerAdapter} instances.
|
||||||
|
*
|
||||||
|
* @author colezlaw
|
||||||
|
*/
|
||||||
|
public class AntLoggerFactory implements ILoggerFactory {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A reference to the Ant logger Adapter.
|
||||||
|
*/
|
||||||
|
private final AntLoggerAdapter antLoggerAdapter;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Constructs a new Ant Logger Factory.
|
||||||
|
*
|
||||||
|
* @param task the Ant task to use for logging
|
||||||
|
*/
|
||||||
|
public AntLoggerFactory(Task task) {
|
||||||
|
super();
|
||||||
|
this.antLoggerAdapter = new AntLoggerAdapter(task);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the Ant logger adapter.
|
||||||
|
*
|
||||||
|
* @param name ignored in this implementation
|
||||||
|
* @return the Ant logger adapter
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
public Logger getLogger(String name) {
|
||||||
|
return antLoggerAdapter;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,4 @@
|
|||||||
|
/**
|
||||||
|
* This package includes the Ant task definitions.
|
||||||
|
*/
|
||||||
|
package org.owasp.dependencycheck.ant.logging;
|
||||||
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,166 @@
|
|||||||
|
/*
|
||||||
|
* 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;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Indicates if dependency-check should fail the build if an exception
|
||||||
|
* occurs.
|
||||||
|
*/
|
||||||
|
private boolean failOnError = true;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the value of failOnError.
|
||||||
|
*
|
||||||
|
* @return the value of failOnError
|
||||||
|
*/
|
||||||
|
public boolean isFailOnError() {
|
||||||
|
return failOnError;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Set the value of failOnError.
|
||||||
|
*
|
||||||
|
* @param failOnError new value of failOnError
|
||||||
|
*/
|
||||||
|
public void setFailOnError(boolean failOnError) {
|
||||||
|
this.failOnError = failOnError;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Executes the dependency-check purge to delete the existing local copy of
|
||||||
|
* the NVD CVE data.
|
||||||
|
*
|
||||||
|
* @throws BuildException thrown if there is a problem deleting the file(s)
|
||||||
|
*/
|
||||||
|
@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 {
|
||||||
|
final String msg = String.format("Unable to delete '%s'; please delete the file manually", db.getAbsolutePath());
|
||||||
|
if (this.failOnError) {
|
||||||
|
throw new BuildException(msg);
|
||||||
|
}
|
||||||
|
log(msg, Project.MSG_ERR);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
final String msg = String.format("Unable to purge database; the database file does not exists: %s", db.getAbsolutePath());
|
||||||
|
if (this.failOnError) {
|
||||||
|
throw new BuildException(msg);
|
||||||
|
}
|
||||||
|
log(msg, Project.MSG_ERR);
|
||||||
|
}
|
||||||
|
} catch (IOException ex) {
|
||||||
|
final String msg = "Unable to delete the database";
|
||||||
|
if (this.failOnError) {
|
||||||
|
throw new BuildException(msg);
|
||||||
|
}
|
||||||
|
log(msg, 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.
|
||||||
|
*
|
||||||
|
* @throws BuildException thrown if the properties file cannot be read.
|
||||||
|
*/
|
||||||
|
protected void populateSettings() throws BuildException {
|
||||||
|
Settings.initialize();
|
||||||
|
try (InputStream taskProperties = this.getClass().getClassLoader().getResourceAsStream(PROPERTIES_FILE)) {
|
||||||
|
Settings.mergeProperties(taskProperties);
|
||||||
|
} catch (IOException ex) {
|
||||||
|
final String msg = "Unable to load the dependency-check ant task.properties file.";
|
||||||
|
if (this.failOnError) {
|
||||||
|
throw new BuildException(msg, ex);
|
||||||
|
}
|
||||||
|
log(msg, ex, Project.MSG_WARN);
|
||||||
|
}
|
||||||
|
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,445 @@
|
|||||||
|
/*
|
||||||
|
* 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.apache.tools.ant.Project;
|
||||||
|
import org.owasp.dependencycheck.Engine;
|
||||||
|
import org.owasp.dependencycheck.data.nvdcve.DatabaseException;
|
||||||
|
import org.owasp.dependencycheck.data.update.exception.UpdateException;
|
||||||
|
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 {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The Proxy Server.
|
||||||
|
*/
|
||||||
|
private String proxyServer;
|
||||||
|
/**
|
||||||
|
* The Proxy Port.
|
||||||
|
*/
|
||||||
|
private String proxyPort;
|
||||||
|
/**
|
||||||
|
* The Proxy username.
|
||||||
|
*/
|
||||||
|
private String proxyUsername;
|
||||||
|
/**
|
||||||
|
* The Proxy password.
|
||||||
|
*/
|
||||||
|
private String proxyPassword;
|
||||||
|
/**
|
||||||
|
* The Connection Timeout.
|
||||||
|
*/
|
||||||
|
private String connectionTimeout;
|
||||||
|
/**
|
||||||
|
* The database driver name; such as org.h2.Driver.
|
||||||
|
*/
|
||||||
|
private String databaseDriverName;
|
||||||
|
/**
|
||||||
|
* The path to the database driver JAR file if it is not on the class path.
|
||||||
|
*/
|
||||||
|
private String databaseDriverPath;
|
||||||
|
/**
|
||||||
|
* The database connection string.
|
||||||
|
*/
|
||||||
|
private String connectionString;
|
||||||
|
/**
|
||||||
|
* The user name for connecting to the database.
|
||||||
|
*/
|
||||||
|
private String databaseUser;
|
||||||
|
/**
|
||||||
|
* The password to use when connecting to the database.
|
||||||
|
*/
|
||||||
|
private String databasePassword;
|
||||||
|
/**
|
||||||
|
* The url for the modified NVD CVE (1.2 schema).
|
||||||
|
*/
|
||||||
|
private String cveUrl12Modified;
|
||||||
|
/**
|
||||||
|
* Base Data Mirror URL for CVE 1.2.
|
||||||
|
*/
|
||||||
|
private String cveUrl12Base;
|
||||||
|
/**
|
||||||
|
* Data Mirror URL for CVE 2.0.
|
||||||
|
*/
|
||||||
|
private String cveUrl20Base;
|
||||||
|
/**
|
||||||
|
* The number of hours to wait before re-checking for updates.
|
||||||
|
*/
|
||||||
|
private Integer cveValidForHours;
|
||||||
|
/**
|
||||||
|
* The url for the modified NVD CVE (2.0 schema).
|
||||||
|
*/
|
||||||
|
private String cveUrl20Modified;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 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);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 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;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 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;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 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;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 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;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 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;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 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;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 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;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 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;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 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;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 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;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 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;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 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;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 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;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 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;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 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());
|
||||||
|
try {
|
||||||
|
engine.doUpdates();
|
||||||
|
} catch (UpdateException ex) {
|
||||||
|
if (this.isFailOnError()) {
|
||||||
|
throw new BuildException(ex);
|
||||||
|
}
|
||||||
|
log(ex.getMessage(), Project.MSG_ERR);
|
||||||
|
}
|
||||||
|
} catch (DatabaseException ex) {
|
||||||
|
final String msg = "Unable to connect to the dependency-check database; unable to update the NVD data";
|
||||||
|
if (this.isFailOnError()) {
|
||||||
|
throw new BuildException(msg, ex);
|
||||||
|
}
|
||||||
|
log(msg, Project.MSG_ERR);
|
||||||
|
} finally {
|
||||||
|
Settings.cleanup(true);
|
||||||
|
if (engine != null) {
|
||||||
|
engine.cleanup();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Takes the properties supplied and updates the dependency-check settings.
|
||||||
|
* Additionally, this sets the system properties required to change the
|
||||||
|
* proxy server, port, and connection timeout.
|
||||||
|
*
|
||||||
|
* @throws BuildException thrown when an invalid setting is configured.
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
protected void populateSettings() throws BuildException {
|
||||||
|
super.populateSettings();
|
||||||
|
Settings.setStringIfNotEmpty(Settings.KEYS.PROXY_SERVER, proxyServer);
|
||||||
|
Settings.setStringIfNotEmpty(Settings.KEYS.PROXY_PORT, proxyPort);
|
||||||
|
Settings.setStringIfNotEmpty(Settings.KEYS.PROXY_USERNAME, proxyUsername);
|
||||||
|
Settings.setStringIfNotEmpty(Settings.KEYS.PROXY_PASSWORD, proxyPassword);
|
||||||
|
Settings.setStringIfNotEmpty(Settings.KEYS.CONNECTION_TIMEOUT, connectionTimeout);
|
||||||
|
Settings.setStringIfNotEmpty(Settings.KEYS.DB_DRIVER_NAME, databaseDriverName);
|
||||||
|
Settings.setStringIfNotEmpty(Settings.KEYS.DB_DRIVER_PATH, databaseDriverPath);
|
||||||
|
Settings.setStringIfNotEmpty(Settings.KEYS.DB_CONNECTION_STRING, connectionString);
|
||||||
|
Settings.setStringIfNotEmpty(Settings.KEYS.DB_USER, databaseUser);
|
||||||
|
Settings.setStringIfNotEmpty(Settings.KEYS.DB_PASSWORD, databasePassword);
|
||||||
|
Settings.setStringIfNotEmpty(Settings.KEYS.CVE_MODIFIED_12_URL, cveUrl12Modified);
|
||||||
|
Settings.setStringIfNotEmpty(Settings.KEYS.CVE_MODIFIED_20_URL, cveUrl20Modified);
|
||||||
|
Settings.setStringIfNotEmpty(Settings.KEYS.CVE_SCHEMA_1_2, cveUrl12Base);
|
||||||
|
Settings.setStringIfNotEmpty(Settings.KEYS.CVE_SCHEMA_2_0, cveUrl20Base);
|
||||||
|
if (cveValidForHours != null) {
|
||||||
|
if (cveValidForHours >= 0) {
|
||||||
|
Settings.setInt(Settings.KEYS.CVE_CHECK_VALID_FOR_HOURS, cveValidForHours);
|
||||||
|
} else {
|
||||||
|
throw new BuildException("Invalid setting: `cpeValidForHours` must be 0 or greater");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,11 +1,4 @@
|
|||||||
/**
|
/**
|
||||||
* <html>
|
* This package includes the a slf4j logging implementation that wraps the Ant logger.
|
||||||
* <head>
|
|
||||||
* <title>org.owasp.dependencycheck.taskdefs</title>
|
|
||||||
* </head>
|
|
||||||
* <body>
|
|
||||||
* This package includes the Ant task definitions.
|
|
||||||
* </body>
|
|
||||||
* </html>
|
|
||||||
*/
|
*/
|
||||||
package org.owasp.dependencycheck.taskdefs;
|
package org.owasp.dependencycheck.taskdefs;
|
||||||
|
|||||||
@@ -0,0 +1,113 @@
|
|||||||
|
/*
|
||||||
|
* This file is part of dependency-check-ant.
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*
|
||||||
|
* Copyright (c) 2015 The OWASP Foundation. All Rights Reserved.
|
||||||
|
*/
|
||||||
|
package org.slf4j.impl;
|
||||||
|
|
||||||
|
import org.apache.tools.ant.Task;
|
||||||
|
import org.owasp.dependencycheck.ant.logging.AntLoggerFactory;
|
||||||
|
import org.slf4j.ILoggerFactory;
|
||||||
|
import org.slf4j.spi.LoggerFactoryBinder;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The binding of org.slf4j.LoggerFactory class with an actual instance of
|
||||||
|
* org.slf4j.ILoggerFactory is performed using information returned by this
|
||||||
|
* class.
|
||||||
|
*
|
||||||
|
* @author colezlaw
|
||||||
|
*/
|
||||||
|
//CSOFF: FinalClass
|
||||||
|
public class StaticLoggerBinder implements LoggerFactoryBinder {
|
||||||
|
//CSON: FinalClass
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The unique instance of this class
|
||||||
|
*/
|
||||||
|
private static final StaticLoggerBinder SINGLETON = new StaticLoggerBinder();
|
||||||
|
/**
|
||||||
|
* Ant tasks have the log method we actually want to call. So we hang onto
|
||||||
|
* the task as a delegate
|
||||||
|
*/
|
||||||
|
private Task task = null;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Return the singleton of this class.
|
||||||
|
*
|
||||||
|
* @return the StaticLoggerBinder singleton
|
||||||
|
*/
|
||||||
|
public static final StaticLoggerBinder getSingleton() {
|
||||||
|
return SINGLETON;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Set the Task which will this is to log through.
|
||||||
|
*
|
||||||
|
* @param task the task through which to log
|
||||||
|
*/
|
||||||
|
public void setTask(Task task) {
|
||||||
|
this.task = task;
|
||||||
|
loggerFactory = new AntLoggerFactory(task);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Declare the version of the SLF4J API this implementation is compiled
|
||||||
|
* against. The value of this filed is usually modified with each release.
|
||||||
|
*/
|
||||||
|
// to avoid constant folding by the compiler, this field must *not* be final
|
||||||
|
//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
|
||||||
|
*/
|
||||||
|
private ILoggerFactory loggerFactory;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Constructs a new static logger binder.
|
||||||
|
*/
|
||||||
|
private StaticLoggerBinder() {
|
||||||
|
loggerFactory = new AntLoggerFactory(task);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the logger factory.
|
||||||
|
*
|
||||||
|
* @return the logger factory
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
public ILoggerFactory getLoggerFactory() {
|
||||||
|
return loggerFactory;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the logger factory class string.
|
||||||
|
*
|
||||||
|
* @return the logger factory class string
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
public String getLoggerFactoryClassStr() {
|
||||||
|
return LOGGER_FACTORY_CLASS;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,4 @@
|
|||||||
|
/**
|
||||||
|
* This package contains the static binder for the slf4j-ant logger.
|
||||||
|
*/
|
||||||
|
package org.slf4j.impl;
|
||||||
@@ -0,0 +1,3 @@
|
|||||||
|
dependency-check=org.owasp.dependencycheck.taskdefs.Check
|
||||||
|
dependency-check-purge=org.owasp.dependencycheck.taskdefs.Purge
|
||||||
|
dependency-check-update=org.owasp.dependencycheck.taskdefs.Update
|
||||||
@@ -1,23 +0,0 @@
|
|||||||
handlers=java.util.logging.ConsoleHandler, java.util.logging.FileHandler
|
|
||||||
|
|
||||||
# logging levels
|
|
||||||
# FINEST, FINER, FINE, CONFIG, INFO, WARNING and SEVERE.
|
|
||||||
|
|
||||||
# Configure the ConsoleHandler.
|
|
||||||
java.util.logging.ConsoleHandler.level=INFO
|
|
||||||
|
|
||||||
#org.owasp.dependencycheck.data.nvdcve.xml
|
|
||||||
|
|
||||||
# Configure the FileHandler.
|
|
||||||
#java.util.logging.FileHandler.formatter=java.util.logging.SimpleFormatter
|
|
||||||
#java.util.logging.FileHandler.level=FINEST
|
|
||||||
|
|
||||||
# The following special tokens can be used in the pattern property
|
|
||||||
# which specifies the location and name of the log file.
|
|
||||||
# / - standard path separator
|
|
||||||
# %t - system temporary directory
|
|
||||||
# %h - value of the user.home system property
|
|
||||||
# %g - generation number for rotating logs
|
|
||||||
# %u - unique number to avoid conflicts
|
|
||||||
# FileHandler writes to %h/demo0.log by default.
|
|
||||||
#java.util.logging.FileHandler.pattern=./target/dependency-check.log
|
|
||||||
@@ -1,2 +1,2 @@
|
|||||||
# the path to the data directory
|
# 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
|
|
||||||
20
dependency-check-ant/src/site/markdown/config-purge.md
Normal file
20
dependency-check-ant/src/site/markdown/config-purge.md
Normal file
@@ -0,0 +1,20 @@
|
|||||||
|
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 becomes 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
|
||||||
|
failOnError | Whether the build should fail if there is an error executing the purge | true
|
||||||
45
dependency-check-ant/src/site/markdown/config-update.md
Normal file
45
dependency-check-ant/src/site/markdown/config-update.md
Normal file
@@ -0,0 +1,45 @@
|
|||||||
|
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
|
||||||
|
than 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. |
|
||||||
|
failOnError | Whether the build should fail if there is an error executing the update | true
|
||||||
|
|
||||||
|
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
|
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
|
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)
|
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),
|
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
|
```xml
|
||||||
<target name="dependency-check" description="Dependency-Check Analysis">
|
<target name="dependency-check" description="Dependency-Check Analysis">
|
||||||
<dependency-check applicationname="Hello World"
|
<dependency-check projectname="Hello World"
|
||||||
reportoutputdirectory="${basedir}"
|
reportoutputdirectory="${basedir}"
|
||||||
reportformat="ALL">
|
reportformat="ALL">
|
||||||
|
|
||||||
@@ -19,24 +25,27 @@ the project's dependencies.
|
|||||||
</target>
|
</target>
|
||||||
```
|
```
|
||||||
|
|
||||||
Configuration
|
Configuration: dependency-check Task
|
||||||
====================
|
--------------------
|
||||||
The following properties can be set on the dependency-check-maven plugin.
|
The following properties can be set on the dependency-check task.
|
||||||
|
|
||||||
Property | Description | Default Value
|
Property | Description | Default Value
|
||||||
---------------------|------------------------------------|------------------
|
----------------------|----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|-----------------
|
||||||
autoUpdate | Sets whether auto-updating of the NVD CVE/CPE data is enabled. It is not recommended that this be turned to false. | true
|
autoUpdate | Sets whether auto-updating of the NVD CVE/CPE data is enabled. It is not recommended that this be turned to false. | true
|
||||||
externalReport | When using as a Site plugin this parameter sets whether or not the external report format should be used. | false
|
cveValidForHours | Sets the number of hours to wait before checking for new updates from the NVD | 4
|
||||||
outputDirectory | The location to write the report(s). Note, this is not used if generating the report as part of a `mvn site` build | 'target'
|
failBuildOnCVSS | Specifies if the build should be failed if a CVSS score above a specified level is identified. The default is 11 which means since the CVSS scores are 0-10, by default the build will never fail. | 11
|
||||||
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
|
failOnError | Whether the build should fail if there is an error executing the dependency-check analysis | true
|
||||||
format | The report format to be generated (HTML, XML, VULN, ALL). This configuration option has no affect if using this within the Site plugin unless the externalReport is set to true. | HTML
|
projectName | The name of the project being scanned. | Dependency-Check
|
||||||
logFile | The file path to write verbose logging information. |
|
reportFormat | The report format to be generated (HTML, XML, VULN, ALL). This configuration option has no affect if using this within the Site plugin unless the externalReport is set to true. | HTML
|
||||||
suppressionFile | The file path to the XML suppression file \- used to suppress [false positives](../suppression.html) |
|
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'
|
||||||
proxyServer | The Proxy Server. |
|
suppressionFile | The file path to the XML suppression file \- used to suppress [false positives](../general/suppression.html) |
|
||||||
proxyPort | The Proxy Port. |
|
hintsFile | The file path to the XML hints file \- used to resolve [false negatives](../general/hints.html) |
|
||||||
proxyUsername | Defines the proxy user name. |
|
proxyServer | The Proxy Server; see the [proxy configuration](../data/proxy.html) page for more information. |
|
||||||
proxyPassword | Defines the proxy password. |
|
proxyPort | The Proxy Port. |
|
||||||
connectionTimeout | The URL Connection Timeout. |
|
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
|
Analyzer Configuration
|
||||||
====================
|
====================
|
||||||
@@ -46,30 +55,43 @@ Note, that specific analyzers will automatically disable themselves if no file
|
|||||||
types that they support are detected - so specifically disabling them may not
|
types that they support are detected - so specifically disabling them may not
|
||||||
be needed.
|
be needed.
|
||||||
|
|
||||||
Property | Description | Default Value
|
Property | Description | Default Value
|
||||||
------------------------|------------------------------------|------------------
|
------------------------------|-----------------------------------------------------------------------------------|------------------
|
||||||
archiveAnalyzerEnabled | Sets whether the Archive Analyzer will be used. | true
|
archiveAnalyzerEnabled | Sets whether the Archive Analyzer will be used. | true
|
||||||
zipExtensions | A comma-separated list of additional file extensions to be treated like a ZIP file, the contents will be extracted and analyzed. |
|
zipExtensions | A comma-separated list of additional file extensions to be treated like a ZIP file, the contents will be extracted and analyzed. |
|
||||||
jarAnalyzer | Sets whether Jar Analyzer will be used. | true
|
jarAnalyzer | Sets whether the Jar Analyzer will be used. | true
|
||||||
nexusAnalyzerEnabled | Sets whether Nexus Analyzer will be used. | true
|
centralAnalyzerEnabled | Sets whether the Central Analyzer will be used. **Disabling this analyzer is not recommended as it could lead to false negatives (e.g. libraries that have vulnerabilities may not be reported correctly).** If this analyzer is being disabled there is a good chance you also want to disable the Nexus Analyzer (see below). | true
|
||||||
nexusUrl | Defines the Nexus URL. | https://repository.sonatype.org/service/local/
|
nexusAnalyzerEnabled | Sets whether Nexus Analyzer will be used. This analyzer is superceded by the Central Analyzer; however, you can configure this to run against a Nexus Pro installation. | true
|
||||||
nexusUsesProxy | Whether or not the defined proxy should be used when connecting to Nexus. | true
|
nexusUrl | Defines the Nexus web service endpoint (example http://domain.enterprise/nexus/service/local/). If not set the Nexus Analyzer will be disabled. |
|
||||||
nuspecAnalyzerEnabled | Sets whether or not the .NET Nuget Nuspec Analyzer will be used. | true
|
nexusUsesProxy | Whether or not the defined proxy should be used when connecting to Nexus. | true
|
||||||
assemblyAnalyzerEnabled | Sets whether or not the .NET Assembly Analyzer should be used. | true
|
pyDistributionAnalyzerEnabled | Sets whether the [experimental](../analyzers/index.html) Python Distribution Analyzer will be used. | true
|
||||||
pathToMono | The path to Mono for .NET assembly analysis on non-windows systems |
|
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
|
||||||
|
cocoapodsAnalyzerEnabled | Sets whether the [experimental](../analyzers/index.html) Cocoapods Analyzer should be used. | true
|
||||||
|
bundleAuditAnalyzerEnabled | Sets whether the [experimental](../analyzers/index.html) Bundle Audit Analyzer should be used. | true
|
||||||
|
bundleAuditPath | Sets the path to the bundle audit executable; only used if bundle audit analyzer is enabled and experimental analyzers are enabled. |
|
||||||
|
swiftPackageManagerAnalyzerEnabled | Sets whether the [experimental](../analyzers/index.html) Switft Package Analyzer should 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
|
Advanced Configuration
|
||||||
====================
|
====================
|
||||||
The following properties can be configured in the plugin. However, they are less frequently changed. One exception
|
The following properties can be configured in the plugin. However, they are less frequently changed. One exception
|
||||||
may be the cvedUrl properties, which can be used to host a mirror of the NVD within an enterprise environment.
|
may be the cvedUrl properties, which can be used to host a mirror of the NVD within an enterprise environment.
|
||||||
|
|
||||||
Property | Description | Default Value
|
Property | Description | Default Value
|
||||||
---------------------|-------------------------------------------------------------------------|------------------
|
---------------------|--------------------------------------------------------------------------|------------------
|
||||||
cveUrl12Modified | URL for the modified CVE 1.2 | http://nvd.nist.gov/download/nvdcve-modified.xml
|
cveUrl12Modified | URL for the modified CVE 1.2. | http://nvd.nist.gov/download/nvdcve-modified.xml
|
||||||
cveUrl20Modified | URL for the modified CVE 2.0 | http://static.nvd.nist.gov/feeds/xml/cve/nvdcve-2.0-modified.xml
|
cveUrl20Modified | URL for the modified CVE 2.0. | http://static.nvd.nist.gov/feeds/xml/cve/nvdcve-2.0-modified.xml
|
||||||
cveUrl12Base | Base URL for each year's CVE 1.2, the %d will be replaced with the year | http://nvd.nist.gov/download/nvdcve-%d.xml
|
cveUrl12Base | Base URL for each year's CVE 1.2, the %d will be replaced with the year. | http://nvd.nist.gov/download/nvdcve-%d.xml
|
||||||
cveUrl20Base | Base URL for each year's CVE 2.0, the %d will be replaced with the year | http://static.nvd.nist.gov/feeds/xml/cve/nvdcve-2.0-%d.xml
|
cveUrl20Base | Base URL for each year's CVE 2.0, the %d will be replaced with the year. | http://static.nvd.nist.gov/feeds/xml/cve/nvdcve-2.0-%d.xml
|
||||||
dataDirectory | Data directory to hold SQL CVEs contents. This should generally not be changed. |
|
dataDirectory | Data directory 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. |
|
databaseDriverName | The name of the database driver. Example: org.h2.Driver. |
|
||||||
databaseDriverPath | The path to the database driver JAR file; only used if the driver is not in the class path. |
|
databaseDriverPath | The path to the database driver JAR file; only used if the driver is not in the class path. |
|
||||||
connectionString | The connection string used to connect to the database. |
|
connectionString | The connection string used to connect to the database. |
|
||||||
|
|||||||
38
dependency-check-ant/src/site/markdown/index.md.vm
Normal file
38
dependency-check-ant/src/site/markdown/index.md.vm
Normal file
@@ -0,0 +1,38 @@
|
|||||||
|
About
|
||||||
|
====================
|
||||||
|
OWASP dependency-check-ant is an Ant Task that uses dependency-check-core to detect publicly
|
||||||
|
disclosed vulnerabilities associated with the project's dependencies. The task will
|
||||||
|
generate a report listing the dependency, any identified Common Platform Enumeration (CPE)
|
||||||
|
identifiers, and the associated Common Vulnerability and Exposure (CVE) entries.
|
||||||
|
|
||||||
|
Installation
|
||||||
|
====================
|
||||||
|
1. Download dependency-check-ant from [bintray here](http://dl.bintray.com/jeremy-long/owasp/dependency-check-ant-${project.version}-release.zip).
|
||||||
|
2. Unzip the archive
|
||||||
|
3. Add the taskdef to your build.xml:
|
||||||
|
|
||||||
|
```xml
|
||||||
|
<!-- Set the value to the installation directory's path -->
|
||||||
|
<property name="dependency-check.home" value="C:/tools/dependency-check-ant"/>
|
||||||
|
<path id="dependency-check.path">
|
||||||
|
<pathelement location="${dependency-check.home}/dependency-check-ant.jar"/>
|
||||||
|
<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.
|
||||||
|
|
||||||
|
|
||||||
|
It is important to understand that the first time this task is executed it may
|
||||||
|
take 10 minutes or more as it downloads and processes the data from the National
|
||||||
|
Vulnerability Database (NVD) hosted by NIST: https://nvd.nist.gov
|
||||||
|
|
||||||
|
After the first batch download, as long as the task is executed at least once every
|
||||||
|
seven days the update will only take a few seconds.
|
||||||
@@ -1,13 +0,0 @@
|
|||||||
Installation
|
|
||||||
====================
|
|
||||||
Download dependency-check-ant from [bintray here](http://dl.bintray.com/jeremy-long/owasp/dependency-check-ant-${project.version}.jar).
|
|
||||||
To install dependency-check-ant place the dependency-check-ant-${project.version}.jar into
|
|
||||||
the lib directory of your Ant instalation directory. Once installed you can add
|
|
||||||
the taskdef to you build.xml and add the task to a new or existing target.
|
|
||||||
|
|
||||||
It is important to understand that the first time this task is executed it may
|
|
||||||
take 20 minutes or more as it downloads and processes the data from the National
|
|
||||||
Vulnerability Database (NVD) hosted by NIST: https://nvd.nist.gov
|
|
||||||
|
|
||||||
After the first batch download, as long as the task is executed at least once every
|
|
||||||
seven days the update will only take a few seconds.
|
|
||||||
@@ -1,25 +0,0 @@
|
|||||||
Usage
|
|
||||||
====================
|
|
||||||
First, add the dependency-check-ant taskdef to your build.xml:
|
|
||||||
|
|
||||||
```xml
|
|
||||||
<taskdef name="dependency-check" classname="org.owasp.dependencycheck.taskdefs.DependencyCheckTask"/>
|
|
||||||
```
|
|
||||||
|
|
||||||
Next, add the task to a target of your choosing:
|
|
||||||
|
|
||||||
```xml
|
|
||||||
<target name="dependency-check" description="Dependency-Check Analysis">
|
|
||||||
<dependency-check applicationname="Hello World"
|
|
||||||
autoupdate="true"
|
|
||||||
reportoutputdirectory="${basedir}"
|
|
||||||
reportformat="HTML">
|
|
||||||
|
|
||||||
<fileset dir="lib">
|
|
||||||
<include name="**/*.jar"/>
|
|
||||||
</fileset>
|
|
||||||
</dependency-check>
|
|
||||||
</target>
|
|
||||||
```
|
|
||||||
|
|
||||||
See the [configuration guide](configuration.html) for more information.
|
|
||||||
File diff suppressed because one or more lines are too long
|
After Width: | Height: | Size: 10 KiB |
@@ -18,18 +18,18 @@ Copyright (c) 2013 Jeremy Long. All Rights Reserved.
|
|||||||
-->
|
-->
|
||||||
<project name="dependency-check-ant">
|
<project name="dependency-check-ant">
|
||||||
<bannerLeft>
|
<bannerLeft>
|
||||||
<name>dependency-check-ant</name>
|
<name>OWASP dependency-check-ant</name>
|
||||||
|
<alt>OWASP dependency-check-ant</alt>
|
||||||
|
<src>./images/dc-ant.svg</src>
|
||||||
</bannerLeft>
|
</bannerLeft>
|
||||||
<body>
|
<body>
|
||||||
<breadcrumbs>
|
<breadcrumbs>
|
||||||
<item name="dependency-check" href="../index.html"/>
|
<item name="dependency-check" href="../index.html"/>
|
||||||
</breadcrumbs>
|
</breadcrumbs>
|
||||||
<menu name="Getting Started">
|
<menu name="Getting Started">
|
||||||
<item name="Installation" href="installation.html"/>
|
<item name="Installation" href="index.html"/>
|
||||||
<item name="Usage" href="usage.html"/>
|
|
||||||
<item name="Configuration" href="configuration.html"/>
|
<item name="Configuration" href="configuration.html"/>
|
||||||
</menu>
|
</menu>
|
||||||
<menu ref="Project Documentation" />
|
|
||||||
<menu ref="reports" />
|
<menu ref="reports" />
|
||||||
</body>
|
</body>
|
||||||
</project>
|
</project>
|
||||||
@@ -18,30 +18,40 @@
|
|||||||
package org.owasp.dependencycheck.taskdefs;
|
package org.owasp.dependencycheck.taskdefs;
|
||||||
|
|
||||||
import java.io.File;
|
import java.io.File;
|
||||||
import org.apache.tools.ant.BuildFileTest;
|
|
||||||
|
import org.apache.tools.ant.BuildException;
|
||||||
|
import org.apache.tools.ant.BuildFileRule;
|
||||||
import org.junit.After;
|
import org.junit.After;
|
||||||
import org.junit.Before;
|
import org.junit.Before;
|
||||||
|
import org.junit.Rule;
|
||||||
import org.junit.Test;
|
import org.junit.Test;
|
||||||
import org.owasp.dependencycheck.data.nvdcve.BaseDBTestCase;
|
import org.junit.rules.ExpectedException;
|
||||||
|
import org.owasp.dependencycheck.BaseDBTestCase;
|
||||||
import org.owasp.dependencycheck.utils.Settings;
|
import org.owasp.dependencycheck.utils.Settings;
|
||||||
|
|
||||||
|
import static org.junit.Assert.assertTrue;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
*
|
*
|
||||||
* @author Jeremy Long <jeremy.long@owasp.org>
|
* @author Jeremy Long
|
||||||
*/
|
*/
|
||||||
public class DependencyCheckTaskTest extends BuildFileTest {
|
public class DependencyCheckTaskTest {
|
||||||
|
|
||||||
|
@Rule
|
||||||
|
public BuildFileRule buildFileRule = new BuildFileRule();
|
||||||
|
|
||||||
|
@Rule
|
||||||
|
public ExpectedException expectedException = ExpectedException.none();
|
||||||
|
|
||||||
@Before
|
@Before
|
||||||
@Override
|
|
||||||
public void setUp() throws Exception {
|
public void setUp() throws Exception {
|
||||||
Settings.initialize();
|
Settings.initialize();
|
||||||
BaseDBTestCase.ensureDBExists();
|
BaseDBTestCase.ensureDBExists();
|
||||||
final String buildFile = this.getClass().getClassLoader().getResource("build.xml").getPath();
|
final String buildFile = this.getClass().getClassLoader().getResource("build.xml").getPath();
|
||||||
configureProject(buildFile);
|
buildFileRule.configureProject(buildFile);
|
||||||
}
|
}
|
||||||
|
|
||||||
@After
|
@After
|
||||||
@Override
|
|
||||||
public void tearDown() {
|
public void tearDown() {
|
||||||
//no cleanup...
|
//no cleanup...
|
||||||
//executeTarget("cleanup");
|
//executeTarget("cleanup");
|
||||||
@@ -54,15 +64,11 @@ public class DependencyCheckTaskTest extends BuildFileTest {
|
|||||||
@Test
|
@Test
|
||||||
public void testAddFileSet() throws Exception {
|
public void testAddFileSet() throws Exception {
|
||||||
File report = new File("target/dependency-check-report.html");
|
File report = new File("target/dependency-check-report.html");
|
||||||
if (report.exists()) {
|
if (report.exists() && !report.delete()) {
|
||||||
if (!report.delete()) {
|
throw new Exception("Unable to delete 'target/DependencyCheck-Report.html' prior to test.");
|
||||||
throw new Exception("Unable to delete 'target/DependencyCheck-Report.html' prior to test.");
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
executeTarget("test.fileset");
|
buildFileRule.executeTarget("test.fileset");
|
||||||
|
|
||||||
assertTrue("DependencyCheck report was not generated", report.exists());
|
assertTrue("DependencyCheck report was not generated", report.exists());
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -78,7 +84,7 @@ public class DependencyCheckTaskTest extends BuildFileTest {
|
|||||||
throw new Exception("Unable to delete 'target/DependencyCheck-Report.xml' prior to test.");
|
throw new Exception("Unable to delete 'target/DependencyCheck-Report.xml' prior to test.");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
executeTarget("test.filelist");
|
buildFileRule.executeTarget("test.filelist");
|
||||||
|
|
||||||
assertTrue("DependencyCheck report was not generated", report.exists());
|
assertTrue("DependencyCheck report was not generated", report.exists());
|
||||||
}
|
}
|
||||||
@@ -96,7 +102,7 @@ public class DependencyCheckTaskTest extends BuildFileTest {
|
|||||||
throw new Exception("Unable to delete 'target/DependencyCheck-Vulnerability.html' prior to test.");
|
throw new Exception("Unable to delete 'target/DependencyCheck-Vulnerability.html' prior to test.");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
executeTarget("test.dirset");
|
buildFileRule.executeTarget("test.dirset");
|
||||||
assertTrue("DependencyCheck report was not generated", report.exists());
|
assertTrue("DependencyCheck report was not generated", report.exists());
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -105,7 +111,7 @@ public class DependencyCheckTaskTest extends BuildFileTest {
|
|||||||
*/
|
*/
|
||||||
@Test
|
@Test
|
||||||
public void testGetFailBuildOnCVSS() {
|
public void testGetFailBuildOnCVSS() {
|
||||||
expectBuildException("failCVSS", "asdfasdfscore");
|
expectedException.expect(BuildException.class);
|
||||||
System.out.println(this.getOutput());
|
buildFileRule.executeTarget("failCVSS");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
<?xml version="1.0" encoding="UTF-8"?>
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
<project name="Dependency-Check Test Build" default="test.fileset" basedir=".">
|
<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">
|
<target name="test.fileset">
|
||||||
<dependency-check
|
<dependency-check
|
||||||
@@ -61,11 +61,14 @@
|
|||||||
|
|
||||||
<target name="failCVSS">
|
<target name="failCVSS">
|
||||||
<dependency-check
|
<dependency-check
|
||||||
applicationName="test formatBAD"
|
applicationName="test failCVSS"
|
||||||
reportOutputDirectory="${project.build.directory}"
|
reportOutputDirectory="${project.build.directory}"
|
||||||
reportFormat="XML"
|
reportFormat="XML"
|
||||||
autoupdate="false"
|
autoupdate="false"
|
||||||
failBuildOnCVSS="8">
|
failBuildOnCVSS="3">
|
||||||
|
<fileset dir="${project.build.directory}/test-classes/jars">
|
||||||
|
<include name="axis-1.4.jar"/>
|
||||||
|
</fileset>
|
||||||
</dependency-check>
|
</dependency-check>
|
||||||
</target>
|
</target>
|
||||||
</project>
|
</project>
|
||||||
|
|||||||
@@ -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
|
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).
|
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
|
Mailing List
|
||||||
------------
|
------------
|
||||||
@@ -19,6 +19,6 @@ Copyright & License
|
|||||||
|
|
||||||
Dependency-Check is Copyright (c) 2012-2014 Jeremy Long. All Rights Reserved.
|
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.
|
||||||
|
|||||||
@@ -15,20 +15,19 @@ limitations under the License.
|
|||||||
|
|
||||||
Copyright (c) 2012 - Jeremy Long. All Rights Reserved.
|
Copyright (c) 2012 - Jeremy Long. All Rights Reserved.
|
||||||
-->
|
-->
|
||||||
|
|
||||||
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
|
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
|
||||||
<modelVersion>4.0.0</modelVersion>
|
<modelVersion>4.0.0</modelVersion>
|
||||||
<parent>
|
<parent>
|
||||||
<groupId>org.owasp</groupId>
|
<groupId>org.owasp</groupId>
|
||||||
<artifactId>dependency-check-parent</artifactId>
|
<artifactId>dependency-check-parent</artifactId>
|
||||||
<version>1.2.3</version>
|
<version>1.4.6-SNAPSHOT</version>
|
||||||
</parent>
|
</parent>
|
||||||
|
|
||||||
<artifactId>dependency-check-cli</artifactId>
|
<artifactId>dependency-check-cli</artifactId>
|
||||||
<packaging>jar</packaging>
|
<packaging>jar</packaging>
|
||||||
|
|
||||||
<name>Dependency-Check Command Line</name>
|
<name>Dependency-Check Command Line</name>
|
||||||
<description>Dependency-Check-Maven is a Maven Plugin that attempts to detect publicly disclosed vulnerabilities contained within project dependencies. It does this by determining if there is a Common Platform Enumeration (CPE) identifier for a given dependency. If found, it will generate a report linking to the associated CVE entries.</description>
|
<description>dependency-check-cli is an command line tool that uses dependency-check-core to detect publicly disclosed vulnerabilities associated with the scanned project dependencies. The tool will generate a report listing the dependency, any identified Common Platform Enumeration (CPE) identifiers, and the associated Common Vulnerability and Exposure (CVE) entries.</description>
|
||||||
<!-- begin copy from http://minds.coremedia.com/2012/09/11/problem-solved-deploy-multi-module-maven-project-site-as-github-pages/ -->
|
<!-- begin copy from http://minds.coremedia.com/2012/09/11/problem-solved-deploy-multi-module-maven-project-site-as-github-pages/ -->
|
||||||
<distributionManagement>
|
<distributionManagement>
|
||||||
<site>
|
<site>
|
||||||
@@ -45,6 +44,7 @@ Copyright (c) 2012 - Jeremy Long. All Rights Reserved.
|
|||||||
<directory>src/main/resources</directory>
|
<directory>src/main/resources</directory>
|
||||||
<includes>
|
<includes>
|
||||||
<include>**/*.properties</include>
|
<include>**/*.properties</include>
|
||||||
|
<include>logback.xml</include>
|
||||||
</includes>
|
</includes>
|
||||||
<filtering>true</filtering>
|
<filtering>true</filtering>
|
||||||
</resource>
|
</resource>
|
||||||
@@ -61,27 +61,21 @@ Copyright (c) 2012 - Jeremy Long. All Rights Reserved.
|
|||||||
<plugin>
|
<plugin>
|
||||||
<groupId>org.apache.maven.plugins</groupId>
|
<groupId>org.apache.maven.plugins</groupId>
|
||||||
<artifactId>maven-jar-plugin</artifactId>
|
<artifactId>maven-jar-plugin</artifactId>
|
||||||
<version>2.4</version>
|
|
||||||
<configuration>
|
<configuration>
|
||||||
<archive>
|
<archive>
|
||||||
<manifest>
|
<manifest>
|
||||||
<mainClass>org.owasp.dependencycheck.App</mainClass>
|
<mainClass>org.owasp.dependencycheck.App</mainClass>
|
||||||
<addDefaultImplementationEntries>true</addDefaultImplementationEntries>
|
|
||||||
</manifest>
|
</manifest>
|
||||||
</archive>
|
</archive>
|
||||||
<excludes>
|
|
||||||
<exclude>**/checkstyle*</exclude>
|
|
||||||
</excludes>
|
|
||||||
</configuration>
|
</configuration>
|
||||||
</plugin>
|
</plugin>
|
||||||
<plugin>
|
<plugin>
|
||||||
<groupId>org.codehaus.mojo</groupId>
|
<groupId>org.codehaus.mojo</groupId>
|
||||||
<artifactId>cobertura-maven-plugin</artifactId>
|
<artifactId>cobertura-maven-plugin</artifactId>
|
||||||
<version>2.6</version>
|
|
||||||
<configuration>
|
<configuration>
|
||||||
<instrumentation>
|
<!--instrumentation>
|
||||||
<ignoreTrivial>true</ignoreTrivial>
|
<ignoreTrivial>true</ignoreTrivial>
|
||||||
</instrumentation>
|
</instrumentation-->
|
||||||
<check>
|
<check>
|
||||||
<branchRate>85</branchRate>
|
<branchRate>85</branchRate>
|
||||||
<lineRate>85</lineRate>
|
<lineRate>85</lineRate>
|
||||||
@@ -115,8 +109,8 @@ Copyright (c) 2012 - Jeremy Long. All Rights Reserved.
|
|||||||
<plugin>
|
<plugin>
|
||||||
<groupId>org.apache.maven.plugins</groupId>
|
<groupId>org.apache.maven.plugins</groupId>
|
||||||
<artifactId>maven-surefire-plugin</artifactId>
|
<artifactId>maven-surefire-plugin</artifactId>
|
||||||
<version>2.16</version>
|
|
||||||
<configuration>
|
<configuration>
|
||||||
|
<argLine>-Dfile.encoding=UTF-8</argLine>
|
||||||
<systemProperties>
|
<systemProperties>
|
||||||
<property>
|
<property>
|
||||||
<name>cpe</name>
|
<name>cpe</name>
|
||||||
@@ -131,165 +125,14 @@ Copyright (c) 2012 - Jeremy Long. All Rights Reserved.
|
|||||||
</systemProperties>
|
</systemProperties>
|
||||||
</configuration>
|
</configuration>
|
||||||
</plugin>
|
</plugin>
|
||||||
<plugin>
|
|
||||||
<groupId>org.apache.maven.plugins</groupId>
|
|
||||||
<artifactId>maven-compiler-plugin</artifactId>
|
|
||||||
<version>3.1</version>
|
|
||||||
<configuration>
|
|
||||||
<showDeprecation>false</showDeprecation>
|
|
||||||
<source>1.6</source>
|
|
||||||
<target>1.6</target>
|
|
||||||
</configuration>
|
|
||||||
</plugin>
|
|
||||||
<plugin>
|
|
||||||
<groupId>org.apache.maven.plugins</groupId>
|
|
||||||
<artifactId>maven-site-plugin</artifactId>
|
|
||||||
<version>3.3</version>
|
|
||||||
<dependencies>
|
|
||||||
<dependency>
|
|
||||||
<groupId>org.apache.maven.doxia</groupId>
|
|
||||||
<artifactId>doxia-module-markdown</artifactId>
|
|
||||||
<version>1.5</version>
|
|
||||||
</dependency>
|
|
||||||
</dependencies>
|
|
||||||
<configuration>
|
|
||||||
<skipDeploy>true</skipDeploy>
|
|
||||||
<reportPlugins>
|
|
||||||
<plugin>
|
|
||||||
<groupId>org.apache.maven.plugins</groupId>
|
|
||||||
<artifactId>maven-project-info-reports-plugin</artifactId>
|
|
||||||
<version>2.7</version>
|
|
||||||
<reportSets>
|
|
||||||
<reportSet>
|
|
||||||
<reports>
|
|
||||||
<report>index</report>
|
|
||||||
<report>summary</report>
|
|
||||||
<report>license</report>
|
|
||||||
<report>help</report>
|
|
||||||
</reports>
|
|
||||||
</reportSet>
|
|
||||||
</reportSets>
|
|
||||||
</plugin>
|
|
||||||
<plugin>
|
|
||||||
<groupId>org.apache.maven.plugins</groupId>
|
|
||||||
<artifactId>maven-javadoc-plugin</artifactId>
|
|
||||||
<version>2.9.1</version>
|
|
||||||
<reportSets>
|
|
||||||
<reportSet>
|
|
||||||
<id>default</id>
|
|
||||||
<reports>
|
|
||||||
<report>javadoc</report>
|
|
||||||
</reports>
|
|
||||||
</reportSet>
|
|
||||||
</reportSets>
|
|
||||||
</plugin>
|
|
||||||
<plugin>
|
|
||||||
<groupId>org.codehaus.mojo</groupId>
|
|
||||||
<artifactId>versions-maven-plugin</artifactId>
|
|
||||||
<version>2.1</version>
|
|
||||||
<reportSets>
|
|
||||||
<reportSet>
|
|
||||||
<reports>
|
|
||||||
<report>dependency-updates-report</report>
|
|
||||||
<report>plugin-updates-report</report>
|
|
||||||
</reports>
|
|
||||||
</reportSet>
|
|
||||||
</reportSets>
|
|
||||||
</plugin>
|
|
||||||
<plugin>
|
|
||||||
<groupId>org.apache.maven.plugins</groupId>
|
|
||||||
<artifactId>maven-jxr-plugin</artifactId>
|
|
||||||
<version>2.4</version>
|
|
||||||
</plugin>
|
|
||||||
<plugin>
|
|
||||||
<groupId>org.codehaus.mojo</groupId>
|
|
||||||
<artifactId>cobertura-maven-plugin</artifactId>
|
|
||||||
<version>2.6</version>
|
|
||||||
</plugin>
|
|
||||||
<plugin>
|
|
||||||
<groupId>org.apache.maven.plugins</groupId>
|
|
||||||
<artifactId>maven-surefire-report-plugin</artifactId>
|
|
||||||
<version>2.16</version>
|
|
||||||
<reportSets>
|
|
||||||
<reportSet>
|
|
||||||
<reports>
|
|
||||||
<report>report-only</report>
|
|
||||||
</reports>
|
|
||||||
</reportSet>
|
|
||||||
</reportSets>
|
|
||||||
</plugin>
|
|
||||||
<plugin>
|
|
||||||
<groupId>org.codehaus.mojo</groupId>
|
|
||||||
<artifactId>taglist-maven-plugin</artifactId>
|
|
||||||
<version>2.4</version>
|
|
||||||
<configuration>
|
|
||||||
<tagListOptions>
|
|
||||||
<tagClasses>
|
|
||||||
<tagClass>
|
|
||||||
<displayName>Todo Work</displayName>
|
|
||||||
<tags>
|
|
||||||
<tag>
|
|
||||||
<matchString>todo</matchString>
|
|
||||||
<matchType>ignoreCase</matchType>
|
|
||||||
</tag>
|
|
||||||
<tag>
|
|
||||||
<matchString>FIXME</matchString>
|
|
||||||
<matchType>exact</matchType>
|
|
||||||
</tag>
|
|
||||||
</tags>
|
|
||||||
</tagClass>
|
|
||||||
</tagClasses>
|
|
||||||
</tagListOptions>
|
|
||||||
</configuration>
|
|
||||||
</plugin>
|
|
||||||
<plugin>
|
|
||||||
<groupId>org.apache.maven.plugins</groupId>
|
|
||||||
<artifactId>maven-checkstyle-plugin</artifactId>
|
|
||||||
<version>2.11</version>
|
|
||||||
<configuration>
|
|
||||||
<enableRulesSummary>false</enableRulesSummary>
|
|
||||||
<configLocation>${basedir}/../src/main/config/checkstyle-checks.xml</configLocation>
|
|
||||||
<headerLocation>${basedir}/../src/main/config/checkstyle-header.txt</headerLocation>
|
|
||||||
<suppressionsLocation>${basedir}/../src/main/config/checkstyle-suppressions.xml</suppressionsLocation>
|
|
||||||
<suppressionsFileExpression>checkstyle.suppressions.file</suppressionsFileExpression>
|
|
||||||
</configuration>
|
|
||||||
</plugin>
|
|
||||||
<plugin>
|
|
||||||
<groupId>org.apache.maven.plugins</groupId>
|
|
||||||
<artifactId>maven-pmd-plugin</artifactId>
|
|
||||||
<version>3.1</version>
|
|
||||||
<configuration>
|
|
||||||
<targetJdk>1.6</targetJdk>
|
|
||||||
<linkXref>true</linkXref>
|
|
||||||
<sourceEncoding>utf-8</sourceEncoding>
|
|
||||||
<excludes>
|
|
||||||
<exclude>**/generated/*.java</exclude>
|
|
||||||
</excludes>
|
|
||||||
<rulesets>
|
|
||||||
<ruleset>../src/main/config/dcrules.xml</ruleset>
|
|
||||||
<ruleset>/rulesets/java/basic.xml</ruleset>
|
|
||||||
<ruleset>/rulesets/java/imports.xml</ruleset>
|
|
||||||
<ruleset>/rulesets/java/unusedcode.xml</ruleset>
|
|
||||||
</rulesets>
|
|
||||||
</configuration>
|
|
||||||
</plugin>
|
|
||||||
<plugin>
|
|
||||||
<groupId>org.codehaus.mojo</groupId>
|
|
||||||
<artifactId>findbugs-maven-plugin</artifactId>
|
|
||||||
<version>2.5.3</version>
|
|
||||||
</plugin>
|
|
||||||
</reportPlugins>
|
|
||||||
</configuration>
|
|
||||||
</plugin>
|
|
||||||
<plugin>
|
<plugin>
|
||||||
<groupId>org.codehaus.mojo</groupId>
|
<groupId>org.codehaus.mojo</groupId>
|
||||||
<artifactId>appassembler-maven-plugin</artifactId>
|
<artifactId>appassembler-maven-plugin</artifactId>
|
||||||
<version>1.7</version>
|
|
||||||
<configuration>
|
<configuration>
|
||||||
<programs>
|
<programs>
|
||||||
<program>
|
<program>
|
||||||
<mainClass>org.owasp.dependencycheck.App</mainClass>
|
<mainClass>org.owasp.dependencycheck.App</mainClass>
|
||||||
<name>dependency-check</name>
|
<id>dependency-check</id>
|
||||||
</program>
|
</program>
|
||||||
</programs>
|
</programs>
|
||||||
<assembleDirectory>${project.build.directory}/release</assembleDirectory>
|
<assembleDirectory>${project.build.directory}/release</assembleDirectory>
|
||||||
@@ -297,6 +140,8 @@ Copyright (c) 2012 - Jeremy Long. All Rights Reserved.
|
|||||||
<binFileExtensions>
|
<binFileExtensions>
|
||||||
<unix>.sh</unix>
|
<unix>.sh</unix>
|
||||||
</binFileExtensions>
|
</binFileExtensions>
|
||||||
|
<configurationDirectory>plugins/*</configurationDirectory>
|
||||||
|
<includeConfigurationDirectoryInClasspath>true</includeConfigurationDirectoryInClasspath>
|
||||||
</configuration>
|
</configuration>
|
||||||
<executions>
|
<executions>
|
||||||
<execution>
|
<execution>
|
||||||
@@ -330,11 +175,46 @@ Copyright (c) 2012 - Jeremy Long. All Rights Reserved.
|
|||||||
</plugin>
|
</plugin>
|
||||||
</plugins>
|
</plugins>
|
||||||
</build>
|
</build>
|
||||||
|
<reporting>
|
||||||
|
<plugins>
|
||||||
|
<plugin>
|
||||||
|
<groupId>org.apache.maven.plugins</groupId>
|
||||||
|
<artifactId>maven-checkstyle-plugin</artifactId>
|
||||||
|
<version>${reporting.checkstyle-plugin.version}</version>
|
||||||
|
<configuration>
|
||||||
|
<enableRulesSummary>false</enableRulesSummary>
|
||||||
|
<enableFilesSummary>false</enableFilesSummary>
|
||||||
|
<configLocation>${basedir}/../src/main/config/checkstyle-checks.xml</configLocation>
|
||||||
|
<headerLocation>${basedir}/../src/main/config/checkstyle-header.txt</headerLocation>
|
||||||
|
<suppressionsLocation>${basedir}/../src/main/config/checkstyle-suppressions.xml</suppressionsLocation>
|
||||||
|
<suppressionsFileExpression>checkstyle.suppressions.file</suppressionsFileExpression>
|
||||||
|
</configuration>
|
||||||
|
</plugin>
|
||||||
|
<plugin>
|
||||||
|
<groupId>org.apache.maven.plugins</groupId>
|
||||||
|
<artifactId>maven-pmd-plugin</artifactId>
|
||||||
|
<version>${reporting.pmd-plugin.version}</version>
|
||||||
|
<configuration>
|
||||||
|
<targetJdk>1.6</targetJdk>
|
||||||
|
<linkXRef>true</linkXRef>
|
||||||
|
<sourceEncoding>utf-8</sourceEncoding>
|
||||||
|
<excludes>
|
||||||
|
<exclude>**/generated/*.java</exclude>
|
||||||
|
</excludes>
|
||||||
|
<rulesets>
|
||||||
|
<ruleset>../src/main/config/dcrules.xml</ruleset>
|
||||||
|
<ruleset>/rulesets/java/basic.xml</ruleset>
|
||||||
|
<ruleset>/rulesets/java/imports.xml</ruleset>
|
||||||
|
<ruleset>/rulesets/java/unusedcode.xml</ruleset>
|
||||||
|
</rulesets>
|
||||||
|
</configuration>
|
||||||
|
</plugin>
|
||||||
|
</plugins>
|
||||||
|
</reporting>
|
||||||
<dependencies>
|
<dependencies>
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>commons-cli</groupId>
|
<groupId>commons-cli</groupId>
|
||||||
<artifactId>commons-cli</artifactId>
|
<artifactId>commons-cli</artifactId>
|
||||||
<version>1.2</version>
|
|
||||||
</dependency>
|
</dependency>
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>org.owasp</groupId>
|
<groupId>org.owasp</groupId>
|
||||||
@@ -346,5 +226,27 @@ Copyright (c) 2012 - Jeremy Long. All Rights Reserved.
|
|||||||
<artifactId>dependency-check-utils</artifactId>
|
<artifactId>dependency-check-utils</artifactId>
|
||||||
<version>${project.parent.version}</version>
|
<version>${project.parent.version}</version>
|
||||||
</dependency>
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.slf4j</groupId>
|
||||||
|
<artifactId>slf4j-api</artifactId>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>ch.qos.logback</groupId>
|
||||||
|
<artifactId>logback-core</artifactId>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>ch.qos.logback</groupId>
|
||||||
|
<artifactId>logback-classic</artifactId>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.apache.ant</groupId>
|
||||||
|
<artifactId>ant</artifactId>
|
||||||
|
<exclusions>
|
||||||
|
<exclusion>
|
||||||
|
<groupId>org.apache.ant</groupId>
|
||||||
|
<artifactId>ant-launcher</artifactId>
|
||||||
|
</exclusion>
|
||||||
|
</exclusions>
|
||||||
|
</dependency>
|
||||||
</dependencies>
|
</dependencies>
|
||||||
</project>
|
</project>
|
||||||
|
|||||||
@@ -2,11 +2,8 @@
|
|||||||
<assembly
|
<assembly
|
||||||
xmlns="http://maven.apache.org/plugins/maven-assembly-plugin/assembly/1.1.2"
|
xmlns="http://maven.apache.org/plugins/maven-assembly-plugin/assembly/1.1.2"
|
||||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||||
xsi:schemaLocation="
|
xsi:schemaLocation="http://maven.apache.org/plugins/maven-assembly-plugin/assembly/1.1.2
|
||||||
http://maven.apache.org/plugins/maven-assembly-plugin/assembly/1.1.2
|
http://maven.apache.org/xsd/assembly-1.1.2.xsd">
|
||||||
http://maven.apache.org/xsd/assembly-1.1.2.xsd
|
|
||||||
"
|
|
||||||
>
|
|
||||||
<id>release</id>
|
<id>release</id>
|
||||||
<formats>
|
<formats>
|
||||||
<format>zip</format>
|
<format>zip</format>
|
||||||
@@ -14,25 +11,48 @@
|
|||||||
<includeBaseDirectory>false</includeBaseDirectory>
|
<includeBaseDirectory>false</includeBaseDirectory>
|
||||||
<fileSets>
|
<fileSets>
|
||||||
<fileSet>
|
<fileSet>
|
||||||
<outputDirectory>/</outputDirectory>
|
<outputDirectory>dependency-check/bin</outputDirectory>
|
||||||
<directory>${project.build.directory}/release</directory>
|
<directory>${project.build.directory}/release/bin</directory>
|
||||||
|
<includes>
|
||||||
|
<include>*.sh</include>
|
||||||
|
</includes>
|
||||||
|
<fileMode>0755</fileMode>
|
||||||
</fileSet>
|
</fileSet>
|
||||||
<fileSet>
|
<fileSet>
|
||||||
|
<outputDirectory>dependency-check/bin</outputDirectory>
|
||||||
|
<directory>${project.build.directory}/release/bin</directory>
|
||||||
|
<includes>
|
||||||
|
<include>*.bat</include>
|
||||||
|
</includes>
|
||||||
|
</fileSet>
|
||||||
|
<fileSet>
|
||||||
|
<outputDirectory>dependency-check/repo</outputDirectory>
|
||||||
|
<directory>${project.build.directory}/release/repo</directory>
|
||||||
|
</fileSet>
|
||||||
|
<fileSet>
|
||||||
|
<directory>.</directory>
|
||||||
|
<outputDirectory>dependency-check/plugins</outputDirectory>
|
||||||
|
<excludes>
|
||||||
|
<exclude>*/**</exclude>
|
||||||
|
</excludes>
|
||||||
|
</fileSet>
|
||||||
|
<fileSet>
|
||||||
|
<outputDirectory>dependency-check</outputDirectory>
|
||||||
<includes>
|
<includes>
|
||||||
<include>LICENSE*</include>
|
<include>LICENSE*</include>
|
||||||
<include>NOTICE*</include>
|
<include>NOTICE*</include>
|
||||||
</includes>
|
</includes>
|
||||||
</fileSet>
|
</fileSet>
|
||||||
<fileSet>
|
<fileSet>
|
||||||
<outputDirectory>licenses</outputDirectory>
|
<outputDirectory>dependency-check/licenses</outputDirectory>
|
||||||
<directory>${basedir}/src/main/resources/META-INF/licenses</directory>
|
<directory>${basedir}/src/main/resources/META-INF/licenses</directory>
|
||||||
</fileSet>
|
</fileSet>
|
||||||
<fileSet>
|
<fileSet>
|
||||||
<outputDirectory>licenses</outputDirectory>
|
<outputDirectory>dependency-check/licenses</outputDirectory>
|
||||||
<directory>${basedir}/../dependency-check-core/src/main/resources/META-INF/licenses</directory>
|
<directory>${basedir}/../dependency-check-core/src/main/resources/META-INF/licenses</directory>
|
||||||
</fileSet>
|
</fileSet>
|
||||||
<fileSet>
|
<fileSet>
|
||||||
<outputDirectory>/</outputDirectory>
|
<outputDirectory>dependency-check</outputDirectory>
|
||||||
<directory>${basedir}</directory>
|
<directory>${basedir}</directory>
|
||||||
<includes>
|
<includes>
|
||||||
<include>README.md</include>
|
<include>README.md</include>
|
||||||
@@ -40,21 +60,4 @@
|
|||||||
</includes>
|
</includes>
|
||||||
</fileSet>
|
</fileSet>
|
||||||
</fileSets>
|
</fileSets>
|
||||||
<!--
|
|
||||||
<fileSets>
|
|
||||||
<fileSet>
|
|
||||||
<outputDirectory>/</outputDirectory>
|
|
||||||
<directory>${project.build.directory}</directory>
|
|
||||||
<includes>
|
|
||||||
<include>dependency-check*.jar</include>
|
|
||||||
</includes>
|
|
||||||
</fileSet>
|
|
||||||
</fileSets>
|
|
||||||
<dependencySets>
|
|
||||||
<dependencySet>
|
|
||||||
<outputDirectory>/lib</outputDirectory>
|
|
||||||
<scope>runtime</scope>
|
|
||||||
</dependencySet>
|
|
||||||
</dependencySets>
|
|
||||||
-->
|
|
||||||
</assembly>
|
</assembly>
|
||||||
@@ -17,39 +17,45 @@
|
|||||||
*/
|
*/
|
||||||
package org.owasp.dependencycheck;
|
package org.owasp.dependencycheck;
|
||||||
|
|
||||||
|
import ch.qos.logback.classic.LoggerContext;
|
||||||
|
import ch.qos.logback.classic.encoder.PatternLayoutEncoder;
|
||||||
|
import ch.qos.logback.classic.spi.ILoggingEvent;
|
||||||
import java.io.File;
|
import java.io.File;
|
||||||
import java.io.FileNotFoundException;
|
import java.io.FileNotFoundException;
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.io.InputStream;
|
import java.util.ArrayList;
|
||||||
|
import java.util.HashSet;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.logging.Level;
|
import java.util.Set;
|
||||||
import java.util.logging.Logger;
|
|
||||||
import org.apache.commons.cli.ParseException;
|
import org.apache.commons.cli.ParseException;
|
||||||
import org.owasp.dependencycheck.cli.CliParser;
|
|
||||||
import org.owasp.dependencycheck.data.nvdcve.CveDB;
|
import org.owasp.dependencycheck.data.nvdcve.CveDB;
|
||||||
import org.owasp.dependencycheck.data.nvdcve.DatabaseException;
|
import org.owasp.dependencycheck.data.nvdcve.DatabaseException;
|
||||||
import org.owasp.dependencycheck.data.nvdcve.DatabaseProperties;
|
import org.owasp.dependencycheck.data.nvdcve.DatabaseProperties;
|
||||||
import org.owasp.dependencycheck.dependency.Dependency;
|
import org.owasp.dependencycheck.dependency.Dependency;
|
||||||
|
import org.apache.tools.ant.DirectoryScanner;
|
||||||
|
import org.owasp.dependencycheck.dependency.Vulnerability;
|
||||||
import org.owasp.dependencycheck.reporting.ReportGenerator;
|
import org.owasp.dependencycheck.reporting.ReportGenerator;
|
||||||
import org.owasp.dependencycheck.utils.LogUtils;
|
|
||||||
import org.owasp.dependencycheck.utils.Settings;
|
import org.owasp.dependencycheck.utils.Settings;
|
||||||
|
import org.slf4j.Logger;
|
||||||
|
import org.slf4j.LoggerFactory;
|
||||||
|
import ch.qos.logback.core.FileAppender;
|
||||||
|
import org.owasp.dependencycheck.data.update.exception.UpdateException;
|
||||||
|
import org.owasp.dependencycheck.exception.ExceptionCollection;
|
||||||
|
import org.owasp.dependencycheck.exception.ReportException;
|
||||||
|
import org.owasp.dependencycheck.utils.InvalidSettingException;
|
||||||
|
import org.slf4j.impl.StaticLoggerBinder;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The command line interface for the DependencyCheck application.
|
* The command line interface for the DependencyCheck application.
|
||||||
*
|
*
|
||||||
* @author Jeremy Long <jeremy.long@owasp.org>
|
* @author Jeremy Long
|
||||||
*/
|
*/
|
||||||
public class App {
|
public class App {
|
||||||
|
|
||||||
/**
|
|
||||||
* The location of the log properties configuration file.
|
|
||||||
*/
|
|
||||||
private static final String LOG_PROPERTIES_FILE = "log.properties";
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The logger.
|
* The logger.
|
||||||
*/
|
*/
|
||||||
private static final Logger LOGGER = Logger.getLogger(App.class.getName());
|
private static final Logger LOGGER = LoggerFactory.getLogger(App.class);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The main method for the application.
|
* The main method for the application.
|
||||||
@@ -57,21 +63,26 @@ public class App {
|
|||||||
* @param args the command line arguments
|
* @param args the command line arguments
|
||||||
*/
|
*/
|
||||||
public static void main(String[] args) {
|
public static void main(String[] args) {
|
||||||
|
int exitCode = 0;
|
||||||
try {
|
try {
|
||||||
Settings.initialize();
|
Settings.initialize();
|
||||||
final App app = new App();
|
final App app = new App();
|
||||||
app.run(args);
|
exitCode = app.run(args);
|
||||||
|
LOGGER.debug("Exit code: " + exitCode);
|
||||||
} finally {
|
} finally {
|
||||||
Settings.cleanup(true);
|
Settings.cleanup(true);
|
||||||
}
|
}
|
||||||
|
System.exit(exitCode);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Main CLI entry-point into the application.
|
* Main CLI entry-point into the application.
|
||||||
*
|
*
|
||||||
* @param args the command line arguments
|
* @param args the command line arguments
|
||||||
|
* @return the exit code to return
|
||||||
*/
|
*/
|
||||||
public void run(String[] args) {
|
public int run(String[] args) {
|
||||||
|
int exitCode = 0;
|
||||||
final CliParser cli = new CliParser();
|
final CliParser cli = new CliParser();
|
||||||
|
|
||||||
try {
|
try {
|
||||||
@@ -79,74 +90,256 @@ public class App {
|
|||||||
} catch (FileNotFoundException ex) {
|
} catch (FileNotFoundException ex) {
|
||||||
System.err.println(ex.getMessage());
|
System.err.println(ex.getMessage());
|
||||||
cli.printHelp();
|
cli.printHelp();
|
||||||
return;
|
return -1;
|
||||||
} catch (ParseException ex) {
|
} catch (ParseException ex) {
|
||||||
System.err.println(ex.getMessage());
|
System.err.println(ex.getMessage());
|
||||||
cli.printHelp();
|
cli.printHelp();
|
||||||
return;
|
return -2;
|
||||||
}
|
}
|
||||||
|
|
||||||
final InputStream in = App.class.getClassLoader().getResourceAsStream(LOG_PROPERTIES_FILE);
|
if (cli.getVerboseLog() != null) {
|
||||||
LogUtils.prepareLogger(in, cli.getVerboseLog());
|
prepareLogger(cli.getVerboseLog());
|
||||||
|
}
|
||||||
|
|
||||||
if (cli.isGetVersion()) {
|
if (cli.isPurge()) {
|
||||||
|
if (cli.getConnectionString() != null) {
|
||||||
|
LOGGER.error("Unable to purge the database when using a non-default connection string");
|
||||||
|
exitCode = -3;
|
||||||
|
} else {
|
||||||
|
try {
|
||||||
|
populateSettings(cli);
|
||||||
|
} catch (InvalidSettingException ex) {
|
||||||
|
LOGGER.error(ex.getMessage());
|
||||||
|
LOGGER.debug("Error loading properties file", ex);
|
||||||
|
exitCode = -4;
|
||||||
|
}
|
||||||
|
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());
|
||||||
|
exitCode = -5;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
LOGGER.error("Unable to purge database; the database file does not exists: {}", db.getAbsolutePath());
|
||||||
|
exitCode = -6;
|
||||||
|
}
|
||||||
|
} catch (IOException ex) {
|
||||||
|
LOGGER.error("Unable to delete the database");
|
||||||
|
exitCode = -7;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else if (cli.isGetVersion()) {
|
||||||
cli.printVersionInfo();
|
cli.printVersionInfo();
|
||||||
|
} else if (cli.isUpdateOnly()) {
|
||||||
|
try {
|
||||||
|
populateSettings(cli);
|
||||||
|
} catch (InvalidSettingException ex) {
|
||||||
|
LOGGER.error(ex.getMessage());
|
||||||
|
LOGGER.debug("Error loading properties file", ex);
|
||||||
|
exitCode = -4;
|
||||||
|
}
|
||||||
|
try {
|
||||||
|
runUpdateOnly();
|
||||||
|
} catch (UpdateException ex) {
|
||||||
|
LOGGER.error(ex.getMessage());
|
||||||
|
exitCode = -8;
|
||||||
|
} catch (DatabaseException ex) {
|
||||||
|
LOGGER.error(ex.getMessage());
|
||||||
|
exitCode = -9;
|
||||||
|
}
|
||||||
} else if (cli.isRunScan()) {
|
} else if (cli.isRunScan()) {
|
||||||
populateSettings(cli);
|
try {
|
||||||
runScan(cli.getReportDirectory(), cli.getReportFormat(), cli.getApplicationName(), cli.getScanFiles());
|
populateSettings(cli);
|
||||||
|
} catch (InvalidSettingException ex) {
|
||||||
|
LOGGER.error(ex.getMessage());
|
||||||
|
LOGGER.debug("Error loading properties file", ex);
|
||||||
|
exitCode = -4;
|
||||||
|
}
|
||||||
|
try {
|
||||||
|
final String[] scanFiles = cli.getScanFiles();
|
||||||
|
if (scanFiles != null) {
|
||||||
|
exitCode = runScan(cli.getReportDirectory(), cli.getReportFormat(), cli.getProjectName(), scanFiles,
|
||||||
|
cli.getExcludeList(), cli.getSymLinkDepth(), cli.getFailOnCVSS());
|
||||||
|
} else {
|
||||||
|
LOGGER.error("No scan files configured");
|
||||||
|
}
|
||||||
|
} catch (InvalidScanPathException ex) {
|
||||||
|
LOGGER.error("An invalid scan path was detected; unable to scan '//*' paths");
|
||||||
|
exitCode = -10;
|
||||||
|
} catch (DatabaseException ex) {
|
||||||
|
LOGGER.error(ex.getMessage());
|
||||||
|
exitCode = -11;
|
||||||
|
} catch (ReportException ex) {
|
||||||
|
LOGGER.error(ex.getMessage());
|
||||||
|
exitCode = -12;
|
||||||
|
} catch (ExceptionCollection ex) {
|
||||||
|
if (ex.isFatal()) {
|
||||||
|
exitCode = -13;
|
||||||
|
LOGGER.error("One or more fatal errors occurred");
|
||||||
|
} else {
|
||||||
|
exitCode = -14;
|
||||||
|
}
|
||||||
|
for (Throwable e : ex.getExceptions()) {
|
||||||
|
LOGGER.error(e.getMessage());
|
||||||
|
}
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
cli.printHelp();
|
cli.printHelp();
|
||||||
}
|
}
|
||||||
|
return exitCode;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Scans the specified directories and writes the dependency reports to the
|
||||||
|
* reportDirectory.
|
||||||
|
*
|
||||||
|
* @param reportDirectory the path to the directory where the reports will
|
||||||
|
* be written
|
||||||
|
* @param outputFormat the output format of the report
|
||||||
|
* @param applicationName the application name for the report
|
||||||
|
* @param files the files/directories to scan
|
||||||
|
* @param excludes the patterns for files/directories to exclude
|
||||||
|
* @param symLinkDepth the depth that symbolic links will be followed
|
||||||
|
* @param cvssFailScore the score to fail on if a vulnerability is found
|
||||||
|
* @return the exit code if there was an error
|
||||||
|
*
|
||||||
|
* @throws InvalidScanPathException thrown if the path to scan starts with
|
||||||
|
* "//"
|
||||||
|
* @throws ReportException thrown when the report cannot be generated
|
||||||
|
* @throws DatabaseException thrown when there is an error connecting to the
|
||||||
|
* database
|
||||||
|
* @throws ExceptionCollection thrown when an exception occurs during
|
||||||
|
* analysis; there may be multiple exceptions contained within the
|
||||||
|
* collection.
|
||||||
|
*/
|
||||||
|
private int runScan(String reportDirectory, String outputFormat, String applicationName, String[] files,
|
||||||
|
String[] excludes, int symLinkDepth, int cvssFailScore) throws InvalidScanPathException, DatabaseException,
|
||||||
|
ExceptionCollection, ReportException {
|
||||||
|
Engine engine = null;
|
||||||
|
int retCode = 0;
|
||||||
|
try {
|
||||||
|
engine = new Engine();
|
||||||
|
final List<String> antStylePaths = new ArrayList<>();
|
||||||
|
for (String file : files) {
|
||||||
|
final String antPath = ensureCanonicalPath(file);
|
||||||
|
antStylePaths.add(antPath);
|
||||||
|
}
|
||||||
|
|
||||||
|
final Set<File> paths = new HashSet<>();
|
||||||
|
for (String file : antStylePaths) {
|
||||||
|
LOGGER.debug("Scanning {}", file);
|
||||||
|
final DirectoryScanner scanner = new DirectoryScanner();
|
||||||
|
String include = file.replace('\\', '/');
|
||||||
|
File baseDir;
|
||||||
|
|
||||||
|
if (include.startsWith("//")) {
|
||||||
|
throw new InvalidScanPathException("Unable to scan paths specified by //");
|
||||||
|
} else {
|
||||||
|
final int pos = getLastFileSeparator(include);
|
||||||
|
final String tmpBase = include.substring(0, pos);
|
||||||
|
final String tmpInclude = include.substring(pos + 1);
|
||||||
|
if (tmpInclude.indexOf('*') >= 0 || tmpInclude.indexOf('?') >= 0
|
||||||
|
|| (new File(include)).isFile()) {
|
||||||
|
baseDir = new File(tmpBase);
|
||||||
|
include = tmpInclude;
|
||||||
|
} else {
|
||||||
|
baseDir = new File(tmpBase, tmpInclude);
|
||||||
|
include = "**/*";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
scanner.setBasedir(baseDir);
|
||||||
|
final String[] includes = {include};
|
||||||
|
scanner.setIncludes(includes);
|
||||||
|
scanner.setMaxLevelsOfSymlinks(symLinkDepth);
|
||||||
|
if (symLinkDepth <= 0) {
|
||||||
|
scanner.setFollowSymlinks(false);
|
||||||
|
}
|
||||||
|
if (excludes != null && excludes.length > 0) {
|
||||||
|
scanner.addExcludes(excludes);
|
||||||
|
}
|
||||||
|
scanner.scan();
|
||||||
|
if (scanner.getIncludedFilesCount() > 0) {
|
||||||
|
for (String s : scanner.getIncludedFiles()) {
|
||||||
|
final File f = new File(baseDir, s);
|
||||||
|
LOGGER.debug("Found file {}", f.toString());
|
||||||
|
paths.add(f);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
engine.scan(paths);
|
||||||
|
|
||||||
|
ExceptionCollection exCol = null;
|
||||||
|
try {
|
||||||
|
engine.analyzeDependencies();
|
||||||
|
} catch (ExceptionCollection ex) {
|
||||||
|
if (ex.isFatal()) {
|
||||||
|
throw ex;
|
||||||
|
}
|
||||||
|
exCol = ex;
|
||||||
|
}
|
||||||
|
final List<Dependency> dependencies = engine.getDependencies();
|
||||||
|
DatabaseProperties prop = null;
|
||||||
|
try (CveDB cve = CveDB.getInstance()) {
|
||||||
|
prop = cve.getDatabaseProperties();
|
||||||
|
} catch (DatabaseException ex) {
|
||||||
|
//TODO shouldn't this be a fatal exception
|
||||||
|
LOGGER.debug("Unable to retrieve DB Properties", ex);
|
||||||
|
}
|
||||||
|
final ReportGenerator report = new ReportGenerator(applicationName, dependencies, engine.getAnalyzers(), prop);
|
||||||
|
|
||||||
|
try {
|
||||||
|
report.generateReports(reportDirectory, outputFormat);
|
||||||
|
} catch (ReportException ex) {
|
||||||
|
if (exCol != null) {
|
||||||
|
exCol.addException(ex);
|
||||||
|
throw exCol;
|
||||||
|
} else {
|
||||||
|
throw ex;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (exCol != null && exCol.getExceptions().size() > 0) {
|
||||||
|
throw exCol;
|
||||||
|
}
|
||||||
|
|
||||||
|
//Set the exit code based on whether we found a high enough vulnerability
|
||||||
|
for (Dependency dep : dependencies) {
|
||||||
|
if (!dep.getVulnerabilities().isEmpty()) {
|
||||||
|
for (Vulnerability vuln : dep.getVulnerabilities()) {
|
||||||
|
LOGGER.debug("VULNERABILITY FOUND " + dep.getDisplayFileName());
|
||||||
|
if (vuln.getCvssScore() > cvssFailScore) {
|
||||||
|
retCode = 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return retCode;
|
||||||
|
} finally {
|
||||||
|
if (engine != null) {
|
||||||
|
engine.cleanup();
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Scans the specified directories and writes the dependency reports to the reportDirectory.
|
* Only executes the update phase of dependency-check.
|
||||||
*
|
*
|
||||||
* @param reportDirectory the path to the directory where the reports will be written
|
* @throws UpdateException thrown if there is an error updating
|
||||||
* @param outputFormat the output format of the report
|
* @throws DatabaseException thrown if a fatal error occurred and a
|
||||||
* @param applicationName the application name for the report
|
* connection to the database could not be established
|
||||||
* @param files the files/directories to scan
|
|
||||||
*/
|
*/
|
||||||
private void runScan(String reportDirectory, String outputFormat, String applicationName, String[] files) {
|
private void runUpdateOnly() throws UpdateException, DatabaseException {
|
||||||
Engine scanner = null;
|
Engine engine = null;
|
||||||
try {
|
try {
|
||||||
scanner = new Engine();
|
engine = new Engine();
|
||||||
|
engine.doUpdates();
|
||||||
for (String file : files) {
|
|
||||||
scanner.scan(file);
|
|
||||||
}
|
|
||||||
|
|
||||||
scanner.analyzeDependencies();
|
|
||||||
final List<Dependency> dependencies = scanner.getDependencies();
|
|
||||||
DatabaseProperties prop = null;
|
|
||||||
CveDB cve = null;
|
|
||||||
try {
|
|
||||||
cve = new CveDB();
|
|
||||||
cve.open();
|
|
||||||
prop = cve.getDatabaseProperties();
|
|
||||||
} catch (DatabaseException ex) {
|
|
||||||
LOGGER.log(Level.FINE, "Unable to retrieve DB Properties", ex);
|
|
||||||
} finally {
|
|
||||||
if (cve != null) {
|
|
||||||
cve.close();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
final ReportGenerator report = new ReportGenerator(applicationName, dependencies, scanner.getAnalyzers(), prop);
|
|
||||||
try {
|
|
||||||
report.generateReports(reportDirectory, outputFormat);
|
|
||||||
} catch (IOException ex) {
|
|
||||||
LOGGER.log(Level.SEVERE, "There was an IO error while attempting to generate the report.");
|
|
||||||
LOGGER.log(Level.FINE, null, ex);
|
|
||||||
} catch (Throwable ex) {
|
|
||||||
LOGGER.log(Level.SEVERE, "There was an error while attempting to generate the report.");
|
|
||||||
LOGGER.log(Level.FINE, null, ex);
|
|
||||||
}
|
|
||||||
} catch (DatabaseException ex) {
|
|
||||||
LOGGER.log(Level.SEVERE, "Unable to connect to the dependency-check database; analysis has stopped");
|
|
||||||
LOGGER.log(Level.FINE, "", ex);
|
|
||||||
} finally {
|
} finally {
|
||||||
if (scanner != null) {
|
if (engine != null) {
|
||||||
scanner.cleanup();
|
engine.cleanup();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -154,11 +347,13 @@ public class App {
|
|||||||
/**
|
/**
|
||||||
* Updates the global Settings.
|
* Updates the global Settings.
|
||||||
*
|
*
|
||||||
* @param cli a reference to the CLI Parser that contains the command line arguments used to set the corresponding
|
* @param cli a reference to the CLI Parser that contains the command line
|
||||||
* settings in the core engine.
|
* arguments used to set the corresponding settings in the core engine.
|
||||||
|
*
|
||||||
|
* @throws InvalidSettingException thrown when a user defined properties
|
||||||
|
* file is unable to be loaded.
|
||||||
*/
|
*/
|
||||||
private void populateSettings(CliParser cli) {
|
private void populateSettings(CliParser cli) throws InvalidSettingException {
|
||||||
|
|
||||||
final boolean autoUpdate = cli.isAutoUpdate();
|
final boolean autoUpdate = cli.isAutoUpdate();
|
||||||
final String connectionTimeout = cli.getConnectionTimeout();
|
final String connectionTimeout = cli.getConnectionTimeout();
|
||||||
final String proxyServer = cli.getProxyServer();
|
final String proxyServer = cli.getProxyServer();
|
||||||
@@ -168,11 +363,7 @@ public class App {
|
|||||||
final String dataDirectory = cli.getDataDirectory();
|
final String dataDirectory = cli.getDataDirectory();
|
||||||
final File propertiesFile = cli.getPropertiesFile();
|
final File propertiesFile = cli.getPropertiesFile();
|
||||||
final String suppressionFile = cli.getSuppressionFile();
|
final String suppressionFile = cli.getSuppressionFile();
|
||||||
final boolean jarDisabled = cli.isJarDisabled();
|
final String hintsFile = cli.getHintsFile();
|
||||||
final boolean archiveDisabled = cli.isArchiveDisabled();
|
|
||||||
final boolean assemblyDisabled = cli.isAssemblyDisabled();
|
|
||||||
final boolean nuspecDisabled = cli.isNuspecDisabled();
|
|
||||||
final boolean nexusDisabled = cli.isNexusDisabled();
|
|
||||||
final String nexusUrl = cli.getNexusUrl();
|
final String nexusUrl = cli.getNexusUrl();
|
||||||
final String databaseDriverName = cli.getDatabaseDriverName();
|
final String databaseDriverName = cli.getDatabaseDriverName();
|
||||||
final String databaseDriverPath = cli.getDatabaseDriverPath();
|
final String databaseDriverPath = cli.getDatabaseDriverPath();
|
||||||
@@ -181,18 +372,20 @@ public class App {
|
|||||||
final String databasePassword = cli.getDatabasePassword();
|
final String databasePassword = cli.getDatabasePassword();
|
||||||
final String additionalZipExtensions = cli.getAdditionalZipExtensions();
|
final String additionalZipExtensions = cli.getAdditionalZipExtensions();
|
||||||
final String pathToMono = cli.getPathToMono();
|
final String pathToMono = cli.getPathToMono();
|
||||||
|
final String cveMod12 = cli.getModifiedCve12Url();
|
||||||
|
final String cveMod20 = cli.getModifiedCve20Url();
|
||||||
|
final String cveBase12 = cli.getBaseCve12Url();
|
||||||
|
final String cveBase20 = cli.getBaseCve20Url();
|
||||||
|
final Integer cveValidForHours = cli.getCveValidForHours();
|
||||||
|
final boolean experimentalEnabled = cli.isExperimentalEnabled();
|
||||||
|
|
||||||
if (propertiesFile != null) {
|
if (propertiesFile != null) {
|
||||||
try {
|
try {
|
||||||
Settings.mergeProperties(propertiesFile);
|
Settings.mergeProperties(propertiesFile);
|
||||||
} catch (FileNotFoundException ex) {
|
} catch (FileNotFoundException ex) {
|
||||||
final String msg = String.format("Unable to load properties file '%s'", propertiesFile.getPath());
|
throw new InvalidSettingException("Unable to find properties file '" + propertiesFile.getPath() + "'", ex);
|
||||||
LOGGER.log(Level.SEVERE, msg);
|
|
||||||
LOGGER.log(Level.FINE, null, ex);
|
|
||||||
} catch (IOException ex) {
|
} catch (IOException ex) {
|
||||||
final String msg = String.format("Unable to find properties file '%s'", propertiesFile.getPath());
|
throw new InvalidSettingException("Error reading properties file '" + propertiesFile.getPath() + "'", ex);
|
||||||
LOGGER.log(Level.SEVERE, msg);
|
|
||||||
LOGGER.log(Level.FINE, null, ex);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// We have to wait until we've merged the properties before attempting to set whether we use
|
// We have to wait until we've merged the properties before attempting to set whether we use
|
||||||
@@ -212,56 +405,139 @@ public class App {
|
|||||||
Settings.setString(Settings.KEYS.DATA_DIRECTORY, dataDir.getAbsolutePath());
|
Settings.setString(Settings.KEYS.DATA_DIRECTORY, dataDir.getAbsolutePath());
|
||||||
}
|
}
|
||||||
Settings.setBoolean(Settings.KEYS.AUTO_UPDATE, autoUpdate);
|
Settings.setBoolean(Settings.KEYS.AUTO_UPDATE, autoUpdate);
|
||||||
if (proxyServer != null && !proxyServer.isEmpty()) {
|
Settings.setStringIfNotEmpty(Settings.KEYS.PROXY_SERVER, proxyServer);
|
||||||
Settings.setString(Settings.KEYS.PROXY_SERVER, proxyServer);
|
Settings.setStringIfNotEmpty(Settings.KEYS.PROXY_PORT, proxyPort);
|
||||||
}
|
Settings.setStringIfNotEmpty(Settings.KEYS.PROXY_USERNAME, proxyUser);
|
||||||
if (proxyPort != null && !proxyPort.isEmpty()) {
|
Settings.setStringIfNotEmpty(Settings.KEYS.PROXY_PASSWORD, proxyPass);
|
||||||
Settings.setString(Settings.KEYS.PROXY_PORT, proxyPort);
|
Settings.setStringIfNotEmpty(Settings.KEYS.CONNECTION_TIMEOUT, connectionTimeout);
|
||||||
}
|
Settings.setStringIfNotEmpty(Settings.KEYS.SUPPRESSION_FILE, suppressionFile);
|
||||||
if (proxyUser != null && !proxyUser.isEmpty()) {
|
Settings.setStringIfNotEmpty(Settings.KEYS.HINTS_FILE, hintsFile);
|
||||||
Settings.setString(Settings.KEYS.PROXY_USERNAME, proxyUser);
|
Settings.setIntIfNotNull(Settings.KEYS.CVE_CHECK_VALID_FOR_HOURS, cveValidForHours);
|
||||||
}
|
|
||||||
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);
|
|
||||||
}
|
|
||||||
|
|
||||||
//File Type Analyzer Settings
|
//File Type Analyzer Settings
|
||||||
Settings.setBoolean(Settings.KEYS.ANALYZER_JAR_ENABLED, !jarDisabled);
|
Settings.setBoolean(Settings.KEYS.ANALYZER_EXPERIMENTAL_ENABLED, experimentalEnabled);
|
||||||
Settings.setBoolean(Settings.KEYS.ANALYZER_ARCHIVE_ENABLED, !archiveDisabled);
|
Settings.setBoolean(Settings.KEYS.ANALYZER_JAR_ENABLED, !cli.isJarDisabled());
|
||||||
Settings.setBoolean(Settings.KEYS.ANALYZER_NUSPEC_ENABLED, !nuspecDisabled);
|
Settings.setBoolean(Settings.KEYS.ANALYZER_ARCHIVE_ENABLED, !cli.isArchiveDisabled());
|
||||||
Settings.setBoolean(Settings.KEYS.ANALYZER_ASSEMBLY_ENABLED, !assemblyDisabled);
|
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_SWIFT_PACKAGE_MANAGER_ENABLED, !cli.isSwiftPackageAnalyzerDisabled());
|
||||||
|
Settings.setBoolean(Settings.KEYS.ANALYZER_COCOAPODS_ENABLED, !cli.isCocoapodsAnalyzerDisabled());
|
||||||
|
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_NEXUS_ENABLED, !nexusDisabled);
|
Settings.setStringIfNotEmpty(Settings.KEYS.ANALYZER_BUNDLE_AUDIT_PATH, cli.getPathToBundleAudit());
|
||||||
if (nexusUrl != null && !nexusUrl.isEmpty()) {
|
Settings.setStringIfNotEmpty(Settings.KEYS.ANALYZER_NEXUS_URL, nexusUrl);
|
||||||
Settings.setString(Settings.KEYS.ANALYZER_NEXUS_URL, nexusUrl);
|
Settings.setBoolean(Settings.KEYS.ANALYZER_NEXUS_USES_PROXY, nexusUsesProxy);
|
||||||
|
Settings.setStringIfNotEmpty(Settings.KEYS.DB_DRIVER_NAME, databaseDriverName);
|
||||||
|
Settings.setStringIfNotEmpty(Settings.KEYS.DB_DRIVER_PATH, databaseDriverPath);
|
||||||
|
Settings.setStringIfNotEmpty(Settings.KEYS.DB_CONNECTION_STRING, connectionString);
|
||||||
|
Settings.setStringIfNotEmpty(Settings.KEYS.DB_USER, databaseUser);
|
||||||
|
Settings.setStringIfNotEmpty(Settings.KEYS.DB_PASSWORD, databasePassword);
|
||||||
|
Settings.setStringIfNotEmpty(Settings.KEYS.ADDITIONAL_ZIP_EXTENSIONS, additionalZipExtensions);
|
||||||
|
Settings.setStringIfNotEmpty(Settings.KEYS.ANALYZER_ASSEMBLY_MONO_PATH, pathToMono);
|
||||||
|
if (cveBase12 != null && !cveBase12.isEmpty()) {
|
||||||
|
Settings.setString(Settings.KEYS.CVE_SCHEMA_1_2, cveBase12);
|
||||||
|
Settings.setString(Settings.KEYS.CVE_SCHEMA_2_0, cveBase20);
|
||||||
|
Settings.setString(Settings.KEYS.CVE_MODIFIED_12_URL, cveMod12);
|
||||||
|
Settings.setString(Settings.KEYS.CVE_MODIFIED_20_URL, cveMod20);
|
||||||
}
|
}
|
||||||
Settings.setBoolean(Settings.KEYS.ANALYZER_NEXUS_PROXY, nexusUsesProxy);
|
}
|
||||||
if (databaseDriverName != null && !databaseDriverName.isEmpty()) {
|
|
||||||
Settings.setString(Settings.KEYS.DB_DRIVER_NAME, databaseDriverName);
|
/**
|
||||||
|
* Creates a file appender and adds it to logback.
|
||||||
|
*
|
||||||
|
* @param verboseLog the path to the verbose log file
|
||||||
|
*/
|
||||||
|
private void prepareLogger(String verboseLog) {
|
||||||
|
final StaticLoggerBinder loggerBinder = StaticLoggerBinder.getSingleton();
|
||||||
|
final LoggerContext context = (LoggerContext) loggerBinder.getLoggerFactory();
|
||||||
|
|
||||||
|
final PatternLayoutEncoder encoder = new PatternLayoutEncoder();
|
||||||
|
encoder.setPattern("%d %C:%L%n%-5level - %msg%n");
|
||||||
|
encoder.setContext(context);
|
||||||
|
encoder.start();
|
||||||
|
final FileAppender<ILoggingEvent> fa = new FileAppender<>();
|
||||||
|
fa.setAppend(true);
|
||||||
|
fa.setEncoder(encoder);
|
||||||
|
fa.setContext(context);
|
||||||
|
fa.setFile(verboseLog);
|
||||||
|
final File f = new File(verboseLog);
|
||||||
|
String name = f.getName();
|
||||||
|
final int i = name.lastIndexOf('.');
|
||||||
|
if (i > 1) {
|
||||||
|
name = name.substring(0, i);
|
||||||
}
|
}
|
||||||
if (databaseDriverPath != null && !databaseDriverPath.isEmpty()) {
|
fa.setName(name);
|
||||||
Settings.setString(Settings.KEYS.DB_DRIVER_PATH, databaseDriverPath);
|
fa.start();
|
||||||
|
final ch.qos.logback.classic.Logger rootLogger = context.getLogger(ch.qos.logback.classic.Logger.ROOT_LOGGER_NAME);
|
||||||
|
rootLogger.addAppender(fa);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Takes a path and resolves it to be a canonical & absolute path. The
|
||||||
|
* caveats are that this method will take an Ant style file selector path
|
||||||
|
* (../someDir/**\/*.jar) and convert it to an absolute/canonical path (at
|
||||||
|
* least to the left of the first * or ?).
|
||||||
|
*
|
||||||
|
* @param path the path to canonicalize
|
||||||
|
* @return the canonical path
|
||||||
|
*/
|
||||||
|
protected String ensureCanonicalPath(String path) {
|
||||||
|
String basePath;
|
||||||
|
String wildCards = null;
|
||||||
|
final String file = path.replace('\\', '/');
|
||||||
|
if (file.contains("*") || file.contains("?")) {
|
||||||
|
|
||||||
|
int pos = getLastFileSeparator(file);
|
||||||
|
if (pos < 0) {
|
||||||
|
return file;
|
||||||
|
}
|
||||||
|
pos += 1;
|
||||||
|
basePath = file.substring(0, pos);
|
||||||
|
wildCards = file.substring(pos);
|
||||||
|
} else {
|
||||||
|
basePath = file;
|
||||||
}
|
}
|
||||||
if (connectionString != null && !connectionString.isEmpty()) {
|
|
||||||
Settings.setString(Settings.KEYS.DB_CONNECTION_STRING, connectionString);
|
File f = new File(basePath);
|
||||||
|
try {
|
||||||
|
f = f.getCanonicalFile();
|
||||||
|
if (wildCards != null) {
|
||||||
|
f = new File(f, wildCards);
|
||||||
|
}
|
||||||
|
} catch (IOException ex) {
|
||||||
|
LOGGER.warn("Invalid path '{}' was provided.", path);
|
||||||
|
LOGGER.debug("Invalid path provided", ex);
|
||||||
}
|
}
|
||||||
if (databaseUser != null && !databaseUser.isEmpty()) {
|
return f.getAbsolutePath().replace('\\', '/');
|
||||||
Settings.setString(Settings.KEYS.DB_USER, databaseUser);
|
}
|
||||||
}
|
|
||||||
if (databasePassword != null && !databasePassword.isEmpty()) {
|
/**
|
||||||
Settings.setString(Settings.KEYS.DB_PASSWORD, databasePassword);
|
* Returns the position of the last file separator.
|
||||||
}
|
*
|
||||||
if (additionalZipExtensions != null && !additionalZipExtensions.isEmpty()) {
|
* @param file a file path
|
||||||
Settings.setString(Settings.KEYS.ADDITIONAL_ZIP_EXTENSIONS, additionalZipExtensions);
|
* @return the position of the last file separator
|
||||||
}
|
*/
|
||||||
if (pathToMono != null && !pathToMono.isEmpty()) {
|
private int getLastFileSeparator(String file) {
|
||||||
Settings.setString(Settings.KEYS.ANALYZER_ASSEMBLY_MONO_PATH, pathToMono);
|
if (file.contains("*") || file.contains("?")) {
|
||||||
|
int p1 = file.indexOf('*');
|
||||||
|
int p2 = file.indexOf('?');
|
||||||
|
p1 = p1 > 0 ? p1 : file.length();
|
||||||
|
p2 = p2 > 0 ? p2 : file.length();
|
||||||
|
int pos = p1 < p2 ? p1 : p2;
|
||||||
|
pos = file.lastIndexOf('/', pos);
|
||||||
|
return pos;
|
||||||
|
} else {
|
||||||
|
return file.lastIndexOf('/');
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,66 @@
|
|||||||
|
/*
|
||||||
|
* This file is part of dependency-check-cli.
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*
|
||||||
|
* Copyright (c) 2014 Jeremy Long. All Rights Reserved.
|
||||||
|
*/
|
||||||
|
package org.owasp.dependencycheck;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Thrown if an invalid path is encountered.
|
||||||
|
*
|
||||||
|
* @author Jeremy Long
|
||||||
|
*/
|
||||||
|
public class InvalidScanPathException extends Exception {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The serial version UID for serialization.
|
||||||
|
*/
|
||||||
|
private static final long serialVersionUID = 1L;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates a new InvalidScanPathException.
|
||||||
|
*/
|
||||||
|
public InvalidScanPathException() {
|
||||||
|
super();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates a new InvalidScanPathException.
|
||||||
|
*
|
||||||
|
* @param msg a message for the exception
|
||||||
|
*/
|
||||||
|
public InvalidScanPathException(String msg) {
|
||||||
|
super(msg);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates a new InvalidScanPathException.
|
||||||
|
*
|
||||||
|
* @param ex the cause of the exception
|
||||||
|
*/
|
||||||
|
public InvalidScanPathException(Throwable ex) {
|
||||||
|
super(ex);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates a new InvalidScanPathException.
|
||||||
|
*
|
||||||
|
* @param msg a message for the exception
|
||||||
|
* @param ex the cause of the exception
|
||||||
|
*/
|
||||||
|
public InvalidScanPathException(String msg, Throwable ex) {
|
||||||
|
super(msg, ex);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,881 +0,0 @@
|
|||||||
/*
|
|
||||||
* This file is part of dependency-check-cli.
|
|
||||||
*
|
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
||||||
* you may not use this file except in compliance with the License.
|
|
||||||
* You may obtain a copy of the License at
|
|
||||||
*
|
|
||||||
* http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
*
|
|
||||||
* Unless required by applicable law or agreed to in writing, software
|
|
||||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
||||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
* See the License for the specific language governing permissions and
|
|
||||||
* limitations under the License.
|
|
||||||
*
|
|
||||||
* Copyright (c) 2012 Jeremy Long. All Rights Reserved.
|
|
||||||
*/
|
|
||||||
package org.owasp.dependencycheck.cli;
|
|
||||||
|
|
||||||
import java.io.File;
|
|
||||||
import java.io.FileNotFoundException;
|
|
||||||
import java.util.logging.Logger;
|
|
||||||
import org.apache.commons.cli.CommandLine;
|
|
||||||
import org.apache.commons.cli.CommandLineParser;
|
|
||||||
import org.apache.commons.cli.HelpFormatter;
|
|
||||||
import org.apache.commons.cli.Option;
|
|
||||||
import org.apache.commons.cli.OptionBuilder;
|
|
||||||
import org.apache.commons.cli.OptionGroup;
|
|
||||||
import org.apache.commons.cli.Options;
|
|
||||||
import org.apache.commons.cli.ParseException;
|
|
||||||
import org.apache.commons.cli.PosixParser;
|
|
||||||
import org.owasp.dependencycheck.reporting.ReportGenerator.Format;
|
|
||||||
import org.owasp.dependencycheck.utils.InvalidSettingException;
|
|
||||||
import org.owasp.dependencycheck.utils.Settings;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* A utility to parse command line arguments for the DependencyCheck.
|
|
||||||
*
|
|
||||||
* @author Jeremy Long <jeremy.long@owasp.org>
|
|
||||||
*/
|
|
||||||
public final class CliParser {
|
|
||||||
|
|
||||||
/**
|
|
||||||
* The logger.
|
|
||||||
*/
|
|
||||||
private static final Logger LOGGER = Logger.getLogger(CliParser.class.getName());
|
|
||||||
/**
|
|
||||||
* The command line.
|
|
||||||
*/
|
|
||||||
private CommandLine line;
|
|
||||||
/**
|
|
||||||
* Indicates whether the arguments are valid.
|
|
||||||
*/
|
|
||||||
private boolean isValid = true;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Parses the arguments passed in and captures the results for later use.
|
|
||||||
*
|
|
||||||
* @param args the command line arguments
|
|
||||||
* @throws FileNotFoundException is thrown when a 'file' argument does not point to a file that exists.
|
|
||||||
* @throws ParseException is thrown when a Parse Exception occurs.
|
|
||||||
*/
|
|
||||||
public void parse(String[] args) throws FileNotFoundException, ParseException {
|
|
||||||
line = parseArgs(args);
|
|
||||||
|
|
||||||
if (line != null) {
|
|
||||||
validateArgs();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Parses the command line arguments.
|
|
||||||
*
|
|
||||||
* @param args the command line arguments
|
|
||||||
* @return the results of parsing the command line arguments
|
|
||||||
* @throws ParseException if the arguments are invalid
|
|
||||||
*/
|
|
||||||
private CommandLine parseArgs(String[] args) throws ParseException {
|
|
||||||
final CommandLineParser parser = new PosixParser();
|
|
||||||
final Options options = createCommandLineOptions();
|
|
||||||
return parser.parse(options, args);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Validates that the command line arguments are valid.
|
|
||||||
*
|
|
||||||
* @throws FileNotFoundException if there is a file specified by either the SCAN or CPE command line arguments that
|
|
||||||
* does not exist.
|
|
||||||
* @throws ParseException is thrown if there is an exception parsing the command line.
|
|
||||||
*/
|
|
||||||
private void validateArgs() throws FileNotFoundException, ParseException {
|
|
||||||
if (isRunScan()) {
|
|
||||||
validatePathExists(getScanFiles(), ARGUMENT.SCAN);
|
|
||||||
validatePathExists(getReportDirectory(), ARGUMENT.OUT);
|
|
||||||
if (getPathToMono() != null) {
|
|
||||||
validatePathExists(getPathToMono(), ARGUMENT.PATH_TO_MONO);
|
|
||||||
}
|
|
||||||
if (!line.hasOption(ARGUMENT.APP_NAME)) {
|
|
||||||
throw new ParseException("Missing 'app' argument; the scan cannot be run without the an application name.");
|
|
||||||
}
|
|
||||||
if (line.hasOption(ARGUMENT.OUTPUT_FORMAT)) {
|
|
||||||
final String format = line.getOptionValue(ARGUMENT.OUTPUT_FORMAT);
|
|
||||||
try {
|
|
||||||
Format.valueOf(format);
|
|
||||||
} catch (IllegalArgumentException ex) {
|
|
||||||
final String msg = String.format("An invalid 'format' of '%s' was specified. "
|
|
||||||
+ "Supported output formats are XML, HTML, VULN, or ALL", format);
|
|
||||||
throw new ParseException(msg);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Validates whether or not the path(s) points at a file that exists; if the path(s) does not point to an existing
|
|
||||||
* file a FileNotFoundException is thrown.
|
|
||||||
*
|
|
||||||
* @param paths the paths to validate if they exists
|
|
||||||
* @param optType the option being validated (e.g. scan, out, etc.)
|
|
||||||
* @throws FileNotFoundException is thrown if one of the paths being validated does not exist.
|
|
||||||
*/
|
|
||||||
private void validatePathExists(String[] paths, String optType) throws FileNotFoundException {
|
|
||||||
for (String path : paths) {
|
|
||||||
validatePathExists(path, optType);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Validates whether or not the path points at a file that exists; if the path does not point to an existing file a
|
|
||||||
* FileNotFoundException is thrown.
|
|
||||||
*
|
|
||||||
* @param path the paths to validate if they exists
|
|
||||||
* @param argumentName the argument being validated (e.g. scan, out, etc.)
|
|
||||||
* @throws FileNotFoundException is thrown if the path being validated does not exist.
|
|
||||||
*/
|
|
||||||
private void validatePathExists(String path, String argumentName) throws FileNotFoundException {
|
|
||||||
if (!path.contains("*.")) {
|
|
||||||
final File f = new File(path);
|
|
||||||
if (!f.exists()) {
|
|
||||||
isValid = false;
|
|
||||||
final String msg = String.format("Invalid '%s' argument: '%s'", argumentName, path);
|
|
||||||
throw new FileNotFoundException(msg);
|
|
||||||
}
|
|
||||||
} // else { // TODO add a validation for *.zip extensions rather then relying on the engine to validate it.
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Generates an Options collection that is used to parse the command line and to display the help message.
|
|
||||||
*
|
|
||||||
* @return the command line options used for parsing the command line
|
|
||||||
*/
|
|
||||||
@SuppressWarnings("static-access")
|
|
||||||
private Options createCommandLineOptions() {
|
|
||||||
|
|
||||||
final Options options = new Options();
|
|
||||||
addStandardOptions(options);
|
|
||||||
addAdvancedOptions(options);
|
|
||||||
addDeprecatedOptions(options);
|
|
||||||
return options;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Adds the standard command line options to the given options collection.
|
|
||||||
*
|
|
||||||
* @param options a collection of command line arguments
|
|
||||||
* @throws IllegalArgumentException thrown if there is an exception
|
|
||||||
*/
|
|
||||||
@SuppressWarnings("static-access")
|
|
||||||
private void addStandardOptions(final Options options) throws IllegalArgumentException {
|
|
||||||
final Option help = new Option(ARGUMENT.HELP_SHORT, ARGUMENT.HELP, false,
|
|
||||||
"Print this message.");
|
|
||||||
|
|
||||||
final Option advancedHelp = OptionBuilder.withLongOpt(ARGUMENT.ADVANCED_HELP)
|
|
||||||
.withDescription("Print the advanced help message.").create();
|
|
||||||
|
|
||||||
final Option version = new Option(ARGUMENT.VERSION_SHORT, ARGUMENT.VERSION,
|
|
||||||
false, "Print the version information.");
|
|
||||||
|
|
||||||
final Option noUpdate = new Option(ARGUMENT.DISABLE_AUTO_UPDATE_SHORT, ARGUMENT.DISABLE_AUTO_UPDATE,
|
|
||||||
false, "Disables the automatic updating of the CPE data.");
|
|
||||||
|
|
||||||
final Option appName = OptionBuilder.withArgName("name").hasArg().withLongOpt(ARGUMENT.APP_NAME)
|
|
||||||
.withDescription("The name of the application being scanned. This is a required argument.")
|
|
||||||
.create(ARGUMENT.APP_NAME_SHORT);
|
|
||||||
|
|
||||||
final Option path = OptionBuilder.withArgName("path").hasArg().withLongOpt(ARGUMENT.SCAN)
|
|
||||||
.withDescription("The path to scan - this option can be specified multiple times. To limit the scan"
|
|
||||||
+ " to specific file types *.[ext] can be added to the end of the path.")
|
|
||||||
.create(ARGUMENT.SCAN_SHORT);
|
|
||||||
|
|
||||||
final Option props = OptionBuilder.withArgName("file").hasArg().withLongOpt(ARGUMENT.PROP)
|
|
||||||
.withDescription("A property file to load.")
|
|
||||||
.create(ARGUMENT.PROP_SHORT);
|
|
||||||
|
|
||||||
final Option out = OptionBuilder.withArgName("folder").hasArg().withLongOpt(ARGUMENT.OUT)
|
|
||||||
.withDescription("The folder to write reports to. This defaults to the current directory.")
|
|
||||||
.create(ARGUMENT.OUT_SHORT);
|
|
||||||
|
|
||||||
final Option outputFormat = OptionBuilder.withArgName("format").hasArg().withLongOpt(ARGUMENT.OUTPUT_FORMAT)
|
|
||||||
.withDescription("The output format to write to (XML, HTML, VULN, ALL). The default is HTML.")
|
|
||||||
.create(ARGUMENT.OUTPUT_FORMAT_SHORT);
|
|
||||||
|
|
||||||
final Option verboseLog = OptionBuilder.withArgName("file").hasArg().withLongOpt(ARGUMENT.VERBOSE_LOG)
|
|
||||||
.withDescription("The file path to write verbose logging information.")
|
|
||||||
.create(ARGUMENT.VERBOSE_LOG_SHORT);
|
|
||||||
|
|
||||||
final Option suppressionFile = OptionBuilder.withArgName("file").hasArg().withLongOpt(ARGUMENT.SUPPRESSION_FILE)
|
|
||||||
.withDescription("The file path to the suppression XML file.")
|
|
||||||
.create();
|
|
||||||
|
|
||||||
//This is an option group because it can be specified more then once.
|
|
||||||
final OptionGroup og = new OptionGroup();
|
|
||||||
og.addOption(path);
|
|
||||||
|
|
||||||
options.addOptionGroup(og)
|
|
||||||
.addOption(out)
|
|
||||||
.addOption(outputFormat)
|
|
||||||
.addOption(appName)
|
|
||||||
.addOption(version)
|
|
||||||
.addOption(help)
|
|
||||||
.addOption(advancedHelp)
|
|
||||||
.addOption(noUpdate)
|
|
||||||
.addOption(props)
|
|
||||||
.addOption(verboseLog)
|
|
||||||
.addOption(suppressionFile);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Adds the advanced command line options to the given options collection. These are split out for purposes of being
|
|
||||||
* able to display two different help messages.
|
|
||||||
*
|
|
||||||
* @param options a collection of command line arguments
|
|
||||||
* @throws IllegalArgumentException thrown if there is an exception
|
|
||||||
*/
|
|
||||||
@SuppressWarnings("static-access")
|
|
||||||
private void addAdvancedOptions(final Options options) throws IllegalArgumentException {
|
|
||||||
|
|
||||||
final Option data = OptionBuilder.withArgName("path").hasArg().withLongOpt(ARGUMENT.DATA_DIRECTORY)
|
|
||||||
.withDescription("The location of the H2 Database file. This option should generally not be set.")
|
|
||||||
.create(ARGUMENT.DATA_DIRECTORY_SHORT);
|
|
||||||
|
|
||||||
final Option connectionTimeout = OptionBuilder.withArgName("timeout").hasArg().withLongOpt(ARGUMENT.CONNECTION_TIMEOUT)
|
|
||||||
.withDescription("The connection timeout (in milliseconds) to use when downloading resources.")
|
|
||||||
.create(ARGUMENT.CONNECTION_TIMEOUT_SHORT);
|
|
||||||
|
|
||||||
final Option proxyServer = OptionBuilder.withArgName("server").hasArg().withLongOpt(ARGUMENT.PROXY_SERVER)
|
|
||||||
.withDescription("The proxy server to use when downloading resources.")
|
|
||||||
.create();
|
|
||||||
|
|
||||||
final Option proxyPort = OptionBuilder.withArgName("port").hasArg().withLongOpt(ARGUMENT.PROXY_PORT)
|
|
||||||
.withDescription("The proxy port to use when downloading resources.")
|
|
||||||
.create();
|
|
||||||
|
|
||||||
final Option proxyUsername = OptionBuilder.withArgName("user").hasArg().withLongOpt(ARGUMENT.PROXY_USERNAME)
|
|
||||||
.withDescription("The proxy username to use when downloading resources.")
|
|
||||||
.create();
|
|
||||||
|
|
||||||
final Option proxyPassword = OptionBuilder.withArgName("pass").hasArg().withLongOpt(ARGUMENT.PROXY_PASSWORD)
|
|
||||||
.withDescription("The proxy password to use when downloading resources.")
|
|
||||||
.create();
|
|
||||||
|
|
||||||
final Option connectionString = OptionBuilder.withArgName("connStr").hasArg().withLongOpt(ARGUMENT.CONNECTION_STRING)
|
|
||||||
.withDescription("The connection string to the database.")
|
|
||||||
.create();
|
|
||||||
|
|
||||||
final Option dbUser = OptionBuilder.withArgName("user").hasArg().withLongOpt(ARGUMENT.DB_NAME)
|
|
||||||
.withDescription("The username used to connect to the database.")
|
|
||||||
.create();
|
|
||||||
|
|
||||||
final Option dbPassword = OptionBuilder.withArgName("password").hasArg().withLongOpt(ARGUMENT.DB_PASSWORD)
|
|
||||||
.withDescription("The password for connecting to the database.")
|
|
||||||
.create();
|
|
||||||
|
|
||||||
final Option dbDriver = OptionBuilder.withArgName("driver").hasArg().withLongOpt(ARGUMENT.DB_DRIVER)
|
|
||||||
.withDescription("The database driver name.")
|
|
||||||
.create();
|
|
||||||
|
|
||||||
final Option dbDriverPath = OptionBuilder.withArgName("path").hasArg().withLongOpt(ARGUMENT.DB_DRIVER_PATH)
|
|
||||||
.withDescription("The path to the database driver; note, this does not need to be set unless the JAR is outside of the classpath.")
|
|
||||||
.create();
|
|
||||||
|
|
||||||
final Option disableJarAnalyzer = OptionBuilder.withLongOpt(ARGUMENT.DISABLE_JAR)
|
|
||||||
.withDescription("Disable the Jar Analyzer.")
|
|
||||||
.create();
|
|
||||||
final Option disableArchiveAnalyzer = OptionBuilder.withLongOpt(ARGUMENT.DISABLE_ARCHIVE)
|
|
||||||
.withDescription("Disable the Archive Analyzer.")
|
|
||||||
.create();
|
|
||||||
final Option disableNuspecAnalyzer = OptionBuilder.withLongOpt(ARGUMENT.DISABLE_NUSPEC)
|
|
||||||
.withDescription("Disable the Nuspec Analyzer.")
|
|
||||||
.create();
|
|
||||||
final Option disableAssemblyAnalyzer = OptionBuilder.withLongOpt(ARGUMENT.DISABLE_ASSEMBLY)
|
|
||||||
.withDescription("Disable the .NET Assembly Analyzer.")
|
|
||||||
.create();
|
|
||||||
|
|
||||||
final Option disableNexusAnalyzer = OptionBuilder.withLongOpt(ARGUMENT.DISABLE_NEXUS)
|
|
||||||
.withDescription("Disable the Nexus Analyzer.")
|
|
||||||
.create();
|
|
||||||
|
|
||||||
final Option nexusUrl = OptionBuilder.withArgName("url").hasArg().withLongOpt(ARGUMENT.NEXUS_URL)
|
|
||||||
.withDescription("The url to the Nexus Server.")
|
|
||||||
.create();
|
|
||||||
|
|
||||||
final Option nexusUsesProxy = OptionBuilder.withArgName("true/false").hasArg().withLongOpt(ARGUMENT.NEXUS_USES_PROXY)
|
|
||||||
.withDescription("Whether or not the configured proxy should be used when connecting to Nexus.")
|
|
||||||
.create();
|
|
||||||
|
|
||||||
final Option additionalZipExtensions = OptionBuilder.withArgName("extensions").hasArg()
|
|
||||||
.withLongOpt(ARGUMENT.ADDITIONAL_ZIP_EXTENSIONS)
|
|
||||||
.withDescription("A comma separated list of additional extensions to be scanned as ZIP files "
|
|
||||||
+ "(ZIP, EAR, WAR are already treated as zip files)")
|
|
||||||
.create();
|
|
||||||
|
|
||||||
final Option pathToMono = OptionBuilder.withArgName("path").hasArg().withLongOpt(ARGUMENT.PATH_TO_MONO)
|
|
||||||
.withDescription("The path to Mono for .NET Assembly analysis on non-windows systems.")
|
|
||||||
.create();
|
|
||||||
|
|
||||||
options.addOption(proxyPort)
|
|
||||||
.addOption(proxyServer)
|
|
||||||
.addOption(proxyUsername)
|
|
||||||
.addOption(proxyPassword)
|
|
||||||
.addOption(connectionTimeout)
|
|
||||||
.addOption(connectionString)
|
|
||||||
.addOption(dbUser)
|
|
||||||
.addOption(data)
|
|
||||||
.addOption(dbPassword)
|
|
||||||
.addOption(dbDriver)
|
|
||||||
.addOption(dbDriverPath)
|
|
||||||
.addOption(disableJarAnalyzer)
|
|
||||||
.addOption(disableArchiveAnalyzer)
|
|
||||||
.addOption(disableAssemblyAnalyzer)
|
|
||||||
.addOption(disableNuspecAnalyzer)
|
|
||||||
.addOption(disableNexusAnalyzer)
|
|
||||||
.addOption(nexusUrl)
|
|
||||||
.addOption(nexusUsesProxy)
|
|
||||||
.addOption(additionalZipExtensions)
|
|
||||||
.addOption(pathToMono);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Adds the deprecated command line options to the given options collection. These are split out for purposes of not
|
|
||||||
* including them in the help message. We need to add the deprecated options so as not to break existing scripts.
|
|
||||||
*
|
|
||||||
* @param options a collection of command line arguments
|
|
||||||
* @throws IllegalArgumentException thrown if there is an exception
|
|
||||||
*/
|
|
||||||
@SuppressWarnings("static-access")
|
|
||||||
private void addDeprecatedOptions(final Options options) throws IllegalArgumentException {
|
|
||||||
|
|
||||||
final Option proxyServer = OptionBuilder.withArgName("url").hasArg().withLongOpt(ARGUMENT.PROXY_URL)
|
|
||||||
.withDescription("The proxy url argument is deprecated, use proxyserver instead.")
|
|
||||||
.create();
|
|
||||||
|
|
||||||
options.addOption(proxyServer);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Determines if the 'version' command line argument was passed in.
|
|
||||||
*
|
|
||||||
* @return whether or not the 'version' command line argument was passed in
|
|
||||||
*/
|
|
||||||
public boolean isGetVersion() {
|
|
||||||
return (line != null) && line.hasOption(ARGUMENT.VERSION);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Determines if the 'help' command line argument was passed in.
|
|
||||||
*
|
|
||||||
* @return whether or not the 'help' command line argument was passed in
|
|
||||||
*/
|
|
||||||
public boolean isGetHelp() {
|
|
||||||
return (line != null) && line.hasOption(ARGUMENT.HELP);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Determines if the 'scan' command line argument was passed in.
|
|
||||||
*
|
|
||||||
* @return whether or not the 'scan' command line argument was passed in
|
|
||||||
*/
|
|
||||||
public boolean isRunScan() {
|
|
||||||
return (line != null) && isValid && line.hasOption(ARGUMENT.SCAN);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Returns true if the disableJar command line argument was specified.
|
|
||||||
*
|
|
||||||
* @return true if the disableJar command line argument was specified; otherwise false
|
|
||||||
*/
|
|
||||||
public boolean isJarDisabled() {
|
|
||||||
return (line != null) && line.hasOption(ARGUMENT.DISABLE_JAR);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Returns true if the disableArchive command line argument was specified.
|
|
||||||
*
|
|
||||||
* @return true if the disableArchive command line argument was specified; otherwise false
|
|
||||||
*/
|
|
||||||
public boolean isArchiveDisabled() {
|
|
||||||
return (line != null) && line.hasOption(ARGUMENT.DISABLE_ARCHIVE);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Returns true if the disableNuspec command line argument was specified.
|
|
||||||
*
|
|
||||||
* @return true if the disableNuspec command line argument was specified; otherwise false
|
|
||||||
*/
|
|
||||||
public boolean isNuspecDisabled() {
|
|
||||||
return (line != null) && line.hasOption(ARGUMENT.DISABLE_NUSPEC);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Returns true if the disableAssembly command line argument was specified.
|
|
||||||
*
|
|
||||||
* @return true if the disableAssembly command line argument was specified; otherwise false
|
|
||||||
*/
|
|
||||||
public boolean isAssemblyDisabled() {
|
|
||||||
return (line != null) && line.hasOption(ARGUMENT.DISABLE_ASSEMBLY);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Returns true if the disableNexus command line argument was specified.
|
|
||||||
*
|
|
||||||
* @return true if the disableNexus command line argument was specified; otherwise false
|
|
||||||
*/
|
|
||||||
public boolean isNexusDisabled() {
|
|
||||||
return (line != null) && line.hasOption(ARGUMENT.DISABLE_NEXUS);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Returns the url to the nexus server if one was specified.
|
|
||||||
*
|
|
||||||
* @return the url to the nexus server; if none was specified this will return null;
|
|
||||||
*/
|
|
||||||
public String getNexusUrl() {
|
|
||||||
if (line == null || !line.hasOption(ARGUMENT.NEXUS_URL)) {
|
|
||||||
return null;
|
|
||||||
} else {
|
|
||||||
return line.getOptionValue(ARGUMENT.NEXUS_URL);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Returns true if the Nexus Analyzer should use the configured proxy to connect to Nexus; otherwise false is
|
|
||||||
* returned.
|
|
||||||
*
|
|
||||||
* @return true if the Nexus Analyzer should use the configured proxy to connect to Nexus; otherwise false
|
|
||||||
*/
|
|
||||||
public boolean isNexusUsesProxy() {
|
|
||||||
// If they didn't specify whether Nexus needs to use the proxy, we should
|
|
||||||
// still honor the property if it's set.
|
|
||||||
if (line == null || !line.hasOption(ARGUMENT.NEXUS_USES_PROXY)) {
|
|
||||||
try {
|
|
||||||
return Settings.getBoolean(Settings.KEYS.ANALYZER_NEXUS_PROXY);
|
|
||||||
} catch (InvalidSettingException ise) {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
return Boolean.parseBoolean(line.getOptionValue(ARGUMENT.NEXUS_USES_PROXY));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Displays the command line help message to the standard output.
|
|
||||||
*/
|
|
||||||
public void printHelp() {
|
|
||||||
final HelpFormatter formatter = new HelpFormatter();
|
|
||||||
final Options options = new Options();
|
|
||||||
addStandardOptions(options);
|
|
||||||
if (line != null && line.hasOption(ARGUMENT.ADVANCED_HELP)) {
|
|
||||||
addAdvancedOptions(options);
|
|
||||||
}
|
|
||||||
final String helpMsg = String.format("%n%s"
|
|
||||||
+ " can be used to identify if there are any known CVE vulnerabilities in libraries utilized by an application. "
|
|
||||||
+ "%s will automatically update required data from the Internet, such as the CVE and CPE data files from nvd.nist.gov.%n%n",
|
|
||||||
Settings.getString("application.name", "DependencyCheck"),
|
|
||||||
Settings.getString("application.name", "DependencyCheck"));
|
|
||||||
|
|
||||||
formatter.printHelp(Settings.getString("application.name", "DependencyCheck"),
|
|
||||||
helpMsg,
|
|
||||||
options,
|
|
||||||
"",
|
|
||||||
true);
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Retrieves the file command line parameter(s) specified for the 'scan' argument.
|
|
||||||
*
|
|
||||||
* @return the file paths specified on the command line for scan
|
|
||||||
*/
|
|
||||||
public String[] getScanFiles() {
|
|
||||||
return line.getOptionValues(ARGUMENT.SCAN);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Returns the directory to write the reports to specified on the command line.
|
|
||||||
*
|
|
||||||
* @return the path to the reports directory.
|
|
||||||
*/
|
|
||||||
public String getReportDirectory() {
|
|
||||||
return line.getOptionValue(ARGUMENT.OUT, ".");
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Returns the path to Mono for .NET Assembly analysis on non-windows systems.
|
|
||||||
*
|
|
||||||
* @return the path to Mono
|
|
||||||
*/
|
|
||||||
public String getPathToMono() {
|
|
||||||
return line.getOptionValue(ARGUMENT.PATH_TO_MONO);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Returns the output format specified on the command line. Defaults to HTML if no format was specified.
|
|
||||||
*
|
|
||||||
* @return the output format name.
|
|
||||||
*/
|
|
||||||
public String getReportFormat() {
|
|
||||||
return line.getOptionValue(ARGUMENT.OUTPUT_FORMAT, "HTML");
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Returns the application name specified on the command line.
|
|
||||||
*
|
|
||||||
* @return the application name.
|
|
||||||
*/
|
|
||||||
public String getApplicationName() {
|
|
||||||
return line.getOptionValue(ARGUMENT.APP_NAME);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Returns the connection timeout.
|
|
||||||
*
|
|
||||||
* @return the connection timeout
|
|
||||||
*/
|
|
||||||
public String getConnectionTimeout() {
|
|
||||||
return line.getOptionValue(ARGUMENT.CONNECTION_TIMEOUT);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Returns the proxy server.
|
|
||||||
*
|
|
||||||
* @return the proxy server
|
|
||||||
*/
|
|
||||||
public String getProxyServer() {
|
|
||||||
|
|
||||||
String server = line.getOptionValue(ARGUMENT.PROXY_SERVER);
|
|
||||||
if (server == null) {
|
|
||||||
server = line.getOptionValue(ARGUMENT.PROXY_URL);
|
|
||||||
if (server != null) {
|
|
||||||
LOGGER.warning("An old command line argument 'proxyurl' was detected; use proxyserver instead");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return server;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Returns the proxy port.
|
|
||||||
*
|
|
||||||
* @return the proxy port
|
|
||||||
*/
|
|
||||||
public String getProxyPort() {
|
|
||||||
return line.getOptionValue(ARGUMENT.PROXY_PORT);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Returns the proxy username.
|
|
||||||
*
|
|
||||||
* @return the proxy username
|
|
||||||
*/
|
|
||||||
public String getProxyUsername() {
|
|
||||||
return line.getOptionValue(ARGUMENT.PROXY_USERNAME);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Returns the proxy password.
|
|
||||||
*
|
|
||||||
* @return the proxy password
|
|
||||||
*/
|
|
||||||
public String getProxyPassword() {
|
|
||||||
return line.getOptionValue(ARGUMENT.PROXY_PASSWORD);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Get the value of dataDirectory.
|
|
||||||
*
|
|
||||||
* @return the value of dataDirectory
|
|
||||||
*/
|
|
||||||
public String getDataDirectory() {
|
|
||||||
return line.getOptionValue(ARGUMENT.DATA_DIRECTORY);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Returns the properties file specified on the command line.
|
|
||||||
*
|
|
||||||
* @return the properties file specified on the command line
|
|
||||||
*/
|
|
||||||
public File getPropertiesFile() {
|
|
||||||
final String path = line.getOptionValue(ARGUMENT.PROP);
|
|
||||||
if (path != null) {
|
|
||||||
return new File(path);
|
|
||||||
}
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Returns the path to the verbose log file.
|
|
||||||
*
|
|
||||||
* @return the path to the verbose log file
|
|
||||||
*/
|
|
||||||
public String getVerboseLog() {
|
|
||||||
return line.getOptionValue(ARGUMENT.VERBOSE_LOG);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Returns the path to the suppression file.
|
|
||||||
*
|
|
||||||
* @return the path to the suppression file
|
|
||||||
*/
|
|
||||||
public String getSuppressionFile() {
|
|
||||||
return line.getOptionValue(ARGUMENT.SUPPRESSION_FILE);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* <p>
|
|
||||||
* Prints the manifest information to standard output.</p>
|
|
||||||
* <ul><li>Implementation-Title: ${pom.name}</li>
|
|
||||||
* <li>Implementation-Version: ${pom.version}</li></ul>
|
|
||||||
*/
|
|
||||||
public void printVersionInfo() {
|
|
||||||
final String version = String.format("%s version %s",
|
|
||||||
Settings.getString("application.name", "DependencyCheck"),
|
|
||||||
Settings.getString("application.version", "Unknown"));
|
|
||||||
System.out.println(version);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Checks if the auto update feature has been disabled. If it has been disabled via the command line this will
|
|
||||||
* return false.
|
|
||||||
*
|
|
||||||
* @return if auto-update is allowed.
|
|
||||||
*/
|
|
||||||
public boolean isAutoUpdate() {
|
|
||||||
return (line == null) || !line.hasOption(ARGUMENT.DISABLE_AUTO_UPDATE);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Returns the database driver name if specified; otherwise null is returned.
|
|
||||||
*
|
|
||||||
* @return the database driver name if specified; otherwise null is returned
|
|
||||||
*/
|
|
||||||
public String getDatabaseDriverName() {
|
|
||||||
return line.getOptionValue(ARGUMENT.DB_DRIVER);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Returns the database driver path if specified; otherwise null is returned.
|
|
||||||
*
|
|
||||||
* @return the database driver name if specified; otherwise null is returned
|
|
||||||
*/
|
|
||||||
public String getDatabaseDriverPath() {
|
|
||||||
return line.getOptionValue(ARGUMENT.DB_DRIVER_PATH);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Returns the database connection string if specified; otherwise null is returned.
|
|
||||||
*
|
|
||||||
* @return the database connection string if specified; otherwise null is returned
|
|
||||||
*/
|
|
||||||
public String getConnectionString() {
|
|
||||||
return line.getOptionValue(ARGUMENT.CONNECTION_STRING);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Returns the database database user name if specified; otherwise null is returned.
|
|
||||||
*
|
|
||||||
* @return the database database user name if specified; otherwise null is returned
|
|
||||||
*/
|
|
||||||
public String getDatabaseUser() {
|
|
||||||
return line.getOptionValue(ARGUMENT.DB_NAME);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Returns the database database password if specified; otherwise null is returned.
|
|
||||||
*
|
|
||||||
* @return the database database password if specified; otherwise null is returned
|
|
||||||
*/
|
|
||||||
public String getDatabasePassword() {
|
|
||||||
return line.getOptionValue(ARGUMENT.DB_PASSWORD);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Returns the additional Extensions if specified; otherwise null is returned.
|
|
||||||
*
|
|
||||||
* @return the additional Extensions; otherwise null is returned
|
|
||||||
*/
|
|
||||||
public String getAdditionalZipExtensions() {
|
|
||||||
return line.getOptionValue(ARGUMENT.ADDITIONAL_ZIP_EXTENSIONS);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* A collection of static final strings that represent the possible command line arguments.
|
|
||||||
*/
|
|
||||||
public static class ARGUMENT {
|
|
||||||
|
|
||||||
/**
|
|
||||||
* The long CLI argument name specifying the directory/file to scan.
|
|
||||||
*/
|
|
||||||
public static final String SCAN = "scan";
|
|
||||||
/**
|
|
||||||
* The short CLI argument name specifying the directory/file to scan.
|
|
||||||
*/
|
|
||||||
public static final String SCAN_SHORT = "s";
|
|
||||||
/**
|
|
||||||
* The long CLI argument name specifying that the CPE/CVE/etc. data should not be automatically updated.
|
|
||||||
*/
|
|
||||||
public static final String DISABLE_AUTO_UPDATE = "noupdate";
|
|
||||||
/**
|
|
||||||
* The short CLI argument name specifying that the CPE/CVE/etc. data should not be automatically updated.
|
|
||||||
*/
|
|
||||||
public static final String DISABLE_AUTO_UPDATE_SHORT = "n";
|
|
||||||
/**
|
|
||||||
* The long CLI argument name specifying the directory to write the reports to.
|
|
||||||
*/
|
|
||||||
public static final String OUT = "out";
|
|
||||||
/**
|
|
||||||
* The short CLI argument name specifying the directory to write the reports to.
|
|
||||||
*/
|
|
||||||
public static final String OUT_SHORT = "o";
|
|
||||||
/**
|
|
||||||
* The long CLI argument name specifying the output format to write the reports to.
|
|
||||||
*/
|
|
||||||
public static final String OUTPUT_FORMAT = "format";
|
|
||||||
/**
|
|
||||||
* The short CLI argument name specifying the output format to write the reports to.
|
|
||||||
*/
|
|
||||||
public static final String OUTPUT_FORMAT_SHORT = "f";
|
|
||||||
/**
|
|
||||||
* The long CLI argument name specifying the name of the application to be scanned.
|
|
||||||
*/
|
|
||||||
public static final String APP_NAME = "app";
|
|
||||||
/**
|
|
||||||
* The short CLI argument name specifying the name of the application to be scanned.
|
|
||||||
*/
|
|
||||||
public static final String APP_NAME_SHORT = "a";
|
|
||||||
/**
|
|
||||||
* The long CLI argument name asking for help.
|
|
||||||
*/
|
|
||||||
public static final String HELP = "help";
|
|
||||||
/**
|
|
||||||
* The long CLI argument name asking for advanced help.
|
|
||||||
*/
|
|
||||||
public static final String ADVANCED_HELP = "advancedHelp";
|
|
||||||
/**
|
|
||||||
* The short CLI argument name asking for help.
|
|
||||||
*/
|
|
||||||
public static final String HELP_SHORT = "h";
|
|
||||||
/**
|
|
||||||
* The long CLI argument name asking for the version.
|
|
||||||
*/
|
|
||||||
public static final String VERSION_SHORT = "v";
|
|
||||||
/**
|
|
||||||
* The short CLI argument name asking for the version.
|
|
||||||
*/
|
|
||||||
public static final String VERSION = "version";
|
|
||||||
/**
|
|
||||||
* The CLI argument name indicating the proxy port.
|
|
||||||
*/
|
|
||||||
public static final String PROXY_PORT = "proxyport";
|
|
||||||
/**
|
|
||||||
* The CLI argument name indicating the proxy server.
|
|
||||||
*/
|
|
||||||
public static final String PROXY_SERVER = "proxyserver";
|
|
||||||
/**
|
|
||||||
* The CLI argument name indicating the proxy url.
|
|
||||||
*
|
|
||||||
* @deprecated use {@link org.owasp.dependencycheck.cli.CliParser.ArgumentName#PROXY_SERVER} instead
|
|
||||||
*/
|
|
||||||
@Deprecated
|
|
||||||
public static final String PROXY_URL = "proxyurl";
|
|
||||||
/**
|
|
||||||
* The CLI argument name indicating the proxy username.
|
|
||||||
*/
|
|
||||||
public static final String PROXY_USERNAME = "proxyuser";
|
|
||||||
/**
|
|
||||||
* The CLI argument name indicating the proxy password.
|
|
||||||
*/
|
|
||||||
public static final String PROXY_PASSWORD = "proxypass";
|
|
||||||
/**
|
|
||||||
* The short CLI argument name indicating the connection timeout.
|
|
||||||
*/
|
|
||||||
public static final String CONNECTION_TIMEOUT_SHORT = "c";
|
|
||||||
/**
|
|
||||||
* The CLI argument name indicating the connection timeout.
|
|
||||||
*/
|
|
||||||
public static final String CONNECTION_TIMEOUT = "connectiontimeout";
|
|
||||||
/**
|
|
||||||
* The short CLI argument name for setting the location of an additional properties file.
|
|
||||||
*/
|
|
||||||
public static final String PROP_SHORT = "P";
|
|
||||||
/**
|
|
||||||
* The CLI argument name for setting the location of an additional properties file.
|
|
||||||
*/
|
|
||||||
public static final String PROP = "propertyfile";
|
|
||||||
/**
|
|
||||||
* The CLI argument name for setting the location of the data directory.
|
|
||||||
*/
|
|
||||||
public static final String DATA_DIRECTORY = "data";
|
|
||||||
/**
|
|
||||||
* The short CLI argument name for setting the location of the data directory.
|
|
||||||
*/
|
|
||||||
public static final String DATA_DIRECTORY_SHORT = "d";
|
|
||||||
/**
|
|
||||||
* The CLI argument name for setting the location of the data directory.
|
|
||||||
*/
|
|
||||||
public static final String VERBOSE_LOG = "log";
|
|
||||||
/**
|
|
||||||
* The short CLI argument name for setting the location of the data directory.
|
|
||||||
*/
|
|
||||||
public static final String VERBOSE_LOG_SHORT = "l";
|
|
||||||
/**
|
|
||||||
* The CLI argument name for setting the location of the suppression file.
|
|
||||||
*/
|
|
||||||
public static final String SUPPRESSION_FILE = "suppression";
|
|
||||||
/**
|
|
||||||
* Disables the Jar Analyzer.
|
|
||||||
*/
|
|
||||||
public static final String DISABLE_JAR = "disableJar";
|
|
||||||
/**
|
|
||||||
* Disables the Archive Analyzer.
|
|
||||||
*/
|
|
||||||
public static final String DISABLE_ARCHIVE = "disableArchive";
|
|
||||||
/**
|
|
||||||
* Disables the Assembly Analyzer.
|
|
||||||
*/
|
|
||||||
public static final String DISABLE_ASSEMBLY = "disableAssembly";
|
|
||||||
/**
|
|
||||||
* Disables the Nuspec Analyzer.
|
|
||||||
*/
|
|
||||||
public static final String DISABLE_NUSPEC = "disableNuspec";
|
|
||||||
/**
|
|
||||||
* Disables the Nexus Analyzer.
|
|
||||||
*/
|
|
||||||
public static final String DISABLE_NEXUS = "disableNexus";
|
|
||||||
/**
|
|
||||||
* The URL of the nexus server.
|
|
||||||
*/
|
|
||||||
public static final String NEXUS_URL = "nexus";
|
|
||||||
/**
|
|
||||||
* Whether or not the defined proxy should be used when connecting to Nexus.
|
|
||||||
*/
|
|
||||||
public static final String NEXUS_USES_PROXY = "nexusUsesProxy";
|
|
||||||
/**
|
|
||||||
* The CLI argument name for setting the connection string.
|
|
||||||
*/
|
|
||||||
public static final String CONNECTION_STRING = "connectionString";
|
|
||||||
/**
|
|
||||||
* The CLI argument name for setting the database user name.
|
|
||||||
*/
|
|
||||||
public static final String DB_NAME = "dbUser";
|
|
||||||
/**
|
|
||||||
* The CLI argument name for setting the database password.
|
|
||||||
*/
|
|
||||||
public static final String DB_PASSWORD = "dbPassword";
|
|
||||||
/**
|
|
||||||
* The CLI argument name for setting the database driver name.
|
|
||||||
*/
|
|
||||||
public static final String DB_DRIVER = "dbDriverName";
|
|
||||||
/**
|
|
||||||
* The CLI argument name for setting the path to the database driver; in case it is not on the class path.
|
|
||||||
*/
|
|
||||||
public static final String DB_DRIVER_PATH = "dbDriverPath";
|
|
||||||
/**
|
|
||||||
* The CLI argument name for setting the path to mono for .NET Assembly analysis on non-windows systems.
|
|
||||||
*/
|
|
||||||
public static final String PATH_TO_MONO = "mono";
|
|
||||||
/**
|
|
||||||
* The CLI argument name for setting extra extensions.
|
|
||||||
*/
|
|
||||||
public static final String ADDITIONAL_ZIP_EXTENSIONS = "zipExtensions";
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,12 +0,0 @@
|
|||||||
/**
|
|
||||||
* <html>
|
|
||||||
* <head>
|
|
||||||
* <title>org.owasp.dependencycheck.cli</title>
|
|
||||||
* </head>
|
|
||||||
* <body>
|
|
||||||
* Includes utility classes such as the CLI Parser,
|
|
||||||
* </body>
|
|
||||||
* </html>
|
|
||||||
*/
|
|
||||||
|
|
||||||
package org.owasp.dependencycheck.cli;
|
|
||||||
@@ -1,12 +1,4 @@
|
|||||||
/**
|
/**
|
||||||
* <html>
|
|
||||||
* <head>
|
|
||||||
* <title>org.owasp.dependencycheck</title>
|
|
||||||
* </head>
|
|
||||||
* <body>
|
|
||||||
* Includes the main entry point for the DependencyChecker.
|
* Includes the main entry point for the DependencyChecker.
|
||||||
* </body>
|
*/
|
||||||
* </html>
|
|
||||||
*/
|
|
||||||
|
|
||||||
package org.owasp.dependencycheck;
|
package org.owasp.dependencycheck;
|
||||||
|
|||||||
@@ -1,22 +0,0 @@
|
|||||||
handlers=java.util.logging.ConsoleHandler
|
|
||||||
#, java.util.logging.FileHandler
|
|
||||||
|
|
||||||
# logging levels
|
|
||||||
# FINEST, FINER, FINE, CONFIG, INFO, WARNING and SEVERE.
|
|
||||||
|
|
||||||
# Configure the ConsoleHandler.
|
|
||||||
java.util.logging.ConsoleHandler.level=INFO
|
|
||||||
|
|
||||||
# Configure the FileHandler.
|
|
||||||
java.util.logging.FileHandler.formatter=java.util.logging.SimpleFormatter
|
|
||||||
java.util.logging.FileHandler.level=FINE
|
|
||||||
|
|
||||||
# The following special tokens can be used in the pattern property
|
|
||||||
# which specifies the location and name of the log file.
|
|
||||||
# / - standard path separator
|
|
||||||
# %t - system temporary directory
|
|
||||||
# %h - value of the user.home system property
|
|
||||||
# %g - generation number for rotating logs
|
|
||||||
# %u - unique number to avoid conflicts
|
|
||||||
# FileHandler writes to %h/demo0.log by default.
|
|
||||||
java.util.logging.FileHandler.pattern=./dependency-check.log
|
|
||||||
16
dependency-check-cli/src/main/resources/logback.xml
Normal file
16
dependency-check-cli/src/main/resources/logback.xml
Normal file
@@ -0,0 +1,16 @@
|
|||||||
|
<configuration>
|
||||||
|
<contextName>dependency-check</contextName>
|
||||||
|
<!-- Logging configuration -->
|
||||||
|
<appender name="console" class="ch.qos.logback.core.ConsoleAppender">
|
||||||
|
<Target>System.out</Target>
|
||||||
|
<filter class="ch.qos.logback.classic.filter.ThresholdFilter">
|
||||||
|
<level>INFO</level>
|
||||||
|
</filter>
|
||||||
|
<encoder>
|
||||||
|
<pattern>[%level] %msg%n</pattern>
|
||||||
|
</encoder>
|
||||||
|
</appender>
|
||||||
|
<root level="DEBUG">
|
||||||
|
<appender-ref ref="console"/>
|
||||||
|
</root>
|
||||||
|
</configuration>
|
||||||
@@ -5,39 +5,63 @@ The following table lists the command line arguments:
|
|||||||
|
|
||||||
Short | Argument Name | Parameter | Description | Requirement
|
Short | Argument Name | Parameter | Description | Requirement
|
||||||
-------|-----------------------|-----------------|-------------|------------
|
-------|-----------------------|-----------------|-------------|------------
|
||||||
\-a | \-\-app | \<name\> | The name of the application being scanned. This is a required argument. | Required
|
| \-\-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 specific file types that should be scanned by supplying a scan path of '[path]/[to]/[scan]/*.zip'. The wild card can only be used to denote any file-name with a specific extension. | Required
|
\-s | \-\-scan | \<path\> | The path to scan \- this option can be specified multiple times. It is also possible to specify Ant style paths (e.g. directory/**/*.jar). | Required
|
||||||
\-o | \-\-out | \<folder\> | The folder to write reports to. This defaults to the current directory. | Optional
|
| \-\-exclude | \<pattern\> | The path patterns to exclude from the scan \- this option can be specified multiple times. This accepts Ant style path patterns (e.g. **/exclude/**). | Optional
|
||||||
|
| \-\-symLink | \<depth\> | The depth that symbolic links will be followed; the default is 0 meaning symbolic links will not be followed. | Optional
|
||||||
|
\-o | \-\-out | \<path\> | The folder to write reports to. This defaults to the current directory. If the format is not set to ALL one could specify a specific file name. | Optional
|
||||||
\-f | \-\-format | \<format\> | The output format to write to (XML, HTML, VULN, ALL). The default is HTML. | Required
|
\-f | \-\-format | \<format\> | The output format to write to (XML, HTML, VULN, ALL). The default is HTML. | Required
|
||||||
|
| \-\-failOnCvss | \<score\> | If the score set between 0 and 10 the exit code from dependency-check will indicate if a vulnerability with a CVSS score equal to or higher was identified. | Optional
|
||||||
\-l | \-\-log | \<file\> | The file path to write verbose logging information. | Optional
|
\-l | \-\-log | \<file\> | The file path to write verbose logging information. | Optional
|
||||||
\-n | \-\-noupdate | | Disables the automatic updating of the CPE data. | Optional
|
\-n | \-\-noupdate | | Disables the automatic updating of the CPE data. | Optional
|
||||||
| \-\-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
|
\-h | \-\-help | | Print the help message. | Optional
|
||||||
| \-\-advancedHelp | | Print the advanced help message. | Optional
|
| \-\-advancedHelp | | Print the advanced help message. | Optional
|
||||||
\-v | \-\-version | | Print the version information. | 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
|
Advanced Options
|
||||||
================
|
================
|
||||||
Short | Argument Name | Parameter | Description | Default Value
|
Short | Argument Name | Parameter | Description | Default Value
|
||||||
-------|-----------------------|-----------------|-------------|---------------
|
-------|-----------------------|-----------------|----------------------------------------------------------------------------------|-------------------
|
||||||
| \-\-disableArchive | | Sets whether the Archive Analyzer will be used. | false
|
| \-\-cveUrl12Modified | \<url\> | URL for the modified CVE 1.2 | 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 [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
|
||||||
|
| \-\-disableCocoapodsAnalyzer | | Sets whether the [experimental](../analyzers/index.html) Cocoapods Analyzer will be used. | false
|
||||||
|
| \-\-disableSwiftPackageManagerAnalyzer | | Sets whether the [experimental](../analyzers/index.html) Swift Package Manager 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 [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. |
|
| \-\-zipExtensions | \<strings\> | A comma-separated list of additional file extensions to be treated like a ZIP file, the contents will be extracted and analyzed. |
|
||||||
| \-\-disableJar | | Sets whether Jar Analyzer will be used. | false
|
| \-\-disableJar | | Sets whether the Jar Analyzer will be disabled. | false
|
||||||
| \-\-disableNexus | | Sets whether Nexus Analyzer will be used. | false
|
| \-\-disableComposer | | Sets whether the [experimental](../analyzers/index.html) PHP Composer Lock File Analyzer will be disabled. | false
|
||||||
| \-\-disableNexus | | Disable the Nexus Analyzer. |
|
| \-\-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
|
||||||
| \-\-nexus | \<url\> | The url to the Nexus Server. | https://repository.sonatype.org/service/local/
|
| \-\-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
|
||||||
| \-\-nexusUsesProxy | \<true\|false\> | Whether or not the defined proxy should be used when connecting to Nexus. | true
|
| \-\-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. |
|
||||||
| \-\-disableNuspec | | Sets whether or not the .NET Nuget Nuspec Analyzer will be used. | false
|
| \-\-nexusUsesProxy | \<true\|false\> | Whether or not the defined proxy should be used when connecting to Nexus. | true
|
||||||
| \-\-disableAssembly | | Sets whether or not the .NET Assembly Analyzer should be used. | false
|
| \-\-disableNuspec | | Sets whether or not the .NET Nuget Nuspec Analyzer will be used. | false
|
||||||
| \-\-pathToMono | \<path\> | The path to Mono for .NET Assembly analysis on non-windows systems. |
|
| \-\-disableAssembly | | Sets whether or not the .NET Assembly Analyzer should be used. | false
|
||||||
| \-\-proxyserver | \<server\> | The proxy server to use when downloading resources. |
|
| \-\-mono | \<path\> | The path to Mono for .NET Assembly analysis on non-windows systems. |
|
||||||
| \-\-proxyport | \<port\> | The proxy port to use when downloading resources. |
|
| \-\-bundleAudit | | The path to the bundle-audit executable. |
|
||||||
| \-\-connectiontimeout | \<timeout\> | The connection timeout (in milliseconds) to use when downloading resources. |
|
| \-\-proxyserver | \<server\> | The proxy server to use when downloading resources; see the [proxy configuration](../data/proxy.html) page for more information. |
|
||||||
| \-\-proxypass | \<pass\> | The proxy password to use when downloading resources. |
|
| \-\-proxyport | \<port\> | The proxy port to use when downloading resources. |
|
||||||
| \-\-proxyuser | \<user\> | The proxy username to use when downloading resources. |
|
| \-\-connectiontimeout | \<timeout\> | The connection timeout (in milliseconds) to use when downloading resources. |
|
||||||
| \-\-connectionString | \<connStr\> | The connection string to the database. |
|
| \-\-proxypass | \<pass\> | The proxy password to use when downloading resources. |
|
||||||
| \-\-dbDriverName | \<driver\> | The database driver name. |
|
| \-\-proxyuser | \<user\> | The proxy username to use when downloading resources. |
|
||||||
|
| \-\-connectionString | \<connStr\> | The connection string to the database. |
|
||||||
|
| \-\-dbDriverName | \<driver\> | The database driver name. |
|
||||||
| \-\-dbDriverPath | \<path\> | The path to the database driver; note, this does not need to be set unless the JAR is outside of the class path. |
|
| \-\-dbDriverPath | \<path\> | The path to the database driver; note, this does not need to be set unless the JAR is outside of the class path. |
|
||||||
| \-\-dbPassword | \<password\> | The password for connecting to the database. |
|
| \-\-dbPassword | \<password\> | The password for connecting to the database. |
|
||||||
| \-\-dbUser | \<user\> | The username used to connect to the database. |
|
| \-\-dbUser | \<user\> | The username used to connect to the database. |
|
||||||
\-d | \-\-data | \<path\> | The location of the data directory used to store persistent data. This option should generally not be set. |
|
\-d | \-\-data | \<path\> | The location of the data directory used to store persistent data. This option should generally not be set. |
|
||||||
|
| \-\-purge | | Delete the local copy of the NVD. This is used to force a refresh of the data. |
|
||||||
36
dependency-check-cli/src/site/markdown/index.md.vm
Normal file
36
dependency-check-cli/src/site/markdown/index.md.vm
Normal file
@@ -0,0 +1,36 @@
|
|||||||
|
About
|
||||||
|
====================
|
||||||
|
OWASP dependency-check-cli is an command line tool that uses dependency-check-core to detect
|
||||||
|
publicly disclosed vulnerabilities associated with the scanned project dependencies. The tool
|
||||||
|
will generate a report listing the dependency, any identified Common Platform Enumeration (CPE)
|
||||||
|
identifiers, and the associated Common Vulnerability and Exposure (CVE) entries.
|
||||||
|
|
||||||
|
Installation & Usage
|
||||||
|
====================
|
||||||
|
Download the dependency-check command line tool [here](http://dl.bintray.com/jeremy-long/owasp/dependency-check-${project.version}-release.zip).
|
||||||
|
Extract the zip file to a location on your computer and put the 'bin' directory into the
|
||||||
|
path environment variable.
|
||||||
|
|
||||||
|
#set( $H = '#' )
|
||||||
|
|
||||||
|
$H$H$H Homebrew
|
||||||
|
$ brew install dependency-check
|
||||||
|
|
||||||
|
This puts an executable `dependency-check` script in the `/bin` directory of
|
||||||
|
your homebrew installation.
|
||||||
|
|
||||||
|
To scan a folder on the system you can run:
|
||||||
|
|
||||||
|
$H$H$H Windows
|
||||||
|
dependency-check.bat --project "My App Name" --scan "c:\java\application\lib"
|
||||||
|
|
||||||
|
$H$H$H *nix
|
||||||
|
dependency-check.sh --project "My App Name" --scan "/java/application/lib"
|
||||||
|
|
||||||
|
To view the command line arguments, see the <a href="arguments.html">arguments page</a>, or you can run:
|
||||||
|
|
||||||
|
$H$H$H Windows
|
||||||
|
dependency-check.bat --help
|
||||||
|
|
||||||
|
$H$H$H *nix
|
||||||
|
dependency-check.sh --help
|
||||||
@@ -1,25 +0,0 @@
|
|||||||
Installation & Usage
|
|
||||||
====================
|
|
||||||
Download the dependency-check command line tool [here](http://dl.bintray.com/jeremy-long/owasp/dependency-check-${project.version}-release.zip).
|
|
||||||
Extract the zip file to a location on your computer and put the 'bin' directory into the
|
|
||||||
path environment variable. On \*nix systems you will likely need to make the shell
|
|
||||||
script executable:
|
|
||||||
|
|
||||||
$ chmod +777 dependency-check.sh
|
|
||||||
|
|
||||||
To scan a folder on the system you can run:
|
|
||||||
#set( $H = '#' )
|
|
||||||
|
|
||||||
$H$H$H Windows
|
|
||||||
dependency-check.bat --app "My App Name" --scan "c:\java\application\lib"
|
|
||||||
|
|
||||||
$H$H$H *nix
|
|
||||||
dependency-check.sh --app "My App Name" --scan "/java/application/lib"
|
|
||||||
|
|
||||||
To view the command line arguments, see the <a href="arguments.html">arguments page</a>, or you can run:
|
|
||||||
|
|
||||||
$H$H$H Windows
|
|
||||||
dependency-check.bat --help
|
|
||||||
|
|
||||||
$H$H$H *nix
|
|
||||||
dependency-check.sh --help
|
|
||||||
File diff suppressed because one or more lines are too long
|
After Width: | Height: | Size: 10 KiB |
@@ -18,17 +18,18 @@ Copyright (c) 2013 Jeremy Long. All Rights Reserved.
|
|||||||
-->
|
-->
|
||||||
<project name="dependency-check-cli">
|
<project name="dependency-check-cli">
|
||||||
<bannerLeft>
|
<bannerLeft>
|
||||||
<name>dependency-check-cli</name>
|
<name>OWASP dependency-check-cli</name>
|
||||||
|
<alt>OWASP dependency-check-cli</alt>
|
||||||
|
<src>./images/dc-cli.svg</src>
|
||||||
</bannerLeft>
|
</bannerLeft>
|
||||||
<body>
|
<body>
|
||||||
<breadcrumbs>
|
<breadcrumbs>
|
||||||
<item name="dependency-check" href="../index.html"/>
|
<item name="dependency-check" href="../index.html"/>
|
||||||
</breadcrumbs>
|
</breadcrumbs>
|
||||||
<menu name="Getting Started">
|
<menu name="Getting Started">
|
||||||
<item name="Installation" href="installation.html"/>
|
<item name="Installation" href="index.html"/>
|
||||||
<item name="Configuration" href="arguments.html"/>
|
<item name="Configuration" href="arguments.html"/>
|
||||||
</menu>
|
</menu>
|
||||||
<menu ref="Project Documentation" />
|
|
||||||
<menu ref="reports" />
|
<menu ref="reports" />
|
||||||
</body>
|
</body>
|
||||||
</project>
|
</project>
|
||||||
@@ -0,0 +1,51 @@
|
|||||||
|
/*
|
||||||
|
* This file is part of dependency-check-core.
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*
|
||||||
|
* Copyright (c) 2015 The OWASP Foundatio. All Rights Reserved.
|
||||||
|
*/
|
||||||
|
package org.owasp.dependencycheck;
|
||||||
|
|
||||||
|
import org.junit.Test;
|
||||||
|
import static org.junit.Assert.*;
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* @author jeremy
|
||||||
|
*/
|
||||||
|
public class AppTest {
|
||||||
|
/**
|
||||||
|
* Test of ensureCanonicalPath method, of class App.
|
||||||
|
*/
|
||||||
|
@Test
|
||||||
|
public void testEnsureCanonicalPath() {
|
||||||
|
String file = "../*.jar";
|
||||||
|
App instance = new App();
|
||||||
|
String result = instance.ensureCanonicalPath(file);
|
||||||
|
assertFalse(result.contains(".."));
|
||||||
|
assertTrue(result.endsWith("*.jar"));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Test of ensureCanonicalPath method, of class App.
|
||||||
|
*/
|
||||||
|
@Test
|
||||||
|
public void testEnsureCanonicalPath2() {
|
||||||
|
String file = "../some/skip/../path/file.txt";
|
||||||
|
App instance = new App();
|
||||||
|
String expResult = "/some/path/file.txt";
|
||||||
|
String result = instance.ensureCanonicalPath(file);
|
||||||
|
assertTrue("result=" + result, result.endsWith(expResult));
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -15,7 +15,7 @@
|
|||||||
*
|
*
|
||||||
* Copyright (c) 2012 Jeremy Long. All Rights Reserved.
|
* Copyright (c) 2012 Jeremy Long. All Rights Reserved.
|
||||||
*/
|
*/
|
||||||
package org.owasp.dependencycheck.cli;
|
package org.owasp.dependencycheck;
|
||||||
|
|
||||||
import java.io.ByteArrayOutputStream;
|
import java.io.ByteArrayOutputStream;
|
||||||
import java.io.File;
|
import java.io.File;
|
||||||
@@ -23,17 +23,15 @@ import java.io.FileNotFoundException;
|
|||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.io.PrintStream;
|
import java.io.PrintStream;
|
||||||
import org.apache.commons.cli.ParseException;
|
import org.apache.commons.cli.ParseException;
|
||||||
import org.junit.After;
|
|
||||||
import org.junit.AfterClass;
|
import org.junit.AfterClass;
|
||||||
import org.junit.Assert;
|
import org.junit.Assert;
|
||||||
import org.junit.Before;
|
|
||||||
import org.junit.BeforeClass;
|
import org.junit.BeforeClass;
|
||||||
import org.junit.Test;
|
import org.junit.Test;
|
||||||
import org.owasp.dependencycheck.utils.Settings;
|
import org.owasp.dependencycheck.utils.Settings;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
*
|
*
|
||||||
* @author Jeremy Long <jeremy.long@owasp.org>
|
* @author Jeremy Long
|
||||||
*/
|
*/
|
||||||
public class CliParserTest {
|
public class CliParserTest {
|
||||||
|
|
||||||
@@ -47,14 +45,6 @@ public class CliParserTest {
|
|||||||
Settings.cleanup(true);
|
Settings.cleanup(true);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Before
|
|
||||||
public void setUp() throws Exception {
|
|
||||||
}
|
|
||||||
|
|
||||||
@After
|
|
||||||
public void tearDown() throws Exception {
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Test of parse method, of class CliParser.
|
* Test of parse method, of class CliParser.
|
||||||
*
|
*
|
||||||
@@ -114,6 +104,63 @@ public class CliParserTest {
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Test of parse method with failOnCVSS without an argument
|
||||||
|
*
|
||||||
|
* @throws Exception thrown when an exception occurs.
|
||||||
|
*/
|
||||||
|
@Test
|
||||||
|
public void testParse_failOnCVSSNoArg() throws Exception {
|
||||||
|
|
||||||
|
String[] args = {"--failOnCVSS"};
|
||||||
|
|
||||||
|
CliParser instance = new CliParser();
|
||||||
|
try {
|
||||||
|
instance.parse(args);
|
||||||
|
} catch (ParseException ex) {
|
||||||
|
Assert.assertTrue(ex.getMessage().contains("Missing argument"));
|
||||||
|
}
|
||||||
|
Assert.assertFalse(instance.isGetVersion());
|
||||||
|
Assert.assertFalse(instance.isGetHelp());
|
||||||
|
Assert.assertFalse(instance.isRunScan());
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Test of parse method with failOnCVSS invalid argument. It should default to 11
|
||||||
|
*
|
||||||
|
* @throws Exception thrown when an exception occurs.
|
||||||
|
*/
|
||||||
|
@Test
|
||||||
|
public void testParse_failOnCVSSInvalidArgument() throws Exception {
|
||||||
|
|
||||||
|
String[] args = {"--failOnCVSS","bad"};
|
||||||
|
|
||||||
|
CliParser instance = new CliParser();
|
||||||
|
instance.parse(args);
|
||||||
|
Assert.assertEquals("Default should be 11", 11, instance.getFailOnCVSS());
|
||||||
|
Assert.assertFalse(instance.isGetVersion());
|
||||||
|
Assert.assertFalse(instance.isGetHelp());
|
||||||
|
Assert.assertFalse(instance.isRunScan());
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Test of parse method with failOnCVSS invalid argument. It should default to 11
|
||||||
|
*
|
||||||
|
* @throws Exception thrown when an exception occurs.
|
||||||
|
*/
|
||||||
|
@Test
|
||||||
|
public void testParse_failOnCVSSValidArgument() throws Exception {
|
||||||
|
|
||||||
|
String[] args = {"--failOnCVSS","6"};
|
||||||
|
|
||||||
|
CliParser instance = new CliParser();
|
||||||
|
instance.parse(args);
|
||||||
|
Assert.assertEquals(6, instance.getFailOnCVSS());
|
||||||
|
Assert.assertFalse(instance.isGetVersion());
|
||||||
|
Assert.assertFalse(instance.isGetHelp());
|
||||||
|
Assert.assertFalse(instance.isRunScan());
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Test of parse method with jar and cpe args, of class CliParser.
|
* Test of parse method with jar and cpe args, of class CliParser.
|
||||||
*
|
*
|
||||||
@@ -195,7 +242,7 @@ public class CliParserTest {
|
|||||||
*/
|
*/
|
||||||
@Test
|
@Test
|
||||||
public void testParse_scan_withFileExists() throws Exception {
|
public void testParse_scan_withFileExists() throws Exception {
|
||||||
File path = new File(this.getClass().getClassLoader().getResource("checkSumTest.file").getPath());
|
File path = new File(this.getClass().getClassLoader().getResource("checkSumTest.file").toURI().getPath());
|
||||||
String[] args = {"-scan", path.getCanonicalPath(), "-out", "./", "-app", "test"};
|
String[] args = {"-scan", path.getCanonicalPath(), "-out", "./", "-app", "test"};
|
||||||
|
|
||||||
CliParser instance = new CliParser();
|
CliParser instance = new CliParser();
|
||||||
@@ -17,7 +17,7 @@ Copyright & License
|
|||||||
|
|
||||||
Dependency-Check is Copyright (c) 2012-2014 Jeremy Long. All Rights Reserved.
|
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.
|
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
|
[wiki]: https://github.com/jeremylong/DependencyCheck/wiki
|
||||||
[subscribe]: mailto:dependency-check+subscribe@googlegroups.com
|
[subscribe]: mailto:dependency-check+subscribe@googlegroups.com
|
||||||
[post]: mailto:dependency-check@googlegroups.com
|
[post]: mailto:dependency-check@googlegroups.com
|
||||||
[notices]: https://github.com/jeremylong/DependencyCheck/blob/master/NOTICES.txt
|
[notices]: https://raw.githubusercontent.com/jeremylong/DependencyCheck/master/NOTICE.txt
|
||||||
@@ -20,13 +20,14 @@ Copyright (c) 2012 Jeremy Long. All Rights Reserved.
|
|||||||
<parent>
|
<parent>
|
||||||
<groupId>org.owasp</groupId>
|
<groupId>org.owasp</groupId>
|
||||||
<artifactId>dependency-check-parent</artifactId>
|
<artifactId>dependency-check-parent</artifactId>
|
||||||
<version>1.2.3</version>
|
<version>1.4.6-SNAPSHOT</version>
|
||||||
</parent>
|
</parent>
|
||||||
|
|
||||||
<artifactId>dependency-check-core</artifactId>
|
<artifactId>dependency-check-core</artifactId>
|
||||||
<packaging>jar</packaging>
|
<packaging>jar</packaging>
|
||||||
|
|
||||||
<name>Dependency-Check Core</name>
|
<name>Dependency-Check Core</name>
|
||||||
|
<description>dependency-check-core is the engine and reporting tool used to identify and report if there are any known, publicly disclosed vulnerabilities in the scanned project's dependencies. The engine extracts meta-data from the dependencies and uses this to do fuzzy key-word matching against the Common Platfrom Enumeration (CPE), if any CPE identifiers are found the associated Common Vulnerability and Exposure (CVE) entries are added to the generated report.</description>
|
||||||
<!-- begin copy from http://minds.coremedia.com/2012/09/11/problem-solved-deploy-multi-module-maven-project-site-as-github-pages/ -->
|
<!-- begin copy from http://minds.coremedia.com/2012/09/11/problem-solved-deploy-multi-module-maven-project-site-as-github-pages/ -->
|
||||||
<distributionManagement>
|
<distributionManagement>
|
||||||
<site>
|
<site>
|
||||||
@@ -82,9 +83,6 @@ Copyright (c) 2012 Jeremy Long. All Rights Reserved.
|
|||||||
</testResource>
|
</testResource>
|
||||||
<testResource>
|
<testResource>
|
||||||
<directory>${basedir}/src/test/resources</directory>
|
<directory>${basedir}/src/test/resources</directory>
|
||||||
<excludes>
|
|
||||||
<exclude>**/mysql-connector-java-5.1.27-bin.jar</exclude>
|
|
||||||
</excludes>
|
|
||||||
<filtering>false</filtering>
|
<filtering>false</filtering>
|
||||||
</testResource>
|
</testResource>
|
||||||
</testResources>
|
</testResources>
|
||||||
@@ -92,7 +90,6 @@ Copyright (c) 2012 Jeremy Long. All Rights Reserved.
|
|||||||
<plugin>
|
<plugin>
|
||||||
<groupId>org.apache.maven.plugins</groupId>
|
<groupId>org.apache.maven.plugins</groupId>
|
||||||
<artifactId>maven-dependency-plugin</artifactId>
|
<artifactId>maven-dependency-plugin</artifactId>
|
||||||
<version>2.8</version>
|
|
||||||
<executions>
|
<executions>
|
||||||
<execution>
|
<execution>
|
||||||
<phase>generate-resources</phase>
|
<phase>generate-resources</phase>
|
||||||
@@ -101,7 +98,7 @@ Copyright (c) 2012 Jeremy Long. All Rights Reserved.
|
|||||||
</goals>
|
</goals>
|
||||||
<configuration>
|
<configuration>
|
||||||
<outputDirectory>${project.build.directory}/test-classes</outputDirectory>
|
<outputDirectory>${project.build.directory}/test-classes</outputDirectory>
|
||||||
<includeScope>provided</includeScope>
|
<includeScope>test</includeScope>
|
||||||
</configuration>
|
</configuration>
|
||||||
</execution>
|
</execution>
|
||||||
</executions>
|
</executions>
|
||||||
@@ -109,41 +106,27 @@ Copyright (c) 2012 Jeremy Long. All Rights Reserved.
|
|||||||
<plugin>
|
<plugin>
|
||||||
<groupId>org.apache.maven.plugins</groupId>
|
<groupId>org.apache.maven.plugins</groupId>
|
||||||
<artifactId>maven-jar-plugin</artifactId>
|
<artifactId>maven-jar-plugin</artifactId>
|
||||||
<version>2.4</version>
|
|
||||||
<executions>
|
<executions>
|
||||||
<execution>
|
|
||||||
<id>jar</id>
|
|
||||||
<phase>package</phase>
|
|
||||||
<goals>
|
|
||||||
<goal>jar</goal>
|
|
||||||
</goals>
|
|
||||||
</execution>
|
|
||||||
<execution>
|
<execution>
|
||||||
<id>test-jar</id>
|
<id>test-jar</id>
|
||||||
<phase>package</phase>
|
<phase>package</phase>
|
||||||
<goals>
|
<goals>
|
||||||
<goal>test-jar</goal>
|
<goal>test-jar</goal>
|
||||||
</goals>
|
</goals>
|
||||||
|
<configuration>
|
||||||
|
<includes>
|
||||||
|
<include>**/*.class</include>
|
||||||
|
</includes>
|
||||||
|
</configuration>
|
||||||
</execution>
|
</execution>
|
||||||
</executions>
|
</executions>
|
||||||
<configuration>
|
|
||||||
<archive>
|
|
||||||
<manifest>
|
|
||||||
<addDefaultImplementationEntries>true</addDefaultImplementationEntries>
|
|
||||||
</manifest>
|
|
||||||
</archive>
|
|
||||||
<excludes>
|
|
||||||
<exclude>**/checkstyle*</exclude>
|
|
||||||
</excludes>
|
|
||||||
</configuration>
|
|
||||||
</plugin>
|
</plugin>
|
||||||
<plugin>
|
<plugin>
|
||||||
<groupId>org.codehaus.mojo</groupId>
|
<groupId>org.codehaus.mojo</groupId>
|
||||||
<artifactId>cobertura-maven-plugin</artifactId>
|
<artifactId>cobertura-maven-plugin</artifactId>
|
||||||
<version>2.6</version>
|
|
||||||
<configuration>
|
<configuration>
|
||||||
<instrumentation>
|
<instrumentation>
|
||||||
<ignoreTrivial>true</ignoreTrivial>
|
<!--ignoreTrivial>true</ignoreTrivial-->
|
||||||
<ignores>
|
<ignores>
|
||||||
<ignore>.*\$KEYS\.class</ignore>
|
<ignore>.*\$KEYS\.class</ignore>
|
||||||
<ignore>.*\$Element\.class</ignore>
|
<ignore>.*\$Element\.class</ignore>
|
||||||
@@ -191,8 +174,8 @@ Copyright (c) 2012 Jeremy Long. All Rights Reserved.
|
|||||||
<plugin>
|
<plugin>
|
||||||
<groupId>org.apache.maven.plugins</groupId>
|
<groupId>org.apache.maven.plugins</groupId>
|
||||||
<artifactId>maven-surefire-plugin</artifactId>
|
<artifactId>maven-surefire-plugin</artifactId>
|
||||||
<version>2.16</version>
|
|
||||||
<configuration>
|
<configuration>
|
||||||
|
<argLine>-Dfile.encoding=UTF-8</argLine>
|
||||||
<systemProperties>
|
<systemProperties>
|
||||||
<property>
|
<property>
|
||||||
<name>data.directory</name>
|
<name>data.directory</name>
|
||||||
@@ -212,7 +195,6 @@ Copyright (c) 2012 Jeremy Long. All Rights Reserved.
|
|||||||
<plugin>
|
<plugin>
|
||||||
<groupId>org.apache.maven.plugins</groupId>
|
<groupId>org.apache.maven.plugins</groupId>
|
||||||
<artifactId>maven-failsafe-plugin</artifactId>
|
<artifactId>maven-failsafe-plugin</artifactId>
|
||||||
<version>2.16</version>
|
|
||||||
<configuration>
|
<configuration>
|
||||||
<systemProperties>
|
<systemProperties>
|
||||||
<property>
|
<property>
|
||||||
@@ -223,186 +205,81 @@ Copyright (c) 2012 Jeremy Long. All Rights Reserved.
|
|||||||
<name>temp.directory</name>
|
<name>temp.directory</name>
|
||||||
<value>${project.build.directory}/temp</value>
|
<value>${project.build.directory}/temp</value>
|
||||||
</property>
|
</property>
|
||||||
|
|
||||||
</systemProperties>
|
</systemProperties>
|
||||||
<includes>
|
|
||||||
<include>**/*IntegrationTest.java</include>
|
|
||||||
</includes>
|
|
||||||
</configuration>
|
|
||||||
<executions>
|
|
||||||
<execution>
|
|
||||||
<goals>
|
|
||||||
<goal>integration-test</goal>
|
|
||||||
<goal>verify</goal>
|
|
||||||
</goals>
|
|
||||||
</execution>
|
|
||||||
</executions>
|
|
||||||
</plugin>
|
|
||||||
<plugin>
|
|
||||||
<groupId>org.apache.maven.plugins</groupId>
|
|
||||||
<artifactId>maven-site-plugin</artifactId>
|
|
||||||
<version>3.3</version>
|
|
||||||
<dependencies>
|
|
||||||
<dependency>
|
|
||||||
<groupId>org.apache.maven.doxia</groupId>
|
|
||||||
<artifactId>doxia-module-markdown</artifactId>
|
|
||||||
<version>1.5</version>
|
|
||||||
</dependency>
|
|
||||||
</dependencies>
|
|
||||||
<configuration>
|
|
||||||
<skipDeploy>true</skipDeploy>
|
|
||||||
<reportPlugins>
|
|
||||||
<plugin>
|
|
||||||
<groupId>org.apache.maven.plugins</groupId>
|
|
||||||
<artifactId>maven-project-info-reports-plugin</artifactId>
|
|
||||||
<version>2.7</version>
|
|
||||||
<reportSets>
|
|
||||||
<reportSet>
|
|
||||||
<reports>
|
|
||||||
<report>index</report>
|
|
||||||
<report>summary</report>
|
|
||||||
<report>license</report>
|
|
||||||
<report>help</report>
|
|
||||||
</reports>
|
|
||||||
</reportSet>
|
|
||||||
</reportSets>
|
|
||||||
</plugin>
|
|
||||||
<plugin>
|
|
||||||
<groupId>org.apache.maven.plugins</groupId>
|
|
||||||
<artifactId>maven-javadoc-plugin</artifactId>
|
|
||||||
<version>2.9.1</version>
|
|
||||||
<reportSets>
|
|
||||||
<reportSet>
|
|
||||||
<id>default</id>
|
|
||||||
<reports>
|
|
||||||
<report>javadoc</report>
|
|
||||||
</reports>
|
|
||||||
</reportSet>
|
|
||||||
</reportSets>
|
|
||||||
</plugin>
|
|
||||||
<plugin>
|
|
||||||
<groupId>org.codehaus.mojo</groupId>
|
|
||||||
<artifactId>versions-maven-plugin</artifactId>
|
|
||||||
<version>2.1</version>
|
|
||||||
<reportSets>
|
|
||||||
<reportSet>
|
|
||||||
<reports>
|
|
||||||
<report>dependency-updates-report</report>
|
|
||||||
<report>plugin-updates-report</report>
|
|
||||||
</reports>
|
|
||||||
</reportSet>
|
|
||||||
</reportSets>
|
|
||||||
</plugin>
|
|
||||||
<plugin>
|
|
||||||
<groupId>org.apache.maven.plugins</groupId>
|
|
||||||
<artifactId>maven-jxr-plugin</artifactId>
|
|
||||||
<version>2.4</version>
|
|
||||||
</plugin>
|
|
||||||
<plugin>
|
|
||||||
<groupId>org.codehaus.mojo</groupId>
|
|
||||||
<artifactId>cobertura-maven-plugin</artifactId>
|
|
||||||
<version>2.6</version>
|
|
||||||
</plugin>
|
|
||||||
<plugin>
|
|
||||||
<groupId>org.apache.maven.plugins</groupId>
|
|
||||||
<artifactId>maven-surefire-report-plugin</artifactId>
|
|
||||||
<version>2.16</version>
|
|
||||||
<reportSets>
|
|
||||||
<reportSet>
|
|
||||||
<reports>
|
|
||||||
<report>report-only</report>
|
|
||||||
</reports>
|
|
||||||
</reportSet>
|
|
||||||
<reportSet>
|
|
||||||
<id>integration-tests</id>
|
|
||||||
<reports>
|
|
||||||
<report>report-only</report>
|
|
||||||
<report>failsafe-report-only</report>
|
|
||||||
</reports>
|
|
||||||
</reportSet>
|
|
||||||
</reportSets>
|
|
||||||
</plugin>
|
|
||||||
<plugin>
|
|
||||||
<groupId>org.codehaus.mojo</groupId>
|
|
||||||
<artifactId>taglist-maven-plugin</artifactId>
|
|
||||||
<version>2.4</version>
|
|
||||||
<configuration>
|
|
||||||
<tagListOptions>
|
|
||||||
<tagClasses>
|
|
||||||
<tagClass>
|
|
||||||
<displayName>Todo Work</displayName>
|
|
||||||
<tags>
|
|
||||||
<tag>
|
|
||||||
<matchString>todo</matchString>
|
|
||||||
<matchType>ignoreCase</matchType>
|
|
||||||
</tag>
|
|
||||||
<tag>
|
|
||||||
<matchString>FIXME</matchString>
|
|
||||||
<matchType>exact</matchType>
|
|
||||||
</tag>
|
|
||||||
</tags>
|
|
||||||
</tagClass>
|
|
||||||
</tagClasses>
|
|
||||||
</tagListOptions>
|
|
||||||
</configuration>
|
|
||||||
</plugin>
|
|
||||||
<plugin>
|
|
||||||
<groupId>org.apache.maven.plugins</groupId>
|
|
||||||
<artifactId>maven-checkstyle-plugin</artifactId>
|
|
||||||
<version>2.11</version>
|
|
||||||
<configuration>
|
|
||||||
<enableRulesSummary>false</enableRulesSummary>
|
|
||||||
<configLocation>${basedir}/../src/main/config/checkstyle-checks.xml</configLocation>
|
|
||||||
<headerLocation>${basedir}/../src/main/config/checkstyle-header.txt</headerLocation>
|
|
||||||
<suppressionsLocation>${basedir}/../src/main/config/checkstyle-suppressions.xml</suppressionsLocation>
|
|
||||||
<suppressionsFileExpression>checkstyle.suppressions.file</suppressionsFileExpression>
|
|
||||||
</configuration>
|
|
||||||
</plugin>
|
|
||||||
<plugin>
|
|
||||||
<groupId>org.apache.maven.plugins</groupId>
|
|
||||||
<artifactId>maven-pmd-plugin</artifactId>
|
|
||||||
<version>3.1</version>
|
|
||||||
<configuration>
|
|
||||||
<targetJdk>1.6</targetJdk>
|
|
||||||
<linkXref>true</linkXref>
|
|
||||||
<sourceEncoding>utf-8</sourceEncoding>
|
|
||||||
<excludes>
|
|
||||||
<exclude>**/generated/*.java</exclude>
|
|
||||||
</excludes>
|
|
||||||
<rulesets>
|
|
||||||
<ruleset>../src/main/config/dcrules.xml</ruleset>
|
|
||||||
<ruleset>/rulesets/java/basic.xml</ruleset>
|
|
||||||
<ruleset>/rulesets/java/imports.xml</ruleset>
|
|
||||||
<ruleset>/rulesets/java/unusedcode.xml</ruleset>
|
|
||||||
</rulesets>
|
|
||||||
</configuration>
|
|
||||||
</plugin>
|
|
||||||
<plugin>
|
|
||||||
<groupId>org.codehaus.mojo</groupId>
|
|
||||||
<artifactId>findbugs-maven-plugin</artifactId>
|
|
||||||
<version>2.5.3</version>
|
|
||||||
</plugin>
|
|
||||||
<dependency>
|
|
||||||
<groupId>org.codehaus.mojo</groupId>
|
|
||||||
<artifactId>javancss-maven-plugin</artifactId>
|
|
||||||
<version>2.0</version>
|
|
||||||
</dependency>
|
|
||||||
</reportPlugins>
|
|
||||||
</configuration>
|
|
||||||
</plugin>
|
|
||||||
<plugin>
|
|
||||||
<groupId>org.apache.maven.plugins</groupId>
|
|
||||||
<artifactId>maven-compiler-plugin</artifactId>
|
|
||||||
<version>3.1</version>
|
|
||||||
<configuration>
|
|
||||||
<showDeprecation>false</showDeprecation>
|
|
||||||
<source>1.6</source>
|
|
||||||
<target>1.6</target>
|
|
||||||
</configuration>
|
</configuration>
|
||||||
</plugin>
|
</plugin>
|
||||||
</plugins>
|
</plugins>
|
||||||
</build>
|
</build>
|
||||||
|
<reporting>
|
||||||
|
<plugins>
|
||||||
|
<plugin>
|
||||||
|
<groupId>org.apache.maven.plugins</groupId>
|
||||||
|
<artifactId>maven-surefire-report-plugin</artifactId>
|
||||||
|
<reportSets>
|
||||||
|
<reportSet>
|
||||||
|
<id>integration-tests</id>
|
||||||
|
<reports>
|
||||||
|
<report>report-only</report>
|
||||||
|
<report>failsafe-report-only</report>
|
||||||
|
</reports>
|
||||||
|
</reportSet>
|
||||||
|
</reportSets>
|
||||||
|
</plugin>
|
||||||
|
<plugin>
|
||||||
|
<groupId>org.apache.maven.plugins</groupId>
|
||||||
|
<artifactId>maven-checkstyle-plugin</artifactId>
|
||||||
|
<version>${reporting.checkstyle-plugin.version}</version>
|
||||||
|
<configuration>
|
||||||
|
<enableRulesSummary>false</enableRulesSummary>
|
||||||
|
<enableFilesSummary>false</enableFilesSummary>
|
||||||
|
<configLocation>${basedir}/../src/main/config/checkstyle-checks.xml</configLocation>
|
||||||
|
<headerLocation>${basedir}/../src/main/config/checkstyle-header.txt</headerLocation>
|
||||||
|
<suppressionsLocation>${basedir}/../src/main/config/checkstyle-suppressions.xml</suppressionsLocation>
|
||||||
|
<suppressionsFileExpression>checkstyle.suppressions.file</suppressionsFileExpression>
|
||||||
|
</configuration>
|
||||||
|
</plugin>
|
||||||
|
<plugin>
|
||||||
|
<groupId>org.apache.maven.plugins</groupId>
|
||||||
|
<artifactId>maven-pmd-plugin</artifactId>
|
||||||
|
<version>${reporting.pmd-plugin.version}</version>
|
||||||
|
<configuration>
|
||||||
|
<targetJdk>1.6</targetJdk>
|
||||||
|
<linkXRef>true</linkXRef>
|
||||||
|
<sourceEncoding>utf-8</sourceEncoding>
|
||||||
|
<excludes>
|
||||||
|
<exclude>**/generated/*.java</exclude>
|
||||||
|
</excludes>
|
||||||
|
<rulesets>
|
||||||
|
<ruleset>../src/main/config/dcrules.xml</ruleset>
|
||||||
|
<ruleset>/rulesets/java/basic.xml</ruleset>
|
||||||
|
<ruleset>/rulesets/java/imports.xml</ruleset>
|
||||||
|
<ruleset>/rulesets/java/unusedcode.xml</ruleset>
|
||||||
|
</rulesets>
|
||||||
|
</configuration>
|
||||||
|
</plugin>
|
||||||
|
</plugins>
|
||||||
|
</reporting>
|
||||||
<dependencies>
|
<dependencies>
|
||||||
|
<!-- Note, to stay compatible with Jenkins installations only JARs compiled to 1.6 can be used -->
|
||||||
|
<dependency>
|
||||||
|
<groupId>joda-time</groupId>
|
||||||
|
<artifactId>joda-time</artifactId>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>com.google.code.findbugs</groupId>
|
||||||
|
<artifactId>annotations</artifactId>
|
||||||
|
<optional>true</optional>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.slf4j</groupId>
|
||||||
|
<artifactId>slf4j-api</artifactId>
|
||||||
|
</dependency>
|
||||||
|
<!-- Set this to test so that each project that uses this has to have its own implementation of SLF4J -->
|
||||||
|
<dependency>
|
||||||
|
<groupId>ch.qos.logback</groupId>
|
||||||
|
<artifactId>logback-classic</artifactId>
|
||||||
|
<scope>test</scope>
|
||||||
|
</dependency>
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>org.owasp</groupId>
|
<groupId>org.owasp</groupId>
|
||||||
<artifactId>dependency-check-utils</artifactId>
|
<artifactId>dependency-check-utils</artifactId>
|
||||||
@@ -411,172 +288,120 @@ Copyright (c) 2012 Jeremy Long. All Rights Reserved.
|
|||||||
<dependency>
|
<dependency>
|
||||||
<groupId>org.apache.lucene</groupId>
|
<groupId>org.apache.lucene</groupId>
|
||||||
<artifactId>lucene-test-framework</artifactId>
|
<artifactId>lucene-test-framework</artifactId>
|
||||||
<version>4.3.1</version>
|
|
||||||
<scope>test</scope>
|
<scope>test</scope>
|
||||||
</dependency>
|
</dependency>
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>com.google.code.findbugs</groupId>
|
<groupId>org.jmockit</groupId>
|
||||||
<artifactId>annotations</artifactId>
|
<artifactId>jmockit</artifactId>
|
||||||
<version>2.0.1</version>
|
<scope>test</scope>
|
||||||
<optional>true</optional>
|
|
||||||
</dependency>
|
|
||||||
<dependency>
|
|
||||||
<groupId>commons-cli</groupId>
|
|
||||||
<artifactId>commons-cli</artifactId>
|
|
||||||
<version>1.2</version>
|
|
||||||
</dependency>
|
</dependency>
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>org.apache.commons</groupId>
|
<groupId>org.apache.commons</groupId>
|
||||||
<artifactId>commons-compress</artifactId>
|
<artifactId>commons-compress</artifactId>
|
||||||
<version>1.8</version>
|
|
||||||
</dependency>
|
</dependency>
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>commons-io</groupId>
|
<groupId>commons-io</groupId>
|
||||||
<artifactId>commons-io</artifactId>
|
<artifactId>commons-io</artifactId>
|
||||||
<version>2.4</version>
|
|
||||||
</dependency>
|
</dependency>
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>commons-lang</groupId>
|
<groupId>org.apache.commons</groupId>
|
||||||
<artifactId>commons-lang</artifactId>
|
<artifactId>commons-lang3</artifactId>
|
||||||
<version>2.5</version>
|
|
||||||
</dependency>
|
</dependency>
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>org.apache.lucene</groupId>
|
<groupId>org.apache.lucene</groupId>
|
||||||
<artifactId>lucene-core</artifactId>
|
<artifactId>lucene-core</artifactId>
|
||||||
<version>4.5.1</version>
|
|
||||||
</dependency>
|
</dependency>
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>org.apache.lucene</groupId>
|
<groupId>org.apache.lucene</groupId>
|
||||||
<artifactId>lucene-analyzers-common</artifactId>
|
<artifactId>lucene-analyzers-common</artifactId>
|
||||||
<version>4.5.1</version>
|
|
||||||
</dependency>
|
</dependency>
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>org.apache.lucene</groupId>
|
<groupId>org.apache.lucene</groupId>
|
||||||
<artifactId>lucene-queryparser</artifactId>
|
<artifactId>lucene-queryparser</artifactId>
|
||||||
<version>4.5.1</version>
|
|
||||||
</dependency>
|
</dependency>
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>org.apache.velocity</groupId>
|
<groupId>org.apache.velocity</groupId>
|
||||||
<artifactId>velocity</artifactId>
|
<artifactId>velocity</artifactId>
|
||||||
<version>1.7</version>
|
|
||||||
</dependency>
|
|
||||||
<dependency>
|
|
||||||
<groupId>org.apache.velocity</groupId>
|
|
||||||
<artifactId>velocity-tools</artifactId>
|
|
||||||
<version>2.0</version>
|
|
||||||
<!-- very limited use of the velocity-tools, not all of the dependencies are needed-->
|
|
||||||
<exclusions>
|
|
||||||
<exclusion>
|
|
||||||
<groupId>commons-chain</groupId>
|
|
||||||
<artifactId>commons-chain</artifactId>
|
|
||||||
</exclusion>
|
|
||||||
<exclusion>
|
|
||||||
<groupId>javax.servlet</groupId>
|
|
||||||
<artifactId>servlet-api</artifactId>
|
|
||||||
</exclusion>
|
|
||||||
<exclusion>
|
|
||||||
<groupId>commons-validator</groupId>
|
|
||||||
<artifactId>commons-validator</artifactId>
|
|
||||||
</exclusion>
|
|
||||||
<exclusion>
|
|
||||||
<groupId>dom4j</groupId>
|
|
||||||
<artifactId>dom4j</artifactId>
|
|
||||||
</exclusion>
|
|
||||||
<exclusion>
|
|
||||||
<groupId>sslext</groupId>
|
|
||||||
<artifactId>sslext</artifactId>
|
|
||||||
</exclusion>
|
|
||||||
<exclusion>
|
|
||||||
<groupId>org.apache.struts</groupId>
|
|
||||||
<artifactId>struts-core</artifactId>
|
|
||||||
</exclusion>
|
|
||||||
<exclusion>
|
|
||||||
<groupId>antlr</groupId>
|
|
||||||
<artifactId>antlr</artifactId>
|
|
||||||
</exclusion>
|
|
||||||
<exclusion>
|
|
||||||
<groupId>org.apache.struts</groupId>
|
|
||||||
<artifactId>struts-taglib</artifactId>
|
|
||||||
</exclusion>
|
|
||||||
<exclusion>
|
|
||||||
<groupId>org.apache.struts</groupId>
|
|
||||||
<artifactId>struts-tiles</artifactId>
|
|
||||||
</exclusion>
|
|
||||||
</exclusions>
|
|
||||||
</dependency>
|
</dependency>
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>com.h2database</groupId>
|
<groupId>com.h2database</groupId>
|
||||||
<artifactId>h2</artifactId>
|
<artifactId>h2</artifactId>
|
||||||
<version>1.3.172</version>
|
<scope>runtime</scope>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.glassfish</groupId>
|
||||||
|
<artifactId>javax.json</artifactId>
|
||||||
</dependency>
|
</dependency>
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>org.jsoup</groupId>
|
<groupId>org.jsoup</groupId>
|
||||||
<artifactId>jsoup</artifactId>
|
<artifactId>jsoup</artifactId>
|
||||||
<version>1.7.2</version>
|
</dependency>
|
||||||
<type>jar</type>
|
<dependency>
|
||||||
|
<groupId>com.sun.mail</groupId>
|
||||||
|
<artifactId>mailapi</artifactId>
|
||||||
</dependency>
|
</dependency>
|
||||||
<!-- The following dependencies are only used during testing -->
|
<!-- The following dependencies are only used during testing -->
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>org.apache.maven.scm</groupId>
|
<groupId>org.apache.maven.scm</groupId>
|
||||||
<artifactId>maven-scm-provider-cvsexe</artifactId>
|
<artifactId>maven-scm-provider-cvsexe</artifactId>
|
||||||
<version>1.8.1</version>
|
<version>1.8.1</version>
|
||||||
<scope>provided</scope>
|
<scope>test</scope>
|
||||||
<optional>true</optional>
|
<optional>true</optional>
|
||||||
</dependency>
|
</dependency>
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>org.springframework</groupId>
|
<groupId>org.springframework</groupId>
|
||||||
<artifactId>spring-webmvc</artifactId>
|
<artifactId>spring-webmvc</artifactId>
|
||||||
<version>2.5.5</version>
|
<version>2.5.5</version>
|
||||||
<scope>provided</scope>
|
<scope>test</scope>
|
||||||
<optional>true</optional>
|
<optional>true</optional>
|
||||||
</dependency>
|
</dependency>
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>org.springframework.security</groupId>
|
<groupId>org.springframework.security</groupId>
|
||||||
<artifactId>spring-security-web</artifactId>
|
<artifactId>spring-security-web</artifactId>
|
||||||
<version>3.0.0.RELEASE</version>
|
<version>3.0.0.RELEASE</version>
|
||||||
<scope>provided</scope>
|
<scope>test</scope>
|
||||||
<optional>true</optional>
|
<optional>true</optional>
|
||||||
</dependency>
|
</dependency>
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>com.hazelcast</groupId>
|
<groupId>com.hazelcast</groupId>
|
||||||
<artifactId>hazelcast</artifactId>
|
<artifactId>hazelcast</artifactId>
|
||||||
<version>2.5</version>
|
<version>2.5</version>
|
||||||
<scope>provided</scope>
|
<scope>test</scope>
|
||||||
<optional>true</optional>
|
<optional>true</optional>
|
||||||
</dependency>
|
</dependency>
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>net.sf.ehcache</groupId>
|
<groupId>net.sf.ehcache</groupId>
|
||||||
<artifactId>ehcache-core</artifactId>
|
<artifactId>ehcache-core</artifactId>
|
||||||
<version>2.2.0</version>
|
<version>2.2.0</version>
|
||||||
<scope>provided</scope>
|
<scope>test</scope>
|
||||||
<optional>true</optional>
|
<optional>true</optional>
|
||||||
</dependency>
|
</dependency>
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>org.apache.struts</groupId>
|
<groupId>org.apache.struts</groupId>
|
||||||
<artifactId>struts2-core</artifactId>
|
<artifactId>struts2-core</artifactId>
|
||||||
<version>2.1.2</version>
|
<version>2.1.2</version>
|
||||||
<scope>provided</scope>
|
<scope>test</scope>
|
||||||
<optional>true</optional>
|
<optional>true</optional>
|
||||||
</dependency>
|
</dependency>
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>org.mortbay.jetty</groupId>
|
<groupId>org.mortbay.jetty</groupId>
|
||||||
<artifactId>jetty</artifactId>
|
<artifactId>jetty</artifactId>
|
||||||
<version>6.1.0</version>
|
<version>6.1.0</version>
|
||||||
<scope>provided</scope>
|
<scope>test</scope>
|
||||||
<optional>true</optional>
|
<optional>true</optional>
|
||||||
</dependency>
|
</dependency>
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>org.apache.axis2</groupId>
|
<groupId>org.apache.axis2</groupId>
|
||||||
<artifactId>axis2-spring</artifactId>
|
<artifactId>axis2-spring</artifactId>
|
||||||
<version>1.4.1</version>
|
<version>1.4.1</version>
|
||||||
<scope>provided</scope>
|
<scope>test</scope>
|
||||||
<optional>true</optional>
|
<optional>true</optional>
|
||||||
</dependency>
|
</dependency>
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>org.apache.axis2</groupId>
|
<groupId>org.apache.axis2</groupId>
|
||||||
<artifactId>axis2-adb</artifactId>
|
<artifactId>axis2-adb</artifactId>
|
||||||
<version>1.4.1</version>
|
<version>1.4.1</version>
|
||||||
<scope>provided</scope>
|
<scope>test</scope>
|
||||||
<optional>true</optional>
|
<optional>true</optional>
|
||||||
</dependency>
|
</dependency>
|
||||||
<dependency>
|
<dependency>
|
||||||
@@ -584,7 +409,7 @@ Copyright (c) 2012 Jeremy Long. All Rights Reserved.
|
|||||||
<artifactId>daytrader-ear</artifactId>
|
<artifactId>daytrader-ear</artifactId>
|
||||||
<version>2.1.7</version>
|
<version>2.1.7</version>
|
||||||
<type>ear</type>
|
<type>ear</type>
|
||||||
<scope>provided</scope>
|
<scope>test</scope>
|
||||||
<optional>true</optional>
|
<optional>true</optional>
|
||||||
</dependency>
|
</dependency>
|
||||||
<dependency>
|
<dependency>
|
||||||
@@ -592,7 +417,7 @@ Copyright (c) 2012 Jeremy Long. All Rights Reserved.
|
|||||||
<artifactId>war</artifactId>
|
<artifactId>war</artifactId>
|
||||||
<version>4.0</version>
|
<version>4.0</version>
|
||||||
<type>war</type>
|
<type>war</type>
|
||||||
<scope>provided</scope>
|
<scope>test</scope>
|
||||||
<optional>true</optional>
|
<optional>true</optional>
|
||||||
</dependency>
|
</dependency>
|
||||||
<dependency>
|
<dependency>
|
||||||
@@ -600,21 +425,49 @@ Copyright (c) 2012 Jeremy Long. All Rights Reserved.
|
|||||||
<artifactId>dojo-war</artifactId>
|
<artifactId>dojo-war</artifactId>
|
||||||
<version>1.3.0</version>
|
<version>1.3.0</version>
|
||||||
<type>war</type>
|
<type>war</type>
|
||||||
<scope>provided</scope>
|
<scope>test</scope>
|
||||||
<optional>true</optional>
|
<optional>true</optional>
|
||||||
</dependency>
|
</dependency>
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>org.apache.openjpa</groupId>
|
<groupId>org.apache.openjpa</groupId>
|
||||||
<artifactId>openjpa</artifactId>
|
<artifactId>openjpa</artifactId>
|
||||||
<version>2.0.1</version>
|
<version>2.0.1</version>
|
||||||
<scope>provided</scope>
|
<scope>test</scope>
|
||||||
<optional>true</optional>
|
<optional>true</optional>
|
||||||
</dependency>
|
</dependency>
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>com.google.inject</groupId>
|
<groupId>com.google.inject</groupId>
|
||||||
<artifactId>guice</artifactId>
|
<artifactId>guice</artifactId>
|
||||||
<version>3.0</version>
|
<version>3.0</version>
|
||||||
<scope>provided</scope>
|
<scope>test</scope>
|
||||||
|
<optional>true</optional>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.springframework.retry</groupId>
|
||||||
|
<artifactId>spring-retry</artifactId>
|
||||||
|
<version>1.1.0.RELEASE</version>
|
||||||
|
<scope>test</scope>
|
||||||
|
<optional>true</optional>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>uk.ltd.getahead</groupId>
|
||||||
|
<artifactId>dwr</artifactId>
|
||||||
|
<version>1.1.1</version>
|
||||||
|
<scope>test</scope>
|
||||||
|
<optional>true</optional>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>xalan</groupId>
|
||||||
|
<artifactId>xalan</artifactId>
|
||||||
|
<version>2.7.0</version>
|
||||||
|
<scope>test</scope>
|
||||||
|
<optional>true</optional>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>com.thoughtworks.xstream</groupId>
|
||||||
|
<artifactId>xstream</artifactId>
|
||||||
|
<version>1.4.8</version>
|
||||||
|
<scope>test</scope>
|
||||||
<optional>true</optional>
|
<optional>true</optional>
|
||||||
</dependency>
|
</dependency>
|
||||||
</dependencies>
|
</dependencies>
|
||||||
@@ -624,7 +477,6 @@ Copyright (c) 2012 Jeremy Long. All Rights Reserved.
|
|||||||
<activation>
|
<activation>
|
||||||
<property>
|
<property>
|
||||||
<name>mysql</name>
|
<name>mysql</name>
|
||||||
<!--value>test</value-->
|
|
||||||
</property>
|
</property>
|
||||||
</activation>
|
</activation>
|
||||||
<build>
|
<build>
|
||||||
@@ -632,7 +484,6 @@ Copyright (c) 2012 Jeremy Long. All Rights Reserved.
|
|||||||
<plugin>
|
<plugin>
|
||||||
<groupId>org.apache.maven.plugins</groupId>
|
<groupId>org.apache.maven.plugins</groupId>
|
||||||
<artifactId>maven-surefire-plugin</artifactId>
|
<artifactId>maven-surefire-plugin</artifactId>
|
||||||
<version>2.16</version>
|
|
||||||
<configuration>
|
<configuration>
|
||||||
<skip>true</skip>
|
<skip>true</skip>
|
||||||
</configuration>
|
</configuration>
|
||||||
@@ -640,12 +491,11 @@ Copyright (c) 2012 Jeremy Long. All Rights Reserved.
|
|||||||
<plugin>
|
<plugin>
|
||||||
<groupId>org.apache.maven.plugins</groupId>
|
<groupId>org.apache.maven.plugins</groupId>
|
||||||
<artifactId>maven-failsafe-plugin</artifactId>
|
<artifactId>maven-failsafe-plugin</artifactId>
|
||||||
<version>2.16</version>
|
|
||||||
<configuration>
|
<configuration>
|
||||||
<systemProperties>
|
<systemProperties>
|
||||||
<property>
|
<property>
|
||||||
<name>data.driver_path</name>
|
<name>data.driver_path</name>
|
||||||
<value>${basedir}/${driver_path}</value>
|
<value>${driver_path}</value>
|
||||||
</property>
|
</property>
|
||||||
<property>
|
<property>
|
||||||
<name>data.driver_name</name>
|
<name>data.driver_name</name>
|
||||||
@@ -673,14 +523,75 @@ Copyright (c) 2012 Jeremy Long. All Rights Reserved.
|
|||||||
</build>
|
</build>
|
||||||
</profile>
|
</profile>
|
||||||
<profile>
|
<profile>
|
||||||
<!-- The following profile adds additional
|
<id>Postgresql-IntegrationTest</id>
|
||||||
dependencies that are only used during testing.
|
<activation>
|
||||||
Additionally, these are only added when using "allTests" to
|
<property>
|
||||||
make the build slightly faster in most cases. -->
|
<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>
|
||||||
|
<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>
|
||||||
|
<!--
|
||||||
|
The following profile adds additional dependencies that are only
|
||||||
|
used during testing.
|
||||||
|
|
||||||
|
TODO move the following FP tests to a seperate invoker test in the
|
||||||
|
maven plugin project. Add checks against the XML to validate that
|
||||||
|
these do not report FP.
|
||||||
|
-->
|
||||||
|
<!--profile>
|
||||||
<id>False Positive Tests</id>
|
<id>False Positive Tests</id>
|
||||||
<activation>
|
<activation>
|
||||||
<property>
|
<property>
|
||||||
<name>allTests</name>
|
<name>releaseTesting</name>
|
||||||
</property>
|
</property>
|
||||||
</activation>
|
</activation>
|
||||||
<dependencies>
|
<dependencies>
|
||||||
@@ -688,52 +599,136 @@ Copyright (c) 2012 Jeremy Long. All Rights Reserved.
|
|||||||
<groupId>org.apache.xmlgraphics</groupId>
|
<groupId>org.apache.xmlgraphics</groupId>
|
||||||
<artifactId>batik-util</artifactId>
|
<artifactId>batik-util</artifactId>
|
||||||
<version>1.7</version>
|
<version>1.7</version>
|
||||||
<scope>provided</scope>
|
<scope>test</scope>
|
||||||
<optional>true</optional>
|
|
||||||
</dependency>
|
|
||||||
<dependency>
|
|
||||||
<groupId>com.thoughtworks.xstream</groupId>
|
|
||||||
<artifactId>xstream</artifactId>
|
|
||||||
<version>1.4.2</version>
|
|
||||||
<scope>provided</scope>
|
|
||||||
<optional>true</optional>
|
<optional>true</optional>
|
||||||
</dependency>
|
</dependency>
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>org.apache.ws.security</groupId>
|
<groupId>org.apache.ws.security</groupId>
|
||||||
<artifactId>wss4j</artifactId>
|
<artifactId>wss4j</artifactId>
|
||||||
<version>1.5.7</version>
|
<version>1.5.7</version>
|
||||||
<scope>provided</scope>
|
<scope>test</scope>
|
||||||
<optional>true</optional>
|
<optional>true</optional>
|
||||||
</dependency>
|
</dependency>
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>com.ganyo</groupId>
|
<groupId>com.ganyo</groupId>
|
||||||
<artifactId>gcm-server</artifactId>
|
<artifactId>gcm-server</artifactId>
|
||||||
<version>1.0.2</version>
|
<version>1.0.2</version>
|
||||||
<scope>provided</scope>
|
<scope>test</scope>
|
||||||
<optional>true</optional>
|
<optional>true</optional>
|
||||||
</dependency>
|
</dependency>
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>org.python</groupId>
|
<groupId>org.python</groupId>
|
||||||
<artifactId>jython-standalone</artifactId>
|
<artifactId>jython-standalone</artifactId>
|
||||||
<version>2.7-b1</version>
|
<version>2.7-b1</version>
|
||||||
<scope>provided</scope>
|
<scope>test</scope>
|
||||||
<optional>true</optional>
|
<optional>true</optional>
|
||||||
</dependency>
|
</dependency>
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>org.jruby</groupId>
|
<groupId>org.jruby</groupId>
|
||||||
<artifactId>jruby-complete</artifactId>
|
<artifactId>jruby-complete</artifactId>
|
||||||
<version>1.7.4</version>
|
<version>1.7.4</version>
|
||||||
<scope>provided</scope>
|
<scope>test</scope>
|
||||||
<optional>true</optional>
|
<optional>true</optional>
|
||||||
</dependency>
|
</dependency>
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>org.jruby</groupId>
|
<groupId>org.jruby</groupId>
|
||||||
<artifactId>jruby</artifactId>
|
<artifactId>jruby</artifactId>
|
||||||
<version>1.6.3</version>
|
<version>1.6.3</version>
|
||||||
<scope>provided</scope>
|
<scope>test</scope>
|
||||||
|
<optional>true</optional>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.glassfish.jersey.core</groupId>
|
||||||
|
<artifactId>jersey-client</artifactId>
|
||||||
|
<version>2.12</version>
|
||||||
|
<scope>test</scope>
|
||||||
|
<optional>true</optional>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>com.sun.jersey</groupId>
|
||||||
|
<artifactId>jersey-client</artifactId>
|
||||||
|
<version>1.11.1</version>
|
||||||
|
<scope>test</scope>
|
||||||
|
<optional>true</optional>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>com.sun.faces</groupId>
|
||||||
|
<artifactId>jsf-impl</artifactId>
|
||||||
|
<version>2.2.8-02</version>
|
||||||
|
<scope>test</scope>
|
||||||
|
<optional>true</optional>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>com.google.inject</groupId>
|
||||||
|
<artifactId>guice</artifactId>
|
||||||
|
<version>3.0</version>
|
||||||
|
<scope>test</scope>
|
||||||
|
<optional>true</optional>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.opensaml</groupId>
|
||||||
|
<artifactId>xmltooling</artifactId>
|
||||||
|
<version>1.4.1</version>
|
||||||
|
<scope>test</scope>
|
||||||
|
<optional>true</optional>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>com.google.code.gson</groupId>
|
||||||
|
<artifactId>gson</artifactId>
|
||||||
|
<version>2.3.1</version>
|
||||||
|
<scope>test</scope>
|
||||||
|
<optional>true</optional>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>com.google.gerrit</groupId>
|
||||||
|
<artifactId>gerrit-extension-api</artifactId>
|
||||||
|
<version>2.11</version>
|
||||||
|
<scope>test</scope>
|
||||||
|
<optional>true</optional>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>com.google.apis</groupId>
|
||||||
|
<artifactId>google-api-services-sqladmin</artifactId>
|
||||||
|
<version>v1beta4-rev5-1.20.0</version>
|
||||||
|
<scope>test</scope>
|
||||||
|
<optional>true</optional>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>com.google.gwt.google-apis</groupId>
|
||||||
|
<artifactId>gwt-gears</artifactId>
|
||||||
|
<version>1.2.1</version>
|
||||||
|
<scope>test</scope>
|
||||||
|
<optional>true</optional>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.mozilla</groupId>
|
||||||
|
<artifactId>rhino</artifactId>
|
||||||
|
<version>1.7.6</version>
|
||||||
|
<scope>test</scope>
|
||||||
|
<optional>true</optional>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>com.microsoft.windowsazure</groupId>
|
||||||
|
<artifactId>microsoft-azure-api-media</artifactId>
|
||||||
|
<version>0.5.0</version>
|
||||||
|
<scope>test</scope>
|
||||||
|
<optional>true</optional>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>com.microsoft.windowsazure</groupId>
|
||||||
|
<artifactId>microsoft-azure-api-management-sql</artifactId>
|
||||||
|
<version>0.5.0</version>
|
||||||
|
<scope>test</scope>
|
||||||
|
<optional>true</optional>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>com.microsoft.bingads</groupId>
|
||||||
|
<artifactId>microsoft.bingads</artifactId>
|
||||||
|
<version>9.3.4</version>
|
||||||
|
<scope>test</scope>
|
||||||
<optional>true</optional>
|
<optional>true</optional>
|
||||||
</dependency>
|
</dependency>
|
||||||
</dependencies>
|
</dependencies>
|
||||||
</profile>
|
</profile-->
|
||||||
</profiles>
|
</profiles>
|
||||||
</project>
|
</project>
|
||||||
|
|||||||
@@ -0,0 +1,129 @@
|
|||||||
|
/*
|
||||||
|
* 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 Stefan Neuhaus. All Rights Reserved.
|
||||||
|
*/
|
||||||
|
package org.owasp.dependencycheck;
|
||||||
|
|
||||||
|
import org.owasp.dependencycheck.analyzer.Analyzer;
|
||||||
|
import org.owasp.dependencycheck.analyzer.FileTypeAnalyzer;
|
||||||
|
import org.owasp.dependencycheck.analyzer.exception.AnalysisException;
|
||||||
|
import org.owasp.dependencycheck.dependency.Dependency;
|
||||||
|
import org.owasp.dependencycheck.utils.Settings;
|
||||||
|
import org.slf4j.Logger;
|
||||||
|
import org.slf4j.LoggerFactory;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.concurrent.Callable;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Task to support parallelism of dependency-check analysis. Analyses a single
|
||||||
|
* {@link Dependency} by a specific {@link Analyzer}.
|
||||||
|
*
|
||||||
|
* @author Stefan Neuhaus
|
||||||
|
*/
|
||||||
|
public class AnalysisTask implements Callable<Void> {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Instance of the logger.
|
||||||
|
*/
|
||||||
|
private static final Logger LOGGER = LoggerFactory.getLogger(AnalysisTask.class);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A reference to the analyzer.
|
||||||
|
*/
|
||||||
|
private final Analyzer analyzer;
|
||||||
|
/**
|
||||||
|
* The dependency to analyze.
|
||||||
|
*/
|
||||||
|
private final Dependency dependency;
|
||||||
|
/**
|
||||||
|
* A reference to the dependency-check engine.
|
||||||
|
*/
|
||||||
|
private final Engine engine;
|
||||||
|
/**
|
||||||
|
* The list of exceptions that may occur during analysis.
|
||||||
|
*/
|
||||||
|
private final List<Throwable> exceptions;
|
||||||
|
/**
|
||||||
|
* A reference to the global settings object.
|
||||||
|
*/
|
||||||
|
private final Settings settings;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates a new analysis task.
|
||||||
|
*
|
||||||
|
* @param analyzer a reference of the analyzer to execute
|
||||||
|
* @param dependency the dependency to analyze
|
||||||
|
* @param engine the dependency-check engine
|
||||||
|
* @param exceptions exceptions that occur during analysis will be added to
|
||||||
|
* this collection of exceptions
|
||||||
|
* @param settings a reference to the global settings object; this is
|
||||||
|
* necessary so that when the thread is started the dependencies have a
|
||||||
|
* correct reference to the global settings.
|
||||||
|
*/
|
||||||
|
AnalysisTask(Analyzer analyzer, Dependency dependency, Engine engine, List<Throwable> exceptions, Settings settings) {
|
||||||
|
this.analyzer = analyzer;
|
||||||
|
this.dependency = dependency;
|
||||||
|
this.engine = engine;
|
||||||
|
this.exceptions = exceptions;
|
||||||
|
this.settings = settings;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Executes the analysis task.
|
||||||
|
*
|
||||||
|
* @return null
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
public Void call() {
|
||||||
|
try {
|
||||||
|
Settings.setInstance(settings);
|
||||||
|
|
||||||
|
if (shouldAnalyze()) {
|
||||||
|
LOGGER.debug("Begin Analysis of '{}' ({})", dependency.getActualFilePath(), analyzer.getName());
|
||||||
|
try {
|
||||||
|
analyzer.analyze(dependency, engine);
|
||||||
|
} catch (AnalysisException ex) {
|
||||||
|
LOGGER.warn("An error occurred while analyzing '{}' ({}).", dependency.getActualFilePath(), analyzer.getName());
|
||||||
|
LOGGER.debug("", ex);
|
||||||
|
exceptions.add(ex);
|
||||||
|
} catch (Throwable ex) {
|
||||||
|
LOGGER.warn("An unexpected error occurred during analysis of '{}' ({}): {}",
|
||||||
|
dependency.getActualFilePath(), analyzer.getName(), ex.getMessage());
|
||||||
|
LOGGER.debug("", ex);
|
||||||
|
exceptions.add(ex);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} finally {
|
||||||
|
Settings.cleanup(false);
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Determines if the analyzer can analyze the given dependency.
|
||||||
|
*
|
||||||
|
* @return whether or not the analyzer can analyze the dependency
|
||||||
|
*/
|
||||||
|
protected boolean shouldAnalyze() {
|
||||||
|
if (analyzer instanceof FileTypeAnalyzer) {
|
||||||
|
final FileTypeAnalyzer fileTypeAnalyzer = (FileTypeAnalyzer) analyzer;
|
||||||
|
return fileTypeAnalyzer.accept(dependency.getActualFile());
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
File diff suppressed because it is too large
Load Diff
@@ -20,8 +20,6 @@ package org.owasp.dependencycheck.agent;
|
|||||||
import java.io.File;
|
import java.io.File;
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.logging.Level;
|
|
||||||
import java.util.logging.Logger;
|
|
||||||
import org.owasp.dependencycheck.Engine;
|
import org.owasp.dependencycheck.Engine;
|
||||||
import org.owasp.dependencycheck.data.nvdcve.CveDB;
|
import org.owasp.dependencycheck.data.nvdcve.CveDB;
|
||||||
import org.owasp.dependencycheck.data.nvdcve.DatabaseException;
|
import org.owasp.dependencycheck.data.nvdcve.DatabaseException;
|
||||||
@@ -29,19 +27,25 @@ import org.owasp.dependencycheck.data.nvdcve.DatabaseProperties;
|
|||||||
import org.owasp.dependencycheck.dependency.Dependency;
|
import org.owasp.dependencycheck.dependency.Dependency;
|
||||||
import org.owasp.dependencycheck.dependency.Identifier;
|
import org.owasp.dependencycheck.dependency.Identifier;
|
||||||
import org.owasp.dependencycheck.dependency.Vulnerability;
|
import org.owasp.dependencycheck.dependency.Vulnerability;
|
||||||
|
import org.owasp.dependencycheck.exception.ExceptionCollection;
|
||||||
|
import org.owasp.dependencycheck.exception.ReportException;
|
||||||
import org.owasp.dependencycheck.exception.ScanAgentException;
|
import org.owasp.dependencycheck.exception.ScanAgentException;
|
||||||
import org.owasp.dependencycheck.reporting.ReportGenerator;
|
import org.owasp.dependencycheck.reporting.ReportGenerator;
|
||||||
import org.owasp.dependencycheck.utils.Settings;
|
import org.owasp.dependencycheck.utils.Settings;
|
||||||
|
import org.slf4j.Logger;
|
||||||
|
import org.slf4j.LoggerFactory;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* This class provides a way to easily conduct a scan solely based on existing evidence metadata rather than collecting
|
* This class provides a way to easily conduct a scan solely based on existing
|
||||||
* evidence from the files themselves. This class is based on the Ant task and Maven plugin with the exception that it
|
* evidence metadata rather than collecting evidence from the files themselves.
|
||||||
* takes a list of dependencies that can be programmatically added from data in a spreadsheet, database or some other
|
* This class is based on the Ant task and Maven plugin with the exception that
|
||||||
* datasource and conduct a scan based on this pre-defined evidence.
|
* it takes a list of dependencies that can be programmatically added from data
|
||||||
|
* in a spreadsheet, database or some other datasource and conduct a scan based
|
||||||
|
* on this pre-defined evidence.
|
||||||
*
|
*
|
||||||
* <h2>Example:</h2>
|
* <h2>Example:</h2>
|
||||||
* <pre>
|
* <pre>
|
||||||
* List<Dependency> dependencies = new ArrayList<Dependency>();
|
* List<Dependency> dependencies = new ArrayList<Dependency>();
|
||||||
* Dependency dependency = new Dependency(new File(FileUtils.getBitBucket()));
|
* Dependency dependency = new Dependency(new File(FileUtils.getBitBucket()));
|
||||||
* dependency.getProductEvidence().addEvidence("my-datasource", "name", "Jetty", Confidence.HIGH);
|
* dependency.getProductEvidence().addEvidence("my-datasource", "name", "Jetty", Confidence.HIGH);
|
||||||
* dependency.getVersionEvidence().addEvidence("my-datasource", "version", "5.1.10", Confidence.HIGH);
|
* dependency.getVersionEvidence().addEvidence("my-datasource", "version", "5.1.10", Confidence.HIGH);
|
||||||
@@ -55,11 +59,12 @@ import org.owasp.dependencycheck.utils.Settings;
|
|||||||
* scan.execute();
|
* scan.execute();
|
||||||
* </pre>
|
* </pre>
|
||||||
*
|
*
|
||||||
* @author Steve Springett <steve.springett@owasp.org>
|
* @author Steve Springett
|
||||||
*/
|
*/
|
||||||
@SuppressWarnings("unused")
|
@SuppressWarnings("unused")
|
||||||
public class DependencyCheckScanAgent {
|
public class DependencyCheckScanAgent {
|
||||||
|
|
||||||
|
//<editor-fold defaultstate="collapsed" desc="private fields">
|
||||||
/**
|
/**
|
||||||
* System specific new line character.
|
* System specific new line character.
|
||||||
*/
|
*/
|
||||||
@@ -67,11 +72,146 @@ public class DependencyCheckScanAgent {
|
|||||||
/**
|
/**
|
||||||
* Logger for use throughout the class.
|
* Logger for use throughout the class.
|
||||||
*/
|
*/
|
||||||
private static final Logger LOGGER = Logger.getLogger(DependencyCheckScanAgent.class.getName());
|
private static final Logger LOGGER = LoggerFactory.getLogger(DependencyCheckScanAgent.class);
|
||||||
/**
|
/**
|
||||||
* The application name for the report.
|
* The application name for the report.
|
||||||
*/
|
*/
|
||||||
private String applicationName = "Dependency-Check";
|
private String applicationName = "Dependency-Check";
|
||||||
|
/**
|
||||||
|
* The pre-determined dependencies to scan
|
||||||
|
*/
|
||||||
|
private List<Dependency> dependencies;
|
||||||
|
/**
|
||||||
|
* The location of the data directory that contains
|
||||||
|
*/
|
||||||
|
private String dataDirectory = null;
|
||||||
|
/**
|
||||||
|
* Specifies the destination directory for the generated Dependency-Check
|
||||||
|
* report.
|
||||||
|
*/
|
||||||
|
private String reportOutputDirectory;
|
||||||
|
/**
|
||||||
|
* Specifies if the build should be failed if a CVSS score above a specified
|
||||||
|
* level is identified. The default is 11 which means since the CVSS scores
|
||||||
|
* are 0-10, by default the build will never fail and the CVSS score is set
|
||||||
|
* to 11. The valid range for the fail build on CVSS is 0 to 11, where
|
||||||
|
* anything above 10 will not cause the build to fail.
|
||||||
|
*/
|
||||||
|
private float failBuildOnCVSS = 11;
|
||||||
|
/**
|
||||||
|
* Sets whether auto-updating of the NVD CVE/CPE data is enabled. It is not
|
||||||
|
* recommended that this be turned to false. Default is true.
|
||||||
|
*/
|
||||||
|
private boolean autoUpdate = true;
|
||||||
|
/**
|
||||||
|
* flag indicating whether or not to generate a report of findings.
|
||||||
|
*/
|
||||||
|
private boolean generateReport = true;
|
||||||
|
/**
|
||||||
|
* The report format to be generated (HTML, XML, VULN, ALL). This
|
||||||
|
* configuration option has no affect if using this within the Site plugin
|
||||||
|
* unless the externalReport is set to true. Default is HTML.
|
||||||
|
*/
|
||||||
|
private ReportGenerator.Format reportFormat = ReportGenerator.Format.HTML;
|
||||||
|
/**
|
||||||
|
* The Proxy Server.
|
||||||
|
*/
|
||||||
|
private String proxyServer;
|
||||||
|
/**
|
||||||
|
* The Proxy Port.
|
||||||
|
*/
|
||||||
|
private String proxyPort;
|
||||||
|
/**
|
||||||
|
* The Proxy username.
|
||||||
|
*/
|
||||||
|
private String proxyUsername;
|
||||||
|
/**
|
||||||
|
* The Proxy password.
|
||||||
|
*/
|
||||||
|
private String proxyPassword;
|
||||||
|
/**
|
||||||
|
* The Connection Timeout.
|
||||||
|
*/
|
||||||
|
private String connectionTimeout;
|
||||||
|
/**
|
||||||
|
* The file path used for verbose logging.
|
||||||
|
*/
|
||||||
|
private String logFile = null;
|
||||||
|
/**
|
||||||
|
* flag indicating whether or not to show a summary of findings.
|
||||||
|
*/
|
||||||
|
private boolean showSummary = true;
|
||||||
|
/**
|
||||||
|
* The path to the suppression file.
|
||||||
|
*/
|
||||||
|
private String suppressionFile;
|
||||||
|
/**
|
||||||
|
* The password to use when connecting to the database.
|
||||||
|
*/
|
||||||
|
private String databasePassword;
|
||||||
|
/**
|
||||||
|
* Whether or not the Maven Central analyzer is enabled.
|
||||||
|
*/
|
||||||
|
private boolean centralAnalyzerEnabled = true;
|
||||||
|
/**
|
||||||
|
* The URL of Maven Central.
|
||||||
|
*/
|
||||||
|
private String centralUrl;
|
||||||
|
/**
|
||||||
|
* Whether or not the nexus analyzer is enabled.
|
||||||
|
*/
|
||||||
|
private boolean nexusAnalyzerEnabled = true;
|
||||||
|
/**
|
||||||
|
* The URL of the Nexus server.
|
||||||
|
*/
|
||||||
|
private String nexusUrl;
|
||||||
|
/**
|
||||||
|
* Whether or not the defined proxy should be used when connecting to Nexus.
|
||||||
|
*/
|
||||||
|
private boolean nexusUsesProxy = true;
|
||||||
|
/**
|
||||||
|
* The database driver name; such as org.h2.Driver.
|
||||||
|
*/
|
||||||
|
private String databaseDriverName;
|
||||||
|
/**
|
||||||
|
* The path to the database driver JAR file if it is not on the class path.
|
||||||
|
*/
|
||||||
|
private String databaseDriverPath;
|
||||||
|
/**
|
||||||
|
* The database connection string.
|
||||||
|
*/
|
||||||
|
private String connectionString;
|
||||||
|
/**
|
||||||
|
* The user name for connecting to the database.
|
||||||
|
*/
|
||||||
|
private String databaseUser;
|
||||||
|
/**
|
||||||
|
* Additional ZIP File extensions to add analyze. This should be a
|
||||||
|
* comma-separated list of file extensions to treat like ZIP files.
|
||||||
|
*/
|
||||||
|
private String zipExtensions;
|
||||||
|
/**
|
||||||
|
* The url for the modified NVD CVE (1.2 schema).
|
||||||
|
*/
|
||||||
|
private String cveUrl12Modified;
|
||||||
|
/**
|
||||||
|
* The url for the modified NVD CVE (2.0 schema).
|
||||||
|
*/
|
||||||
|
private String cveUrl20Modified;
|
||||||
|
/**
|
||||||
|
* Base Data Mirror URL for CVE 1.2.
|
||||||
|
*/
|
||||||
|
private String cveUrl12Base;
|
||||||
|
/**
|
||||||
|
* Data Mirror URL for CVE 2.0.
|
||||||
|
*/
|
||||||
|
private String cveUrl20Base;
|
||||||
|
/**
|
||||||
|
* The path to Mono for .NET assembly analysis on non-windows systems.
|
||||||
|
*/
|
||||||
|
private String pathToMono;
|
||||||
|
//</editor-fold>
|
||||||
|
//<editor-fold defaultstate="collapsed" desc="getters/setters">
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get the value of applicationName.
|
* Get the value of applicationName.
|
||||||
@@ -91,11 +231,6 @@ public class DependencyCheckScanAgent {
|
|||||||
this.applicationName = applicationName;
|
this.applicationName = applicationName;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* The pre-determined dependencies to scan
|
|
||||||
*/
|
|
||||||
private List<Dependency> dependencies;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns a list of pre-determined dependencies.
|
* Returns a list of pre-determined dependencies.
|
||||||
*
|
*
|
||||||
@@ -114,11 +249,6 @@ public class DependencyCheckScanAgent {
|
|||||||
this.dependencies = dependencies;
|
this.dependencies = dependencies;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* The location of the data directory that contains
|
|
||||||
*/
|
|
||||||
private String dataDirectory = null;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get the value of dataDirectory.
|
* Get the value of dataDirectory.
|
||||||
*
|
*
|
||||||
@@ -137,11 +267,6 @@ public class DependencyCheckScanAgent {
|
|||||||
this.dataDirectory = dataDirectory;
|
this.dataDirectory = dataDirectory;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Specifies the destination directory for the generated Dependency-Check report.
|
|
||||||
*/
|
|
||||||
private String reportOutputDirectory;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get the value of reportOutputDirectory.
|
* Get the value of reportOutputDirectory.
|
||||||
*
|
*
|
||||||
@@ -160,13 +285,6 @@ public class DependencyCheckScanAgent {
|
|||||||
this.reportOutputDirectory = reportOutputDirectory;
|
this.reportOutputDirectory = reportOutputDirectory;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Specifies if the build should be failed if a CVSS score above a specified level is identified. The default is 11
|
|
||||||
* which means since the CVSS scores are 0-10, by default the build will never fail and the CVSS score is set to 11.
|
|
||||||
* The valid range for the fail build on CVSS is 0 to 11, where anything above 10 will not cause the build to fail.
|
|
||||||
*/
|
|
||||||
private float failBuildOnCVSS = 11;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get the value of failBuildOnCVSS.
|
* Get the value of failBuildOnCVSS.
|
||||||
*
|
*
|
||||||
@@ -185,12 +303,6 @@ public class DependencyCheckScanAgent {
|
|||||||
this.failBuildOnCVSS = failBuildOnCVSS;
|
this.failBuildOnCVSS = failBuildOnCVSS;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Sets whether auto-updating of the NVD CVE/CPE data is enabled. It is not recommended that this be turned to
|
|
||||||
* false. Default is true.
|
|
||||||
*/
|
|
||||||
private boolean autoUpdate = true;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get the value of autoUpdate.
|
* Get the value of autoUpdate.
|
||||||
*
|
*
|
||||||
@@ -210,10 +322,22 @@ public class DependencyCheckScanAgent {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The report format to be generated (HTML, XML, VULN, ALL). This configuration option has no affect if using this
|
* Get the value of generateReport.
|
||||||
* within the Site plugin unless the externalReport is set to true. Default is HTML.
|
*
|
||||||
|
* @return the value of generateReport
|
||||||
*/
|
*/
|
||||||
private ReportGenerator.Format reportFormat = ReportGenerator.Format.HTML;
|
public boolean isGenerateReport() {
|
||||||
|
return generateReport;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Set the value of generateReport.
|
||||||
|
*
|
||||||
|
* @param generateReport new value of generateReport
|
||||||
|
*/
|
||||||
|
public void setGenerateReport(boolean generateReport) {
|
||||||
|
this.generateReport = generateReport;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get the value of reportFormat.
|
* Get the value of reportFormat.
|
||||||
@@ -233,11 +357,6 @@ public class DependencyCheckScanAgent {
|
|||||||
this.reportFormat = reportFormat;
|
this.reportFormat = reportFormat;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* The Proxy Server.
|
|
||||||
*/
|
|
||||||
private String proxyServer;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get the value of proxyServer.
|
* Get the value of proxyServer.
|
||||||
*
|
*
|
||||||
@@ -260,7 +379,9 @@ public class DependencyCheckScanAgent {
|
|||||||
* Get the value of proxyServer.
|
* Get the value of proxyServer.
|
||||||
*
|
*
|
||||||
* @return the value of proxyServer
|
* @return the value of proxyServer
|
||||||
* @deprecated use {@link org.owasp.dependencycheck.agent.DependencyCheckScanAgent#getProxyServer()} instead
|
* @deprecated use
|
||||||
|
* {@link org.owasp.dependencycheck.agent.DependencyCheckScanAgent#getProxyServer()}
|
||||||
|
* instead
|
||||||
*/
|
*/
|
||||||
@Deprecated
|
@Deprecated
|
||||||
public String getProxyUrl() {
|
public String getProxyUrl() {
|
||||||
@@ -279,11 +400,6 @@ public class DependencyCheckScanAgent {
|
|||||||
this.proxyServer = proxyUrl;
|
this.proxyServer = proxyUrl;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* The Proxy Port.
|
|
||||||
*/
|
|
||||||
private String proxyPort;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get the value of proxyPort.
|
* Get the value of proxyPort.
|
||||||
*
|
*
|
||||||
@@ -302,11 +418,6 @@ public class DependencyCheckScanAgent {
|
|||||||
this.proxyPort = proxyPort;
|
this.proxyPort = proxyPort;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* The Proxy username.
|
|
||||||
*/
|
|
||||||
private String proxyUsername;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get the value of proxyUsername.
|
* Get the value of proxyUsername.
|
||||||
*
|
*
|
||||||
@@ -325,11 +436,6 @@ public class DependencyCheckScanAgent {
|
|||||||
this.proxyUsername = proxyUsername;
|
this.proxyUsername = proxyUsername;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* The Proxy password.
|
|
||||||
*/
|
|
||||||
private String proxyPassword;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get the value of proxyPassword.
|
* Get the value of proxyPassword.
|
||||||
*
|
*
|
||||||
@@ -348,11 +454,6 @@ public class DependencyCheckScanAgent {
|
|||||||
this.proxyPassword = proxyPassword;
|
this.proxyPassword = proxyPassword;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* The Connection Timeout.
|
|
||||||
*/
|
|
||||||
private String connectionTimeout;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get the value of connectionTimeout.
|
* Get the value of connectionTimeout.
|
||||||
*
|
*
|
||||||
@@ -371,11 +472,6 @@ public class DependencyCheckScanAgent {
|
|||||||
this.connectionTimeout = connectionTimeout;
|
this.connectionTimeout = connectionTimeout;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* The file path used for verbose logging.
|
|
||||||
*/
|
|
||||||
private String logFile = null;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get the value of logFile.
|
* Get the value of logFile.
|
||||||
*
|
*
|
||||||
@@ -394,11 +490,6 @@ public class DependencyCheckScanAgent {
|
|||||||
this.logFile = logFile;
|
this.logFile = logFile;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* The path to the suppression file.
|
|
||||||
*/
|
|
||||||
private String suppressionFile;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get the value of suppressionFile.
|
* Get the value of suppressionFile.
|
||||||
*
|
*
|
||||||
@@ -417,11 +508,6 @@ public class DependencyCheckScanAgent {
|
|||||||
this.suppressionFile = suppressionFile;
|
this.suppressionFile = suppressionFile;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* flag indicating whether or not to show a summary of findings.
|
|
||||||
*/
|
|
||||||
private boolean showSummary = true;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get the value of showSummary.
|
* Get the value of showSummary.
|
||||||
*
|
*
|
||||||
@@ -441,9 +527,40 @@ public class DependencyCheckScanAgent {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Whether or not the nexus analyzer is enabled.
|
* Get the value of centralAnalyzerEnabled.
|
||||||
|
*
|
||||||
|
* @return the value of centralAnalyzerEnabled
|
||||||
*/
|
*/
|
||||||
private boolean nexusAnalyzerEnabled = true;
|
public boolean isCentralAnalyzerEnabled() {
|
||||||
|
return centralAnalyzerEnabled;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Set the value of centralAnalyzerEnabled.
|
||||||
|
*
|
||||||
|
* @param centralAnalyzerEnabled new value of centralAnalyzerEnabled
|
||||||
|
*/
|
||||||
|
public void setCentralAnalyzerEnabled(boolean centralAnalyzerEnabled) {
|
||||||
|
this.centralAnalyzerEnabled = centralAnalyzerEnabled;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the value of centralUrl.
|
||||||
|
*
|
||||||
|
* @return the value of centralUrl
|
||||||
|
*/
|
||||||
|
public String getCentralUrl() {
|
||||||
|
return centralUrl;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Set the value of centralUrl.
|
||||||
|
*
|
||||||
|
* @param centralUrl new value of centralUrl
|
||||||
|
*/
|
||||||
|
public void setCentralUrl(String centralUrl) {
|
||||||
|
this.centralUrl = centralUrl;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get the value of nexusAnalyzerEnabled.
|
* Get the value of nexusAnalyzerEnabled.
|
||||||
@@ -463,11 +580,6 @@ public class DependencyCheckScanAgent {
|
|||||||
this.nexusAnalyzerEnabled = nexusAnalyzerEnabled;
|
this.nexusAnalyzerEnabled = nexusAnalyzerEnabled;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* The URL of the Nexus server.
|
|
||||||
*/
|
|
||||||
private String nexusUrl;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get the value of nexusUrl.
|
* Get the value of nexusUrl.
|
||||||
*
|
*
|
||||||
@@ -486,11 +598,6 @@ public class DependencyCheckScanAgent {
|
|||||||
this.nexusUrl = nexusUrl;
|
this.nexusUrl = nexusUrl;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Whether or not the defined proxy should be used when connecting to Nexus.
|
|
||||||
*/
|
|
||||||
private boolean nexusUsesProxy = true;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get the value of nexusUsesProxy.
|
* Get the value of nexusUsesProxy.
|
||||||
*
|
*
|
||||||
@@ -509,11 +616,6 @@ public class DependencyCheckScanAgent {
|
|||||||
this.nexusUsesProxy = nexusUsesProxy;
|
this.nexusUsesProxy = nexusUsesProxy;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* The database driver name; such as org.h2.Driver.
|
|
||||||
*/
|
|
||||||
private String databaseDriverName;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get the value of databaseDriverName.
|
* Get the value of databaseDriverName.
|
||||||
*
|
*
|
||||||
@@ -532,11 +634,6 @@ public class DependencyCheckScanAgent {
|
|||||||
this.databaseDriverName = 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.
|
* Get the value of databaseDriverPath.
|
||||||
*
|
*
|
||||||
@@ -555,11 +652,6 @@ public class DependencyCheckScanAgent {
|
|||||||
this.databaseDriverPath = databaseDriverPath;
|
this.databaseDriverPath = databaseDriverPath;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* The database connection string.
|
|
||||||
*/
|
|
||||||
private String connectionString;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get the value of connectionString.
|
* Get the value of connectionString.
|
||||||
*
|
*
|
||||||
@@ -578,11 +670,6 @@ public class DependencyCheckScanAgent {
|
|||||||
this.connectionString = connectionString;
|
this.connectionString = connectionString;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* The user name for connecting to the database.
|
|
||||||
*/
|
|
||||||
private String databaseUser;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get the value of databaseUser.
|
* Get the value of databaseUser.
|
||||||
*
|
*
|
||||||
@@ -601,11 +688,6 @@ public class DependencyCheckScanAgent {
|
|||||||
this.databaseUser = databaseUser;
|
this.databaseUser = databaseUser;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* The password to use when connecting to the database.
|
|
||||||
*/
|
|
||||||
private String databasePassword;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get the value of databasePassword.
|
* Get the value of databasePassword.
|
||||||
*
|
*
|
||||||
@@ -624,12 +706,6 @@ public class DependencyCheckScanAgent {
|
|||||||
this.databasePassword = databasePassword;
|
this.databasePassword = databasePassword;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Additional ZIP File extensions to add analyze. This should be a comma-separated list of file extensions to treat
|
|
||||||
* like ZIP files.
|
|
||||||
*/
|
|
||||||
private String zipExtensions;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get the value of zipExtensions.
|
* Get the value of zipExtensions.
|
||||||
*
|
*
|
||||||
@@ -648,11 +724,6 @@ public class DependencyCheckScanAgent {
|
|||||||
this.zipExtensions = zipExtensions;
|
this.zipExtensions = zipExtensions;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* The url for the modified NVD CVE (1.2 schema).
|
|
||||||
*/
|
|
||||||
private String cveUrl12Modified;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get the value of cveUrl12Modified.
|
* Get the value of cveUrl12Modified.
|
||||||
*
|
*
|
||||||
@@ -671,11 +742,6 @@ public class DependencyCheckScanAgent {
|
|||||||
this.cveUrl12Modified = cveUrl12Modified;
|
this.cveUrl12Modified = cveUrl12Modified;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* The url for the modified NVD CVE (2.0 schema).
|
|
||||||
*/
|
|
||||||
private String cveUrl20Modified;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get the value of cveUrl20Modified.
|
* Get the value of cveUrl20Modified.
|
||||||
*
|
*
|
||||||
@@ -694,11 +760,6 @@ public class DependencyCheckScanAgent {
|
|||||||
this.cveUrl20Modified = cveUrl20Modified;
|
this.cveUrl20Modified = cveUrl20Modified;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Base Data Mirror URL for CVE 1.2.
|
|
||||||
*/
|
|
||||||
private String cveUrl12Base;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get the value of cveUrl12Base.
|
* Get the value of cveUrl12Base.
|
||||||
*
|
*
|
||||||
@@ -717,11 +778,6 @@ public class DependencyCheckScanAgent {
|
|||||||
this.cveUrl12Base = cveUrl12Base;
|
this.cveUrl12Base = cveUrl12Base;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Data Mirror URL for CVE 2.0.
|
|
||||||
*/
|
|
||||||
private String cveUrl20Base;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get the value of cveUrl20Base.
|
* Get the value of cveUrl20Base.
|
||||||
*
|
*
|
||||||
@@ -740,11 +796,6 @@ public class DependencyCheckScanAgent {
|
|||||||
this.cveUrl20Base = cveUrl20Base;
|
this.cveUrl20Base = cveUrl20Base;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* The path to Mono for .NET assembly analysis on non-windows systems.
|
|
||||||
*/
|
|
||||||
private String pathToMono;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get the value of pathToMono.
|
* Get the value of pathToMono.
|
||||||
*
|
*
|
||||||
@@ -762,18 +813,23 @@ public class DependencyCheckScanAgent {
|
|||||||
public void setPathToMono(String pathToMono) {
|
public void setPathToMono(String pathToMono) {
|
||||||
this.pathToMono = pathToMono;
|
this.pathToMono = pathToMono;
|
||||||
}
|
}
|
||||||
|
//</editor-fold>
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Executes the Dependency-Check on the dependent libraries.
|
* Executes the Dependency-Check on the dependent libraries.
|
||||||
*
|
*
|
||||||
* @return the Engine used to scan the dependencies.
|
* @return the Engine used to scan the dependencies.
|
||||||
* @throws org.owasp.dependencycheck.data.nvdcve.DatabaseException thrown if there is an exception connecting to the
|
* @throws ExceptionCollection a collection of one or more exceptions that
|
||||||
* database
|
* occurred during analysis.
|
||||||
*/
|
*/
|
||||||
private Engine executeDependencyCheck() throws DatabaseException {
|
private Engine executeDependencyCheck() throws ExceptionCollection {
|
||||||
populateSettings();
|
populateSettings();
|
||||||
Engine engine = null;
|
final Engine engine;
|
||||||
engine = new Engine();
|
try {
|
||||||
|
engine = new Engine();
|
||||||
|
} catch (DatabaseException ex) {
|
||||||
|
throw new ExceptionCollection(ex, true);
|
||||||
|
}
|
||||||
engine.setDependencies(this.dependencies);
|
engine.setDependencies(this.dependencies);
|
||||||
engine.analyzeDependencies();
|
engine.analyzeDependencies();
|
||||||
return engine;
|
return engine;
|
||||||
@@ -787,35 +843,25 @@ public class DependencyCheckScanAgent {
|
|||||||
*/
|
*/
|
||||||
private void generateExternalReports(Engine engine, File outDirectory) {
|
private void generateExternalReports(Engine engine, File outDirectory) {
|
||||||
DatabaseProperties prop = null;
|
DatabaseProperties prop = null;
|
||||||
CveDB cve = null;
|
try (CveDB cve = CveDB.getInstance()) {
|
||||||
try {
|
|
||||||
cve = new CveDB();
|
|
||||||
cve.open();
|
|
||||||
prop = cve.getDatabaseProperties();
|
prop = cve.getDatabaseProperties();
|
||||||
} catch (DatabaseException ex) {
|
} catch (DatabaseException ex) {
|
||||||
LOGGER.log(Level.FINE, "Unable to retrieve DB Properties", ex);
|
//TODO shouldn't this be a fatal exception
|
||||||
} finally {
|
LOGGER.debug("Unable to retrieve DB Properties", ex);
|
||||||
if (cve != null) {
|
|
||||||
cve.close();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
final ReportGenerator r = new ReportGenerator(this.applicationName, engine.getDependencies(), engine.getAnalyzers(), prop);
|
final ReportGenerator r = new ReportGenerator(this.applicationName, engine.getDependencies(), engine.getAnalyzers(), prop);
|
||||||
try {
|
try {
|
||||||
r.generateReports(outDirectory.getCanonicalPath(), this.reportFormat.name());
|
r.generateReports(outDirectory.getCanonicalPath(), this.reportFormat.name());
|
||||||
} catch (IOException ex) {
|
} catch (IOException | ReportException ex) {
|
||||||
LOGGER.log(Level.SEVERE,
|
LOGGER.error("Unexpected exception occurred during analysis; please see the verbose error log for more details.");
|
||||||
"Unexpected exception occurred during analysis; please see the verbose error log for more details.");
|
LOGGER.debug("", ex);
|
||||||
LOGGER.log(Level.FINE, null, ex);
|
|
||||||
} catch (Throwable ex) {
|
|
||||||
LOGGER.log(Level.SEVERE,
|
|
||||||
"Unexpected exception occurred during analysis; please see the verbose error log for more details.");
|
|
||||||
LOGGER.log(Level.FINE, null, ex);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Takes the properties supplied and updates the dependency-check settings. Additionally, this sets the system
|
* Takes the properties supplied and updates the dependency-check settings.
|
||||||
* properties required to change the proxy server, port, and connection timeout.
|
* Additionally, this sets the system properties required to change the
|
||||||
|
* proxy server, port, and connection timeout.
|
||||||
*/
|
*/
|
||||||
private void populateSettings() {
|
private void populateSettings() {
|
||||||
Settings.initialize();
|
Settings.initialize();
|
||||||
@@ -830,101 +876,72 @@ public class DependencyCheckScanAgent {
|
|||||||
}
|
}
|
||||||
|
|
||||||
Settings.setBoolean(Settings.KEYS.AUTO_UPDATE, autoUpdate);
|
Settings.setBoolean(Settings.KEYS.AUTO_UPDATE, autoUpdate);
|
||||||
|
Settings.setStringIfNotEmpty(Settings.KEYS.PROXY_SERVER, proxyServer);
|
||||||
if (proxyServer != null && !proxyServer.isEmpty()) {
|
Settings.setStringIfNotEmpty(Settings.KEYS.PROXY_PORT, proxyPort);
|
||||||
Settings.setString(Settings.KEYS.PROXY_SERVER, proxyServer);
|
Settings.setStringIfNotEmpty(Settings.KEYS.PROXY_USERNAME, proxyUsername);
|
||||||
}
|
Settings.setStringIfNotEmpty(Settings.KEYS.PROXY_PASSWORD, proxyPassword);
|
||||||
if (proxyPort != null && !proxyPort.isEmpty()) {
|
Settings.setStringIfNotEmpty(Settings.KEYS.CONNECTION_TIMEOUT, connectionTimeout);
|
||||||
Settings.setString(Settings.KEYS.PROXY_PORT, proxyPort);
|
Settings.setStringIfNotEmpty(Settings.KEYS.SUPPRESSION_FILE, suppressionFile);
|
||||||
}
|
Settings.setBoolean(Settings.KEYS.ANALYZER_CENTRAL_ENABLED, centralAnalyzerEnabled);
|
||||||
if (proxyUsername != null && !proxyUsername.isEmpty()) {
|
Settings.setStringIfNotEmpty(Settings.KEYS.ANALYZER_CENTRAL_URL, centralUrl);
|
||||||
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.setBoolean(Settings.KEYS.ANALYZER_NEXUS_ENABLED, nexusAnalyzerEnabled);
|
Settings.setBoolean(Settings.KEYS.ANALYZER_NEXUS_ENABLED, nexusAnalyzerEnabled);
|
||||||
if (nexusUrl != null && !nexusUrl.isEmpty()) {
|
Settings.setStringIfNotEmpty(Settings.KEYS.ANALYZER_NEXUS_URL, nexusUrl);
|
||||||
Settings.setString(Settings.KEYS.ANALYZER_NEXUS_URL, nexusUrl);
|
Settings.setBoolean(Settings.KEYS.ANALYZER_NEXUS_USES_PROXY, nexusUsesProxy);
|
||||||
}
|
Settings.setStringIfNotEmpty(Settings.KEYS.DB_DRIVER_NAME, databaseDriverName);
|
||||||
Settings.setBoolean(Settings.KEYS.ANALYZER_NEXUS_PROXY, nexusUsesProxy);
|
Settings.setStringIfNotEmpty(Settings.KEYS.DB_DRIVER_PATH, databaseDriverPath);
|
||||||
if (databaseDriverName != null && !databaseDriverName.isEmpty()) {
|
Settings.setStringIfNotEmpty(Settings.KEYS.DB_CONNECTION_STRING, connectionString);
|
||||||
Settings.setString(Settings.KEYS.DB_DRIVER_NAME, databaseDriverName);
|
Settings.setStringIfNotEmpty(Settings.KEYS.DB_USER, databaseUser);
|
||||||
}
|
Settings.setStringIfNotEmpty(Settings.KEYS.DB_PASSWORD, databasePassword);
|
||||||
if (databaseDriverPath != null && !databaseDriverPath.isEmpty()) {
|
Settings.setStringIfNotEmpty(Settings.KEYS.ADDITIONAL_ZIP_EXTENSIONS, zipExtensions);
|
||||||
Settings.setString(Settings.KEYS.DB_DRIVER_PATH, databaseDriverPath);
|
Settings.setStringIfNotEmpty(Settings.KEYS.CVE_MODIFIED_12_URL, cveUrl12Modified);
|
||||||
}
|
Settings.setStringIfNotEmpty(Settings.KEYS.CVE_MODIFIED_20_URL, cveUrl20Modified);
|
||||||
if (connectionString != null && !connectionString.isEmpty()) {
|
Settings.setStringIfNotEmpty(Settings.KEYS.CVE_SCHEMA_1_2, cveUrl12Base);
|
||||||
Settings.setString(Settings.KEYS.DB_CONNECTION_STRING, connectionString);
|
Settings.setStringIfNotEmpty(Settings.KEYS.CVE_SCHEMA_2_0, cveUrl20Base);
|
||||||
}
|
Settings.setStringIfNotEmpty(Settings.KEYS.ANALYZER_ASSEMBLY_MONO_PATH, pathToMono);
|
||||||
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);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Executes the dependency-check and generates the report.
|
* Executes the dependency-check and generates the report.
|
||||||
*
|
*
|
||||||
* @throws org.owasp.dependencycheck.exception.ScanAgentException thrown if there is an exception executing the
|
* @return a reference to the engine used to perform the scan.
|
||||||
* scan.
|
* @throws org.owasp.dependencycheck.exception.ScanAgentException thrown if
|
||||||
|
* there is an exception executing the scan.
|
||||||
*/
|
*/
|
||||||
public void execute() throws ScanAgentException {
|
public Engine execute() throws ScanAgentException {
|
||||||
Engine engine = null;
|
Engine engine = null;
|
||||||
try {
|
try {
|
||||||
engine = executeDependencyCheck();
|
engine = executeDependencyCheck();
|
||||||
generateExternalReports(engine, new File(this.reportOutputDirectory));
|
if (this.generateReport) {
|
||||||
|
generateExternalReports(engine, new File(this.reportOutputDirectory));
|
||||||
|
}
|
||||||
if (this.showSummary) {
|
if (this.showSummary) {
|
||||||
showSummary(engine.getDependencies());
|
showSummary(engine.getDependencies());
|
||||||
}
|
}
|
||||||
if (this.failBuildOnCVSS <= 10) {
|
if (this.failBuildOnCVSS <= 10) {
|
||||||
checkForFailure(engine.getDependencies());
|
checkForFailure(engine.getDependencies());
|
||||||
}
|
}
|
||||||
} catch (DatabaseException ex) {
|
} catch (ExceptionCollection ex) {
|
||||||
LOGGER.log(Level.SEVERE,
|
if (ex.isFatal()) {
|
||||||
"Unable to connect to the dependency-check database; analysis has stopped");
|
LOGGER.error("A fatal exception occurred during analysis; analysis has stopped. Please see the debug log for more details.");
|
||||||
LOGGER.log(Level.FINE, "", ex);
|
LOGGER.debug("", ex);
|
||||||
|
}
|
||||||
|
throw new ScanAgentException("One or more exceptions occurred during analysis; please see the debug log for more details.", ex);
|
||||||
} finally {
|
} finally {
|
||||||
Settings.cleanup(true);
|
Settings.cleanup(true);
|
||||||
if (engine != null) {
|
if (engine != null) {
|
||||||
engine.cleanup();
|
engine.cleanup();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
return engine;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Checks to see if a vulnerability has been identified with a CVSS score that is above the threshold set in the
|
* Checks to see if a vulnerability has been identified with a CVSS score
|
||||||
* configuration.
|
* that is above the threshold set in the configuration.
|
||||||
*
|
*
|
||||||
* @param dependencies the list of dependency objects
|
* @param dependencies the list of dependency objects
|
||||||
* @throws org.owasp.dependencycheck.exception.ScanAgentException thrown if there is an exception executing the
|
* @throws org.owasp.dependencycheck.exception.ScanAgentException thrown if
|
||||||
* scan.
|
* there is an exception executing the scan.
|
||||||
*/
|
*/
|
||||||
private void checkForFailure(List<Dependency> dependencies) throws ScanAgentException {
|
private void checkForFailure(List<Dependency> dependencies) throws ScanAgentException {
|
||||||
final StringBuilder ids = new StringBuilder();
|
final StringBuilder ids = new StringBuilder();
|
||||||
@@ -944,7 +961,7 @@ public class DependencyCheckScanAgent {
|
|||||||
}
|
}
|
||||||
if (ids.length() > 0) {
|
if (ids.length() > 0) {
|
||||||
final String msg = String.format("%n%nDependency-Check Failure:%n"
|
final String msg = String.format("%n%nDependency-Check Failure:%n"
|
||||||
+ "One or more dependencies were identified with vulnerabilities that have a CVSS score greater then '%.1f': %s%n"
|
+ "One or more dependencies were identified with vulnerabilities that have a CVSS score greater than '%.1f': %s%n"
|
||||||
+ "See the dependency-check report for more details.%n%n", failBuildOnCVSS, ids.toString());
|
+ "See the dependency-check report for more details.%n%n", failBuildOnCVSS, ids.toString());
|
||||||
|
|
||||||
throw new ScanAgentException(msg);
|
throw new ScanAgentException(msg);
|
||||||
@@ -952,7 +969,8 @@ public class DependencyCheckScanAgent {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Generates a warning message listing a summary of dependencies and their associated CPE and CVE entries.
|
* Generates a warning message listing a summary of dependencies and their
|
||||||
|
* associated CPE and CVE entries.
|
||||||
*
|
*
|
||||||
* @param dependencies a list of dependency objects
|
* @param dependencies a list of dependency objects
|
||||||
*/
|
*/
|
||||||
@@ -984,11 +1002,9 @@ public class DependencyCheckScanAgent {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (summary.length() > 0) {
|
if (summary.length() > 0) {
|
||||||
final String msg = String.format("%n%n"
|
LOGGER.warn("\n\nOne or more dependencies were identified with known vulnerabilities:\n\n{}\n\n"
|
||||||
+ "One or more dependencies were identified with known vulnerabilities:%n%n%s"
|
+ "See the dependency-check report for more details.\n\n",
|
||||||
+ "%n%nSee the dependency-check report for more details.%n%n", summary.toString());
|
summary.toString());
|
||||||
LOGGER.log(Level.WARNING, msg);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,13 +1,6 @@
|
|||||||
/**
|
/**
|
||||||
* <html>
|
* The agent package holds an agent API that can be used by other applications that have information about dependencies; but would
|
||||||
* <head>
|
* rather implement something in their code directly rather then spawn a process to run the entire dependency-check engine. This
|
||||||
* <title>org.owasp.dependencycheck.agent</title>
|
* basically provides programmatic access to running a scan.
|
||||||
* </head>
|
|
||||||
* <body>
|
|
||||||
* The agent package holds an agent API that can be used by other applications that have information about dependencies;
|
|
||||||
* but would rather implement something in their code directly rather then spawn a process to run the entire
|
|
||||||
* dependency-check engine. This basically provides programmatic access to running a scan.
|
|
||||||
* </body>
|
|
||||||
* </html>
|
|
||||||
*/
|
*/
|
||||||
package org.owasp.dependencycheck.agent;
|
package org.owasp.dependencycheck.agent;
|
||||||
|
|||||||
@@ -17,20 +17,125 @@
|
|||||||
*/
|
*/
|
||||||
package org.owasp.dependencycheck.analyzer;
|
package org.owasp.dependencycheck.analyzer;
|
||||||
|
|
||||||
|
import org.owasp.dependencycheck.Engine;
|
||||||
|
import org.owasp.dependencycheck.analyzer.exception.AnalysisException;
|
||||||
|
import org.owasp.dependencycheck.dependency.Dependency;
|
||||||
|
import org.owasp.dependencycheck.exception.InitializationException;
|
||||||
|
import org.owasp.dependencycheck.utils.InvalidSettingException;
|
||||||
|
import org.owasp.dependencycheck.utils.Settings;
|
||||||
|
import org.slf4j.Logger;
|
||||||
|
import org.slf4j.LoggerFactory;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
* Base class for analyzers to avoid code duplication of initialize and close as
|
||||||
|
* most analyzers do not need these methods.
|
||||||
*
|
*
|
||||||
* @author Jeremy Long <jeremy.long@owasp.org>
|
* @author Jeremy Long
|
||||||
*/
|
*/
|
||||||
public abstract class AbstractAnalyzer implements Analyzer {
|
public abstract class AbstractAnalyzer implements Analyzer {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The initialize method does nothing for this Analyzer.
|
* The logger.
|
||||||
|
*/
|
||||||
|
private static final Logger LOGGER = LoggerFactory.getLogger(AbstractAnalyzer.class);
|
||||||
|
/**
|
||||||
|
* A flag indicating whether or not the analyzer is enabled.
|
||||||
|
*/
|
||||||
|
private volatile boolean enabled = true;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the value of enabled.
|
||||||
|
*
|
||||||
|
* @return the value of enabled
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
public boolean isEnabled() {
|
||||||
|
return enabled;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Set the value of enabled.
|
||||||
|
*
|
||||||
|
* @param enabled new value of enabled
|
||||||
|
*/
|
||||||
|
public void setEnabled(boolean enabled) {
|
||||||
|
this.enabled = enabled;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* <p>
|
||||||
|
* Returns the setting key to determine if the analyzer is enabled.</p>
|
||||||
|
*
|
||||||
|
* @return the key for the analyzer's enabled property
|
||||||
|
*/
|
||||||
|
protected abstract String getAnalyzerEnabledSettingKey();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Analyzes a given dependency. If the dependency is an archive, such as a
|
||||||
|
* WAR or EAR, the contents are extracted, scanned, and added to the list of
|
||||||
|
* dependencies within the engine.
|
||||||
|
*
|
||||||
|
* @param dependency the dependency to analyze
|
||||||
|
* @param engine the engine scanning
|
||||||
|
* @throws AnalysisException thrown if there is an analysis exception
|
||||||
|
*/
|
||||||
|
protected abstract void analyzeDependency(Dependency dependency, Engine engine) throws AnalysisException;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Initializes a given Analyzer. This will be skipped if the analyzer is
|
||||||
|
* disabled.
|
||||||
|
*
|
||||||
|
* @throws InitializationException thrown if there is an exception
|
||||||
|
*/
|
||||||
|
protected void initializeAnalyzer() throws InitializationException {
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Closes a given Analyzer. This will be skipped if the analyzer is
|
||||||
|
* disabled.
|
||||||
*
|
*
|
||||||
* @throws Exception thrown if there is an exception
|
* @throws Exception thrown if there is an exception
|
||||||
*/
|
*/
|
||||||
|
protected void closeAnalyzer() throws Exception {
|
||||||
|
// Intentionally empty, analyzer will override this if they must close a resource.
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Analyzes a given dependency. If the dependency is an archive, such as a
|
||||||
|
* WAR or EAR, the contents are extracted, scanned, and added to the list of
|
||||||
|
* dependencies within the engine.
|
||||||
|
*
|
||||||
|
* @param dependency the dependency to analyze
|
||||||
|
* @param engine the engine scanning
|
||||||
|
* @throws AnalysisException thrown if there is an analysis exception
|
||||||
|
*/
|
||||||
@Override
|
@Override
|
||||||
public void initialize() throws Exception {
|
public final void analyze(Dependency dependency, Engine engine) throws AnalysisException {
|
||||||
//do nothing
|
if (this.isEnabled()) {
|
||||||
|
analyzeDependency(dependency, engine);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The initialize method does nothing for this Analyzer.
|
||||||
|
*
|
||||||
|
* @throws InitializationException thrown if there is an exception
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
public final void initialize() throws InitializationException {
|
||||||
|
final String key = getAnalyzerEnabledSettingKey();
|
||||||
|
try {
|
||||||
|
this.setEnabled(Settings.getBoolean(key, true));
|
||||||
|
} catch (InvalidSettingException ex) {
|
||||||
|
LOGGER.warn("Invalid setting for property '{}'", key);
|
||||||
|
LOGGER.debug("", ex);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (isEnabled()) {
|
||||||
|
initializeAnalyzer();
|
||||||
|
} else {
|
||||||
|
LOGGER.debug("{} has been disabled", getName());
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -39,7 +144,19 @@ public abstract class AbstractAnalyzer implements Analyzer {
|
|||||||
* @throws Exception thrown if there is an exception
|
* @throws Exception thrown if there is an exception
|
||||||
*/
|
*/
|
||||||
@Override
|
@Override
|
||||||
public void close() throws Exception {
|
public final void close() throws Exception {
|
||||||
//do nothing
|
if (isEnabled()) {
|
||||||
|
closeAnalyzer();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The default is to support parallel processing.
|
||||||
|
*
|
||||||
|
* @return true
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
public boolean supportsParallelProcessing() {
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -17,55 +17,37 @@
|
|||||||
*/
|
*/
|
||||||
package org.owasp.dependencycheck.analyzer;
|
package org.owasp.dependencycheck.analyzer;
|
||||||
|
|
||||||
|
import org.slf4j.Logger;
|
||||||
|
import org.slf4j.LoggerFactory;
|
||||||
|
|
||||||
|
import java.io.File;
|
||||||
|
import java.io.FileFilter;
|
||||||
import java.util.Collections;
|
import java.util.Collections;
|
||||||
import java.util.HashSet;
|
import java.util.HashSet;
|
||||||
import java.util.Set;
|
import java.util.Set;
|
||||||
import java.util.logging.Level;
|
import org.owasp.dependencycheck.exception.InitializationException;
|
||||||
import java.util.logging.Logger;
|
|
||||||
import org.owasp.dependencycheck.Engine;
|
|
||||||
import org.owasp.dependencycheck.analyzer.exception.AnalysisException;
|
|
||||||
import org.owasp.dependencycheck.dependency.Dependency;
|
|
||||||
import org.owasp.dependencycheck.utils.InvalidSettingException;
|
|
||||||
import org.owasp.dependencycheck.utils.Settings;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The base FileTypeAnalyzer that all analyzers that have specific file types they analyze should extend.
|
* The base FileTypeAnalyzer that all analyzers that have specific file types
|
||||||
|
* they analyze should extend.
|
||||||
*
|
*
|
||||||
* @author Jeremy Long <jeremy.long@owasp.org>
|
* @author Jeremy Long
|
||||||
*/
|
*/
|
||||||
public abstract class AbstractFileTypeAnalyzer extends AbstractAnalyzer implements FileTypeAnalyzer {
|
public abstract class AbstractFileTypeAnalyzer extends AbstractAnalyzer implements FileTypeAnalyzer {
|
||||||
|
|
||||||
//<editor-fold defaultstate="collapsed" desc="Constructor">
|
//<editor-fold defaultstate="collapsed" desc="Field definitions, getters, and setters ">
|
||||||
/**
|
|
||||||
* Base constructor that all children must call. This checks the configuration to determine if the analyzer is
|
|
||||||
* enabled.
|
|
||||||
*/
|
|
||||||
public AbstractFileTypeAnalyzer() {
|
|
||||||
final String key = getAnalyzerEnabledSettingKey();
|
|
||||||
try {
|
|
||||||
enabled = Settings.getBoolean(key, true);
|
|
||||||
} catch (InvalidSettingException ex) {
|
|
||||||
String msg = String.format("Invalid setting for property '%s'", key);
|
|
||||||
LOGGER.log(Level.WARNING, msg);
|
|
||||||
LOGGER.log(Level.FINE, "", ex);
|
|
||||||
msg = String.format("%s has been disabled", getName());
|
|
||||||
LOGGER.log(Level.WARNING, msg);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
//</editor-fold>
|
|
||||||
|
|
||||||
//<editor-fold defaultstate="collapsed" desc="Field definitions">
|
|
||||||
/**
|
/**
|
||||||
* The logger.
|
* The logger.
|
||||||
*/
|
*/
|
||||||
private static final Logger LOGGER = Logger.getLogger(AbstractFileTypeAnalyzer.class.getName());
|
private static final Logger LOGGER = LoggerFactory.getLogger(AbstractFileTypeAnalyzer.class);
|
||||||
/**
|
/**
|
||||||
* Whether the file type analyzer detected any files it needs to analyze.
|
* Whether the file type analyzer detected any files it needs to analyze.
|
||||||
*/
|
*/
|
||||||
private boolean filesMatched = false;
|
private boolean filesMatched = false;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get the value of filesMatched. A flag indicating whether the scan included any file types this analyzer supports.
|
* Get the value of filesMatched. A flag indicating whether the scan
|
||||||
|
* included any file types this analyzer supports.
|
||||||
*
|
*
|
||||||
* @return the value of filesMatched
|
* @return the value of filesMatched
|
||||||
*/
|
*/
|
||||||
@@ -74,7 +56,8 @@ public abstract class AbstractFileTypeAnalyzer extends AbstractAnalyzer implemen
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Set the value of filesMatched. A flag indicating whether the scan included any file types this analyzer supports.
|
* Set the value of filesMatched. A flag indicating whether the scan
|
||||||
|
* included any file types this analyzer supports.
|
||||||
*
|
*
|
||||||
* @param filesMatched new value of filesMatched
|
* @param filesMatched new value of filesMatched
|
||||||
*/
|
*/
|
||||||
@@ -82,136 +65,74 @@ public abstract class AbstractFileTypeAnalyzer extends AbstractAnalyzer implemen
|
|||||||
this.filesMatched = filesMatched;
|
this.filesMatched = filesMatched;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
//</editor-fold>
|
||||||
* A flag indicating whether or not the analyzer is enabled.
|
|
||||||
*/
|
|
||||||
private boolean enabled = true;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Get the value of enabled.
|
|
||||||
*
|
|
||||||
* @return the value of enabled
|
|
||||||
*/
|
|
||||||
public boolean isEnabled() {
|
|
||||||
return enabled;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Set the value of enabled.
|
|
||||||
*
|
|
||||||
* @param enabled new value of enabled
|
|
||||||
*/
|
|
||||||
public void setEnabled(boolean enabled) {
|
|
||||||
this.enabled = enabled;
|
|
||||||
}
|
|
||||||
//</editor-fold>
|
|
||||||
|
|
||||||
//<editor-fold defaultstate="collapsed" desc="Abstract methods children must implement">
|
|
||||||
/**
|
|
||||||
* <p>
|
|
||||||
* Returns a list of supported file extensions. An example would be an analyzer that inspected java jar files. The
|
|
||||||
* getSupportedExtensions function would return a set with a single element "jar".</p>
|
|
||||||
*
|
|
||||||
* <p>
|
|
||||||
* <b>Note:</b> when implementing this the extensions returned MUST be lowercase.</p>
|
|
||||||
*
|
|
||||||
* @return The file extensions supported by this analyzer.
|
|
||||||
*
|
|
||||||
* <p>
|
|
||||||
* If the analyzer returns null it will not cause additional files to be analyzed but will be executed against every
|
|
||||||
* file loaded</p>
|
|
||||||
*/
|
|
||||||
protected abstract Set<String> getSupportedExtensions();
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Initializes the file type analyzer.
|
|
||||||
*
|
|
||||||
* @throws Exception thrown if there is an exception during initialization
|
|
||||||
*/
|
|
||||||
protected abstract void initializeFileTypeAnalyzer() throws Exception;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Analyzes a given dependency. If the dependency is an archive, such as a WAR or EAR, the contents are extracted,
|
|
||||||
* scanned, and added to the list of dependencies within the engine.
|
|
||||||
*
|
|
||||||
* @param dependency the dependency to analyze
|
|
||||||
* @param engine the engine scanning
|
|
||||||
* @throws AnalysisException thrown if there is an analysis exception
|
|
||||||
*/
|
|
||||||
protected abstract void analyzeFileType(Dependency dependency, Engine engine) throws AnalysisException;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* <p>
|
|
||||||
* Returns the setting key to determine if the analyzer is enabled.</p>
|
|
||||||
*
|
|
||||||
* @return the key for the analyzer's enabled property
|
|
||||||
*/
|
|
||||||
protected abstract String getAnalyzerEnabledSettingKey();
|
|
||||||
|
|
||||||
//</editor-fold>
|
|
||||||
//<editor-fold defaultstate="collapsed" desc="Final implementations for the Analyzer interface">
|
//<editor-fold defaultstate="collapsed" desc="Final implementations for the Analyzer interface">
|
||||||
/**
|
/**
|
||||||
* Initializes the analyzer.
|
* Initializes the analyzer.
|
||||||
*
|
*
|
||||||
* @throws Exception thrown if there is an exception during initialization
|
* @throws InitializationException thrown if there is an exception during
|
||||||
|
* initialization
|
||||||
*/
|
*/
|
||||||
@Override
|
@Override
|
||||||
public final void initialize() throws Exception {
|
protected final void initializeAnalyzer() throws InitializationException {
|
||||||
if (filesMatched) {
|
if (filesMatched) {
|
||||||
initializeFileTypeAnalyzer();
|
initializeFileTypeAnalyzer();
|
||||||
} else {
|
} else {
|
||||||
enabled = false;
|
this.setEnabled(false);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
//</editor-fold>
|
||||||
* Analyzes a given dependency. If the dependency is an archive, such as a WAR or EAR, the contents are extracted,
|
//<editor-fold defaultstate="collapsed" desc="Abstract methods children must implement">
|
||||||
* scanned, and added to the list of dependencies within the engine.
|
|
||||||
*
|
|
||||||
* @param dependency the dependency to analyze
|
|
||||||
* @param engine the engine scanning
|
|
||||||
* @throws AnalysisException thrown if there is an analysis exception
|
|
||||||
*/
|
|
||||||
@Override
|
|
||||||
public final void analyze(Dependency dependency, Engine engine) throws AnalysisException {
|
|
||||||
if (enabled) {
|
|
||||||
analyzeFileType(dependency, engine);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Returns whether or not this analyzer can process the given extension.
|
|
||||||
*
|
|
||||||
* @param extension the file extension to test for support.
|
|
||||||
* @return whether or not the specified file extension is supported by this analyzer.
|
|
||||||
*/
|
|
||||||
@Override
|
|
||||||
public final boolean supportsExtension(String extension) {
|
|
||||||
if (!enabled) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
final Set<String> ext = getSupportedExtensions();
|
|
||||||
if (ext == null) {
|
|
||||||
final String msg = String.format("The '%s' analyzer is misconfigured and does not have any file extensions;"
|
|
||||||
+ " it will be disabled", getName());
|
|
||||||
LOGGER.log(Level.SEVERE, msg);
|
|
||||||
return false;
|
|
||||||
} else {
|
|
||||||
final boolean match = ext.contains(extension);
|
|
||||||
if (match) {
|
|
||||||
filesMatched = match;
|
|
||||||
}
|
|
||||||
return match;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
//</editor-fold>
|
|
||||||
|
|
||||||
//<editor-fold defaultstate="collapsed" desc="Static utility methods">
|
|
||||||
/**
|
/**
|
||||||
* <p>
|
* <p>
|
||||||
* Utility method to help in the creation of the extensions set. This constructs a new Set that can be used in a
|
* Returns the {@link java.io.FileFilter} used to determine which files are
|
||||||
* final static declaration.</p>
|
* to be analyzed. An example would be an analyzer that inspected Java jar
|
||||||
|
* files. Implementors may use
|
||||||
|
* {@link org.owasp.dependencycheck.utils.FileFilterBuilder}.</p>
|
||||||
|
* <p>
|
||||||
|
* 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();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Initializes the file type analyzer.
|
||||||
|
*
|
||||||
|
* @throws InitializationException thrown if there is an exception during
|
||||||
|
* initialization
|
||||||
|
*/
|
||||||
|
protected abstract void initializeFileTypeAnalyzer() throws InitializationException;
|
||||||
|
|
||||||
|
//</editor-fold>
|
||||||
|
/**
|
||||||
|
* Determines if the file can be analyzed by the analyzer.
|
||||||
|
*
|
||||||
|
* @param pathname the path to the file
|
||||||
|
* @return true if the file can be analyzed by the given analyzer; otherwise
|
||||||
|
* false
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
public boolean accept(File pathname) {
|
||||||
|
final FileFilter filter = getFileFilter();
|
||||||
|
boolean accepted = false;
|
||||||
|
if (null == filter) {
|
||||||
|
LOGGER.error("The '{}' analyzer is misconfigured and does not have a file filter; it will be disabled", getName());
|
||||||
|
} else if (this.isEnabled()) {
|
||||||
|
accepted = filter.accept(pathname);
|
||||||
|
if (accepted) {
|
||||||
|
filesMatched = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return accepted;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* <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
|
* This implementation was copied from
|
||||||
* http://stackoverflow.com/questions/2041778/initialize-java-hashset-values-by-construction</p>
|
* http://stackoverflow.com/questions/2041778/initialize-java-hashset-values-by-construction</p>
|
||||||
@@ -220,10 +141,8 @@ public abstract class AbstractFileTypeAnalyzer extends AbstractAnalyzer implemen
|
|||||||
* @return a Set of strings.
|
* @return a Set of strings.
|
||||||
*/
|
*/
|
||||||
protected static Set<String> newHashSet(String... strings) {
|
protected static Set<String> newHashSet(String... strings) {
|
||||||
final Set<String> set = new HashSet<String>();
|
final Set<String> set = new HashSet<>(strings.length);
|
||||||
|
|
||||||
Collections.addAll(set, strings);
|
Collections.addAll(set, strings);
|
||||||
return set;
|
return set;
|
||||||
}
|
}
|
||||||
//</editor-fold>
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -24,28 +24,31 @@ import java.net.MalformedURLException;
|
|||||||
import java.net.URL;
|
import java.net.URL;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Set;
|
import java.util.Set;
|
||||||
import java.util.logging.Level;
|
|
||||||
import java.util.logging.Logger;
|
|
||||||
import java.util.regex.Pattern;
|
import java.util.regex.Pattern;
|
||||||
import org.owasp.dependencycheck.suppression.SuppressionParseException;
|
import org.owasp.dependencycheck.exception.InitializationException;
|
||||||
import org.owasp.dependencycheck.suppression.SuppressionParser;
|
import org.owasp.dependencycheck.xml.suppression.SuppressionParseException;
|
||||||
import org.owasp.dependencycheck.suppression.SuppressionRule;
|
import org.owasp.dependencycheck.xml.suppression.SuppressionParser;
|
||||||
|
import org.owasp.dependencycheck.xml.suppression.SuppressionRule;
|
||||||
import org.owasp.dependencycheck.utils.DownloadFailedException;
|
import org.owasp.dependencycheck.utils.DownloadFailedException;
|
||||||
import org.owasp.dependencycheck.utils.Downloader;
|
import org.owasp.dependencycheck.utils.Downloader;
|
||||||
import org.owasp.dependencycheck.utils.FileUtils;
|
import org.owasp.dependencycheck.utils.FileUtils;
|
||||||
import org.owasp.dependencycheck.utils.Settings;
|
import org.owasp.dependencycheck.utils.Settings;
|
||||||
|
import org.slf4j.Logger;
|
||||||
|
import org.slf4j.LoggerFactory;
|
||||||
|
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 <jeremy.long@owasp.org>
|
* @author Jeremy Long
|
||||||
*/
|
*/
|
||||||
public abstract class AbstractSuppressionAnalyzer extends AbstractAnalyzer {
|
public abstract class AbstractSuppressionAnalyzer extends AbstractAnalyzer {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The Logger for use throughout the class
|
* The Logger for use throughout the class
|
||||||
*/
|
*/
|
||||||
private static final Logger LOGGER = Logger.getLogger(AbstractSuppressionAnalyzer.class.getName());
|
private static final Logger LOGGER = LoggerFactory.getLogger(AbstractSuppressionAnalyzer.class);
|
||||||
|
|
||||||
//<editor-fold defaultstate="collapsed" desc="All standard implementation details of Analyzer">
|
//<editor-fold defaultstate="collapsed" desc="All standard implementation details of Analyzer">
|
||||||
/**
|
/**
|
||||||
@@ -61,12 +64,15 @@ public abstract class AbstractSuppressionAnalyzer extends AbstractAnalyzer {
|
|||||||
/**
|
/**
|
||||||
* The initialize method loads the suppression XML file.
|
* The initialize method loads the suppression XML file.
|
||||||
*
|
*
|
||||||
* @throws Exception thrown if there is an exception
|
* @throws InitializationException thrown if there is an exception
|
||||||
*/
|
*/
|
||||||
@Override
|
@Override
|
||||||
public void initialize() throws Exception {
|
public void initializeAnalyzer() throws InitializationException {
|
||||||
super.initialize();
|
try {
|
||||||
loadSuppressionData();
|
loadSuppressionData();
|
||||||
|
} catch (SuppressionParseException ex) {
|
||||||
|
throw new InitializationException("Error initializing the suppression analyzer", ex);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -101,9 +107,10 @@ public abstract class AbstractSuppressionAnalyzer extends AbstractAnalyzer {
|
|||||||
final SuppressionParser parser = new SuppressionParser();
|
final SuppressionParser parser = new SuppressionParser();
|
||||||
File file = null;
|
File file = null;
|
||||||
try {
|
try {
|
||||||
rules = parser.parseSuppressionRules(this.getClass().getClassLoader().getResourceAsStream("dependencycheck-base-suppression.xml"));
|
final InputStream in = this.getClass().getClassLoader().getResourceAsStream("dependencycheck-base-suppression.xml");
|
||||||
} catch (SuppressionParseException ex) {
|
rules = parser.parseSuppressionRules(in);
|
||||||
LOGGER.log(Level.FINE, "Unable to parse the base suppression data file", ex);
|
} catch (SAXException ex) {
|
||||||
|
throw new SuppressionParseException("Unable to parse the base suppression data file", ex);
|
||||||
}
|
}
|
||||||
final String suppressionFilePath = Settings.getString(Settings.KEYS.SUPPRESSION_FILE);
|
final String suppressionFilePath = Settings.getString(Settings.KEYS.SUPPRESSION_FILE);
|
||||||
if (suppressionFilePath == null) {
|
if (suppressionFilePath == null) {
|
||||||
@@ -123,30 +130,33 @@ public abstract class AbstractSuppressionAnalyzer extends AbstractAnalyzer {
|
|||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
file = new File(suppressionFilePath);
|
file = new File(suppressionFilePath);
|
||||||
|
|
||||||
if (!file.exists()) {
|
if (!file.exists()) {
|
||||||
final InputStream suppressionsFromClasspath = this.getClass().getClassLoader().getResourceAsStream(suppressionFilePath);
|
try (InputStream suppressionsFromClasspath = this.getClass().getClassLoader().getResourceAsStream(suppressionFilePath)) {
|
||||||
if (suppressionsFromClasspath != null) {
|
if (suppressionsFromClasspath != null) {
|
||||||
deleteTempFile = true;
|
deleteTempFile = true;
|
||||||
file = FileUtils.getTempFile("suppression", "xml");
|
file = FileUtils.getTempFile("suppression", "xml");
|
||||||
try {
|
try {
|
||||||
org.apache.commons.io.FileUtils.copyInputStreamToFile(suppressionsFromClasspath, file);
|
org.apache.commons.io.FileUtils.copyInputStreamToFile(suppressionsFromClasspath, file);
|
||||||
} catch (IOException ex) {
|
} catch (IOException ex) {
|
||||||
throwSuppressionParseException("Unable to locate suppressions file in classpath", ex);
|
throwSuppressionParseException("Unable to locate suppressions file in classpath", ex);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (file != null) {
|
if (file != null) {
|
||||||
|
if (!file.exists()) {
|
||||||
|
final String msg = String.format("Suppression file '%s' does not exists", file.getPath());
|
||||||
|
LOGGER.warn(msg);
|
||||||
|
throw new SuppressionParseException(msg);
|
||||||
|
}
|
||||||
try {
|
try {
|
||||||
//rules = parser.parseSuppressionRules(file);
|
|
||||||
rules.addAll(parser.parseSuppressionRules(file));
|
rules.addAll(parser.parseSuppressionRules(file));
|
||||||
LOGGER.log(Level.FINE, rules.size() + " suppression rules were loaded.");
|
LOGGER.debug("{} suppression rules were loaded.", rules.size());
|
||||||
} catch (SuppressionParseException ex) {
|
} catch (SuppressionParseException ex) {
|
||||||
final String msg = String.format("Unable to parse suppression xml file '%s'", file.getPath());
|
LOGGER.warn("Unable to parse suppression xml file '{}'", file.getPath());
|
||||||
LOGGER.log(Level.WARNING, msg);
|
LOGGER.warn(ex.getMessage());
|
||||||
LOGGER.log(Level.WARNING, ex.getMessage());
|
|
||||||
LOGGER.log(Level.FINE, "", ex);
|
|
||||||
throw ex;
|
throw ex;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -154,6 +164,8 @@ public abstract class AbstractSuppressionAnalyzer extends AbstractAnalyzer {
|
|||||||
throwSuppressionParseException("Unable to fetch the configured suppression file", ex);
|
throwSuppressionParseException("Unable to fetch the configured suppression file", ex);
|
||||||
} catch (MalformedURLException ex) {
|
} catch (MalformedURLException ex) {
|
||||||
throwSuppressionParseException("Configured suppression file has an invalid URL", ex);
|
throwSuppressionParseException("Configured suppression file has an invalid URL", ex);
|
||||||
|
} catch (SuppressionParseException ex) {
|
||||||
|
throw ex;
|
||||||
} catch (IOException ex) {
|
} catch (IOException ex) {
|
||||||
throwSuppressionParseException("Unable to create temp file for suppressions", ex);
|
throwSuppressionParseException("Unable to create temp file for suppressions", ex);
|
||||||
} finally {
|
} finally {
|
||||||
@@ -168,11 +180,12 @@ public abstract class AbstractSuppressionAnalyzer extends AbstractAnalyzer {
|
|||||||
*
|
*
|
||||||
* @param message the exception message
|
* @param message the exception message
|
||||||
* @param exception the cause of the exception
|
* @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 {
|
private void throwSuppressionParseException(String message, Exception exception) throws SuppressionParseException {
|
||||||
LOGGER.log(Level.WARNING, message);
|
LOGGER.warn(message);
|
||||||
LOGGER.log(Level.FINE, "", exception);
|
LOGGER.debug("", exception);
|
||||||
throw new SuppressionParseException(message, exception);
|
throw new SuppressionParseException(message, exception);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -20,7 +20,7 @@ package org.owasp.dependencycheck.analyzer;
|
|||||||
/**
|
/**
|
||||||
* An enumeration defining the phases of analysis.
|
* An enumeration defining the phases of analysis.
|
||||||
*
|
*
|
||||||
* @author Jeremy Long <jeremy.long@owasp.org>
|
* @author Jeremy Long
|
||||||
*/
|
*/
|
||||||
public enum AnalysisPhase {
|
public enum AnalysisPhase {
|
||||||
|
|
||||||
@@ -28,10 +28,18 @@ public enum AnalysisPhase {
|
|||||||
* Initialization phase.
|
* Initialization phase.
|
||||||
*/
|
*/
|
||||||
INITIAL,
|
INITIAL,
|
||||||
|
/**
|
||||||
|
* Pre information collection phase.
|
||||||
|
*/
|
||||||
|
PRE_INFORMATION_COLLECTION,
|
||||||
/**
|
/**
|
||||||
* Information collection phase.
|
* Information collection phase.
|
||||||
*/
|
*/
|
||||||
INFORMATION_COLLECTION,
|
INFORMATION_COLLECTION,
|
||||||
|
/**
|
||||||
|
* Post information collection phase.
|
||||||
|
*/
|
||||||
|
POST_INFORMATION_COLLECTION,
|
||||||
/**
|
/**
|
||||||
* Pre identifier analysis phase.
|
* Pre identifier analysis phase.
|
||||||
*/
|
*/
|
||||||
|
|||||||
@@ -20,24 +20,28 @@ package org.owasp.dependencycheck.analyzer;
|
|||||||
import org.owasp.dependencycheck.Engine;
|
import org.owasp.dependencycheck.Engine;
|
||||||
import org.owasp.dependencycheck.analyzer.exception.AnalysisException;
|
import org.owasp.dependencycheck.analyzer.exception.AnalysisException;
|
||||||
import org.owasp.dependencycheck.dependency.Dependency;
|
import org.owasp.dependencycheck.dependency.Dependency;
|
||||||
|
import org.owasp.dependencycheck.exception.InitializationException;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* An interface that defines an Analyzer that is used to identify Dependencies. An analyzer will collect information
|
* An interface that defines an Analyzer that is used to identify Dependencies.
|
||||||
* about the dependency in the form of Evidence.
|
* An analyzer will collect information about the dependency in the form of
|
||||||
|
* Evidence.
|
||||||
*
|
*
|
||||||
* @author Jeremy Long <jeremy.long@owasp.org>
|
* @author Jeremy Long
|
||||||
*/
|
*/
|
||||||
public interface Analyzer {
|
public interface Analyzer {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Analyzes the given dependency. The analysis could be anything from identifying an Identifier for the dependency,
|
* Analyzes the given dependency. The analysis could be anything from
|
||||||
* to finding vulnerabilities, etc. Additionally, if the analyzer collects enough information to add a description
|
* identifying an Identifier for the dependency, to finding vulnerabilities,
|
||||||
* or license information for the dependency it should be added.
|
* etc. Additionally, if the analyzer collects enough information to add a
|
||||||
|
* description or license information for the dependency it should be added.
|
||||||
*
|
*
|
||||||
* @param dependency a dependency to analyze.
|
* @param dependency a dependency to analyze.
|
||||||
* @param engine the engine that is scanning the dependencies - this is useful if we need to check other
|
* @param engine the engine that is scanning the dependencies - this is
|
||||||
* dependencies
|
* useful if we need to check other dependencies
|
||||||
* @throws AnalysisException is thrown if there is an error analyzing the dependency file
|
* @throws AnalysisException is thrown if there is an error analyzing the
|
||||||
|
* dependency file
|
||||||
*/
|
*/
|
||||||
void analyze(Dependency dependency, Engine engine) throws AnalysisException;
|
void analyze(Dependency dependency, Engine engine) throws AnalysisException;
|
||||||
|
|
||||||
@@ -56,16 +60,33 @@ public interface Analyzer {
|
|||||||
AnalysisPhase getAnalysisPhase();
|
AnalysisPhase getAnalysisPhase();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The initialize method is called (once) prior to the analyze method being called on all of the dependencies.
|
* The initialize method is called (once) prior to the analyze method being
|
||||||
|
* called on all of the dependencies.
|
||||||
*
|
*
|
||||||
* @throws Exception is thrown if an exception occurs initializing the analyzer.
|
* @throws InitializationException is thrown if an exception occurs
|
||||||
|
* initializing the analyzer.
|
||||||
*/
|
*/
|
||||||
void initialize() throws Exception;
|
void initialize() throws InitializationException;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The close method is called after all of the dependencies have been analyzed.
|
* The close method is called after all of the dependencies have been
|
||||||
|
* analyzed.
|
||||||
*
|
*
|
||||||
* @throws Exception is thrown if an exception occurs closing the analyzer.
|
* @throws Exception is thrown if an exception occurs closing the analyzer.
|
||||||
*/
|
*/
|
||||||
void close() throws Exception;
|
void close() throws Exception;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns whether multiple instances of the same type of analyzer can run in parallel.
|
||||||
|
* Note that running analyzers of different types in parallel is not supported at all.
|
||||||
|
*
|
||||||
|
* @return {@code true} if the analyzer supports parallel processing, {@code false} else
|
||||||
|
*/
|
||||||
|
boolean supportsParallelProcessing();
|
||||||
|
/**
|
||||||
|
* Get the value of enabled.
|
||||||
|
*
|
||||||
|
* @return the value of enabled
|
||||||
|
*/
|
||||||
|
boolean isEnabled();
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -17,21 +17,30 @@
|
|||||||
*/
|
*/
|
||||||
package org.owasp.dependencycheck.analyzer;
|
package org.owasp.dependencycheck.analyzer;
|
||||||
|
|
||||||
|
import java.util.ArrayList;
|
||||||
import java.util.Iterator;
|
import java.util.Iterator;
|
||||||
|
import java.util.List;
|
||||||
import java.util.ServiceLoader;
|
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
|
* The Analyzer Service Loader. This class loads all services that implement
|
||||||
* org.owasp.dependencycheck.analyzer.Analyzer.
|
* org.owasp.dependencycheck.analyzer.Analyzer.
|
||||||
*
|
*
|
||||||
* @author Jeremy Long <jeremy.long@owasp.org>
|
* @author Jeremy Long
|
||||||
*/
|
*/
|
||||||
public class AnalyzerService {
|
public class AnalyzerService {
|
||||||
|
/**
|
||||||
|
* The Logger for use throughout the class.
|
||||||
|
*/
|
||||||
|
private static final org.slf4j.Logger LOGGER = LoggerFactory.getLogger(AnalyzerService.class);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The service loader for analyzers.
|
* The service loader for analyzers.
|
||||||
*/
|
*/
|
||||||
private final ServiceLoader<Analyzer> loader;
|
private final ServiceLoader<Analyzer> service;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Creates a new instance of AnalyzerService.
|
* 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
|
* @param classLoader the ClassLoader to use when dynamically loading Analyzer and Update services
|
||||||
*/
|
*/
|
||||||
public AnalyzerService(ClassLoader classLoader) {
|
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() {
|
public List<Analyzer> getAnalyzers() {
|
||||||
return loader.iterator();
|
final List<Analyzer> analyzers = new ArrayList<>();
|
||||||
|
final Iterator<Analyzer> iterator = service.iterator();
|
||||||
|
boolean experimentalEnabled = false;
|
||||||
|
try {
|
||||||
|
experimentalEnabled = Settings.getBoolean(Settings.KEYS.ANALYZER_EXPERIMENTAL_ENABLED, false);
|
||||||
|
} catch (InvalidSettingException ex) {
|
||||||
|
LOGGER.error("invalid 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,21 +18,17 @@
|
|||||||
package org.owasp.dependencycheck.analyzer;
|
package org.owasp.dependencycheck.analyzer;
|
||||||
|
|
||||||
import java.io.BufferedInputStream;
|
import java.io.BufferedInputStream;
|
||||||
import java.io.BufferedOutputStream;
|
|
||||||
import java.io.File;
|
import java.io.File;
|
||||||
|
import java.io.FileFilter;
|
||||||
import java.io.FileInputStream;
|
import java.io.FileInputStream;
|
||||||
import java.io.FileNotFoundException;
|
import java.io.FileNotFoundException;
|
||||||
import java.io.FileOutputStream;
|
import java.io.FileOutputStream;
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.util.ArrayList;
|
|
||||||
import java.util.Arrays;
|
|
||||||
import java.util.Collections;
|
import java.util.Collections;
|
||||||
import java.util.Enumeration;
|
import java.util.Enumeration;
|
||||||
import java.util.HashSet;
|
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Set;
|
import java.util.Set;
|
||||||
import java.util.logging.Level;
|
|
||||||
import java.util.logging.Logger;
|
|
||||||
import org.apache.commons.compress.archivers.ArchiveEntry;
|
import org.apache.commons.compress.archivers.ArchiveEntry;
|
||||||
import org.apache.commons.compress.archivers.ArchiveInputStream;
|
import org.apache.commons.compress.archivers.ArchiveInputStream;
|
||||||
import org.apache.commons.compress.archivers.tar.TarArchiveInputStream;
|
import org.apache.commons.compress.archivers.tar.TarArchiveInputStream;
|
||||||
@@ -40,34 +36,40 @@ import org.apache.commons.compress.archivers.zip.ZipArchiveEntry;
|
|||||||
import org.apache.commons.compress.archivers.zip.ZipArchiveInputStream;
|
import org.apache.commons.compress.archivers.zip.ZipArchiveInputStream;
|
||||||
import org.apache.commons.compress.archivers.zip.ZipFile;
|
import org.apache.commons.compress.archivers.zip.ZipFile;
|
||||||
import org.apache.commons.compress.compressors.CompressorInputStream;
|
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.GzipCompressorInputStream;
|
||||||
import org.apache.commons.compress.compressors.gzip.GzipUtils;
|
import org.apache.commons.compress.compressors.gzip.GzipUtils;
|
||||||
|
import org.apache.commons.compress.utils.IOUtils;
|
||||||
|
|
||||||
import org.owasp.dependencycheck.Engine;
|
import org.owasp.dependencycheck.Engine;
|
||||||
import org.owasp.dependencycheck.analyzer.exception.AnalysisException;
|
import org.owasp.dependencycheck.analyzer.exception.AnalysisException;
|
||||||
import org.owasp.dependencycheck.analyzer.exception.ArchiveExtractionException;
|
import org.owasp.dependencycheck.analyzer.exception.ArchiveExtractionException;
|
||||||
import org.owasp.dependencycheck.dependency.Dependency;
|
import org.owasp.dependencycheck.dependency.Dependency;
|
||||||
|
import org.owasp.dependencycheck.exception.InitializationException;
|
||||||
|
import org.owasp.dependencycheck.utils.FileFilterBuilder;
|
||||||
import org.owasp.dependencycheck.utils.FileUtils;
|
import org.owasp.dependencycheck.utils.FileUtils;
|
||||||
import org.owasp.dependencycheck.utils.Settings;
|
import org.owasp.dependencycheck.utils.Settings;
|
||||||
|
|
||||||
|
import org.slf4j.Logger;
|
||||||
|
import org.slf4j.LoggerFactory;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* <p>
|
* <p>
|
||||||
* An analyzer that extracts files from archives and ensures any supported files contained within the archive are added
|
* An analyzer that extracts files from archives and ensures any supported files
|
||||||
* to the dependency list.</p>
|
* contained within the archive are added to the dependency list.</p>
|
||||||
*
|
*
|
||||||
* @author Jeremy Long <jeremy.long@owasp.org>
|
* @author Jeremy Long
|
||||||
*/
|
*/
|
||||||
public class ArchiveAnalyzer extends AbstractFileTypeAnalyzer {
|
public class ArchiveAnalyzer extends AbstractFileTypeAnalyzer {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The logger.
|
* The logger.
|
||||||
*/
|
*/
|
||||||
private static final Logger LOGGER = Logger.getLogger(ArchiveAnalyzer.class.getName());
|
private static final Logger LOGGER = LoggerFactory.getLogger(ArchiveAnalyzer.class);
|
||||||
/**
|
/**
|
||||||
* The buffer size to use when extracting files from the archive.
|
* The count of directories created during analysis. This is used for
|
||||||
*/
|
* creating temporary directories.
|
||||||
private static final int BUFFER_SIZE = 4096;
|
|
||||||
/**
|
|
||||||
* The count of directories created during analysis. This is used for creating temporary directories.
|
|
||||||
*/
|
*/
|
||||||
private static int dirCount = 0;
|
private static int dirCount = 0;
|
||||||
/**
|
/**
|
||||||
@@ -75,7 +77,8 @@ public class ArchiveAnalyzer extends AbstractFileTypeAnalyzer {
|
|||||||
*/
|
*/
|
||||||
private File tempFileLocation = null;
|
private File tempFileLocation = null;
|
||||||
/**
|
/**
|
||||||
* The max scan depth that the analyzer will recursively extract nested archives.
|
* The max scan depth that the analyzer will recursively extract nested
|
||||||
|
* archives.
|
||||||
*/
|
*/
|
||||||
private static final int MAX_SCAN_DEPTH = Settings.getInt("archive.scan.depth", 3);
|
private static final int MAX_SCAN_DEPTH = Settings.getInt("archive.scan.depth", 3);
|
||||||
/**
|
/**
|
||||||
@@ -95,35 +98,43 @@ public class ArchiveAnalyzer extends AbstractFileTypeAnalyzer {
|
|||||||
/**
|
/**
|
||||||
* The set of things we can handle with Zip methods
|
* The set of things we can handle with Zip methods
|
||||||
*/
|
*/
|
||||||
private static final Set<String> ZIPPABLES = newHashSet("zip", "ear", "war", "jar", "sar", "apk", "nupkg");
|
private static final Set<String> KNOWN_ZIP_EXT = newHashSet("zip", "ear", "war", "jar", "sar", "apk", "nupkg");
|
||||||
/**
|
/**
|
||||||
* The set of file extensions supported by this analyzer. Note for developers, any additions to this list will need
|
* The set of file extensions supported by this analyzer. Note for
|
||||||
* to be explicitly handled in extractFiles().
|
* developers, any additions to this list will need to be explicitly handled
|
||||||
|
* in {@link #extractFiles(File, File, Engine)}.
|
||||||
*/
|
*/
|
||||||
private static final Set<String> EXTENSIONS = newHashSet("tar", "gz", "tgz");
|
private static final Set<String> EXTENSIONS = newHashSet("tar", "gz", "tgz", "bz2", "tbz2");
|
||||||
|
|
||||||
/**
|
|
||||||
* The set of file extensions to remove from the engine's collection of dependencies.
|
|
||||||
*/
|
|
||||||
private static final Set<String> REMOVE_FROM_ANALYSIS = newHashSet("zip", "tar", "gz", "tgz"); //TODO add nupkg, apk, sar?
|
|
||||||
|
|
||||||
static {
|
static {
|
||||||
final String additionalZipExt = Settings.getString(Settings.KEYS.ADDITIONAL_ZIP_EXTENSIONS);
|
final String additionalZipExt = Settings.getString(Settings.KEYS.ADDITIONAL_ZIP_EXTENSIONS);
|
||||||
if (additionalZipExt != null) {
|
if (additionalZipExt != null) {
|
||||||
final HashSet ext = new HashSet<String>(Arrays.asList(additionalZipExt));
|
final String[] ext = additionalZipExt.split("\\s*,\\s*");
|
||||||
ZIPPABLES.addAll(ext);
|
Collections.addAll(KNOWN_ZIP_EXT, ext);
|
||||||
}
|
}
|
||||||
EXTENSIONS.addAll(ZIPPABLES);
|
EXTENSIONS.addAll(KNOWN_ZIP_EXT);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns a list of file EXTENSIONS supported by this analyzer.
|
* Detects files with extensions to remove from the engine's collection of
|
||||||
*
|
* dependencies.
|
||||||
* @return a list of file EXTENSIONS supported by this analyzer.
|
|
||||||
*/
|
*/
|
||||||
|
private static final FileFilter REMOVE_FROM_ANALYSIS = FileFilterBuilder.newInstance()
|
||||||
|
.addExtensions("zip", "tar", "gz", "tgz", "bz2", "tbz2").build();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The file filter used to filter supported files.
|
||||||
|
*/
|
||||||
|
private static final FileFilter FILTER = FileFilterBuilder.newInstance().addExtensions(EXTENSIONS).build();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Detects files with .zip extension.
|
||||||
|
*/
|
||||||
|
private static final FileFilter ZIP_FILTER = FileFilterBuilder.newInstance().addExtensions("zip").build();
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Set<String> getSupportedExtensions() {
|
protected FileFilter getFileFilter() {
|
||||||
return EXTENSIONS;
|
return FILTER;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -148,7 +159,8 @@ public class ArchiveAnalyzer extends AbstractFileTypeAnalyzer {
|
|||||||
//</editor-fold>
|
//</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
|
* @return the analyzer's enabled property setting key
|
||||||
*/
|
*/
|
||||||
@@ -160,120 +172,184 @@ public class ArchiveAnalyzer extends AbstractFileTypeAnalyzer {
|
|||||||
/**
|
/**
|
||||||
* The initialize method does nothing for this Analyzer.
|
* The initialize method does nothing for this Analyzer.
|
||||||
*
|
*
|
||||||
* @throws Exception is thrown if there is an exception deleting or creating temporary files
|
* @throws InitializationException is thrown if there is an exception
|
||||||
|
* deleting or creating temporary files
|
||||||
*/
|
*/
|
||||||
@Override
|
@Override
|
||||||
public void initializeFileTypeAnalyzer() throws Exception {
|
public void initializeFileTypeAnalyzer() throws InitializationException {
|
||||||
final File baseDir = Settings.getTempDirectory();
|
try {
|
||||||
tempFileLocation = File.createTempFile("check", "tmp", baseDir);
|
final File baseDir = Settings.getTempDirectory();
|
||||||
if (!tempFileLocation.delete()) {
|
tempFileLocation = File.createTempFile("check", "tmp", baseDir);
|
||||||
final String msg = String.format("Unable to delete temporary file '%s'.", tempFileLocation.getAbsolutePath());
|
if (!tempFileLocation.delete()) {
|
||||||
throw new AnalysisException(msg);
|
setEnabled(false);
|
||||||
}
|
final String msg = String.format("Unable to delete temporary file '%s'.", tempFileLocation.getAbsolutePath());
|
||||||
if (!tempFileLocation.mkdirs()) {
|
throw new InitializationException(msg);
|
||||||
final String msg = String.format("Unable to create directory '%s'.", tempFileLocation.getAbsolutePath());
|
}
|
||||||
throw new AnalysisException(msg);
|
if (!tempFileLocation.mkdirs()) {
|
||||||
|
setEnabled(false);
|
||||||
|
final String msg = String.format("Unable to create directory '%s'.", tempFileLocation.getAbsolutePath());
|
||||||
|
throw new InitializationException(msg);
|
||||||
|
}
|
||||||
|
} catch (IOException ex) {
|
||||||
|
setEnabled(false);
|
||||||
|
throw new InitializationException("Unable to create a temporary file", ex);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The close method deletes any temporary files and directories created during analysis.
|
* The close method deletes any temporary files and directories created
|
||||||
|
* during analysis.
|
||||||
*
|
*
|
||||||
* @throws Exception thrown if there is an exception deleting temporary files
|
* @throws Exception thrown if there is an exception deleting temporary
|
||||||
|
* files
|
||||||
*/
|
*/
|
||||||
@Override
|
@Override
|
||||||
public void close() throws Exception {
|
public void closeAnalyzer() throws Exception {
|
||||||
if (tempFileLocation != null && tempFileLocation.exists()) {
|
if (tempFileLocation != null && tempFileLocation.exists()) {
|
||||||
LOGGER.log(Level.FINE, "Attempting to delete temporary files");
|
LOGGER.debug("Attempting to delete temporary files");
|
||||||
final boolean success = FileUtils.delete(tempFileLocation);
|
final boolean success = FileUtils.delete(tempFileLocation);
|
||||||
if (!success && tempFileLocation != null & tempFileLocation.exists()) {
|
if (!success && tempFileLocation.exists()) {
|
||||||
LOGGER.log(Level.WARNING, "Failed to delete some temporary files, see the log for more details");
|
final String[] l = tempFileLocation.list();
|
||||||
|
if (l != null && l.length > 0) {
|
||||||
|
LOGGER.warn("Failed to delete some temporary files, see the log for more details");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Analyzes a given dependency. If the dependency is an archive, such as a WAR or EAR, the contents are extracted,
|
* Does not support parallel processing as it both modifies and iterates
|
||||||
* scanned, and added to the list of dependencies within the engine.
|
* over the engine's list of dependencies.
|
||||||
|
*
|
||||||
|
* @return <code>true</code> if the analyzer supports parallel processing;
|
||||||
|
* otherwise <code>false</code>
|
||||||
|
* @see #analyzeDependency(Dependency, Engine)
|
||||||
|
* @see #findMoreDependencies(Engine, File)
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
public boolean supportsParallelProcessing() {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Analyzes a given dependency. If the dependency is an archive, such as a
|
||||||
|
* WAR or EAR, the contents are extracted, scanned, and added to the list of
|
||||||
|
* dependencies within the engine.
|
||||||
*
|
*
|
||||||
* @param dependency the dependency to analyze
|
* @param dependency the dependency to analyze
|
||||||
* @param engine the engine scanning
|
* @param engine the engine scanning
|
||||||
* @throws AnalysisException thrown if there is an analysis exception
|
* @throws AnalysisException thrown if there is an analysis exception
|
||||||
*/
|
*/
|
||||||
@Override
|
@Override
|
||||||
public void analyzeFileType(Dependency dependency, Engine engine) throws AnalysisException {
|
public void analyzeDependency(Dependency dependency, Engine engine) throws AnalysisException {
|
||||||
final File f = new File(dependency.getActualFilePath());
|
final File f = new File(dependency.getActualFilePath());
|
||||||
final File tmpDir = getNextTempDirectory();
|
final File tmpDir = getNextTempDirectory();
|
||||||
extractFiles(f, tmpDir, engine);
|
extractFiles(f, tmpDir, engine);
|
||||||
|
|
||||||
//make a copy
|
//make a copy
|
||||||
List<Dependency> dependencies = new ArrayList<Dependency>(engine.getDependencies());
|
final List<Dependency> dependencySet = findMoreDependencies(engine, tmpDir);
|
||||||
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);
|
|
||||||
|
|
||||||
|
if (dependencySet != null && !dependencySet.isEmpty()) {
|
||||||
for (Dependency d : dependencySet) {
|
for (Dependency d : dependencySet) {
|
||||||
//fix the dependency's display name and path
|
if (d.getFilePath().startsWith(tmpDir.getAbsolutePath())) {
|
||||||
final String displayPath = String.format("%s%s",
|
//fix the dependency's display name and path
|
||||||
dependency.getFilePath(),
|
final String displayPath = String.format("%s%s",
|
||||||
d.getActualFilePath().substring(tmpDir.getAbsolutePath().length()));
|
dependency.getFilePath(),
|
||||||
final String displayName = String.format("%s%s%s",
|
d.getActualFilePath().substring(tmpDir.getAbsolutePath().length()));
|
||||||
dependency.getFileName(),
|
final String displayName = String.format("%s: %s",
|
||||||
File.separator,
|
dependency.getFileName(),
|
||||||
d.getFileName());
|
d.getFileName());
|
||||||
d.setFilePath(displayPath);
|
d.setFilePath(displayPath);
|
||||||
d.setFileName(displayName);
|
d.setFileName(displayName);
|
||||||
|
d.setProjectReferences(dependency.getProjectReferences());
|
||||||
|
|
||||||
//TODO - can we get more evidence from the parent? EAR contains module name, etc.
|
//TODO - can we get more evidence from the parent? EAR contains module name, etc.
|
||||||
//analyze the dependency (i.e. extract files) if it is a supported type.
|
//analyze the dependency (i.e. extract files) if it is a supported type.
|
||||||
if (this.supportsExtension(d.getFileExtension()) && scanDepth < MAX_SCAN_DEPTH) {
|
if (this.accept(d.getActualFile()) && scanDepth < MAX_SCAN_DEPTH) {
|
||||||
scanDepth += 1;
|
scanDepth += 1;
|
||||||
analyze(d, engine);
|
analyze(d, engine);
|
||||||
scanDepth -= 1;
|
scanDepth -= 1;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
for (Dependency sub : dependencySet) {
|
||||||
|
if (sub.getFilePath().startsWith(tmpDir.getAbsolutePath())) {
|
||||||
|
final String displayPath = String.format("%s%s",
|
||||||
|
dependency.getFilePath(),
|
||||||
|
sub.getActualFilePath().substring(tmpDir.getAbsolutePath().length()));
|
||||||
|
final String displayName = String.format("%s: %s",
|
||||||
|
dependency.getFileName(),
|
||||||
|
sub.getFileName());
|
||||||
|
sub.setFilePath(displayPath);
|
||||||
|
sub.setFileName(displayName);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (this.REMOVE_FROM_ANALYSIS.contains(dependency.getFileExtension())) {
|
if (REMOVE_FROM_ANALYSIS.accept(dependency.getActualFile())) {
|
||||||
if ("zip".equals(dependency.getFileExtension()) && isZipFileActuallyJarFile(dependency)) {
|
addDisguisedJarsToDependencies(dependency, engine);
|
||||||
final File tdir = getNextTempDirectory();
|
|
||||||
final String fileName = dependency.getFileName();
|
|
||||||
|
|
||||||
LOGGER.info(String.format("The zip file '%s' appears to be a JAR file, making a deep copy and analyzing it as a JAR.", fileName));
|
|
||||||
|
|
||||||
final File tmpLoc = new File(tdir, fileName.substring(0, fileName.length() - 3) + "jar");
|
|
||||||
try {
|
|
||||||
org.apache.commons.io.FileUtils.copyFile(tdir, tmpLoc);
|
|
||||||
dependencies = new ArrayList<Dependency>(engine.getDependencies());
|
|
||||||
engine.scan(tmpLoc);
|
|
||||||
newDependencies = engine.getDependencies();
|
|
||||||
if (dependencies.size() != newDependencies.size()) {
|
|
||||||
//get the new dependencies
|
|
||||||
final Set<Dependency> dependencySet = new HashSet<Dependency>();
|
|
||||||
dependencySet.addAll(newDependencies);
|
|
||||||
dependencySet.removeAll(dependencies);
|
|
||||||
if (dependencySet.size() != 1) {
|
|
||||||
LOGGER.info("Deep copy of ZIP to JAR file resulted in more then one dependency?");
|
|
||||||
}
|
|
||||||
for (Dependency d : dependencySet) {
|
|
||||||
//fix the dependency's display name and path
|
|
||||||
d.setFilePath(dependency.getFilePath());
|
|
||||||
d.setDisplayFileName(dependency.getFileName());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} catch (IOException ex) {
|
|
||||||
final String msg = String.format("Unable to perform deep copy on '%s'", dependency.getActualFile().getPath());
|
|
||||||
LOGGER.log(Level.FINE, msg, ex);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
engine.getDependencies().remove(dependency);
|
engine.getDependencies().remove(dependency);
|
||||||
}
|
}
|
||||||
Collections.sort(engine.getDependencies());
|
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 tempDir = 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(tempDir, fileName.substring(0, fileName.length() - 3) + "jar");
|
||||||
|
//store the archives sha1 and change it so that the engine doesn't think the zip and jar file are the same
|
||||||
|
// and add it is a related dependency.
|
||||||
|
final String archiveSha1 = dependency.getSha1sum();
|
||||||
|
try {
|
||||||
|
dependency.setSha1sum("");
|
||||||
|
org.apache.commons.io.FileUtils.copyFile(dependency.getActualFile(), tmpLoc);
|
||||||
|
final List<Dependency> dependencySet = findMoreDependencies(engine, tmpLoc);
|
||||||
|
if (dependencySet != null && !dependencySet.isEmpty()) {
|
||||||
|
for (Dependency d : dependencySet) {
|
||||||
|
//fix the dependency's display name and path
|
||||||
|
if (d.getActualFile().equals(tmpLoc)) {
|
||||||
|
d.setFilePath(dependency.getFilePath());
|
||||||
|
d.setDisplayFileName(dependency.getFileName());
|
||||||
|
} else {
|
||||||
|
for (Dependency sub : d.getRelatedDependencies()) {
|
||||||
|
if (sub.getActualFile().equals(tmpLoc)) {
|
||||||
|
sub.setFilePath(dependency.getFilePath());
|
||||||
|
sub.setDisplayFileName(dependency.getFileName());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} catch (IOException ex) {
|
||||||
|
LOGGER.debug("Unable to perform deep copy on '{}'", dependency.getActualFile().getPath(), ex);
|
||||||
|
} finally {
|
||||||
|
dependency.setSha1sum(archiveSha1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 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 List<Dependency> findMoreDependencies(Engine engine, File file) {
|
||||||
|
return engine.scan(file);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Retrieves the next temporary directory to extract an archive too.
|
* Retrieves the next temporary directory to extract an archive too.
|
||||||
*
|
*
|
||||||
@@ -303,43 +379,119 @@ public class ArchiveAnalyzer extends AbstractFileTypeAnalyzer {
|
|||||||
* @throws AnalysisException thrown if the archive is not found
|
* @throws AnalysisException thrown if the archive is not found
|
||||||
*/
|
*/
|
||||||
private void extractFiles(File archive, File destination, Engine engine) throws AnalysisException {
|
private void extractFiles(File archive, File destination, Engine engine) throws AnalysisException {
|
||||||
if (archive == null || destination == null) {
|
if (archive != null && destination != null) {
|
||||||
return;
|
String archiveExt = FileUtils.getFileExtension(archive.getName());
|
||||||
}
|
if (archiveExt == null) {
|
||||||
|
return;
|
||||||
FileInputStream fis = null;
|
|
||||||
try {
|
|
||||||
fis = new FileInputStream(archive);
|
|
||||||
} catch (FileNotFoundException ex) {
|
|
||||||
LOGGER.log(Level.FINE, null, ex);
|
|
||||||
throw new AnalysisException("Archive file was not found.", ex);
|
|
||||||
}
|
|
||||||
final String archiveExt = FileUtils.getFileExtension(archive.getName()).toLowerCase();
|
|
||||||
try {
|
|
||||||
if (ZIPPABLES.contains(archiveExt)) {
|
|
||||||
extractArchive(new ZipArchiveInputStream(new BufferedInputStream(fis)), destination, engine);
|
|
||||||
} else if ("tar".equals(archiveExt)) {
|
|
||||||
extractArchive(new TarArchiveInputStream(new BufferedInputStream(fis)), destination, engine);
|
|
||||||
} else if ("gz".equals(archiveExt) || "tgz".equals(archiveExt)) {
|
|
||||||
final String uncompressedName = GzipUtils.getUncompressedFilename(archive.getName());
|
|
||||||
final String uncompressedExt = FileUtils.getFileExtension(uncompressedName).toLowerCase();
|
|
||||||
if (engine.supportsExtension(uncompressedExt)) {
|
|
||||||
decompressFile(new GzipCompressorInputStream(new BufferedInputStream(fis)), new File(destination, uncompressedName));
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
} catch (ArchiveExtractionException ex) {
|
archiveExt = archiveExt.toLowerCase();
|
||||||
final String msg = String.format("Exception extracting archive '%s'.", archive.getName());
|
|
||||||
LOGGER.log(Level.WARNING, msg);
|
final FileInputStream fis;
|
||||||
LOGGER.log(Level.FINE, null, ex);
|
|
||||||
} catch (IOException ex) {
|
|
||||||
final String msg = String.format("Exception reading archive '%s'.", archive.getName());
|
|
||||||
LOGGER.log(Level.WARNING, msg);
|
|
||||||
LOGGER.log(Level.FINE, null, ex);
|
|
||||||
} finally {
|
|
||||||
try {
|
try {
|
||||||
fis.close();
|
fis = new FileInputStream(archive);
|
||||||
|
} catch (FileNotFoundException ex) {
|
||||||
|
LOGGER.debug("", ex);
|
||||||
|
throw new AnalysisException("Archive file was not found.", ex);
|
||||||
|
}
|
||||||
|
BufferedInputStream in = null;
|
||||||
|
ZipArchiveInputStream zin = null;
|
||||||
|
TarArchiveInputStream tin = null;
|
||||||
|
GzipCompressorInputStream gin = null;
|
||||||
|
BZip2CompressorInputStream bzin = null;
|
||||||
|
try {
|
||||||
|
if (KNOWN_ZIP_EXT.contains(archiveExt)) {
|
||||||
|
in = new BufferedInputStream(fis);
|
||||||
|
ensureReadableJar(archiveExt, in);
|
||||||
|
zin = new ZipArchiveInputStream(in);
|
||||||
|
extractArchive(zin, destination, engine);
|
||||||
|
} else if ("tar".equals(archiveExt)) {
|
||||||
|
in = new BufferedInputStream(fis);
|
||||||
|
tin = new TarArchiveInputStream(in);
|
||||||
|
extractArchive(tin, 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)) {
|
||||||
|
in = new BufferedInputStream(fis);
|
||||||
|
gin = new GzipCompressorInputStream(in);
|
||||||
|
decompressFile(gin, 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)) {
|
||||||
|
in = new BufferedInputStream(fis);
|
||||||
|
bzin = new BZip2CompressorInputStream(in);
|
||||||
|
decompressFile(bzin, f);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} catch (ArchiveExtractionException ex) {
|
||||||
|
LOGGER.warn("Exception extracting archive '{}'.", archive.getName());
|
||||||
|
LOGGER.debug("", ex);
|
||||||
} catch (IOException ex) {
|
} catch (IOException ex) {
|
||||||
LOGGER.log(Level.FINEST, null, ex);
|
LOGGER.warn("Exception reading archive '{}'.", archive.getName());
|
||||||
|
LOGGER.debug("", ex);
|
||||||
|
} finally {
|
||||||
|
//overly verbose and not needed... but keeping it anyway due to
|
||||||
|
//having issue with file handles being left open
|
||||||
|
FileUtils.close(fis);
|
||||||
|
FileUtils.close(in);
|
||||||
|
FileUtils.close(zin);
|
||||||
|
FileUtils.close(tin);
|
||||||
|
FileUtils.close(gin);
|
||||||
|
FileUtils.close(bzin);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Checks if the file being scanned is a JAR that begins with '#!/bin' which
|
||||||
|
* indicates it is a fully executable jar. If a fully executable JAR is
|
||||||
|
* identified the input stream will be advanced to the start of the actual
|
||||||
|
* JAR file ( skipping the script).
|
||||||
|
*
|
||||||
|
* @see
|
||||||
|
* <a href="http://docs.spring.io/spring-boot/docs/1.3.0.BUILD-SNAPSHOT/reference/htmlsingle/#deployment-install">Installing
|
||||||
|
* Spring Boot Applications</a>
|
||||||
|
* @param archiveExt the file extension
|
||||||
|
* @param in the input stream
|
||||||
|
* @throws IOException thrown if there is an error reading the stream
|
||||||
|
*/
|
||||||
|
private void ensureReadableJar(final String archiveExt, BufferedInputStream in) throws IOException {
|
||||||
|
if ("jar".equals(archiveExt) && in.markSupported()) {
|
||||||
|
in.mark(7);
|
||||||
|
final byte[] b = new byte[7];
|
||||||
|
final int read = in.read(b);
|
||||||
|
if (read == 7
|
||||||
|
&& b[0] == '#'
|
||||||
|
&& b[1] == '!'
|
||||||
|
&& b[2] == '/'
|
||||||
|
&& b[3] == 'b'
|
||||||
|
&& b[4] == 'i'
|
||||||
|
&& b[5] == 'n'
|
||||||
|
&& b[6] == '/') {
|
||||||
|
boolean stillLooking = true;
|
||||||
|
int chr;
|
||||||
|
int nxtChr;
|
||||||
|
while (stillLooking && (chr = in.read()) != -1) {
|
||||||
|
if (chr == '\n' || chr == '\r') {
|
||||||
|
in.mark(4);
|
||||||
|
if ((chr = in.read()) != -1) {
|
||||||
|
if (chr == 'P' && (chr = in.read()) != -1) {
|
||||||
|
if (chr == 'K' && (chr = in.read()) != -1) {
|
||||||
|
if ((chr == 3 || chr == 5 || chr == 7) && (nxtChr = in.read()) != -1) {
|
||||||
|
if (nxtChr == chr + 1) {
|
||||||
|
stillLooking = false;
|
||||||
|
in.reset();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
in.reset();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -350,74 +502,54 @@ public class ArchiveAnalyzer extends AbstractFileTypeAnalyzer {
|
|||||||
* @param input the archive to extract files from
|
* @param input the archive to extract files from
|
||||||
* @param destination the location to write the files too
|
* @param destination the location to write the files too
|
||||||
* @param engine the dependency-check engine
|
* @param engine the dependency-check engine
|
||||||
* @throws ArchiveExtractionException thrown if there is an exception extracting files from the archive
|
* @throws ArchiveExtractionException thrown if there is an exception
|
||||||
|
* extracting files from the archive
|
||||||
*/
|
*/
|
||||||
private void extractArchive(ArchiveInputStream input, File destination, Engine engine) throws ArchiveExtractionException {
|
private void extractArchive(ArchiveInputStream input, File destination, Engine engine) throws ArchiveExtractionException {
|
||||||
ArchiveEntry entry;
|
ArchiveEntry entry;
|
||||||
try {
|
try {
|
||||||
while ((entry = input.getNextEntry()) != null) {
|
while ((entry = input.getNextEntry()) != null) {
|
||||||
|
final File file = new File(destination, entry.getName());
|
||||||
if (entry.isDirectory()) {
|
if (entry.isDirectory()) {
|
||||||
final File d = new File(destination, entry.getName());
|
if (!file.exists() && !file.mkdirs()) {
|
||||||
if (!d.exists()) {
|
final String msg = String.format("Unable to create directory '%s'.", file.getAbsolutePath());
|
||||||
if (!d.mkdirs()) {
|
throw new AnalysisException(msg);
|
||||||
final String msg = String.format("Unable to create directory '%s'.", d.getAbsolutePath());
|
|
||||||
throw new AnalysisException(msg);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
final File file = new File(destination, entry.getName());
|
|
||||||
final String ext = FileUtils.getFileExtension(file.getName());
|
|
||||||
if (engine.supportsExtension(ext)) {
|
|
||||||
BufferedOutputStream bos = null;
|
|
||||||
FileOutputStream fos;
|
|
||||||
try {
|
|
||||||
final File parent = file.getParentFile();
|
|
||||||
if (!parent.isDirectory()) {
|
|
||||||
if (!parent.mkdirs()) {
|
|
||||||
final String msg = String.format("Unable to build directory '%s'.", parent.getAbsolutePath());
|
|
||||||
throw new AnalysisException(msg);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
fos = new FileOutputStream(file);
|
|
||||||
bos = new BufferedOutputStream(fos, BUFFER_SIZE);
|
|
||||||
int count;
|
|
||||||
final byte data[] = new byte[BUFFER_SIZE];
|
|
||||||
while ((count = input.read(data, 0, BUFFER_SIZE)) != -1) {
|
|
||||||
bos.write(data, 0, count);
|
|
||||||
}
|
|
||||||
bos.flush();
|
|
||||||
} catch (FileNotFoundException ex) {
|
|
||||||
LOGGER.log(Level.FINE, null, ex);
|
|
||||||
final String msg = String.format("Unable to find file '%s'.", file.getName());
|
|
||||||
throw new AnalysisException(msg, ex);
|
|
||||||
} catch (IOException ex) {
|
|
||||||
LOGGER.log(Level.FINE, null, ex);
|
|
||||||
final String msg = String.format("IO Exception while parsing file '%s'.", file.getName());
|
|
||||||
throw new AnalysisException(msg, ex);
|
|
||||||
} finally {
|
|
||||||
if (bos != null) {
|
|
||||||
try {
|
|
||||||
bos.close();
|
|
||||||
} catch (IOException ex) {
|
|
||||||
LOGGER.log(Level.FINEST, null, ex);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
} else if (engine.accept(file)) {
|
||||||
|
extractAcceptedFile(input, file);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} catch (IOException ex) {
|
} catch (IOException | AnalysisException ex) {
|
||||||
throw new ArchiveExtractionException(ex);
|
|
||||||
} catch (Throwable ex) {
|
|
||||||
throw new ArchiveExtractionException(ex);
|
throw new ArchiveExtractionException(ex);
|
||||||
} finally {
|
} finally {
|
||||||
if (input != null) {
|
FileUtils.close(input);
|
||||||
try {
|
}
|
||||||
input.close();
|
}
|
||||||
} catch (IOException ex) {
|
|
||||||
LOGGER.log(Level.FINEST, null, ex);
|
/**
|
||||||
}
|
* 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());
|
||||||
|
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);
|
||||||
|
}
|
||||||
|
try (FileOutputStream 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);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -426,31 +558,16 @@ public class ArchiveAnalyzer extends AbstractFileTypeAnalyzer {
|
|||||||
*
|
*
|
||||||
* @param inputStream the compressed file
|
* @param inputStream the compressed file
|
||||||
* @param outputFile the location to write the decompressed file
|
* @param outputFile the location to write the decompressed file
|
||||||
* @throws ArchiveExtractionException thrown if there is an exception decompressing the file
|
* @throws ArchiveExtractionException thrown if there is an exception
|
||||||
|
* decompressing the file
|
||||||
*/
|
*/
|
||||||
private void decompressFile(CompressorInputStream inputStream, File outputFile) throws ArchiveExtractionException {
|
private void decompressFile(CompressorInputStream inputStream, File outputFile) throws ArchiveExtractionException {
|
||||||
FileOutputStream out = null;
|
LOGGER.debug("Decompressing '{}'", outputFile.getPath());
|
||||||
try {
|
try (FileOutputStream out = new FileOutputStream(outputFile)) {
|
||||||
out = new FileOutputStream(outputFile);
|
IOUtils.copy(inputStream, out);
|
||||||
final byte[] buffer = new byte[BUFFER_SIZE];
|
|
||||||
int n = 0;
|
|
||||||
while (-1 != (n = inputStream.read(buffer))) {
|
|
||||||
out.write(buffer, 0, n);
|
|
||||||
}
|
|
||||||
} catch (FileNotFoundException ex) {
|
|
||||||
LOGGER.log(Level.FINE, null, ex);
|
|
||||||
throw new ArchiveExtractionException(ex);
|
|
||||||
} catch (IOException ex) {
|
} catch (IOException ex) {
|
||||||
LOGGER.log(Level.FINE, null, ex);
|
LOGGER.debug("", ex);
|
||||||
throw new ArchiveExtractionException(ex);
|
throw new ArchiveExtractionException(ex);
|
||||||
} finally {
|
|
||||||
if (out != null) {
|
|
||||||
try {
|
|
||||||
out.close();
|
|
||||||
} catch (IOException ex) {
|
|
||||||
LOGGER.log(Level.FINEST, null, ex);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -480,11 +597,10 @@ public class ArchiveAnalyzer extends AbstractFileTypeAnalyzer {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
} catch (IOException ex) {
|
} catch (IOException ex) {
|
||||||
LOGGER.log(Level.FINE, String.format("Unable to unzip zip file '%s'", dependency.getFilePath()), ex);
|
LOGGER.debug("Unable to unzip zip file '{}'", dependency.getFilePath(), ex);
|
||||||
} finally {
|
} finally {
|
||||||
ZipFile.closeQuietly(zip);
|
ZipFile.closeQuietly(zip);
|
||||||
}
|
}
|
||||||
|
|
||||||
return isJar;
|
return isJar;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -17,33 +17,39 @@
|
|||||||
*/
|
*/
|
||||||
package org.owasp.dependencycheck.analyzer;
|
package org.owasp.dependencycheck.analyzer;
|
||||||
|
|
||||||
import java.io.BufferedReader;
|
|
||||||
import java.io.File;
|
import java.io.File;
|
||||||
|
import java.io.FileFilter;
|
||||||
import java.io.FileOutputStream;
|
import java.io.FileOutputStream;
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.io.InputStream;
|
import java.io.InputStream;
|
||||||
import java.io.InputStreamReader;
|
import org.apache.commons.io.IOUtils;
|
||||||
import java.util.ArrayList;
|
import org.apache.commons.io.output.NullOutputStream;
|
||||||
import java.util.List;
|
|
||||||
import java.util.Set;
|
|
||||||
import java.util.logging.Level;
|
|
||||||
import java.util.logging.Logger;
|
|
||||||
import javax.xml.parsers.DocumentBuilder;
|
|
||||||
import javax.xml.parsers.DocumentBuilderFactory;
|
|
||||||
import javax.xml.xpath.XPath;
|
|
||||||
import javax.xml.xpath.XPathExpressionException;
|
|
||||||
import javax.xml.xpath.XPathFactory;
|
|
||||||
import org.owasp.dependencycheck.Engine;
|
import org.owasp.dependencycheck.Engine;
|
||||||
import org.owasp.dependencycheck.analyzer.exception.AnalysisException;
|
import org.owasp.dependencycheck.analyzer.exception.AnalysisException;
|
||||||
import org.owasp.dependencycheck.dependency.Confidence;
|
import org.owasp.dependencycheck.dependency.Confidence;
|
||||||
import org.owasp.dependencycheck.dependency.Dependency;
|
import org.owasp.dependencycheck.dependency.Dependency;
|
||||||
import org.owasp.dependencycheck.dependency.Evidence;
|
import org.owasp.dependencycheck.dependency.Evidence;
|
||||||
|
import org.owasp.dependencycheck.utils.FileFilterBuilder;
|
||||||
import org.owasp.dependencycheck.utils.Settings;
|
import org.owasp.dependencycheck.utils.Settings;
|
||||||
|
import org.slf4j.Logger;
|
||||||
|
import org.slf4j.LoggerFactory;
|
||||||
import org.w3c.dom.Document;
|
import org.w3c.dom.Document;
|
||||||
import org.xml.sax.SAXException;
|
import org.xml.sax.SAXException;
|
||||||
|
|
||||||
|
import javax.xml.parsers.DocumentBuilder;
|
||||||
|
import javax.xml.xpath.XPath;
|
||||||
|
import javax.xml.xpath.XPathExpressionException;
|
||||||
|
import javax.xml.xpath.XPathFactory;
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.List;
|
||||||
|
import javax.xml.parsers.ParserConfigurationException;
|
||||||
|
import org.owasp.dependencycheck.exception.InitializationException;
|
||||||
|
import org.apache.commons.lang3.SystemUtils;
|
||||||
|
import org.owasp.dependencycheck.utils.XmlUtils;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Analyzer for getting company, product, and version information from a .NET assembly.
|
* Analyzer for getting company, product, and version information from a .NET
|
||||||
|
* assembly.
|
||||||
*
|
*
|
||||||
* @author colezlaw
|
* @author colezlaw
|
||||||
*
|
*
|
||||||
@@ -61,37 +67,34 @@ public class AssemblyAnalyzer extends AbstractFileTypeAnalyzer {
|
|||||||
/**
|
/**
|
||||||
* The list of supported extensions
|
* The list of supported extensions
|
||||||
*/
|
*/
|
||||||
private static final Set<String> SUPPORTED_EXTENSIONS = newHashSet("dll", "exe");
|
private static final String[] SUPPORTED_EXTENSIONS = {"dll", "exe"};
|
||||||
/**
|
/**
|
||||||
* The temp value for GrokAssembly.exe
|
* The temp value for GrokAssembly.exe
|
||||||
*/
|
*/
|
||||||
private File grokAssemblyExe = null;
|
private File grokAssemblyExe = null;
|
||||||
/**
|
|
||||||
* The DocumentBuilder for parsing the XML
|
|
||||||
*/
|
|
||||||
private DocumentBuilder builder;
|
|
||||||
/**
|
/**
|
||||||
* Logger
|
* Logger
|
||||||
*/
|
*/
|
||||||
private static final Logger LOGGER = Logger.getLogger(AssemblyAnalyzer.class.getName(), "dependencycheck-resources");
|
private static final Logger LOGGER = LoggerFactory.getLogger(AssemblyAnalyzer.class);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Builds the beginnings of a List for ProcessBuilder
|
* Builds the beginnings of a List for ProcessBuilder
|
||||||
*
|
*
|
||||||
* @return the list of arguments to begin populating the ProcessBuilder
|
* @return the list of arguments to begin populating the ProcessBuilder
|
||||||
*/
|
*/
|
||||||
private List<String> buildArgumentList() {
|
protected List<String> buildArgumentList() {
|
||||||
// Use file.separator as a wild guess as to whether this is Windows
|
// Use file.separator as a wild guess as to whether this is Windows
|
||||||
final List<String> args = new ArrayList<String>();
|
final List<String> args = new ArrayList<>();
|
||||||
if (!"\\".equals(System.getProperty("file.separator"))) {
|
if (!SystemUtils.IS_OS_WINDOWS) {
|
||||||
if (Settings.getString(Settings.KEYS.ANALYZER_ASSEMBLY_MONO_PATH) != null) {
|
if (Settings.getString(Settings.KEYS.ANALYZER_ASSEMBLY_MONO_PATH) != null) {
|
||||||
args.add(Settings.getString(Settings.KEYS.ANALYZER_ASSEMBLY_MONO_PATH));
|
args.add(Settings.getString(Settings.KEYS.ANALYZER_ASSEMBLY_MONO_PATH));
|
||||||
} else {
|
} else if (isInPath("mono")) {
|
||||||
args.add("mono");
|
args.add("mono");
|
||||||
|
} else {
|
||||||
|
return null;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
args.add(grokAssemblyExe.getPath());
|
args.add(grokAssemblyExe.getPath());
|
||||||
|
|
||||||
return args;
|
return args;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -103,46 +106,54 @@ public class AssemblyAnalyzer extends AbstractFileTypeAnalyzer {
|
|||||||
* @throws AnalysisException if anything goes sideways
|
* @throws AnalysisException if anything goes sideways
|
||||||
*/
|
*/
|
||||||
@Override
|
@Override
|
||||||
public void analyzeFileType(Dependency dependency, Engine engine)
|
public void analyzeDependency(Dependency dependency, Engine engine)
|
||||||
throws AnalysisException {
|
throws AnalysisException {
|
||||||
if (grokAssemblyExe == null) {
|
if (grokAssemblyExe == null) {
|
||||||
LOGGER.warning("analyzer.AssemblyAnalyzer.notdeployed");
|
LOGGER.warn("GrokAssembly didn't get deployed");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
final List<String> args = buildArgumentList();
|
final List<String> args = buildArgumentList();
|
||||||
|
if (args == null) {
|
||||||
|
LOGGER.warn("Assembly Analyzer was unable to execute");
|
||||||
|
return;
|
||||||
|
}
|
||||||
args.add(dependency.getActualFilePath());
|
args.add(dependency.getActualFilePath());
|
||||||
final ProcessBuilder pb = new ProcessBuilder(args);
|
final ProcessBuilder pb = new ProcessBuilder(args);
|
||||||
BufferedReader rdr = null;
|
|
||||||
Document doc = null;
|
Document doc = null;
|
||||||
try {
|
try {
|
||||||
final Process proc = pb.start();
|
final Process proc = pb.start();
|
||||||
// Try evacuating the error stream
|
final DocumentBuilder builder = XmlUtils.buildSecureDocumentBuilder();
|
||||||
rdr = new BufferedReader(new InputStreamReader(proc.getErrorStream(), "UTF-8"));
|
|
||||||
String line = null;
|
|
||||||
while (rdr.ready() && (line = rdr.readLine()) != null) {
|
|
||||||
LOGGER.log(Level.WARNING, "analyzer.AssemblyAnalyzer.grokassembly.stderr", line);
|
|
||||||
}
|
|
||||||
int rc = 0;
|
|
||||||
doc = builder.parse(proc.getInputStream());
|
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 {
|
try {
|
||||||
rc = proc.waitFor();
|
rc = proc.waitFor();
|
||||||
} catch (InterruptedException ie) {
|
} catch (InterruptedException ie) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if (rc == 3) {
|
if (rc == 3) {
|
||||||
LOGGER.log(Level.FINE, "analyzer.AssemblyAnalyzer.notassembly", dependency.getActualFilePath());
|
LOGGER.debug("{} is not a .NET assembly or executable and as such cannot be analyzed by dependency-check",
|
||||||
|
dependency.getActualFilePath());
|
||||||
return;
|
return;
|
||||||
} else if (rc != 0) {
|
} else if (rc != 0) {
|
||||||
LOGGER.log(Level.WARNING, "analyzer.AssemblyAnalyzer.grokassembly.rc", rc);
|
LOGGER.debug("Return code {} from GrokAssembly; dependency-check is unable to analyze the library: {}",
|
||||||
|
rc, dependency.getActualFilePath());
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
final XPath xpath = XPathFactory.newInstance().newXPath();
|
final XPath xpath = XPathFactory.newInstance().newXPath();
|
||||||
|
|
||||||
// First, see if there was an error
|
// First, see if there was an error
|
||||||
final String error = xpath.evaluate("/assembly/error", doc);
|
final String error = xpath.evaluate("/assembly/error", doc);
|
||||||
if (error != null && !"".equals(error)) {
|
if (error != null && !error.isEmpty()) {
|
||||||
throw new AnalysisException(error);
|
throw new AnalysisException(error);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -164,129 +175,128 @@ public class AssemblyAnalyzer extends AbstractFileTypeAnalyzer {
|
|||||||
product, Confidence.HIGH));
|
product, Confidence.HIGH));
|
||||||
}
|
}
|
||||||
|
|
||||||
} catch (IOException ioe) {
|
} catch (ParserConfigurationException pce) {
|
||||||
|
throw new AnalysisException("Error initializing the assembly analyzer", pce);
|
||||||
|
} catch (IOException | XPathExpressionException ioe) {
|
||||||
throw new AnalysisException(ioe);
|
throw new AnalysisException(ioe);
|
||||||
} catch (SAXException saxe) {
|
} catch (SAXException saxe) {
|
||||||
throw new AnalysisException("Couldn't parse GrokAssembly result", saxe);
|
LOGGER.error("----------------------------------------------------");
|
||||||
} catch (XPathExpressionException xpe) {
|
LOGGER.error("Failed to read the Assembly Analyzer results. "
|
||||||
// This shouldn't happen
|
+ "On some systems mono-runtime and mono-devel need to be installed.");
|
||||||
throw new AnalysisException(xpe);
|
LOGGER.error("----------------------------------------------------");
|
||||||
} finally {
|
throw new AnalysisException("Couldn't parse Assembly Analyzer results (GrokAssembly)", saxe);
|
||||||
if (rdr != null) {
|
|
||||||
try {
|
|
||||||
rdr.close();
|
|
||||||
} catch (IOException ex) {
|
|
||||||
LOGGER.log(Level.FINEST, "ignore", ex);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
// This shouldn't happen
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Initialize the analyzer. In this case, extract GrokAssembly.exe to a temporary location.
|
* Initialize the analyzer. In this case, extract GrokAssembly.exe to a
|
||||||
|
* temporary location.
|
||||||
*
|
*
|
||||||
* @throws Exception if anything goes wrong
|
* @throws InitializationException thrown if anything goes wrong
|
||||||
*/
|
*/
|
||||||
@Override
|
@Override
|
||||||
public void initializeFileTypeAnalyzer() throws Exception {
|
public void initializeFileTypeAnalyzer() throws InitializationException {
|
||||||
final File tempFile = File.createTempFile("GKA", ".exe", Settings.getTempDirectory());
|
final File tempFile;
|
||||||
FileOutputStream fos = null;
|
final String cfg;
|
||||||
InputStream is = null;
|
|
||||||
try {
|
try {
|
||||||
fos = new FileOutputStream(tempFile);
|
tempFile = File.createTempFile("GKA", ".exe", Settings.getTempDirectory());
|
||||||
is = AssemblyAnalyzer.class.getClassLoader().getResourceAsStream("GrokAssembly.exe");
|
cfg = tempFile.getPath() + ".config";
|
||||||
final byte[] buff = new byte[4096];
|
} catch (IOException ex) {
|
||||||
int bread = -1;
|
setEnabled(false);
|
||||||
while ((bread = is.read(buff)) >= 0) {
|
throw new InitializationException("Unable to create temporary file for the assembly analyzer", ex);
|
||||||
fos.write(buff, 0, bread);
|
}
|
||||||
}
|
try (FileOutputStream fos = new FileOutputStream(tempFile);
|
||||||
|
InputStream is = AssemblyAnalyzer.class.getClassLoader().getResourceAsStream("GrokAssembly.exe");
|
||||||
|
FileOutputStream fosCfg = new FileOutputStream(cfg);
|
||||||
|
InputStream isCfg = AssemblyAnalyzer.class.getClassLoader().getResourceAsStream("GrokAssembly.exe.config")) {
|
||||||
|
IOUtils.copy(is, fos);
|
||||||
grokAssemblyExe = tempFile;
|
grokAssemblyExe = tempFile;
|
||||||
// Set the temp file to get deleted when we're done
|
LOGGER.debug("Extracted GrokAssembly.exe to {}", grokAssemblyExe.getPath());
|
||||||
grokAssemblyExe.deleteOnExit();
|
IOUtils.copy(isCfg, fosCfg);
|
||||||
LOGGER.log(Level.FINE, "analyzer.AssemblyAnalyzer.grokassembly.deployed", grokAssemblyExe.getPath());
|
LOGGER.debug("Extracted GrokAssembly.exe.config to {}", cfg);
|
||||||
} catch (IOException ioe) {
|
} catch (IOException ioe) {
|
||||||
this.setEnabled(false);
|
this.setEnabled(false);
|
||||||
LOGGER.log(Level.WARNING, "analyzer.AssemblyAnalyzer.grokassembly.notdeployed", ioe.getMessage());
|
LOGGER.warn("Could not extract GrokAssembly.exe: {}", ioe.getMessage());
|
||||||
throw new AnalysisException("Could not extract GrokAssembly.exe", ioe);
|
throw new InitializationException("Could not extract GrokAssembly.exe", ioe);
|
||||||
} finally {
|
|
||||||
if (fos != null) {
|
|
||||||
try {
|
|
||||||
fos.close();
|
|
||||||
} catch (Throwable e) {
|
|
||||||
LOGGER.fine("Error closing output stream");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (is != null) {
|
|
||||||
try {
|
|
||||||
is.close();
|
|
||||||
} catch (Throwable e) {
|
|
||||||
LOGGER.fine("Error closing input stream");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Now, need to see if GrokAssembly actually runs from this location.
|
// Now, need to see if GrokAssembly actually runs from this location.
|
||||||
final List<String> args = buildArgumentList();
|
final List<String> args = buildArgumentList();
|
||||||
BufferedReader rdr = null;
|
//TODO this creates an "unreported" error - if someone doesn't look
|
||||||
|
// at the command output this could easily be missed (especially in an
|
||||||
|
// Ant or Maven build.
|
||||||
|
//
|
||||||
|
// We need to create a non-fatal warning error type that will
|
||||||
|
// get added to the report.
|
||||||
|
//TODO this idea needs to get replicated to the bundle audit analyzer.
|
||||||
|
if (args == null) {
|
||||||
|
setEnabled(false);
|
||||||
|
LOGGER.error("----------------------------------------------------");
|
||||||
|
LOGGER.error(".NET Assembly Analyzer could not be initialized and at least one "
|
||||||
|
+ "'exe' or 'dll' was scanned. The 'mono' executable could not be found on "
|
||||||
|
+ "the path; either disable the Assembly Analyzer or configure the path mono. "
|
||||||
|
+ "On some systems mono-runtime and mono-devel need to be installed.");
|
||||||
|
LOGGER.error("----------------------------------------------------");
|
||||||
|
return;
|
||||||
|
}
|
||||||
try {
|
try {
|
||||||
final ProcessBuilder pb = new ProcessBuilder(args);
|
final ProcessBuilder pb = new ProcessBuilder(args);
|
||||||
final Process p = pb.start();
|
final Process p = pb.start();
|
||||||
// Try evacuating the error stream
|
// Try evacuating the error stream
|
||||||
rdr = new BufferedReader(new InputStreamReader(p.getErrorStream(), "UTF-8"));
|
IOUtils.copy(p.getErrorStream(), NullOutputStream.NULL_OUTPUT_STREAM);
|
||||||
while (rdr.ready() && rdr.readLine() != null) {
|
|
||||||
// We expect this to complain
|
final DocumentBuilder builder = XmlUtils.buildSecureDocumentBuilder();
|
||||||
}
|
final Document doc = builder.parse(p.getInputStream());
|
||||||
final Document doc = DocumentBuilderFactory.newInstance().newDocumentBuilder().parse(p.getInputStream());
|
|
||||||
final XPath xpath = XPathFactory.newInstance().newXPath();
|
final XPath xpath = XPathFactory.newInstance().newXPath();
|
||||||
final String error = xpath.evaluate("/assembly/error", doc);
|
final String error = xpath.evaluate("/assembly/error", doc);
|
||||||
if (p.waitFor() != 1 || error == null || "".equals(error)) {
|
if (p.waitFor() != 1 || error == null || error.isEmpty()) {
|
||||||
LOGGER.warning("An error occurred with the .NET AssemblyAnalyzer, please see the log for more details.");
|
LOGGER.warn("An error occurred with the .NET AssemblyAnalyzer, please see the log for more details.");
|
||||||
LOGGER.fine("GrokAssembly.exe is not working properly");
|
LOGGER.debug("GrokAssembly.exe is not working properly");
|
||||||
grokAssemblyExe = null;
|
grokAssemblyExe = null;
|
||||||
this.setEnabled(false);
|
setEnabled(false);
|
||||||
throw new AnalysisException("Could not execute .NET AssemblyAnalyzer");
|
throw new InitializationException("Could not execute .NET AssemblyAnalyzer");
|
||||||
}
|
}
|
||||||
} catch (Throwable e) {
|
} catch (InitializationException e) {
|
||||||
if (e instanceof AnalysisException) {
|
setEnabled(false);
|
||||||
throw (AnalysisException) e;
|
throw e;
|
||||||
} else {
|
} catch (IOException | ParserConfigurationException | SAXException | XPathExpressionException | InterruptedException e) {
|
||||||
LOGGER.warning("analyzer.AssemblyAnalyzer.grokassembly.initialization.failed");
|
LOGGER.warn("An error occurred with the .NET AssemblyAnalyzer;\n"
|
||||||
LOGGER.log(Level.FINE, "analyzer.AssemblyAnalyzer.grokassembly.initialization.message", e.getMessage());
|
+ "this can be ignored unless you are scanning .NET DLLs. Please see the log for more details.");
|
||||||
this.setEnabled(false);
|
LOGGER.debug("Could not execute GrokAssembly {}", e.getMessage());
|
||||||
throw new AnalysisException("An error occured with the .NET AssemblyAnalyzer", e);
|
setEnabled(false);
|
||||||
}
|
throw new InitializationException("An error occurred with the .NET AssemblyAnalyzer", e);
|
||||||
} finally {
|
|
||||||
if (rdr != null) {
|
|
||||||
try {
|
|
||||||
rdr.close();
|
|
||||||
} catch (IOException ex) {
|
|
||||||
LOGGER.log(Level.FINEST, "ignore", ex);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
builder = DocumentBuilderFactory.newInstance().newDocumentBuilder();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void close() throws Exception {
|
|
||||||
super.close();
|
|
||||||
try {
|
|
||||||
if (grokAssemblyExe != null && !grokAssemblyExe.delete()) {
|
|
||||||
grokAssemblyExe.deleteOnExit();
|
|
||||||
}
|
|
||||||
} catch (SecurityException se) {
|
|
||||||
LOGGER.fine("analyzer.AssemblyAnalyzer.grokassembly.notdeleted");
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Gets the set of extensions supported by this analyzer.
|
* Removes resources used from the local file system.
|
||||||
*
|
*
|
||||||
* @return the list of supported extensions
|
* @throws Exception thrown if there is a problem closing the analyzer
|
||||||
*/
|
*/
|
||||||
@Override
|
@Override
|
||||||
public Set<String> getSupportedExtensions() {
|
public void closeAnalyzer() throws Exception {
|
||||||
return SUPPORTED_EXTENSIONS;
|
try {
|
||||||
|
if (grokAssemblyExe != null && !grokAssemblyExe.delete()) {
|
||||||
|
LOGGER.debug("Unable to delete temporary GrokAssembly.exe; attempting delete on exit");
|
||||||
|
grokAssemblyExe.deleteOnExit();
|
||||||
|
}
|
||||||
|
} catch (SecurityException se) {
|
||||||
|
LOGGER.debug("Can't delete temporary GrokAssembly.exe");
|
||||||
|
grokAssemblyExe.deleteOnExit();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The File Filter used to filter supported extensions.
|
||||||
|
*/
|
||||||
|
private static final FileFilter FILTER = FileFilterBuilder.newInstance().addExtensions(
|
||||||
|
SUPPORTED_EXTENSIONS).build();
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected FileFilter getFileFilter() {
|
||||||
|
return FILTER;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -310,7 +320,8 @@ public class AssemblyAnalyzer extends AbstractFileTypeAnalyzer {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 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
|
* @return the analyzer's enabled property setting key
|
||||||
*/
|
*/
|
||||||
@@ -318,4 +329,27 @@ public class AssemblyAnalyzer extends AbstractFileTypeAnalyzer {
|
|||||||
protected String getAnalyzerEnabledSettingKey() {
|
protected String getAnalyzerEnabledSettingKey() {
|
||||||
return Settings.KEYS.ANALYZER_ASSEMBLY_ENABLED;
|
return Settings.KEYS.ANALYZER_ASSEMBLY_ENABLED;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Tests to see if a file is in the system path. <b>Note</b> - the current
|
||||||
|
* implementation only works on non-windows platforms. For purposes of the
|
||||||
|
* AssemblyAnalyzer this is okay as this is only needed on Mac/*nix.
|
||||||
|
*
|
||||||
|
* @param file the executable to look for
|
||||||
|
* @return <code>true</code> if the file exists; otherwise
|
||||||
|
* <code>false</code>
|
||||||
|
*/
|
||||||
|
private boolean isInPath(String file) {
|
||||||
|
final ProcessBuilder pb = new ProcessBuilder("which", file);
|
||||||
|
try {
|
||||||
|
final Process proc = pb.start();
|
||||||
|
final int retCode = proc.waitFor();
|
||||||
|
if (retCode == 0) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
} catch (IOException | InterruptedException ex) {
|
||||||
|
LOGGER.debug("Path search failed for " + file, ex);
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,278 @@
|
|||||||
|
/*
|
||||||
|
* This file is part of dependency-check-core.
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*
|
||||||
|
* Copyright (c) 2015 Institute for Defense Analyses. All Rights Reserved.
|
||||||
|
*/
|
||||||
|
package org.owasp.dependencycheck.analyzer;
|
||||||
|
|
||||||
|
import org.apache.commons.io.FileUtils;
|
||||||
|
import org.owasp.dependencycheck.Engine;
|
||||||
|
import org.owasp.dependencycheck.analyzer.exception.AnalysisException;
|
||||||
|
import org.owasp.dependencycheck.dependency.Confidence;
|
||||||
|
import org.owasp.dependencycheck.dependency.Dependency;
|
||||||
|
import org.owasp.dependencycheck.dependency.EvidenceCollection;
|
||||||
|
import org.owasp.dependencycheck.utils.FileFilterBuilder;
|
||||||
|
import org.owasp.dependencycheck.utils.Settings;
|
||||||
|
import org.owasp.dependencycheck.utils.UrlStringUtils;
|
||||||
|
|
||||||
|
import java.io.File;
|
||||||
|
import java.io.FileFilter;
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.nio.charset.Charset;
|
||||||
|
import java.util.regex.Matcher;
|
||||||
|
import java.util.regex.Pattern;
|
||||||
|
import org.owasp.dependencycheck.exception.InitializationException;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Used to analyze Autoconf input files named configure.ac or configure.in.
|
||||||
|
* Files simply named "configure" are also analyzed, assuming they are generated
|
||||||
|
* by Autoconf, and contain certain special package descriptor variables.
|
||||||
|
*
|
||||||
|
* @author Dale Visser
|
||||||
|
* @see <a href="https://www.gnu.org/software/autoconf/">Autoconf - GNU Project
|
||||||
|
* - Free Software Foundation (FSF)</a>
|
||||||
|
*/
|
||||||
|
@Experimental
|
||||||
|
public class AutoconfAnalyzer extends AbstractFileTypeAnalyzer {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Autoconf output filename.
|
||||||
|
*/
|
||||||
|
private static final String CONFIGURE = "configure";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Autoconf input filename.
|
||||||
|
*/
|
||||||
|
private static final String CONFIGURE_IN = "configure.in";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Autoconf input filename.
|
||||||
|
*/
|
||||||
|
private static final String CONFIGURE_AC = "configure.ac";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The name of the analyzer.
|
||||||
|
*/
|
||||||
|
private static final String ANALYZER_NAME = "Autoconf Analyzer";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The phase that this analyzer is intended to run in.
|
||||||
|
*/
|
||||||
|
private static final AnalysisPhase ANALYSIS_PHASE = AnalysisPhase.INFORMATION_COLLECTION;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The set of file extensions supported by this analyzer.
|
||||||
|
*/
|
||||||
|
private static final String[] EXTENSIONS = {"ac", "in"};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Matches AC_INIT variables in the output configure script.
|
||||||
|
*/
|
||||||
|
private static final Pattern PACKAGE_VAR = Pattern.compile(
|
||||||
|
"PACKAGE_(.+?)='(.*?)'", Pattern.DOTALL | Pattern.CASE_INSENSITIVE);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Matches AC_INIT statement in configure.ac file.
|
||||||
|
*/
|
||||||
|
private static final Pattern AC_INIT_PATTERN;
|
||||||
|
|
||||||
|
static {
|
||||||
|
// each instance of param or sep_param has a capture group
|
||||||
|
final String param = "\\[{0,2}(.+?)\\]{0,2}";
|
||||||
|
final String sepParam = "\\s*,\\s*" + param;
|
||||||
|
// Group 1: Package
|
||||||
|
// Group 2: Version
|
||||||
|
// Group 3: optional
|
||||||
|
// Group 4: Bug report address (if it exists)
|
||||||
|
// Group 5: optional
|
||||||
|
// Group 6: Tarname (if it exists)
|
||||||
|
// Group 7: optional
|
||||||
|
// Group 8: URL (if it exists)
|
||||||
|
AC_INIT_PATTERN = Pattern.compile(String.format(
|
||||||
|
"AC_INIT\\(%s%s(%s)?(%s)?(%s)?\\s*\\)", param, sepParam,
|
||||||
|
sepParam, sepParam, sepParam), Pattern.DOTALL
|
||||||
|
| Pattern.CASE_INSENSITIVE);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The file filter used to determine which files this analyzer supports.
|
||||||
|
*/
|
||||||
|
private static final FileFilter FILTER = FileFilterBuilder.newInstance().addFilenames(CONFIGURE).addExtensions(
|
||||||
|
EXTENSIONS).build();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the FileFilter
|
||||||
|
*
|
||||||
|
* @return the FileFilter
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
protected FileFilter getFileFilter() {
|
||||||
|
return FILTER;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the name of the analyzer.
|
||||||
|
*
|
||||||
|
* @return the name of the analyzer.
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
public String getName() {
|
||||||
|
return ANALYZER_NAME;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the phase that the analyzer is intended to run in.
|
||||||
|
*
|
||||||
|
* @return the phase that the analyzer is intended to run in.
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
public AnalysisPhase getAnalysisPhase() {
|
||||||
|
return ANALYSIS_PHASE;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the key used in the properties file to reference the analyzer's
|
||||||
|
* enabled property.
|
||||||
|
*
|
||||||
|
* @return the analyzer's enabled property setting key
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
protected String getAnalyzerEnabledSettingKey() {
|
||||||
|
return Settings.KEYS.ANALYZER_PYTHON_DISTRIBUTION_ENABLED;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void analyzeDependency(Dependency dependency, Engine engine)
|
||||||
|
throws AnalysisException {
|
||||||
|
final File actualFile = dependency.getActualFile();
|
||||||
|
final String name = actualFile.getName();
|
||||||
|
if (name.startsWith(CONFIGURE)) {
|
||||||
|
final File parent = actualFile.getParentFile();
|
||||||
|
final String parentName = parent.getName();
|
||||||
|
dependency.setDisplayFileName(parentName + "/" + name);
|
||||||
|
final boolean isOutputScript = CONFIGURE.equals(name);
|
||||||
|
if (isOutputScript || CONFIGURE_AC.equals(name)
|
||||||
|
|| CONFIGURE_IN.equals(name)) {
|
||||||
|
final String contents = getFileContents(actualFile);
|
||||||
|
if (!contents.isEmpty()) {
|
||||||
|
if (isOutputScript) {
|
||||||
|
extractConfigureScriptEvidence(dependency, name,
|
||||||
|
contents);
|
||||||
|
} else {
|
||||||
|
gatherEvidence(dependency, name, contents);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
engine.getDependencies().remove(dependency);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Extracts evidence from the configuration.
|
||||||
|
*
|
||||||
|
* @param dependency the dependency being analyzed
|
||||||
|
* @param name the name of the source of evidence
|
||||||
|
* @param contents the contents to analyze for evidence
|
||||||
|
*/
|
||||||
|
private void extractConfigureScriptEvidence(Dependency dependency,
|
||||||
|
final String name, final String contents) {
|
||||||
|
final Matcher matcher = PACKAGE_VAR.matcher(contents);
|
||||||
|
while (matcher.find()) {
|
||||||
|
final String variable = matcher.group(1);
|
||||||
|
final String value = matcher.group(2);
|
||||||
|
if (!value.isEmpty()) {
|
||||||
|
if (variable.endsWith("NAME")) {
|
||||||
|
dependency.getProductEvidence().addEvidence(name, variable,
|
||||||
|
value, Confidence.HIGHEST);
|
||||||
|
} else if ("VERSION".equals(variable)) {
|
||||||
|
dependency.getVersionEvidence().addEvidence(name, variable,
|
||||||
|
value, Confidence.HIGHEST);
|
||||||
|
} else if ("BUGREPORT".equals(variable)) {
|
||||||
|
dependency.getVendorEvidence().addEvidence(name, variable,
|
||||||
|
value, Confidence.HIGH);
|
||||||
|
} else if ("URL".equals(variable)) {
|
||||||
|
dependency.getVendorEvidence().addEvidence(name, variable,
|
||||||
|
value, Confidence.HIGH);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Retrieves the contents of a given file.
|
||||||
|
*
|
||||||
|
* @param actualFile the file to read
|
||||||
|
* @return the contents of the file
|
||||||
|
* @throws AnalysisException thrown if there is an IO Exception
|
||||||
|
*/
|
||||||
|
private String getFileContents(final File actualFile)
|
||||||
|
throws AnalysisException {
|
||||||
|
try {
|
||||||
|
return FileUtils.readFileToString(actualFile, Charset.defaultCharset()).trim();
|
||||||
|
} catch (IOException e) {
|
||||||
|
throw new AnalysisException(
|
||||||
|
"Problem occurred while reading dependency file.", e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gathers evidence from a given file
|
||||||
|
*
|
||||||
|
* @param dependency the dependency to add evidence to
|
||||||
|
* @param name the source of the evidence
|
||||||
|
* @param contents the evidence to analyze
|
||||||
|
*/
|
||||||
|
private void gatherEvidence(Dependency dependency, final String name,
|
||||||
|
String contents) {
|
||||||
|
final Matcher matcher = AC_INIT_PATTERN.matcher(contents);
|
||||||
|
if (matcher.find()) {
|
||||||
|
final EvidenceCollection productEvidence = dependency
|
||||||
|
.getProductEvidence();
|
||||||
|
productEvidence.addEvidence(name, "Package", matcher.group(1),
|
||||||
|
Confidence.HIGHEST);
|
||||||
|
dependency.getVersionEvidence().addEvidence(name,
|
||||||
|
"Package Version", matcher.group(2), Confidence.HIGHEST);
|
||||||
|
final EvidenceCollection vendorEvidence = dependency
|
||||||
|
.getVendorEvidence();
|
||||||
|
if (null != matcher.group(3)) {
|
||||||
|
vendorEvidence.addEvidence(name, "Bug report address",
|
||||||
|
matcher.group(4), Confidence.HIGH);
|
||||||
|
}
|
||||||
|
if (null != matcher.group(5)) {
|
||||||
|
productEvidence.addEvidence(name, "Tarname", matcher.group(6),
|
||||||
|
Confidence.HIGH);
|
||||||
|
}
|
||||||
|
if (null != matcher.group(7)) {
|
||||||
|
final String url = matcher.group(8);
|
||||||
|
if (UrlStringUtils.isUrl(url)) {
|
||||||
|
vendorEvidence.addEvidence(name, "URL", url,
|
||||||
|
Confidence.HIGH);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Initializes the file type analyzer.
|
||||||
|
*
|
||||||
|
* @throws InitializationException thrown if there is an exception during
|
||||||
|
* initialization
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
protected void initializeFileTypeAnalyzer() throws InitializationException {
|
||||||
|
// No initialization needed.
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,255 @@
|
|||||||
|
/*
|
||||||
|
* This file is part of dependency-check-core.
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*
|
||||||
|
* Copyright (c) 2015 Institute for Defense Analyses. All Rights Reserved.
|
||||||
|
*/
|
||||||
|
package org.owasp.dependencycheck.analyzer;
|
||||||
|
|
||||||
|
import org.apache.commons.io.FileUtils;
|
||||||
|
import org.apache.commons.lang3.StringUtils;
|
||||||
|
import org.owasp.dependencycheck.Engine;
|
||||||
|
import org.owasp.dependencycheck.analyzer.exception.AnalysisException;
|
||||||
|
import org.owasp.dependencycheck.dependency.Confidence;
|
||||||
|
import org.owasp.dependencycheck.dependency.Dependency;
|
||||||
|
import org.owasp.dependencycheck.utils.Checksum;
|
||||||
|
import org.owasp.dependencycheck.utils.FileFilterBuilder;
|
||||||
|
import org.owasp.dependencycheck.utils.Settings;
|
||||||
|
import org.slf4j.Logger;
|
||||||
|
import org.slf4j.LoggerFactory;
|
||||||
|
|
||||||
|
import java.io.File;
|
||||||
|
import java.io.FileFilter;
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.io.UnsupportedEncodingException;
|
||||||
|
import java.nio.charset.Charset;
|
||||||
|
import java.security.MessageDigest;
|
||||||
|
import java.security.NoSuchAlgorithmException;
|
||||||
|
import java.util.regex.Matcher;
|
||||||
|
import java.util.regex.Pattern;
|
||||||
|
import org.owasp.dependencycheck.exception.InitializationException;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* <p>
|
||||||
|
* Used to analyze CMake build files, and collect information that can be used
|
||||||
|
* to determine the associated CPE.</p>
|
||||||
|
* <p>
|
||||||
|
* Note: This analyzer catches straightforward invocations of the project
|
||||||
|
* command, plus some other observed patterns of version inclusion in real CMake
|
||||||
|
* projects. Many projects make use of older versions of CMake and/or use custom
|
||||||
|
* "homebrew" ways to insert version information. Hopefully as the newer CMake
|
||||||
|
* call pattern grows in usage, this analyzer allow more CPEs to be
|
||||||
|
* identified.</p>
|
||||||
|
*
|
||||||
|
* @author Dale Visser
|
||||||
|
*/
|
||||||
|
@Experimental
|
||||||
|
public class CMakeAnalyzer extends AbstractFileTypeAnalyzer {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The logger.
|
||||||
|
*/
|
||||||
|
private static final Logger LOGGER = LoggerFactory.getLogger(CMakeAnalyzer.class);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Used when compiling file scanning regex patterns.
|
||||||
|
*/
|
||||||
|
private static final int REGEX_OPTIONS = Pattern.DOTALL
|
||||||
|
| Pattern.CASE_INSENSITIVE | Pattern.MULTILINE;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Regex to extract the product information.
|
||||||
|
*/
|
||||||
|
private static final Pattern PROJECT = Pattern.compile(
|
||||||
|
"^ *project *\\([ \\n]*(\\w+)[ \\n]*.*?\\)", REGEX_OPTIONS);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Regex to extract product and version information.
|
||||||
|
*
|
||||||
|
* Group 1: Product
|
||||||
|
*
|
||||||
|
* Group 2: Version
|
||||||
|
*/
|
||||||
|
private static final Pattern SET_VERSION = Pattern
|
||||||
|
.compile(
|
||||||
|
"^ *set\\s*\\(\\s*(\\w+)_version\\s+\"?(\\d+(?:\\.\\d+)+)[\\s\"]?\\)",
|
||||||
|
REGEX_OPTIONS);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Detects files that can be analyzed.
|
||||||
|
*/
|
||||||
|
private static final FileFilter FILTER = FileFilterBuilder.newInstance().addExtensions(".cmake")
|
||||||
|
.addFilenames("CMakeLists.txt").build();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the name of the CMake analyzer.
|
||||||
|
*
|
||||||
|
* @return the name of the analyzer
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
public String getName() {
|
||||||
|
return "CMake Analyzer";
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Tell that we are used for information collection.
|
||||||
|
*
|
||||||
|
* @return INFORMATION_COLLECTION
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
public AnalysisPhase getAnalysisPhase() {
|
||||||
|
return AnalysisPhase.INFORMATION_COLLECTION;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the set of supported file extensions.
|
||||||
|
*
|
||||||
|
* @return the set of supported file extensions
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
protected FileFilter getFileFilter() {
|
||||||
|
return FILTER;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Initializes the analyzer.
|
||||||
|
*
|
||||||
|
* @throws InitializationException thrown if an exception occurs getting an
|
||||||
|
* instance of SHA1
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
protected void initializeFileTypeAnalyzer() throws InitializationException {
|
||||||
|
try {
|
||||||
|
getSha1MessageDigest();
|
||||||
|
} catch (IllegalStateException ex) {
|
||||||
|
setEnabled(false);
|
||||||
|
throw new InitializationException("Unable to create SHA1 MessageDigest", ex);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Analyzes python packages and adds evidence to the dependency.
|
||||||
|
*
|
||||||
|
* @param dependency the dependency being analyzed
|
||||||
|
* @param engine the engine being used to perform the scan
|
||||||
|
* @throws AnalysisException thrown if there is an unrecoverable error
|
||||||
|
* analyzing the dependency
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
protected void analyzeDependency(Dependency dependency, Engine engine)
|
||||||
|
throws AnalysisException {
|
||||||
|
final File file = dependency.getActualFile();
|
||||||
|
final String parentName = file.getParentFile().getName();
|
||||||
|
final String name = file.getName();
|
||||||
|
dependency.setDisplayFileName(String.format("%s%c%s", parentName, File.separatorChar, name));
|
||||||
|
String contents;
|
||||||
|
try {
|
||||||
|
contents = FileUtils.readFileToString(file, Charset.defaultCharset()).trim();
|
||||||
|
} catch (IOException e) {
|
||||||
|
throw new AnalysisException(
|
||||||
|
"Problem occurred while reading dependency file.", e);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (StringUtils.isNotBlank(contents)) {
|
||||||
|
final Matcher m = PROJECT.matcher(contents);
|
||||||
|
int count = 0;
|
||||||
|
while (m.find()) {
|
||||||
|
count++;
|
||||||
|
LOGGER.debug(String.format(
|
||||||
|
"Found project command match with %d groups: %s",
|
||||||
|
m.groupCount(), m.group(0)));
|
||||||
|
final String group = m.group(1);
|
||||||
|
LOGGER.debug("Group 1: " + group);
|
||||||
|
dependency.getProductEvidence().addEvidence(name, "Project",
|
||||||
|
group, Confidence.HIGH);
|
||||||
|
}
|
||||||
|
LOGGER.debug("Found {} matches.", count);
|
||||||
|
analyzeSetVersionCommand(dependency, engine, contents);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Extracts the version information from the contents. If more then one
|
||||||
|
* version is found additional dependencies are added to the dependency
|
||||||
|
* list.
|
||||||
|
*
|
||||||
|
* @param dependency the dependency being analyzed
|
||||||
|
* @param engine the dependency-check engine
|
||||||
|
* @param contents the version information
|
||||||
|
*/
|
||||||
|
@edu.umd.cs.findbugs.annotations.SuppressFBWarnings(
|
||||||
|
value = "DM_DEFAULT_ENCODING",
|
||||||
|
justification = "Default encoding is only used if UTF-8 is not available")
|
||||||
|
private void analyzeSetVersionCommand(Dependency dependency, Engine engine, String contents) {
|
||||||
|
Dependency currentDep = dependency;
|
||||||
|
|
||||||
|
final Matcher m = SET_VERSION.matcher(contents);
|
||||||
|
int count = 0;
|
||||||
|
while (m.find()) {
|
||||||
|
count++;
|
||||||
|
LOGGER.debug("Found project command match with {} groups: {}",
|
||||||
|
m.groupCount(), m.group(0));
|
||||||
|
String product = m.group(1);
|
||||||
|
final String version = m.group(2);
|
||||||
|
LOGGER.debug("Group 1: " + product);
|
||||||
|
LOGGER.debug("Group 2: " + version);
|
||||||
|
final String aliasPrefix = "ALIASOF_";
|
||||||
|
if (product.startsWith(aliasPrefix)) {
|
||||||
|
product = product.replaceFirst(aliasPrefix, "");
|
||||||
|
}
|
||||||
|
if (count > 1) {
|
||||||
|
//TODO - refactor so we do not assign to the parameter (checkstyle)
|
||||||
|
currentDep = new Dependency(dependency.getActualFile());
|
||||||
|
currentDep.setDisplayFileName(String.format("%s:%s", dependency.getDisplayFileName(), product));
|
||||||
|
final String filePath = String.format("%s:%s", dependency.getFilePath(), product);
|
||||||
|
currentDep.setFilePath(filePath);
|
||||||
|
|
||||||
|
byte[] path;
|
||||||
|
try {
|
||||||
|
path = filePath.getBytes("UTF-8");
|
||||||
|
} catch (UnsupportedEncodingException ex) {
|
||||||
|
path = filePath.getBytes();
|
||||||
|
}
|
||||||
|
final MessageDigest sha1 = getSha1MessageDigest();
|
||||||
|
currentDep.setSha1sum(Checksum.getHex(sha1.digest(path)));
|
||||||
|
engine.getDependencies().add(currentDep);
|
||||||
|
}
|
||||||
|
final String source = currentDep.getDisplayFileName();
|
||||||
|
currentDep.getProductEvidence().addEvidence(source, "Product",
|
||||||
|
product, Confidence.MEDIUM);
|
||||||
|
currentDep.getVersionEvidence().addEvidence(source, "Version",
|
||||||
|
version, Confidence.MEDIUM);
|
||||||
|
}
|
||||||
|
LOGGER.debug(String.format("Found %d matches.", count));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected String getAnalyzerEnabledSettingKey() {
|
||||||
|
return Settings.KEYS.ANALYZER_CMAKE_ENABLED;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the sha1 message digest.
|
||||||
|
*
|
||||||
|
* @return the sha1 message digest
|
||||||
|
*/
|
||||||
|
private MessageDigest getSha1MessageDigest() {
|
||||||
|
try {
|
||||||
|
return MessageDigest.getInstance("SHA1");
|
||||||
|
} catch (NoSuchAlgorithmException e) {
|
||||||
|
LOGGER.error(e.getMessage());
|
||||||
|
throw new IllegalStateException("Failed to obtain the SHA1 message digest.", e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -25,8 +25,8 @@ import java.util.Collections;
|
|||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Set;
|
import java.util.Set;
|
||||||
import java.util.StringTokenizer;
|
import java.util.StringTokenizer;
|
||||||
import java.util.logging.Level;
|
import java.util.concurrent.TimeUnit;
|
||||||
import java.util.logging.Logger;
|
import org.apache.commons.lang3.builder.CompareToBuilder;
|
||||||
import org.apache.lucene.document.Document;
|
import org.apache.lucene.document.Document;
|
||||||
import org.apache.lucene.index.CorruptIndexException;
|
import org.apache.lucene.index.CorruptIndexException;
|
||||||
import org.apache.lucene.queryparser.classic.ParseException;
|
import org.apache.lucene.queryparser.classic.ParseException;
|
||||||
@@ -47,41 +47,49 @@ import org.owasp.dependencycheck.dependency.Evidence;
|
|||||||
import org.owasp.dependencycheck.dependency.EvidenceCollection;
|
import org.owasp.dependencycheck.dependency.EvidenceCollection;
|
||||||
import org.owasp.dependencycheck.dependency.Identifier;
|
import org.owasp.dependencycheck.dependency.Identifier;
|
||||||
import org.owasp.dependencycheck.dependency.VulnerableSoftware;
|
import org.owasp.dependencycheck.dependency.VulnerableSoftware;
|
||||||
|
import org.owasp.dependencycheck.exception.InitializationException;
|
||||||
import org.owasp.dependencycheck.utils.DependencyVersion;
|
import org.owasp.dependencycheck.utils.DependencyVersion;
|
||||||
import org.owasp.dependencycheck.utils.DependencyVersionUtil;
|
import org.owasp.dependencycheck.utils.DependencyVersionUtil;
|
||||||
|
import org.owasp.dependencycheck.utils.Settings;
|
||||||
|
import org.slf4j.Logger;
|
||||||
|
import org.slf4j.LoggerFactory;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* CPEAnalyzer is a utility class that takes a project dependency and attempts to discern if there is an associated CPE.
|
* CPEAnalyzer is a utility class that takes a project dependency and attempts
|
||||||
* It uses the evidence contained within the dependency to search the Lucene index.
|
* to discern if there is an associated CPE. It uses the evidence contained
|
||||||
|
* within the dependency to search the Lucene index.
|
||||||
*
|
*
|
||||||
* @author Jeremy Long <jeremy.long@owasp.org>
|
* @author Jeremy Long
|
||||||
*/
|
*/
|
||||||
public class CPEAnalyzer implements Analyzer {
|
public class CPEAnalyzer extends AbstractAnalyzer {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The Logger.
|
* The Logger.
|
||||||
*/
|
*/
|
||||||
private static final Logger LOGGER = Logger.getLogger(CPEAnalyzer.class.getName());
|
private static final Logger LOGGER = LoggerFactory.getLogger(CPEAnalyzer.class);
|
||||||
/**
|
/**
|
||||||
* The maximum number of query results to return.
|
* The maximum number of query results to return.
|
||||||
*/
|
*/
|
||||||
static final int MAX_QUERY_RESULTS = 25;
|
private static final int MAX_QUERY_RESULTS = 25;
|
||||||
/**
|
/**
|
||||||
* The weighting boost to give terms when constructing the Lucene query.
|
* The weighting boost to give terms when constructing the Lucene query.
|
||||||
*/
|
*/
|
||||||
static final String WEIGHTING_BOOST = "^5";
|
private 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 ._-]";
|
private 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]*";
|
private 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;
|
private static final int STRING_BUILDER_BUFFER = 20;
|
||||||
/**
|
/**
|
||||||
* The CPE in memory index.
|
* The CPE in memory index.
|
||||||
*/
|
*/
|
||||||
@@ -117,33 +125,55 @@ public class CPEAnalyzer implements Analyzer {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Creates the CPE Lucene Index.
|
* The default is to support parallel processing.
|
||||||
*
|
*
|
||||||
* @throws Exception is thrown if there is an issue opening the index.
|
* @return false
|
||||||
*/
|
*/
|
||||||
@Override
|
@Override
|
||||||
public void initialize() throws Exception {
|
public boolean supportsParallelProcessing() {
|
||||||
this.open();
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates the CPE Lucene Index.
|
||||||
|
*
|
||||||
|
* @throws InitializationException is thrown if there is an issue opening
|
||||||
|
* the index.
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
public void initializeAnalyzer() throws InitializationException {
|
||||||
|
try {
|
||||||
|
this.open();
|
||||||
|
} catch (IOException ex) {
|
||||||
|
LOGGER.debug("Exception initializing the Lucene Index", ex);
|
||||||
|
throw new InitializationException("An exception occurred initializing the Lucene Index", ex);
|
||||||
|
} catch (DatabaseException ex) {
|
||||||
|
LOGGER.debug("Exception accessing the database", ex);
|
||||||
|
throw new InitializationException("An exception occurred accessing the database", ex);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Opens the data source.
|
* Opens the data source.
|
||||||
*
|
*
|
||||||
* @throws IOException when the Lucene directory to be queried does not exist or is corrupt.
|
* @throws IOException when the Lucene directory to be queried does not
|
||||||
* @throws DatabaseException when the database throws an exception. This usually occurs when the database is in use
|
* exist or is corrupt.
|
||||||
* by another process.
|
* @throws DatabaseException when the database throws an exception. This
|
||||||
|
* usually occurs when the database is in use by another process.
|
||||||
*/
|
*/
|
||||||
public void open() throws IOException, DatabaseException {
|
public void open() throws IOException, DatabaseException {
|
||||||
LOGGER.log(Level.FINE, "Opening the CVE Database");
|
if (!isOpen()) {
|
||||||
cve = new CveDB();
|
cve = CveDB.getInstance();
|
||||||
cve.open();
|
cpe = CpeMemoryIndex.getInstance();
|
||||||
LOGGER.log(Level.FINE, "Creating the Lucene CPE Index");
|
try {
|
||||||
cpe = CpeMemoryIndex.getInstance();
|
final long creationStart = System.currentTimeMillis();
|
||||||
try {
|
cpe.open(cve);
|
||||||
cpe.open(cve);
|
final long creationSeconds = TimeUnit.MILLISECONDS.toSeconds(System.currentTimeMillis() - creationStart);
|
||||||
} catch (IndexException ex) {
|
LOGGER.info("Created CPE Index ({} seconds)", creationSeconds);
|
||||||
LOGGER.log(Level.FINE, "IndexException", ex);
|
} catch (IndexException ex) {
|
||||||
throw new DatabaseException(ex);
|
LOGGER.debug("IndexException", ex);
|
||||||
|
throw new DatabaseException(ex);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -151,18 +181,30 @@ public class CPEAnalyzer implements Analyzer {
|
|||||||
* Closes the data sources.
|
* Closes the data sources.
|
||||||
*/
|
*/
|
||||||
@Override
|
@Override
|
||||||
public void close() {
|
public void closeAnalyzer() {
|
||||||
if (cpe != null) {
|
|
||||||
cpe.close();
|
|
||||||
}
|
|
||||||
if (cve != null) {
|
if (cve != null) {
|
||||||
cve.close();
|
cve.close();
|
||||||
|
cve = null;
|
||||||
|
}
|
||||||
|
if (cpe != null) {
|
||||||
|
cpe.close();
|
||||||
|
cpe = null;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Searches the data store of CPE entries, trying to identify the CPE for the given dependency based on the evidence
|
* Returns whether or not the analyzer is open.
|
||||||
* contained within. The dependency passed in is updated with any identified CPE values.
|
*
|
||||||
|
* @return <code>true</code> if the analyzer is open
|
||||||
|
*/
|
||||||
|
public boolean isOpen() {
|
||||||
|
return cpe != null && cpe.isOpen();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Searches the data store of CPE entries, trying to identify the CPE for
|
||||||
|
* the given dependency based on the evidence contained within. The
|
||||||
|
* dependency passed in is updated with any identified CPE values.
|
||||||
*
|
*
|
||||||
* @param dependency the dependency to search for CPE entries on.
|
* @param dependency the dependency to search for CPE entries on.
|
||||||
* @throws CorruptIndexException is thrown when the Lucene index is corrupt.
|
* @throws CorruptIndexException is thrown when the Lucene index is corrupt.
|
||||||
@@ -170,47 +212,46 @@ public class CPEAnalyzer implements Analyzer {
|
|||||||
* @throws ParseException is thrown when the Lucene query cannot be parsed.
|
* @throws ParseException is thrown when the Lucene query cannot be parsed.
|
||||||
*/
|
*/
|
||||||
protected void determineCPE(Dependency dependency) throws CorruptIndexException, IOException, ParseException {
|
protected void determineCPE(Dependency dependency) throws CorruptIndexException, IOException, ParseException {
|
||||||
Confidence confidence = Confidence.HIGHEST;
|
//TODO test dojo-war against this. we should get dojo-toolkit:dojo-toolkit AND dojo-toolkit:toolkit
|
||||||
|
String vendors = "";
|
||||||
String vendors = addEvidenceWithoutDuplicateTerms("", dependency.getVendorEvidence(), confidence);
|
String products = "";
|
||||||
String products = addEvidenceWithoutDuplicateTerms("", dependency.getProductEvidence(), confidence);
|
for (Confidence confidence : Confidence.values()) {
|
||||||
/* bug fix for #40 - version evidence is not showing up as "used" in the reports if there is no
|
|
||||||
* CPE identified. As such, we are "using" the evidence and ignoring the results. */
|
|
||||||
addEvidenceWithoutDuplicateTerms("", dependency.getVersionEvidence(), confidence);
|
|
||||||
|
|
||||||
int ctr = 0;
|
|
||||||
do {
|
|
||||||
if (!vendors.isEmpty() && !products.isEmpty()) {
|
|
||||||
final List<IndexEntry> entries = searchCPE(vendors, products, dependency.getProductEvidence().getWeighting(),
|
|
||||||
dependency.getVendorEvidence().getWeighting());
|
|
||||||
|
|
||||||
for (IndexEntry e : entries) {
|
|
||||||
if (verifyEntry(e, dependency)) {
|
|
||||||
final String vendor = e.getVendor();
|
|
||||||
final String product = e.getProduct();
|
|
||||||
determineIdentifiers(dependency, vendor, product);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
confidence = reduceConfidence(confidence);
|
|
||||||
if (dependency.getVendorEvidence().contains(confidence)) {
|
if (dependency.getVendorEvidence().contains(confidence)) {
|
||||||
vendors = addEvidenceWithoutDuplicateTerms(vendors, dependency.getVendorEvidence(), confidence);
|
vendors = addEvidenceWithoutDuplicateTerms(vendors, dependency.getVendorEvidence(), confidence);
|
||||||
|
LOGGER.debug("vendor search: {}", vendors);
|
||||||
}
|
}
|
||||||
if (dependency.getProductEvidence().contains(confidence)) {
|
if (dependency.getProductEvidence().contains(confidence)) {
|
||||||
products = addEvidenceWithoutDuplicateTerms(products, dependency.getProductEvidence(), confidence);
|
products = addEvidenceWithoutDuplicateTerms(products, dependency.getProductEvidence(), confidence);
|
||||||
|
LOGGER.debug("product search: {}", products);
|
||||||
}
|
}
|
||||||
/* bug fix for #40 - version evidence is not showing up as "used" in the reports if there is no
|
if (!vendors.isEmpty() && !products.isEmpty()) {
|
||||||
* CPE identified. As such, we are "using" the evidence and ignoring the results. */
|
final List<IndexEntry> entries = searchCPE(vendors, products, dependency.getVendorEvidence().getWeighting(),
|
||||||
if (dependency.getVersionEvidence().contains(confidence)) {
|
dependency.getProductEvidence().getWeighting());
|
||||||
addEvidenceWithoutDuplicateTerms("", dependency.getVersionEvidence(), confidence);
|
if (entries == null) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
boolean identifierAdded = false;
|
||||||
|
for (IndexEntry e : entries) {
|
||||||
|
LOGGER.debug("Verifying entry: {}", e);
|
||||||
|
if (verifyEntry(e, dependency)) {
|
||||||
|
final String vendor = e.getVendor();
|
||||||
|
final String product = e.getProduct();
|
||||||
|
LOGGER.debug("identified vendor/product: {}/{}", vendor, product);
|
||||||
|
identifierAdded |= determineIdentifiers(dependency, vendor, product, confidence);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (identifierAdded) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
} while ((++ctr) < 4);
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns the text created by concatenating the text and the values from the EvidenceCollection (filtered for a
|
* Returns the text created by concatenating the text and the values from
|
||||||
* specific confidence). This attempts to prevent duplicate terms from being added.<br/<br/> Note, if the evidence
|
* the EvidenceCollection (filtered for a specific confidence). This
|
||||||
* is longer then 200 characters it will be truncated.
|
* 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 text the base text.
|
||||||
* @param ec an EvidenceCollection
|
* @param ec an EvidenceCollection
|
||||||
@@ -239,85 +280,73 @@ public class CPEAnalyzer implements Analyzer {
|
|||||||
return sb.toString().trim();
|
return sb.toString().trim();
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Reduces the given confidence by one level. This returns LOW if the confidence passed in is not HIGH.
|
|
||||||
*
|
|
||||||
* @param c the confidence to reduce.
|
|
||||||
* @return One less then the confidence passed in.
|
|
||||||
*/
|
|
||||||
private Confidence reduceConfidence(final Confidence c) {
|
|
||||||
if (c == Confidence.HIGHEST) {
|
|
||||||
return Confidence.HIGH;
|
|
||||||
} else if (c == Confidence.HIGH) {
|
|
||||||
return Confidence.MEDIUM;
|
|
||||||
} else {
|
|
||||||
return Confidence.LOW;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* <p>
|
* <p>
|
||||||
* Searches the Lucene CPE index to identify possible CPE entries associated with the supplied vendor, product, and
|
* Searches the Lucene CPE index to identify possible CPE entries associated
|
||||||
* version.</p>
|
* with the supplied vendor, product, and version.</p>
|
||||||
*
|
*
|
||||||
* <p>
|
* <p>
|
||||||
* If either the vendorWeightings or productWeightings lists have been populated this data is used to add weighting
|
* If either the vendorWeightings or productWeightings lists have been
|
||||||
* factors to the search.</p>
|
* populated this data is used to add weighting factors to the search.</p>
|
||||||
*
|
*
|
||||||
* @param vendor the text used to search the vendor field
|
* @param vendor the text used to search the vendor field
|
||||||
* @param product the text used to search the product field
|
* @param product the text used to search the product field
|
||||||
* @param vendorWeightings a list of strings to use to add weighting factors to the vendor field
|
* @param vendorWeightings a list of strings to use to add weighting factors
|
||||||
* @param productWeightings Adds a list of strings that will be used to add weighting factors to the product search
|
* 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
|
* @return a list of possible CPE values
|
||||||
* @throws CorruptIndexException when the Lucene index is corrupt
|
|
||||||
* @throws IOException when the Lucene index is not found
|
|
||||||
* @throws ParseException when the generated query is not valid
|
|
||||||
*/
|
*/
|
||||||
protected List<IndexEntry> searchCPE(String vendor, String product,
|
protected List<IndexEntry> searchCPE(String vendor, String product,
|
||||||
Set<String> vendorWeightings, Set<String> productWeightings)
|
Set<String> vendorWeightings, Set<String> productWeightings) {
|
||||||
throws CorruptIndexException, IOException, ParseException {
|
|
||||||
final ArrayList<IndexEntry> ret = new ArrayList<IndexEntry>(MAX_QUERY_RESULTS);
|
final List<IndexEntry> ret = new ArrayList<>(MAX_QUERY_RESULTS);
|
||||||
|
|
||||||
final String searchString = buildSearch(vendor, product, vendorWeightings, productWeightings);
|
final String searchString = buildSearch(vendor, product, vendorWeightings, productWeightings);
|
||||||
if (searchString == null) {
|
if (searchString == null) {
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
try {
|
||||||
final TopDocs docs = cpe.search(searchString, MAX_QUERY_RESULTS);
|
final TopDocs docs = cpe.search(searchString, MAX_QUERY_RESULTS);
|
||||||
for (ScoreDoc d : docs.scoreDocs) {
|
for (ScoreDoc d : docs.scoreDocs) {
|
||||||
if (d.score >= 0.08) {
|
if (d.score >= 0.08) {
|
||||||
final Document doc = cpe.getDocument(d.doc);
|
final Document doc = cpe.getDocument(d.doc);
|
||||||
final IndexEntry entry = new IndexEntry();
|
final IndexEntry entry = new IndexEntry();
|
||||||
entry.setVendor(doc.get(Fields.VENDOR));
|
entry.setVendor(doc.get(Fields.VENDOR));
|
||||||
entry.setProduct(doc.get(Fields.PRODUCT));
|
entry.setProduct(doc.get(Fields.PRODUCT));
|
||||||
// if (d.score < 0.08) {
|
entry.setSearchScore(d.score);
|
||||||
// System.out.print(entry.getVendor());
|
if (!ret.contains(entry)) {
|
||||||
// System.out.print(":");
|
ret.add(entry);
|
||||||
// System.out.print(entry.getProduct());
|
}
|
||||||
// System.out.print(":");
|
|
||||||
// System.out.println(d.score);
|
|
||||||
// }
|
|
||||||
entry.setSearchScore(d.score);
|
|
||||||
if (!ret.contains(entry)) {
|
|
||||||
ret.add(entry);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
return ret;
|
||||||
|
} catch (ParseException ex) {
|
||||||
|
LOGGER.warn("An error 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 occurred reading CPE data. See the log for more details.");
|
||||||
|
LOGGER.info("IO Error with search string: {}", searchString, ex);
|
||||||
}
|
}
|
||||||
return ret;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* <p>
|
* <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>
|
* <p>
|
||||||
* If either the possibleVendor or possibleProducts lists have been populated this data is used to add weighting
|
* If either the possibleVendor or possibleProducts lists have been
|
||||||
* factors to the search string generated.</p>
|
* populated this data is used to add weighting factors to the search string
|
||||||
|
* generated.</p>
|
||||||
*
|
*
|
||||||
* @param vendor text to search the vendor field
|
* @param vendor text to search the vendor field
|
||||||
* @param product text to search the product field
|
* @param product text to search the product field
|
||||||
* @param vendorWeighting a list of strings to apply to the vendor to boost the terms weight
|
* @param vendorWeighting a list of strings to apply to the vendor to boost
|
||||||
* @param productWeightings a list of strings to apply to the product to boost the terms weight
|
* the terms weight
|
||||||
|
* @param productWeightings a list of strings to apply to the product to
|
||||||
|
* boost the terms weight
|
||||||
* @return the Lucene query
|
* @return the Lucene query
|
||||||
*/
|
*/
|
||||||
protected String buildSearch(String vendor, String product,
|
protected String buildSearch(String vendor, String product,
|
||||||
@@ -338,22 +367,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
|
* This method constructs a Lucene query for a given field. The searchText
|
||||||
* word is within the list of weighted words then an additional weighting is applied to the term as it is appended
|
* is split into separate words and if the word is within the list of
|
||||||
* into the query.
|
* 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 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 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.
|
* @return if the append was successful.
|
||||||
*/
|
*/
|
||||||
private boolean appendWeightedSearch(StringBuilder sb, String field, String searchText, Set<String> weightedText) {
|
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);
|
final String cleanText = cleanseText(searchText);
|
||||||
|
|
||||||
if ("".equals(cleanText)) {
|
if (cleanText.isEmpty()) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -363,20 +395,27 @@ public class CPEAnalyzer implements Analyzer {
|
|||||||
final StringTokenizer tokens = new StringTokenizer(cleanText);
|
final StringTokenizer tokens = new StringTokenizer(cleanText);
|
||||||
while (tokens.hasMoreElements()) {
|
while (tokens.hasMoreElements()) {
|
||||||
final String word = tokens.nextToken();
|
final String word = tokens.nextToken();
|
||||||
String temp = null;
|
StringBuilder temp = null;
|
||||||
for (String weighted : weightedText) {
|
for (String weighted : weightedText) {
|
||||||
final String weightedStr = cleanseText(weighted);
|
final String weightedStr = cleanseText(weighted);
|
||||||
if (equalsIgnoreCaseAndNonAlpha(word, weightedStr)) {
|
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)) {
|
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) {
|
if (temp == null) {
|
||||||
temp = LuceneUtils.escapeLuceneQuery(word);
|
LuceneUtils.appendEscapedLuceneQuery(sb, word);
|
||||||
|
} else {
|
||||||
|
sb.append(temp);
|
||||||
}
|
}
|
||||||
sb.append(" ").append(temp);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
sb.append(" ) ");
|
sb.append(" ) ");
|
||||||
@@ -384,7 +423,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.
|
* @param text is the text to remove the characters from.
|
||||||
* @return the text having removed some characters.
|
* @return the text having removed some characters.
|
||||||
@@ -394,7 +434,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 l string one to compare.
|
||||||
* @param r string two to compare.
|
* @param r string two to compare.
|
||||||
@@ -411,8 +452,9 @@ public class CPEAnalyzer implements Analyzer {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Ensures that the CPE Identified matches the dependency. This validates that the product, vendor, and version
|
* Ensures that the CPE Identified matches the dependency. This validates
|
||||||
* information for the CPE are contained within the dependencies evidence.
|
* that the product, vendor, and version information for the CPE are
|
||||||
|
* contained within the dependencies evidence.
|
||||||
*
|
*
|
||||||
* @param entry a CPE entry.
|
* @param entry a CPE entry.
|
||||||
* @param dependency the dependency that the CPE entries could be for.
|
* @param dependency the dependency that the CPE entries could be for.
|
||||||
@@ -421,6 +463,8 @@ public class CPEAnalyzer implements Analyzer {
|
|||||||
private boolean verifyEntry(final IndexEntry entry, final Dependency dependency) {
|
private boolean verifyEntry(final IndexEntry entry, final Dependency dependency) {
|
||||||
boolean isValid = false;
|
boolean isValid = false;
|
||||||
|
|
||||||
|
//TODO - does this nullify some of the fuzzy matching that happens in the lucene search?
|
||||||
|
// for instance CPE some-component and in the evidence we have SomeComponent.
|
||||||
if (collectionContainsString(dependency.getProductEvidence(), entry.getProduct())
|
if (collectionContainsString(dependency.getProductEvidence(), entry.getProduct())
|
||||||
&& collectionContainsString(dependency.getVendorEvidence(), entry.getVendor())) {
|
&& collectionContainsString(dependency.getVendorEvidence(), entry.getVendor())) {
|
||||||
//&& collectionContainsVersion(dependency.getVersionEvidence(), entry.getVersion())
|
//&& collectionContainsVersion(dependency.getVersionEvidence(), entry.getVersion())
|
||||||
@@ -437,23 +481,12 @@ public class CPEAnalyzer implements Analyzer {
|
|||||||
* @return whether or not the EvidenceCollection contains the string
|
* @return whether or not the EvidenceCollection contains the string
|
||||||
*/
|
*/
|
||||||
private boolean collectionContainsString(EvidenceCollection ec, String text) {
|
private boolean collectionContainsString(EvidenceCollection ec, String text) {
|
||||||
|
|
||||||
//<editor-fold defaultstate="collapsed" desc="This code fold contains an old version of the code, delete once more testing is done">
|
|
||||||
// String[] splitText = text.split("[\\s_-]");
|
|
||||||
//
|
|
||||||
// for (String search : splitText) {
|
|
||||||
// //final String search = text.replaceAll("[\\s_-]", "").toLowerCase();
|
|
||||||
// if (ec.containsUsedString(search)) {
|
|
||||||
// return true;
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
//</editor-fold>
|
|
||||||
//TODO - likely need to change the split... not sure if this will work for CPE with special chars
|
//TODO - likely need to change the split... not sure if this will work for CPE with special chars
|
||||||
if (text == null) {
|
if (text == null) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
final String[] words = text.split("[\\s_-]");
|
final String[] words = text.split("[\\s_-]");
|
||||||
final List<String> list = new ArrayList<String>();
|
final List<String> list = new ArrayList<>();
|
||||||
String tempWord = null;
|
String tempWord = null;
|
||||||
for (String word : words) {
|
for (String word : words) {
|
||||||
/*
|
/*
|
||||||
@@ -469,9 +502,16 @@ public class CPEAnalyzer implements Analyzer {
|
|||||||
list.add(word);
|
list.add(word);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (tempWord != null && !list.isEmpty()) {
|
if (tempWord != null) {
|
||||||
final String tmp = list.get(list.size() - 1) + tempWord;
|
if (!list.isEmpty()) {
|
||||||
list.add(tmp);
|
final String tmp = list.get(list.size() - 1) + tempWord;
|
||||||
|
list.add(tmp);
|
||||||
|
} else {
|
||||||
|
list.add(tempWord);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (list.isEmpty()) {
|
||||||
|
return false;
|
||||||
}
|
}
|
||||||
boolean contains = true;
|
boolean contains = true;
|
||||||
for (String word : list) {
|
for (String word : list) {
|
||||||
@@ -481,14 +521,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 dependency The Dependency to analyze.
|
||||||
* @param engine The analysis engine
|
* @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
|
@Override
|
||||||
public void analyze(Dependency dependency, Engine engine) throws AnalysisException {
|
protected synchronized void analyzeDependency(Dependency dependency, Engine engine) throws AnalysisException {
|
||||||
try {
|
try {
|
||||||
determineCPE(dependency);
|
determineCPE(dependency);
|
||||||
} catch (CorruptIndexException ex) {
|
} catch (CorruptIndexException ex) {
|
||||||
@@ -501,20 +543,32 @@ public class CPEAnalyzer implements Analyzer {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Retrieves a list of CPE values from the CveDB based on the vendor and product passed in. The list is then
|
* Retrieves a list of CPE values from the CveDB based on the vendor and
|
||||||
* validated to find only CPEs that are valid for the given dependency. It is possible that the CPE identified is a
|
* product passed in. The list is then validated to find only CPEs that are
|
||||||
* best effort "guess" based on the vendor, product, and version information.
|
* 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 dependency the Dependency being analyzed
|
||||||
* @param vendor the vendor for the CPE being analyzed
|
* @param vendor the vendor for the CPE being analyzed
|
||||||
* @param product the product for the CPE being analyzed
|
* @param product the product for the CPE being analyzed
|
||||||
|
* @param currentConfidence the current confidence being used during
|
||||||
|
* analysis
|
||||||
|
* @return <code>true</code> if an identifier was added to the dependency;
|
||||||
|
* otherwise <code>false</code>
|
||||||
* @throws UnsupportedEncodingException is thrown if UTF-8 is not supported
|
* @throws UnsupportedEncodingException is thrown if UTF-8 is not supported
|
||||||
*/
|
*/
|
||||||
private void determineIdentifiers(Dependency dependency, String vendor, String product) throws UnsupportedEncodingException {
|
protected boolean determineIdentifiers(Dependency dependency, String vendor, String product,
|
||||||
|
Confidence currentConfidence) throws UnsupportedEncodingException {
|
||||||
final Set<VulnerableSoftware> cpes = cve.getCPEs(vendor, product);
|
final Set<VulnerableSoftware> cpes = cve.getCPEs(vendor, product);
|
||||||
DependencyVersion bestGuess = new DependencyVersion("-");
|
DependencyVersion bestGuess = new DependencyVersion("-");
|
||||||
Confidence bestGuessConf = null;
|
Confidence bestGuessConf = null;
|
||||||
final List<IdentifierMatch> collected = new ArrayList<IdentifierMatch>();
|
boolean hasBroadMatch = false;
|
||||||
|
final List<IdentifierMatch> collected = new ArrayList<>();
|
||||||
|
|
||||||
|
//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()) {
|
for (Confidence conf : Confidence.values()) {
|
||||||
for (Evidence evidence : dependency.getVersionEvidence().iterator(conf)) {
|
for (Evidence evidence : dependency.getVersionEvidence().iterator(conf)) {
|
||||||
final DependencyVersion evVer = DependencyVersionUtil.parseVersion(evidence.getValue());
|
final DependencyVersion evVer = DependencyVersionUtil.parseVersion(evidence.getValue());
|
||||||
@@ -523,49 +577,57 @@ public class CPEAnalyzer implements Analyzer {
|
|||||||
}
|
}
|
||||||
for (VulnerableSoftware vs : cpes) {
|
for (VulnerableSoftware vs : cpes) {
|
||||||
DependencyVersion dbVer;
|
DependencyVersion dbVer;
|
||||||
if (vs.getRevision() != null && !vs.getRevision().isEmpty()) {
|
if (vs.getUpdate() != null && !vs.getUpdate().isEmpty()) {
|
||||||
dbVer = DependencyVersionUtil.parseVersion(vs.getVersion() + "." + vs.getRevision());
|
dbVer = DependencyVersionUtil.parseVersion(vs.getVersion() + '.' + vs.getUpdate());
|
||||||
} else {
|
} else {
|
||||||
dbVer = DependencyVersionUtil.parseVersion(vs.getVersion());
|
dbVer = DependencyVersionUtil.parseVersion(vs.getVersion());
|
||||||
}
|
}
|
||||||
if (dbVer == null //special case, no version specified - everything is vulnerable
|
if (dbVer == null) { //special case, no version specified - everything is vulnerable
|
||||||
|| evVer.equals(dbVer)) { //yeah! exact match
|
hasBroadMatch = true;
|
||||||
|
final String url = String.format(NVD_SEARCH_URL, URLEncoder.encode(vs.getName(), "UTF-8"));
|
||||||
|
final IdentifierMatch match = new IdentifierMatch("cpe", vs.getName(), url, IdentifierConfidence.BROAD_MATCH, conf);
|
||||||
|
collected.add(match);
|
||||||
|
} else if (evVer.equals(dbVer)) { //yeah! exact match
|
||||||
final String url = String.format(NVD_SEARCH_URL, URLEncoder.encode(vs.getName(), "UTF-8"));
|
final String url = String.format(NVD_SEARCH_URL, URLEncoder.encode(vs.getName(), "UTF-8"));
|
||||||
final IdentifierMatch match = new IdentifierMatch("cpe", vs.getName(), url, IdentifierConfidence.EXACT_MATCH, conf);
|
final IdentifierMatch match = new IdentifierMatch("cpe", vs.getName(), url, IdentifierConfidence.EXACT_MATCH, conf);
|
||||||
collected.add(match);
|
collected.add(match);
|
||||||
} else {
|
|
||||||
//TODO the following isn't quite right is it? need to think about this guessing game a bit more.
|
//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()
|
} else if (evVer.getVersionParts().size() <= dbVer.getVersionParts().size()
|
||||||
&& evVer.matchesAtLeastThreeLevels(dbVer)) {
|
&& evVer.matchesAtLeastThreeLevels(dbVer)) {
|
||||||
if (bestGuessConf == null || bestGuessConf.compareTo(conf) > 0) {
|
if (bestGuessConf == null || bestGuessConf.compareTo(conf) > 0) {
|
||||||
if (bestGuess.getVersionParts().size() < dbVer.getVersionParts().size()) {
|
if (bestGuess.getVersionParts().size() < dbVer.getVersionParts().size()) {
|
||||||
bestGuess = dbVer;
|
bestGuess = dbVer;
|
||||||
bestGuessConf = conf;
|
bestGuessConf = conf;
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (bestGuessConf == null || bestGuessConf.compareTo(conf) > 0) {
|
if ((bestGuessConf == null || bestGuessConf.compareTo(conf) > 0)
|
||||||
if (bestGuess.getVersionParts().size() < evVer.getVersionParts().size()) {
|
&& bestGuess.getVersionParts().size() < evVer.getVersionParts().size()) {
|
||||||
bestGuess = evVer;
|
bestGuess = evVer;
|
||||||
bestGuessConf = conf;
|
bestGuessConf = conf;
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
final String cpeName = String.format("cpe:/a:%s:%s:%s", vendor, product, bestGuess.toString());
|
final String cpeName = String.format("cpe:/a:%s:%s:%s", vendor, product, bestGuess.toString());
|
||||||
final String url = null;
|
String url = null;
|
||||||
if (bestGuessConf == null) {
|
if (hasBroadMatch) { //if we have a broad match we can add the URL to the best guess.
|
||||||
|
final String cpeUrlName = String.format("cpe:/a:%s:%s", vendor, product);
|
||||||
|
url = String.format(NVD_SEARCH_URL, URLEncoder.encode(cpeUrlName, "UTF-8"));
|
||||||
|
}
|
||||||
|
if (bestGuessConf
|
||||||
|
== null) {
|
||||||
bestGuessConf = Confidence.LOW;
|
bestGuessConf = Confidence.LOW;
|
||||||
}
|
}
|
||||||
final IdentifierMatch match = new IdentifierMatch("cpe", cpeName, url, IdentifierConfidence.BEST_GUESS, bestGuessConf);
|
final IdentifierMatch match = new IdentifierMatch("cpe", cpeName, url, IdentifierConfidence.BEST_GUESS, bestGuessConf);
|
||||||
|
|
||||||
collected.add(match);
|
collected.add(match);
|
||||||
|
|
||||||
Collections.sort(collected);
|
Collections.sort(collected);
|
||||||
final IdentifierConfidence bestIdentifierQuality = collected.get(0).getConfidence();
|
final IdentifierConfidence bestIdentifierQuality = collected.get(0).getConfidence();
|
||||||
final Confidence bestEvidenceQuality = collected.get(0).getEvidenceConfidence();
|
final Confidence bestEvidenceQuality = collected.get(0).getEvidenceConfidence();
|
||||||
|
boolean identifierAdded = false;
|
||||||
for (IdentifierMatch m : collected) {
|
for (IdentifierMatch m : collected) {
|
||||||
if (bestIdentifierQuality.equals(m.getConfidence())
|
if (bestIdentifierQuality.equals(m.getConfidence())
|
||||||
&& bestEvidenceQuality.equals(m.getEvidenceConfidence())) {
|
&& bestEvidenceQuality.equals(m.getEvidenceConfidence())) {
|
||||||
@@ -576,8 +638,22 @@ public class CPEAnalyzer implements Analyzer {
|
|||||||
i.setConfidence(bestEvidenceQuality);
|
i.setConfidence(bestEvidenceQuality);
|
||||||
}
|
}
|
||||||
dependency.addIdentifier(i);
|
dependency.addIdentifier(i);
|
||||||
|
identifierAdded = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
return identifierAdded;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* <p>
|
||||||
|
* Returns the setting key to determine if the analyzer is enabled.</p>
|
||||||
|
*
|
||||||
|
* @return the key for the analyzer's enabled property
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
protected String getAnalyzerEnabledSettingKey() {
|
||||||
|
return Settings.KEYS.ANALYZER_CPE_ENABLED;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -592,34 +668,52 @@ public class CPEAnalyzer implements Analyzer {
|
|||||||
/**
|
/**
|
||||||
* A best guess for the CPE.
|
* A best guess for the CPE.
|
||||||
*/
|
*/
|
||||||
BEST_GUESS
|
BEST_GUESS,
|
||||||
|
/**
|
||||||
|
* The entire vendor/product group must be added (without a guess at
|
||||||
|
* version) because there is a CVE with a VS that only specifies
|
||||||
|
* vendor/product.
|
||||||
|
*/
|
||||||
|
BROAD_MATCH
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 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> {
|
private static class IdentifierMatch implements Comparable<IdentifierMatch> {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The confidence in the evidence used to identify this match.
|
||||||
|
*/
|
||||||
|
private Confidence evidenceConfidence;
|
||||||
|
/**
|
||||||
|
* The confidence whether this is an exact match, or a best guess.
|
||||||
|
*/
|
||||||
|
private IdentifierConfidence confidence;
|
||||||
|
/**
|
||||||
|
* The CPE identifier.
|
||||||
|
*/
|
||||||
|
private Identifier identifier;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Constructs an IdentifierMatch.
|
* Constructs an IdentifierMatch.
|
||||||
*
|
*
|
||||||
* @param type the type of identifier (such as CPE)
|
* @param type the type of identifier (such as CPE)
|
||||||
* @param value the value of the identifier
|
* @param value the value of the identifier
|
||||||
* @param url the URL of the identifier
|
* @param url the URL of the identifier
|
||||||
* @param identifierConfidence the confidence in the identifier: best guess or exact match
|
* @param identifierConfidence the confidence in the identifier: best
|
||||||
* @param evidenceConfidence the confidence of the evidence used to find the identifier
|
* 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) {
|
IdentifierMatch(String type, String value, String url, IdentifierConfidence identifierConfidence, Confidence evidenceConfidence) {
|
||||||
this.identifier = new Identifier(type, value, url);
|
this.identifier = new Identifier(type, value, url);
|
||||||
this.confidence = identifierConfidence;
|
this.confidence = identifierConfidence;
|
||||||
this.evidenceConfidence = evidenceConfidence;
|
this.evidenceConfidence = evidenceConfidence;
|
||||||
}
|
}
|
||||||
//<editor-fold defaultstate="collapsed" desc="Property implementations: evidenceConfidence, confidence, identifier">
|
|
||||||
/**
|
|
||||||
* The confidence in the evidence used to identify this match.
|
|
||||||
*/
|
|
||||||
private Confidence evidenceConfidence;
|
|
||||||
|
|
||||||
|
//<editor-fold defaultstate="collapsed" desc="Property implementations: evidenceConfidence, confidence, identifier">
|
||||||
/**
|
/**
|
||||||
* Get the value of evidenceConfidence
|
* Get the value of evidenceConfidence
|
||||||
*
|
*
|
||||||
@@ -637,10 +731,6 @@ public class CPEAnalyzer implements Analyzer {
|
|||||||
public void setEvidenceConfidence(Confidence evidenceConfidence) {
|
public void setEvidenceConfidence(Confidence evidenceConfidence) {
|
||||||
this.evidenceConfidence = evidenceConfidence;
|
this.evidenceConfidence = evidenceConfidence;
|
||||||
}
|
}
|
||||||
/**
|
|
||||||
* The confidence whether this is an exact match, or a best guess.
|
|
||||||
*/
|
|
||||||
private IdentifierConfidence confidence;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get the value of confidence.
|
* Get the value of confidence.
|
||||||
@@ -659,10 +749,6 @@ public class CPEAnalyzer implements Analyzer {
|
|||||||
public void setConfidence(IdentifierConfidence confidence) {
|
public void setConfidence(IdentifierConfidence confidence) {
|
||||||
this.confidence = confidence;
|
this.confidence = confidence;
|
||||||
}
|
}
|
||||||
/**
|
|
||||||
* The CPE identifier.
|
|
||||||
*/
|
|
||||||
private Identifier identifier;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get the value of identifier.
|
* Get the value of identifier.
|
||||||
@@ -730,30 +816,24 @@ public class CPEAnalyzer implements Analyzer {
|
|||||||
if (this.confidence != other.confidence) {
|
if (this.confidence != other.confidence) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
if (this.identifier != other.identifier && (this.identifier == null || !this.identifier.equals(other.identifier))) {
|
return !(this.identifier != other.identifier && (this.identifier == null || !this.identifier.equals(other.identifier)));
|
||||||
return false;
|
|
||||||
}
|
|
||||||
return true;
|
|
||||||
}
|
}
|
||||||
//</editor-fold>
|
//</editor-fold>
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Standard implementation of compareTo that compares identifier confidence, evidence confidence, and then the
|
* Standard implementation of compareTo that compares identifier
|
||||||
* identifier.
|
* confidence, evidence confidence, and then the identifier.
|
||||||
*
|
*
|
||||||
* @param o the IdentifierMatch to compare to
|
* @param o the IdentifierMatch to compare to
|
||||||
* @return the natural ordering of IdentifierMatch
|
* @return the natural ordering of IdentifierMatch
|
||||||
*/
|
*/
|
||||||
@Override
|
@Override
|
||||||
public int compareTo(IdentifierMatch o) {
|
public int compareTo(IdentifierMatch o) {
|
||||||
int conf = this.confidence.compareTo(o.confidence);
|
return new CompareToBuilder()
|
||||||
if (conf == 0) {
|
.append(confidence, o.confidence)
|
||||||
conf = this.evidenceConfidence.compareTo(o.evidenceConfidence);
|
.append(evidenceConfidence, o.evidenceConfidence)
|
||||||
if (conf == 0) {
|
.append(identifier, o.identifier)
|
||||||
conf = identifier.compareTo(o.identifier);
|
.toComparison();
|
||||||
}
|
|
||||||
}
|
|
||||||
return conf;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,249 @@
|
|||||||
|
/*
|
||||||
|
* This file is part of dependency-check-core.
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*
|
||||||
|
* Copyright (c) 2014 Jeremy Long. All Rights Reserved.
|
||||||
|
*/
|
||||||
|
package org.owasp.dependencycheck.analyzer;
|
||||||
|
|
||||||
|
import org.apache.commons.io.FileUtils;
|
||||||
|
import org.owasp.dependencycheck.Engine;
|
||||||
|
import org.owasp.dependencycheck.analyzer.exception.AnalysisException;
|
||||||
|
import org.owasp.dependencycheck.data.central.CentralSearch;
|
||||||
|
import org.owasp.dependencycheck.data.nexus.MavenArtifact;
|
||||||
|
import org.owasp.dependencycheck.dependency.Confidence;
|
||||||
|
import org.owasp.dependencycheck.dependency.Dependency;
|
||||||
|
import org.owasp.dependencycheck.dependency.Evidence;
|
||||||
|
import org.owasp.dependencycheck.xml.pom.PomUtils;
|
||||||
|
import org.slf4j.Logger;
|
||||||
|
import org.slf4j.LoggerFactory;
|
||||||
|
|
||||||
|
import java.io.File;
|
||||||
|
import java.io.FileFilter;
|
||||||
|
import java.io.FileNotFoundException;
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.net.MalformedURLException;
|
||||||
|
import java.net.URL;
|
||||||
|
import java.util.List;
|
||||||
|
import org.owasp.dependencycheck.exception.InitializationException;
|
||||||
|
import org.owasp.dependencycheck.utils.DownloadFailedException;
|
||||||
|
import org.owasp.dependencycheck.utils.Downloader;
|
||||||
|
import org.owasp.dependencycheck.utils.FileFilterBuilder;
|
||||||
|
import org.owasp.dependencycheck.utils.InvalidSettingException;
|
||||||
|
import org.owasp.dependencycheck.utils.Settings;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Analyzer which will attempt to locate a dependency, and the GAV information,
|
||||||
|
* by querying Central for the dependency's SHA-1 digest.
|
||||||
|
*
|
||||||
|
* @author colezlaw
|
||||||
|
*/
|
||||||
|
public class CentralAnalyzer extends AbstractFileTypeAnalyzer {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The logger.
|
||||||
|
*/
|
||||||
|
private static final Logger LOGGER = LoggerFactory.getLogger(CentralAnalyzer.class);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The name of the analyzer.
|
||||||
|
*/
|
||||||
|
private static final String ANALYZER_NAME = "Central Analyzer";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The phase in which this analyzer runs.
|
||||||
|
*/
|
||||||
|
private static final AnalysisPhase ANALYSIS_PHASE = AnalysisPhase.INFORMATION_COLLECTION;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The types of files on which this will work.
|
||||||
|
*/
|
||||||
|
private static final String SUPPORTED_EXTENSIONS = "jar";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The analyzer should be disabled if there are errors, so this is a flag to
|
||||||
|
* determine if such an error has occurred.
|
||||||
|
*/
|
||||||
|
private volatile boolean errorFlag = false;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The searcher itself.
|
||||||
|
*/
|
||||||
|
private CentralSearch searcher;
|
||||||
|
/**
|
||||||
|
* Field indicating if the analyzer is enabled.
|
||||||
|
*/
|
||||||
|
private final boolean enabled = checkEnabled();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Determine whether to enable this analyzer or not.
|
||||||
|
*
|
||||||
|
* @return whether the analyzer should be enabled
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
public boolean isEnabled() {
|
||||||
|
return enabled;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Determines if this analyzer is enabled.
|
||||||
|
*
|
||||||
|
* @return <code>true</code> if the analyzer is enabled; otherwise
|
||||||
|
* <code>false</code>
|
||||||
|
*/
|
||||||
|
private boolean checkEnabled() {
|
||||||
|
boolean retVal = false;
|
||||||
|
|
||||||
|
try {
|
||||||
|
if (Settings.getBoolean(Settings.KEYS.ANALYZER_CENTRAL_ENABLED)) {
|
||||||
|
if (!Settings.getBoolean(Settings.KEYS.ANALYZER_NEXUS_ENABLED)
|
||||||
|
|| NexusAnalyzer.DEFAULT_URL.equals(Settings.getString(Settings.KEYS.ANALYZER_NEXUS_URL))) {
|
||||||
|
LOGGER.debug("Enabling the Central analyzer");
|
||||||
|
retVal = true;
|
||||||
|
} else {
|
||||||
|
LOGGER.info("Nexus analyzer is enabled, disabling the Central Analyzer");
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
LOGGER.info("Central analyzer disabled");
|
||||||
|
}
|
||||||
|
} catch (InvalidSettingException ise) {
|
||||||
|
LOGGER.warn("Invalid setting. Disabling the Central analyzer");
|
||||||
|
}
|
||||||
|
return retVal;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Initializes the analyzer once before any analysis is performed.
|
||||||
|
*
|
||||||
|
* @throws InitializationException if there's an error during initialization
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
public void initializeFileTypeAnalyzer() throws InitializationException {
|
||||||
|
LOGGER.debug("Initializing Central analyzer");
|
||||||
|
LOGGER.debug("Central analyzer enabled: {}", isEnabled());
|
||||||
|
if (isEnabled()) {
|
||||||
|
final String searchUrl = Settings.getString(Settings.KEYS.ANALYZER_CENTRAL_URL);
|
||||||
|
LOGGER.debug("Central Analyzer URL: {}", searchUrl);
|
||||||
|
try {
|
||||||
|
searcher = new CentralSearch(new URL(searchUrl));
|
||||||
|
} catch (MalformedURLException ex) {
|
||||||
|
setEnabled(false);
|
||||||
|
throw new InitializationException("The configured URL to Maven Central is malformed: " + searchUrl, ex);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the analyzer's name.
|
||||||
|
*
|
||||||
|
* @return the name of the analyzer
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
public String getName() {
|
||||||
|
return ANALYZER_NAME;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the key used in the properties file to to reference the
|
||||||
|
* analyzer's enabled property.
|
||||||
|
*
|
||||||
|
* @return the analyzer's enabled property setting key.
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
protected String getAnalyzerEnabledSettingKey() {
|
||||||
|
return Settings.KEYS.ANALYZER_CENTRAL_ENABLED;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the analysis phase under which the analyzer runs.
|
||||||
|
*
|
||||||
|
* @return the phase under which the analyzer runs
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
public AnalysisPhase getAnalysisPhase() {
|
||||||
|
return ANALYSIS_PHASE;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The file filter used to determine which files this analyzer supports.
|
||||||
|
*/
|
||||||
|
private static final FileFilter FILTER = FileFilterBuilder.newInstance().addExtensions(SUPPORTED_EXTENSIONS).build();
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected FileFilter getFileFilter() {
|
||||||
|
return FILTER;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Performs the analysis.
|
||||||
|
*
|
||||||
|
* @param dependency the dependency to analyze
|
||||||
|
* @param engine the engine
|
||||||
|
* @throws AnalysisException when there's an exception during analysis
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
public void analyzeDependency(Dependency dependency, Engine engine) throws AnalysisException {
|
||||||
|
if (errorFlag || !isEnabled()) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
final List<MavenArtifact> mas = searcher.searchSha1(dependency.getSha1sum());
|
||||||
|
final Confidence confidence = mas.size() > 1 ? Confidence.HIGH : Confidence.HIGHEST;
|
||||||
|
for (MavenArtifact ma : mas) {
|
||||||
|
LOGGER.debug("Central analyzer found artifact ({}) for dependency ({})", ma, dependency.getFileName());
|
||||||
|
dependency.addAsEvidence("central", ma, confidence);
|
||||||
|
boolean pomAnalyzed = false;
|
||||||
|
for (Evidence e : dependency.getVendorEvidence()) {
|
||||||
|
if ("pom".equals(e.getSource())) {
|
||||||
|
pomAnalyzed = true;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (!pomAnalyzed && ma.getPomUrl() != null) {
|
||||||
|
File pomFile = null;
|
||||||
|
try {
|
||||||
|
final File baseDir = Settings.getTempDirectory();
|
||||||
|
pomFile = File.createTempFile("pom", ".xml", baseDir);
|
||||||
|
if (!pomFile.delete()) {
|
||||||
|
LOGGER.warn("Unable to fetch pom.xml for {} from Central; "
|
||||||
|
+ "this could result in undetected CPE/CVEs.", dependency.getFileName());
|
||||||
|
LOGGER.debug("Unable to delete temp file");
|
||||||
|
}
|
||||||
|
LOGGER.debug("Downloading {}", ma.getPomUrl());
|
||||||
|
Downloader.fetchFile(new URL(ma.getPomUrl()), pomFile);
|
||||||
|
PomUtils.analyzePOM(dependency, pomFile);
|
||||||
|
|
||||||
|
} catch (DownloadFailedException ex) {
|
||||||
|
LOGGER.warn("Unable to download pom.xml for {} from Central; "
|
||||||
|
+ "this could result in undetected CPE/CVEs.", dependency.getFileName());
|
||||||
|
} finally {
|
||||||
|
if (pomFile != null && pomFile.exists() && !FileUtils.deleteQuietly(pomFile)) {
|
||||||
|
LOGGER.debug("Failed to delete temporary pom file {}", pomFile.toString());
|
||||||
|
pomFile.deleteOnExit();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
} catch (IllegalArgumentException iae) {
|
||||||
|
LOGGER.info("invalid sha1-hash on {}", dependency.getFileName());
|
||||||
|
} catch (FileNotFoundException fnfe) {
|
||||||
|
LOGGER.debug("Artifact not found in repository: '{}", dependency.getFileName());
|
||||||
|
} catch (IOException ioe) {
|
||||||
|
LOGGER.debug("Could not connect to Central search", ioe);
|
||||||
|
errorFlag = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,205 @@
|
|||||||
|
/*
|
||||||
|
* 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 IBM Corporation. All Rights Reserved.
|
||||||
|
*/
|
||||||
|
package org.owasp.dependencycheck.analyzer;
|
||||||
|
|
||||||
|
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;
|
||||||
|
|
||||||
|
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;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This analyzer is used to analyze SWIFT and Objective-C packages by collecting
|
||||||
|
* information from .podspec files. CocoaPods dependency manager see
|
||||||
|
* https://cocoapods.org/.
|
||||||
|
*
|
||||||
|
* @author Bianca Jiang (https://twitter.com/biancajiang)
|
||||||
|
*/
|
||||||
|
@Experimental
|
||||||
|
public class CocoaPodsAnalyzer extends AbstractFileTypeAnalyzer {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The logger.
|
||||||
|
*/
|
||||||
|
// private static final Logger LOGGER = LoggerFactory.getLogger(CocoaPodsAnalyzer.class);
|
||||||
|
/**
|
||||||
|
* The name of the analyzer.
|
||||||
|
*/
|
||||||
|
private static final String ANALYZER_NAME = "CocoaPods 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 PODSPEC = "podspec";
|
||||||
|
/**
|
||||||
|
* Filter that detects files named "*.podspec".
|
||||||
|
*/
|
||||||
|
private static final FileFilter PODSPEC_FILTER = FileFilterBuilder.newInstance().addExtensions(PODSPEC).build();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The capture group #1 is the block variable. e.g. "Pod::Spec.new do
|
||||||
|
* |spec|"
|
||||||
|
*/
|
||||||
|
private static final Pattern PODSPEC_BLOCK_PATTERN = Pattern.compile("Pod::Spec\\.new\\s+?do\\s+?\\|(.+?)\\|");
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the FileFilter
|
||||||
|
*
|
||||||
|
* @return the FileFilter
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
protected FileFilter getFileFilter() {
|
||||||
|
return PODSPEC_FILTER;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void initializeFileTypeAnalyzer() {
|
||||||
|
// 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_COCOAPODS_ENABLED;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void analyzeDependency(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 = PODSPEC_BLOCK_PATTERN.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 EvidenceCollection version = dependency.getVersionEvidence();
|
||||||
|
|
||||||
|
final String name = addStringEvidence(product, contents, blockVariable, "name", "name", Confidence.HIGHEST);
|
||||||
|
if (!name.isEmpty()) {
|
||||||
|
vendor.addEvidence(PODSPEC, "name_project", name, Confidence.HIGHEST);
|
||||||
|
}
|
||||||
|
addStringEvidence(product, contents, blockVariable, "summary", "summary", Confidence.HIGHEST);
|
||||||
|
|
||||||
|
addStringEvidence(vendor, contents, blockVariable, "author", "authors?", Confidence.HIGHEST);
|
||||||
|
addStringEvidence(vendor, contents, blockVariable, "homepage", "homepage", Confidence.HIGHEST);
|
||||||
|
addStringEvidence(vendor, contents, blockVariable, "license", "licen[cs]es?", Confidence.HIGHEST);
|
||||||
|
|
||||||
|
addStringEvidence(version, contents, blockVariable, "version", "version", Confidence.HIGHEST);
|
||||||
|
}
|
||||||
|
|
||||||
|
setPackagePath(dependency);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Extracts evidence from the contents and adds it to the given evidence
|
||||||
|
* collection.
|
||||||
|
*
|
||||||
|
* @param evidences the evidence collection to update
|
||||||
|
* @param contents the text to extract evidence from
|
||||||
|
* @param blockVariable the block variable within the content to search for
|
||||||
|
* @param field the name of the field being searched for
|
||||||
|
* @param fieldPattern the field pattern within the contents to search for
|
||||||
|
* @param confidence the confidence level of the evidence if found
|
||||||
|
* @return the string that was added as evidence
|
||||||
|
*/
|
||||||
|
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*?\\{\\s*?(.*?)\\s*?\\}", blockVariable, fieldPattern),
|
||||||
|
Pattern.CASE_INSENSITIVE).matcher(contents);
|
||||||
|
if (arrayMatcher.find()) {
|
||||||
|
value = arrayMatcher.group(1);
|
||||||
|
} 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(PODSPEC, field, value, confidence);
|
||||||
|
}
|
||||||
|
return value;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets the package path on the given dependency.
|
||||||
|
*
|
||||||
|
* @param dep the dependency to update
|
||||||
|
*/
|
||||||
|
private void setPackagePath(Dependency dep) {
|
||||||
|
final File file = new File(dep.getFilePath());
|
||||||
|
final String parent = file.getParent();
|
||||||
|
if (parent != null) {
|
||||||
|
dep.setPackagePath(parent);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,171 @@
|
|||||||
|
/*
|
||||||
|
* This file is part of dependency-check-core.
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*
|
||||||
|
* Copyright (c) 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.exception.InitializationException;
|
||||||
|
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.IOException;
|
||||||
|
import java.nio.charset.Charset;
|
||||||
|
import java.security.MessageDigest;
|
||||||
|
import java.security.NoSuchAlgorithmException;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 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 InitializationException thrown if an exception occurs getting an
|
||||||
|
* instance of SHA1
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
protected void initializeFileTypeAnalyzer() throws InitializationException {
|
||||||
|
try {
|
||||||
|
getSha1MessageDigest();
|
||||||
|
} catch (IllegalStateException ex) {
|
||||||
|
setEnabled(false);
|
||||||
|
throw new InitializationException("Unable to create SHA1 MessageDigest", ex);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 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 analyzeDependency(Dependency dependency, Engine engine) throws AnalysisException {
|
||||||
|
try (FileInputStream 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());
|
||||||
|
final MessageDigest sha1 = getSha1MessageDigest();
|
||||||
|
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 (IOException ex) {
|
||||||
|
LOGGER.warn("Error opening dependency {}", dependency.getActualFilePath());
|
||||||
|
} catch (ComposerException ce) {
|
||||||
|
LOGGER.warn("Error parsing composer.json {}", dependency.getActualFilePath(), ce);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 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;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the sha1 message digest.
|
||||||
|
*
|
||||||
|
* @return the sha1 message digest
|
||||||
|
*/
|
||||||
|
private MessageDigest getSha1MessageDigest() {
|
||||||
|
try {
|
||||||
|
return MessageDigest.getInstance("SHA1");
|
||||||
|
} catch (NoSuchAlgorithmException e) {
|
||||||
|
LOGGER.error(e.getMessage());
|
||||||
|
throw new IllegalStateException("Failed to obtain the SHA1 message digest.", e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -20,13 +20,14 @@ package org.owasp.dependencycheck.analyzer;
|
|||||||
import org.owasp.dependencycheck.analyzer.exception.AnalysisException;
|
import org.owasp.dependencycheck.analyzer.exception.AnalysisException;
|
||||||
import org.owasp.dependencycheck.Engine;
|
import org.owasp.dependencycheck.Engine;
|
||||||
import org.owasp.dependencycheck.dependency.Dependency;
|
import org.owasp.dependencycheck.dependency.Dependency;
|
||||||
import org.owasp.dependencycheck.suppression.SuppressionRule;
|
import org.owasp.dependencycheck.utils.Settings;
|
||||||
|
import org.owasp.dependencycheck.xml.suppression.SuppressionRule;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The suppression analyzer processes an externally defined XML document that complies with the suppressions.xsd schema.
|
* The suppression analyzer processes an externally defined XML document that complies with the suppressions.xsd schema.
|
||||||
* Any identified CPE entries within the dependencies that match will be removed.
|
* Any identified CPE entries within the dependencies that match will be removed.
|
||||||
*
|
*
|
||||||
* @author Jeremy Long <jeremy.long@owasp.org>
|
* @author Jeremy Long
|
||||||
*/
|
*/
|
||||||
public class CpeSuppressionAnalyzer extends AbstractSuppressionAnalyzer {
|
public class CpeSuppressionAnalyzer extends AbstractSuppressionAnalyzer {
|
||||||
|
|
||||||
@@ -62,7 +63,7 @@ public class CpeSuppressionAnalyzer extends AbstractSuppressionAnalyzer {
|
|||||||
//</editor-fold>
|
//</editor-fold>
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void analyze(final Dependency dependency, final Engine engine) throws AnalysisException {
|
protected void analyzeDependency(Dependency dependency, Engine engine) throws AnalysisException {
|
||||||
|
|
||||||
if (getRules() == null || getRules().size() <= 0) {
|
if (getRules() == null || getRules().size() <= 0) {
|
||||||
return;
|
return;
|
||||||
@@ -72,4 +73,15 @@ public class CpeSuppressionAnalyzer extends AbstractSuppressionAnalyzer {
|
|||||||
rule.process(dependency);
|
rule.process(dependency);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* <p>
|
||||||
|
* Returns the setting key to determine if the analyzer is enabled.</p>
|
||||||
|
*
|
||||||
|
* @return the key for the analyzer's enabled property
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
protected String getAnalyzerEnabledSettingKey() {
|
||||||
|
return Settings.KEYS.ANALYZER_CPE_SUPPRESSION_ENABLED;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -22,8 +22,6 @@ import java.util.HashSet;
|
|||||||
import java.util.Iterator;
|
import java.util.Iterator;
|
||||||
import java.util.ListIterator;
|
import java.util.ListIterator;
|
||||||
import java.util.Set;
|
import java.util.Set;
|
||||||
import java.util.logging.Level;
|
|
||||||
import java.util.logging.Logger;
|
|
||||||
import java.util.regex.Matcher;
|
import java.util.regex.Matcher;
|
||||||
import java.util.regex.Pattern;
|
import java.util.regex.Pattern;
|
||||||
import org.owasp.dependencycheck.Engine;
|
import org.owasp.dependencycheck.Engine;
|
||||||
@@ -32,34 +30,52 @@ import org.owasp.dependencycheck.dependency.Dependency;
|
|||||||
import org.owasp.dependencycheck.dependency.Identifier;
|
import org.owasp.dependencycheck.dependency.Identifier;
|
||||||
import org.owasp.dependencycheck.utils.DependencyVersion;
|
import org.owasp.dependencycheck.utils.DependencyVersion;
|
||||||
import org.owasp.dependencycheck.utils.DependencyVersionUtil;
|
import org.owasp.dependencycheck.utils.DependencyVersionUtil;
|
||||||
import org.owasp.dependencycheck.utils.LogUtils;
|
import org.owasp.dependencycheck.utils.Settings;
|
||||||
|
import org.slf4j.Logger;
|
||||||
|
import org.slf4j.LoggerFactory;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* <p>
|
* <p>
|
||||||
* This analyzer ensures dependencies that should be grouped together, to remove excess noise from the report, are
|
* This analyzer ensures dependencies that should be grouped together, to remove
|
||||||
* grouped. An example would be Spring, Spring Beans, Spring MVC, etc. If they are all for the same version and have the
|
* excess noise from the report, are grouped. An example would be Spring, Spring
|
||||||
* same relative path then these should be grouped into a single dependency under the core/main library.</p>
|
* 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>
|
* <p>
|
||||||
* Note, this grouping only works on dependencies with identified CVE entries</p>
|
* Note, this grouping only works on dependencies with identified CVE
|
||||||
|
* entries</p>
|
||||||
*
|
*
|
||||||
* @author Jeremy Long <jeremy.long@owasp.org>
|
* @author Jeremy Long
|
||||||
*/
|
*/
|
||||||
public class DependencyBundlingAnalyzer extends AbstractAnalyzer implements Analyzer {
|
public class DependencyBundlingAnalyzer extends AbstractAnalyzer {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The Logger.
|
* The Logger.
|
||||||
*/
|
*/
|
||||||
private static final Logger LOGGER = Logger.getLogger(DependencyBundlingAnalyzer.class.getName());
|
private static final Logger LOGGER = LoggerFactory.getLogger(DependencyBundlingAnalyzer.class);
|
||||||
|
|
||||||
//<editor-fold defaultstate="collapsed" desc="Constants and Member Variables">
|
//<editor-fold defaultstate="collapsed" desc="Constants and Member Variables">
|
||||||
/**
|
/**
|
||||||
* A pattern for obtaining the first part of a filename.
|
* A pattern for obtaining the first part of a filename.
|
||||||
*/
|
*/
|
||||||
private static final Pattern STARTING_TEXT_PATTERN = Pattern.compile("^[a-zA-Z]*");
|
private static final Pattern STARTING_TEXT_PATTERN = Pattern.compile("^[a-zA-Z0-9]*");
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* a flag indicating if this analyzer has run. This analyzer only runs once.
|
* a flag indicating if this analyzer has run. This analyzer only runs once.
|
||||||
*/
|
*/
|
||||||
private boolean analyzed = false;
|
private boolean analyzed = false;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns a flag indicating if this analyzer has run. This analyzer only
|
||||||
|
* runs once. Note this is currently only used in the unit tests.
|
||||||
|
*
|
||||||
|
* @return a flag indicating if this analyzer has run. This analyzer only
|
||||||
|
* runs once
|
||||||
|
*/
|
||||||
|
protected synchronized boolean getAnalyzed() {
|
||||||
|
return analyzed;
|
||||||
|
}
|
||||||
|
|
||||||
//</editor-fold>
|
//</editor-fold>
|
||||||
//<editor-fold defaultstate="collapsed" desc="All standard implementation details of Analyzer">
|
//<editor-fold defaultstate="collapsed" desc="All standard implementation details of Analyzer">
|
||||||
/**
|
/**
|
||||||
@@ -69,13 +85,14 @@ public class DependencyBundlingAnalyzer extends AbstractAnalyzer implements Anal
|
|||||||
/**
|
/**
|
||||||
* The phase that this analyzer is intended to run in.
|
* The phase that this analyzer is intended to run in.
|
||||||
*/
|
*/
|
||||||
private static final AnalysisPhase ANALYSIS_PHASE = AnalysisPhase.PRE_FINDING_ANALYSIS;
|
private static final AnalysisPhase ANALYSIS_PHASE = AnalysisPhase.FINAL;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns the name of the analyzer.
|
* Returns the name of the analyzer.
|
||||||
*
|
*
|
||||||
* @return the name of the analyzer.
|
* @return the name of the analyzer.
|
||||||
*/
|
*/
|
||||||
|
@Override
|
||||||
public String getName() {
|
public String getName() {
|
||||||
return ANALYZER_NAME;
|
return ANALYZER_NAME;
|
||||||
}
|
}
|
||||||
@@ -85,52 +102,86 @@ public class DependencyBundlingAnalyzer extends AbstractAnalyzer implements Anal
|
|||||||
*
|
*
|
||||||
* @return 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() {
|
public AnalysisPhase getAnalysisPhase() {
|
||||||
return ANALYSIS_PHASE;
|
return ANALYSIS_PHASE;
|
||||||
}
|
}
|
||||||
//</editor-fold>
|
//</editor-fold>
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Analyzes a set of dependencies. If they have been found to have the same base path and the same set of
|
* Does not support parallel processing as it only runs once and then
|
||||||
* identifiers they are likely related. The related dependencies are bundled into a single reportable item.
|
* operates on <em>all</em> dependencies.
|
||||||
|
*
|
||||||
|
* @return whether or not parallel processing is enabled
|
||||||
|
* @see #analyze(Dependency, Engine)
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
public boolean supportsParallelProcessing() {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* <p>
|
||||||
|
* Returns the setting key to determine if the analyzer is enabled.</p>
|
||||||
|
*
|
||||||
|
* @return the key for the analyzer's enabled property
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
protected String getAnalyzerEnabledSettingKey() {
|
||||||
|
return Settings.KEYS.ANALYZER_DEPENDENCY_BUNDLING_ENABLED;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 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 ignore this analyzer ignores the dependency being analyzed
|
||||||
* @param engine the engine that is scanning the dependencies
|
* @param engine the engine that is scanning the dependencies
|
||||||
* @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
|
@Override
|
||||||
public void analyze(Dependency ignore, Engine engine) throws AnalysisException {
|
protected synchronized void analyzeDependency(Dependency ignore, Engine engine) throws AnalysisException {
|
||||||
if (!analyzed) {
|
if (!analyzed) {
|
||||||
analyzed = true;
|
analyzed = true;
|
||||||
final Set<Dependency> dependenciesToRemove = new HashSet<Dependency>();
|
final Set<Dependency> dependenciesToRemove = new HashSet<>();
|
||||||
final ListIterator<Dependency> mainIterator = engine.getDependencies().listIterator();
|
final ListIterator<Dependency> mainIterator = engine.getDependencies().listIterator();
|
||||||
//for (Dependency nextDependency : engine.getDependencies()) {
|
//for (Dependency nextDependency : engine.getDependencies()) {
|
||||||
while (mainIterator.hasNext()) {
|
while (mainIterator.hasNext()) {
|
||||||
final Dependency dependency = mainIterator.next();
|
final Dependency dependency = mainIterator.next();
|
||||||
if (mainIterator.hasNext()) {
|
if (mainIterator.hasNext() && !dependenciesToRemove.contains(dependency)) {
|
||||||
final ListIterator<Dependency> subIterator = engine.getDependencies().listIterator(mainIterator.nextIndex());
|
final ListIterator<Dependency> subIterator = engine.getDependencies().listIterator(mainIterator.nextIndex());
|
||||||
while (subIterator.hasNext()) {
|
while (subIterator.hasNext()) {
|
||||||
final Dependency nextDependency = subIterator.next();
|
final Dependency nextDependency = subIterator.next();
|
||||||
if (hashesMatch(dependency, nextDependency)) {
|
if (hashesMatch(dependency, nextDependency)) {
|
||||||
if (isCore(dependency, nextDependency)) {
|
if (!containedInWar(dependency.getFilePath())
|
||||||
mergeDependencies(dependency, nextDependency, dependenciesToRemove);
|
&& !containedInWar(nextDependency.getFilePath())) {
|
||||||
} else {
|
if (firstPathIsShortest(dependency.getFilePath(), nextDependency.getFilePath())) {
|
||||||
mergeDependencies(nextDependency, dependency, dependenciesToRemove);
|
mergeDependencies(dependency, nextDependency, dependenciesToRemove);
|
||||||
|
} else {
|
||||||
|
mergeDependencies(nextDependency, dependency, dependenciesToRemove);
|
||||||
|
break; //since we merged into the next dependency - skip forward to the next in mainIterator
|
||||||
|
}
|
||||||
}
|
}
|
||||||
} else if (isShadedJar(dependency, nextDependency)) {
|
} else if (isShadedJar(dependency, nextDependency)) {
|
||||||
if (dependency.getFileName().toLowerCase().endsWith("pom.xml")) {
|
if (dependency.getFileName().toLowerCase().endsWith("pom.xml")) {
|
||||||
dependenciesToRemove.add(dependency);
|
mergeDependencies(nextDependency, dependency, dependenciesToRemove);
|
||||||
|
nextDependency.getRelatedDependencies().remove(dependency);
|
||||||
|
break;
|
||||||
} else {
|
} else {
|
||||||
dependenciesToRemove.add(nextDependency);
|
mergeDependencies(dependency, nextDependency, dependenciesToRemove);
|
||||||
|
dependency.getRelatedDependencies().remove(nextDependency);
|
||||||
}
|
}
|
||||||
} else if (cpeIdentifiersMatch(dependency, nextDependency)
|
} else if (cpeIdentifiersMatch(dependency, nextDependency)
|
||||||
&& hasSameBasePath(dependency, nextDependency)
|
&& hasSameBasePath(dependency, nextDependency)
|
||||||
|
&& vulnCountMatches(dependency, nextDependency)
|
||||||
&& fileNameMatch(dependency, nextDependency)) {
|
&& fileNameMatch(dependency, nextDependency)) {
|
||||||
|
|
||||||
if (isCore(dependency, nextDependency)) {
|
if (isCore(dependency, nextDependency)) {
|
||||||
mergeDependencies(dependency, nextDependency, dependenciesToRemove);
|
mergeDependencies(dependency, nextDependency, dependenciesToRemove);
|
||||||
} else {
|
} else {
|
||||||
mergeDependencies(nextDependency, dependency, dependenciesToRemove);
|
mergeDependencies(nextDependency, dependency, dependenciesToRemove);
|
||||||
|
break; //since we merged into the next dependency - skip forward to the next in mainIterator
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -138,9 +189,7 @@ public class DependencyBundlingAnalyzer extends AbstractAnalyzer implements Anal
|
|||||||
}
|
}
|
||||||
//removing dependencies here as ensuring correctness and avoiding ConcurrentUpdateExceptions
|
//removing dependencies here as ensuring correctness and avoiding ConcurrentUpdateExceptions
|
||||||
// was difficult because of the inner iterator.
|
// was difficult because of the inner iterator.
|
||||||
for (Dependency d : dependenciesToRemove) {
|
engine.getDependencies().removeAll(dependenciesToRemove);
|
||||||
engine.getDependencies().remove(d);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -148,10 +197,11 @@ public class DependencyBundlingAnalyzer extends AbstractAnalyzer implements Anal
|
|||||||
* Adds the relatedDependency to the dependency's related dependencies.
|
* Adds the relatedDependency to the dependency's related dependencies.
|
||||||
*
|
*
|
||||||
* @param dependency the main dependency
|
* @param dependency the main dependency
|
||||||
* @param relatedDependency a collection of dependencies to be removed from the main analysis loop, this is the
|
* @param relatedDependency a collection of dependencies to be removed from
|
||||||
* source of dependencies to remove
|
* 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
|
* @param dependenciesToRemove a collection of dependencies that will be
|
||||||
* function adds to this collection
|
* 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) {
|
private void mergeDependencies(final Dependency dependency, final Dependency relatedDependency, final Set<Dependency> dependenciesToRemove) {
|
||||||
dependency.addRelatedDependency(relatedDependency);
|
dependency.addRelatedDependency(relatedDependency);
|
||||||
@@ -160,6 +210,9 @@ public class DependencyBundlingAnalyzer extends AbstractAnalyzer implements Anal
|
|||||||
dependency.addRelatedDependency(i.next());
|
dependency.addRelatedDependency(i.next());
|
||||||
i.remove();
|
i.remove();
|
||||||
}
|
}
|
||||||
|
if (dependency.getSha1sum().equals(relatedDependency.getSha1sum())) {
|
||||||
|
dependency.addAllProjectReferences(relatedDependency.getProjectReferences());
|
||||||
|
}
|
||||||
dependenciesToRemove.add(relatedDependency);
|
dependenciesToRemove.add(relatedDependency);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -171,7 +224,12 @@ public class DependencyBundlingAnalyzer extends AbstractAnalyzer implements Anal
|
|||||||
* @return a string representing the base path.
|
* @return a string representing the base path.
|
||||||
*/
|
*/
|
||||||
private String getBaseRepoPath(final String path) {
|
private String getBaseRepoPath(final String path) {
|
||||||
int pos = path.indexOf("repository" + File.separator) + 11;
|
int pos;
|
||||||
|
if (path.contains("local-repo")) {
|
||||||
|
pos = path.indexOf("local-repo" + File.separator) + 11;
|
||||||
|
} else {
|
||||||
|
pos = path.indexOf("repository" + File.separator) + 11;
|
||||||
|
}
|
||||||
if (pos < 0) {
|
if (pos < 0) {
|
||||||
return path;
|
return path;
|
||||||
}
|
}
|
||||||
@@ -190,44 +248,27 @@ 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 dependency1 a dependency2 to compare
|
||||||
* @param dependency2 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) {
|
private boolean fileNameMatch(Dependency dependency1, Dependency dependency2) {
|
||||||
if (dependency1 == null || dependency1.getFileName() == null
|
if (dependency1 == null || dependency1.getFileName() == null
|
||||||
|| dependency2 == null || dependency2.getFileName() == null) {
|
|| dependency2 == null || dependency2.getFileName() == null) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
String fileName1 = dependency1.getFileName();
|
final String fileName1 = dependency1.getActualFile().getName();
|
||||||
String fileName2 = dependency2.getFileName();
|
final String fileName2 = dependency2.getActualFile().getName();
|
||||||
|
|
||||||
//update to deal with archive analyzer, the starting name maybe the same
|
|
||||||
// as this is incorrectly looking at the starting path
|
|
||||||
final File one = new File(fileName1);
|
|
||||||
final File two = new File(fileName2);
|
|
||||||
final String oneParent = one.getParent();
|
|
||||||
final String twoParent = two.getParent();
|
|
||||||
if (oneParent != null) {
|
|
||||||
if (oneParent.equals(twoParent)) {
|
|
||||||
fileName1 = one.getName();
|
|
||||||
fileName2 = two.getName();
|
|
||||||
} else {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
} else if (twoParent != null) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
//version check
|
//version check
|
||||||
final DependencyVersion version1 = DependencyVersionUtil.parseVersion(fileName1);
|
final DependencyVersion version1 = DependencyVersionUtil.parseVersion(fileName1);
|
||||||
final DependencyVersion version2 = DependencyVersionUtil.parseVersion(fileName2);
|
final DependencyVersion version2 = DependencyVersionUtil.parseVersion(fileName2);
|
||||||
if (version1 != null && version2 != null) {
|
if (version1 != null && version2 != null && !version1.equals(version2)) {
|
||||||
if (!version1.equals(version2)) {
|
return false;
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
//filename check
|
//filename check
|
||||||
@@ -241,11 +282,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 dependency1 a dependency2 to compare
|
||||||
* @param dependency2 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) {
|
private boolean cpeIdentifiersMatch(Dependency dependency1, Dependency dependency2) {
|
||||||
if (dependency1 == null || dependency1.getIdentifiers() == null
|
if (dependency1 == null || dependency1.getIdentifiers() == null
|
||||||
@@ -267,19 +310,31 @@ public class DependencyBundlingAnalyzer extends AbstractAnalyzer implements Anal
|
|||||||
}
|
}
|
||||||
if (cpeCount1 > 0 && cpeCount1 == cpeCount2) {
|
if (cpeCount1 > 0 && cpeCount1 == cpeCount2) {
|
||||||
for (Identifier i : dependency1.getIdentifiers()) {
|
for (Identifier i : dependency1.getIdentifiers()) {
|
||||||
matches |= dependency2.getIdentifiers().contains(i);
|
if ("cpe".equals(i.getType())) {
|
||||||
if (!matches) {
|
matches |= dependency2.getIdentifiers().contains(i);
|
||||||
break;
|
if (!matches) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (LogUtils.isVerboseLoggingEnabled()) {
|
LOGGER.debug("IdentifiersMatch={} ({}, {})", matches, dependency1.getFileName(), dependency2.getFileName());
|
||||||
final String msg = String.format("IdentifiersMatch=%s (%s, %s)", matches, dependency1.getFileName(), dependency2.getFileName());
|
|
||||||
LOGGER.log(Level.FINE, msg);
|
|
||||||
}
|
|
||||||
return matches;
|
return matches;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns true if the two dependencies have the same vulnerability count.
|
||||||
|
*
|
||||||
|
* @param dependency1 a dependency2 to compare
|
||||||
|
* @param dependency2 a dependency2 to compare
|
||||||
|
* @return true if the two dependencies have the same vulnerability count
|
||||||
|
*/
|
||||||
|
private boolean vulnCountMatches(Dependency dependency1, Dependency dependency2) {
|
||||||
|
return dependency1.getVulnerabilities() != null && dependency2.getVulnerabilities() != null
|
||||||
|
&& dependency1.getVulnerabilities().size() == dependency2.getVulnerabilities().size();
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Determines if the two dependencies have the same base path.
|
* Determines if the two dependencies have the same base path.
|
||||||
*
|
*
|
||||||
@@ -297,11 +352,14 @@ public class DependencyBundlingAnalyzer extends AbstractAnalyzer implements Anal
|
|||||||
String right = rFile.getParent();
|
String right = rFile.getParent();
|
||||||
if (left == null) {
|
if (left == null) {
|
||||||
return right == null;
|
return right == null;
|
||||||
|
} else if (right == null) {
|
||||||
|
return false;
|
||||||
}
|
}
|
||||||
if (left.equalsIgnoreCase(right)) {
|
if (left.equalsIgnoreCase(right)) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
if (left.matches(".*[/\\\\]repository[/\\\\].*") && right.matches(".*[/\\\\]repository[/\\\\].*")) {
|
|
||||||
|
if (left.matches(".*[/\\\\](repository|local-repo)[/\\\\].*") && right.matches(".*[/\\\\](repository|local-repo)[/\\\\].*")) {
|
||||||
left = getBaseRepoPath(left);
|
left = getBaseRepoPath(left);
|
||||||
right = getBaseRepoPath(right);
|
right = getBaseRepoPath(right);
|
||||||
}
|
}
|
||||||
@@ -318,14 +376,15 @@ public class DependencyBundlingAnalyzer extends AbstractAnalyzer implements Anal
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* This is likely a very broken attempt at determining if the 'left' dependency is the 'core' library in comparison
|
* This is likely a very broken attempt at determining if the 'left'
|
||||||
* to the 'right' library.
|
* dependency is the 'core' library in comparison to the 'right' library.
|
||||||
*
|
*
|
||||||
* @param left the dependency to test
|
* @param left the dependency to test
|
||||||
* @param right the dependency to test against
|
* @param right the dependency to test against
|
||||||
* @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) {
|
protected boolean isCore(Dependency left, Dependency right) {
|
||||||
final String leftName = left.getFileName().toLowerCase();
|
final String leftName = left.getFileName().toLowerCase();
|
||||||
final String rightName = right.getFileName().toLowerCase();
|
final String rightName = right.getFileName().toLowerCase();
|
||||||
|
|
||||||
@@ -350,19 +409,18 @@ public class DependencyBundlingAnalyzer extends AbstractAnalyzer implements Anal
|
|||||||
*/
|
*/
|
||||||
returnVal = leftName.length() <= rightName.length();
|
returnVal = leftName.length() <= rightName.length();
|
||||||
}
|
}
|
||||||
if (LogUtils.isVerboseLoggingEnabled()) {
|
LOGGER.debug("IsCore={} ({}, {})", returnVal, left.getFileName(), right.getFileName());
|
||||||
final String msg = String.format("IsCore=%s (%s, %s)", returnVal, left.getFileName(), right.getFileName());
|
|
||||||
LOGGER.log(Level.FINE, msg);
|
|
||||||
}
|
|
||||||
return returnVal;
|
return returnVal;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 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 dependency1 a dependency object to compare
|
||||||
* @param dependency2 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) {
|
private boolean hashesMatch(Dependency dependency1, Dependency dependency2) {
|
||||||
if (dependency1 == null || dependency2 == null || dependency1.getSha1sum() == null || dependency2.getSha1sum() == null) {
|
if (dependency1 == null || dependency2 == null || dependency1.getSha1sum() == null || dependency2.getSha1sum() == null) {
|
||||||
@@ -372,13 +430,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
|
* Determines if the jar is shaded and the created pom.xml identified the
|
||||||
* dependency should be removed.
|
* same CPE as the jar - if so, the pom.xml dependency should be removed.
|
||||||
*
|
*
|
||||||
* @param dependency a dependency to check
|
* @param dependency a dependency to check
|
||||||
* @param nextDependency another dependency to check
|
* @param nextDependency another dependency to check
|
||||||
* @return true if on of the dependencies is a pom.xml and the identifiers between the two collections match;
|
* @return true if on of the dependencies is a pom.xml and the identifiers
|
||||||
* otherwise false
|
* between the two collections match; otherwise false
|
||||||
*/
|
*/
|
||||||
private boolean isShadedJar(Dependency dependency, Dependency nextDependency) {
|
private boolean isShadedJar(Dependency dependency, Dependency nextDependency) {
|
||||||
final String mainName = dependency.getFileName().toLowerCase();
|
final String mainName = dependency.getFileName().toLowerCase();
|
||||||
@@ -390,4 +448,58 @@ public class DependencyBundlingAnalyzer extends AbstractAnalyzer implements Anal
|
|||||||
}
|
}
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Determines which path is shortest; if path lengths are equal then we use
|
||||||
|
* compareTo of the string method to determine if the first path is smaller.
|
||||||
|
*
|
||||||
|
* @param left the first path to compare
|
||||||
|
* @param right the second path to compare
|
||||||
|
* @return <code>true</code> if the leftPath is the shortest; otherwise
|
||||||
|
* <code>false</code>
|
||||||
|
*/
|
||||||
|
protected boolean firstPathIsShortest(String left, String right) {
|
||||||
|
if (left.contains("dctemp")) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
final String leftPath = left.replace('\\', '/');
|
||||||
|
final String rightPath = right.replace('\\', '/');
|
||||||
|
|
||||||
|
final int leftCount = countChar(leftPath, '/');
|
||||||
|
final int rightCount = countChar(rightPath, '/');
|
||||||
|
if (leftCount == rightCount) {
|
||||||
|
return leftPath.compareTo(rightPath) <= 0;
|
||||||
|
} else {
|
||||||
|
return leftCount < rightCount;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Counts the number of times the character is present in the string.
|
||||||
|
*
|
||||||
|
* @param string the string to count the characters in
|
||||||
|
* @param c the character to count
|
||||||
|
* @return the number of times the character is present in the string
|
||||||
|
*/
|
||||||
|
private int countChar(String string, char c) {
|
||||||
|
int count = 0;
|
||||||
|
final int max = string.length();
|
||||||
|
for (int i = 0; i < max; i++) {
|
||||||
|
if (c == string.charAt(i)) {
|
||||||
|
count++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return count;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Checks if the given file path is contained within a war or ear file.
|
||||||
|
*
|
||||||
|
* @param filePath the file path to check
|
||||||
|
* @return true if the path contains '.war\' or '.ear\'.
|
||||||
|
*/
|
||||||
|
private boolean containedInWar(String filePath) {
|
||||||
|
return filePath != null && filePath.matches(".*\\.(ear|war)[\\\\/].*");
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,283 @@
|
|||||||
|
/*
|
||||||
|
* This file is part of dependency-check-core.
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*
|
||||||
|
* Copyright (c) 2012 Jeremy Long. All Rights Reserved.
|
||||||
|
*/
|
||||||
|
package org.owasp.dependencycheck.analyzer;
|
||||||
|
|
||||||
|
import java.io.File;
|
||||||
|
import java.util.HashSet;
|
||||||
|
import java.util.Iterator;
|
||||||
|
import java.util.ListIterator;
|
||||||
|
import java.util.Set;
|
||||||
|
import org.owasp.dependencycheck.Engine;
|
||||||
|
import org.owasp.dependencycheck.analyzer.exception.AnalysisException;
|
||||||
|
import org.owasp.dependencycheck.dependency.Dependency;
|
||||||
|
import org.owasp.dependencycheck.utils.Settings;
|
||||||
|
import org.slf4j.Logger;
|
||||||
|
import org.slf4j.LoggerFactory;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* <p>
|
||||||
|
* This analyzer will merge dependencies, created from different source, into a
|
||||||
|
* single dependency.</p>
|
||||||
|
*
|
||||||
|
* @author Jeremy Long
|
||||||
|
*/
|
||||||
|
public class DependencyMergingAnalyzer extends AbstractAnalyzer {
|
||||||
|
|
||||||
|
//<editor-fold defaultstate="collapsed" desc="Constants and Member Variables">
|
||||||
|
/**
|
||||||
|
* The Logger.
|
||||||
|
*/
|
||||||
|
private static final Logger LOGGER = LoggerFactory.getLogger(DependencyMergingAnalyzer.class);
|
||||||
|
/**
|
||||||
|
* a flag indicating if this analyzer has run. This analyzer only runs once.
|
||||||
|
*/
|
||||||
|
private boolean analyzed = false;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns a flag indicating if this analyzer has run. This analyzer only
|
||||||
|
* runs once. Note this is currently only used in the unit tests.
|
||||||
|
*
|
||||||
|
* @return a flag indicating if this analyzer has run. This analyzer only
|
||||||
|
* runs once
|
||||||
|
*/
|
||||||
|
protected synchronized boolean getAnalyzed() {
|
||||||
|
return analyzed;
|
||||||
|
}
|
||||||
|
|
||||||
|
//</editor-fold>
|
||||||
|
//<editor-fold defaultstate="collapsed" desc="All standard implementation details of Analyzer">
|
||||||
|
/**
|
||||||
|
* The name of the analyzer.
|
||||||
|
*/
|
||||||
|
private static final String ANALYZER_NAME = "Dependency Merging Analyzer";
|
||||||
|
/**
|
||||||
|
* The phase that this analyzer is intended to run in.
|
||||||
|
*/
|
||||||
|
private static final AnalysisPhase ANALYSIS_PHASE = AnalysisPhase.POST_INFORMATION_COLLECTION;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 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;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Does not support parallel processing as it only runs once and then
|
||||||
|
* operates on <em>all</em> dependencies.
|
||||||
|
*
|
||||||
|
* @return whether or not parallel processing is enabled
|
||||||
|
* @see #analyze(Dependency, Engine)
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
public boolean supportsParallelProcessing() {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* <p>
|
||||||
|
* Returns the setting key to determine if the analyzer is enabled.</p>
|
||||||
|
*
|
||||||
|
* @return the key for the analyzer's enabled property
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
protected String getAnalyzerEnabledSettingKey() {
|
||||||
|
return Settings.KEYS.ANALYZER_DEPENDENCY_MERGING_ENABLED;
|
||||||
|
}
|
||||||
|
//</editor-fold>
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Analyzes a set of dependencies. If they have been found to be the same
|
||||||
|
* dependency created by more multiple FileTypeAnalyzers (i.e. a gemspec
|
||||||
|
* dependency and a dependency from the Bundle Audit Analyzer. The
|
||||||
|
* dependencies are then merged 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.
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
protected synchronized void analyzeDependency(Dependency ignore, Engine engine) throws AnalysisException {
|
||||||
|
if (!analyzed) {
|
||||||
|
analyzed = true;
|
||||||
|
final Set<Dependency> dependenciesToRemove = new HashSet<>();
|
||||||
|
final ListIterator<Dependency> mainIterator = engine.getDependencies().listIterator();
|
||||||
|
//for (Dependency nextDependency : engine.getDependencies()) {
|
||||||
|
while (mainIterator.hasNext()) {
|
||||||
|
final Dependency dependency = mainIterator.next();
|
||||||
|
if (mainIterator.hasNext() && !dependenciesToRemove.contains(dependency)) {
|
||||||
|
final ListIterator<Dependency> subIterator = engine.getDependencies().listIterator(mainIterator.nextIndex());
|
||||||
|
while (subIterator.hasNext()) {
|
||||||
|
final Dependency nextDependency = subIterator.next();
|
||||||
|
Dependency main;
|
||||||
|
if ((main = getMainGemspecDependency(dependency, nextDependency)) != null) {
|
||||||
|
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
|
||||||
|
}
|
||||||
|
} else if ((main = getMainSwiftDependency(dependency, nextDependency)) != null) {
|
||||||
|
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
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
//removing dependencies here as ensuring correctness and avoiding ConcurrentUpdateExceptions
|
||||||
|
// was difficult because of the inner iterator.
|
||||||
|
engine.getDependencies().removeAll(dependenciesToRemove);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 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
|
||||||
|
*/
|
||||||
|
private void mergeDependencies(final Dependency dependency, final Dependency relatedDependency, final Set<Dependency> dependenciesToRemove) {
|
||||||
|
LOGGER.debug("Merging '{}' into '{}'", relatedDependency.getFilePath(), dependency.getFilePath());
|
||||||
|
dependency.addRelatedDependency(relatedDependency);
|
||||||
|
dependency.getVendorEvidence().getEvidence().addAll(relatedDependency.getVendorEvidence().getEvidence());
|
||||||
|
dependency.getProductEvidence().getEvidence().addAll(relatedDependency.getProductEvidence().getEvidence());
|
||||||
|
dependency.getVersionEvidence().getEvidence().addAll(relatedDependency.getVersionEvidence().getEvidence());
|
||||||
|
|
||||||
|
final Iterator<Dependency> i = relatedDependency.getRelatedDependencies().iterator();
|
||||||
|
while (i.hasNext()) {
|
||||||
|
dependency.addRelatedDependency(i.next());
|
||||||
|
i.remove();
|
||||||
|
}
|
||||||
|
if (dependency.getSha1sum().equals(relatedDependency.getSha1sum())) {
|
||||||
|
dependency.addAllProjectReferences(relatedDependency.getProjectReferences());
|
||||||
|
}
|
||||||
|
dependenciesToRemove.add(relatedDependency);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 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;
|
||||||
|
}
|
||||||
|
return dependency1.getPackagePath().equalsIgnoreCase(dependency2.getPackagePath());
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 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;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Bundling same swift dependencies with the same packagePath but identified
|
||||||
|
* by different file type analyzers.
|
||||||
|
*
|
||||||
|
* @param dependency1 dependency to test
|
||||||
|
* @param dependency2 dependency to test
|
||||||
|
* @return <code>true</code> if the dependencies appear to be the same;
|
||||||
|
* otherwise <code>false</code>
|
||||||
|
*/
|
||||||
|
private boolean isSameSwiftPackage(Dependency dependency1, Dependency dependency2) {
|
||||||
|
if (dependency1 == null || dependency2 == null
|
||||||
|
|| (!dependency1.getFileName().endsWith(".podspec")
|
||||||
|
&& !dependency1.getFileName().equals("Package.swift"))
|
||||||
|
|| (!dependency2.getFileName().endsWith(".podspec")
|
||||||
|
&& !dependency2.getFileName().equals("Package.swift"))
|
||||||
|
|| dependency1.getPackagePath() == null
|
||||||
|
|| dependency2.getPackagePath() == null) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return dependency1.getPackagePath().equalsIgnoreCase(dependency2.getPackagePath());
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Determines which of the swift dependencies should be considered the
|
||||||
|
* primary.
|
||||||
|
*
|
||||||
|
* @param dependency1 the first swift dependency to compare
|
||||||
|
* @param dependency2 the second swift dependency to compare
|
||||||
|
* @return the primary swift dependency
|
||||||
|
*/
|
||||||
|
private Dependency getMainSwiftDependency(Dependency dependency1, Dependency dependency2) {
|
||||||
|
if (isSameSwiftPackage(dependency1, dependency2)) {
|
||||||
|
if (dependency1.getFileName().endsWith(".podspec")) {
|
||||||
|
return dependency1;
|
||||||
|
}
|
||||||
|
return dependency2;
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -13,25 +13,22 @@
|
|||||||
* See the License for the specific language governing permissions and
|
* See the License for the specific language governing permissions and
|
||||||
* limitations under the License.
|
* limitations under the License.
|
||||||
*
|
*
|
||||||
* Copyright (c) 2012 Jeremy Long. All Rights Reserved.
|
* Copyright (c) 2016 Jeremy Long. All Rights Reserved.
|
||||||
*/
|
*/
|
||||||
package org.owasp.dependencycheck.data.cpe;
|
package org.owasp.dependencycheck.analyzer;
|
||||||
|
|
||||||
import org.junit.Before;
|
import java.lang.annotation.ElementType;
|
||||||
import org.owasp.dependencycheck.BaseTest;
|
import java.lang.annotation.Retention;
|
||||||
import org.owasp.dependencycheck.data.nvdcve.BaseDBTestCase;
|
import java.lang.annotation.RetentionPolicy;
|
||||||
|
import java.lang.annotation.Target;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* An abstract database test case that is used to ensure the H2 DB exists prior to performing tests that utilize the
|
* Annotation used to flag an analyzer as experimental.
|
||||||
* data contained within.
|
|
||||||
*
|
*
|
||||||
* @author Jeremy Long <jeremy.long@owasp.org>
|
* @author jeremy long
|
||||||
*/
|
*/
|
||||||
public abstract class AbstractDatabaseTestCase extends BaseTest {
|
@Retention(RetentionPolicy.RUNTIME)
|
||||||
|
@Target(ElementType.TYPE)
|
||||||
@Before
|
public @interface Experimental {
|
||||||
public void setUp() throws Exception {
|
|
||||||
BaseDBTestCase.ensureDBExists();
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
}
|
||||||
@@ -17,6 +17,7 @@
|
|||||||
*/
|
*/
|
||||||
package org.owasp.dependencycheck.analyzer;
|
package org.owasp.dependencycheck.analyzer;
|
||||||
|
|
||||||
|
import java.io.FileFilter;
|
||||||
import java.io.UnsupportedEncodingException;
|
import java.io.UnsupportedEncodingException;
|
||||||
import java.net.URLEncoder;
|
import java.net.URLEncoder;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
@@ -25,8 +26,6 @@ import java.util.Iterator;
|
|||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.ListIterator;
|
import java.util.ListIterator;
|
||||||
import java.util.Set;
|
import java.util.Set;
|
||||||
import java.util.logging.Level;
|
|
||||||
import java.util.logging.Logger;
|
|
||||||
import java.util.regex.Matcher;
|
import java.util.regex.Matcher;
|
||||||
import java.util.regex.Pattern;
|
import java.util.regex.Pattern;
|
||||||
import org.owasp.dependencycheck.Engine;
|
import org.owasp.dependencycheck.Engine;
|
||||||
@@ -34,18 +33,29 @@ import org.owasp.dependencycheck.analyzer.exception.AnalysisException;
|
|||||||
import org.owasp.dependencycheck.dependency.Dependency;
|
import org.owasp.dependencycheck.dependency.Dependency;
|
||||||
import org.owasp.dependencycheck.dependency.Identifier;
|
import org.owasp.dependencycheck.dependency.Identifier;
|
||||||
import org.owasp.dependencycheck.dependency.VulnerableSoftware;
|
import org.owasp.dependencycheck.dependency.VulnerableSoftware;
|
||||||
|
import org.owasp.dependencycheck.utils.FileFilterBuilder;
|
||||||
|
import org.owasp.dependencycheck.utils.Settings;
|
||||||
|
import org.slf4j.Logger;
|
||||||
|
import org.slf4j.LoggerFactory;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* This analyzer attempts to remove some well known false positives - specifically regarding the java runtime.
|
* This analyzer attempts to remove some well known false positives -
|
||||||
|
* specifically regarding the java runtime.
|
||||||
*
|
*
|
||||||
* @author Jeremy Long <jeremy.long@owasp.org>
|
* @author Jeremy Long
|
||||||
*/
|
*/
|
||||||
public class FalsePositiveAnalyzer extends AbstractAnalyzer {
|
public class FalsePositiveAnalyzer extends AbstractAnalyzer {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The Logger.
|
* The Logger.
|
||||||
*/
|
*/
|
||||||
private static final Logger LOGGER = Logger.getLogger(FalsePositiveAnalyzer.class.getName());
|
private static final Logger LOGGER = LoggerFactory.getLogger(FalsePositiveAnalyzer.class);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The file filter used to find DLL and EXE.
|
||||||
|
*/
|
||||||
|
private static final FileFilter DLL_EXE_FILTER = FileFilterBuilder.newInstance().addExtensions("dll", "exe").build();
|
||||||
|
|
||||||
//<editor-fold defaultstate="collapsed" desc="All standard implementation details of Analyzer">
|
//<editor-fold defaultstate="collapsed" desc="All standard implementation details of Analyzer">
|
||||||
/**
|
/**
|
||||||
* The name of the analyzer.
|
* The name of the analyzer.
|
||||||
@@ -61,6 +71,7 @@ public class FalsePositiveAnalyzer extends AbstractAnalyzer {
|
|||||||
*
|
*
|
||||||
* @return the name of the analyzer.
|
* @return the name of the analyzer.
|
||||||
*/
|
*/
|
||||||
|
@Override
|
||||||
public String getName() {
|
public String getName() {
|
||||||
return ANALYZER_NAME;
|
return ANALYZER_NAME;
|
||||||
}
|
}
|
||||||
@@ -70,31 +81,81 @@ public class FalsePositiveAnalyzer extends AbstractAnalyzer {
|
|||||||
*
|
*
|
||||||
* @return 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() {
|
public AnalysisPhase getAnalysisPhase() {
|
||||||
return ANALYSIS_PHASE;
|
return ANALYSIS_PHASE;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* <p>
|
||||||
|
* Returns the setting key to determine if the analyzer is enabled.</p>
|
||||||
|
*
|
||||||
|
* @return the key for the analyzer's enabled property
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
protected String getAnalyzerEnabledSettingKey() {
|
||||||
|
return Settings.KEYS.ANALYZER_FALSE_POSITIVE_ENABLED;
|
||||||
|
}
|
||||||
//</editor-fold>
|
//</editor-fold>
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Analyzes the dependencies and removes bad/incorrect CPE associations based on various heuristics.
|
* Analyzes the dependencies and removes bad/incorrect CPE associations
|
||||||
|
* based on various heuristics.
|
||||||
*
|
*
|
||||||
* @param dependency the dependency to analyze.
|
* @param dependency the dependency to analyze.
|
||||||
* @param engine the engine that is scanning the dependencies
|
* @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
|
@Override
|
||||||
public void analyze(Dependency dependency, Engine engine) throws AnalysisException {
|
protected void analyzeDependency(Dependency dependency, Engine engine) throws AnalysisException {
|
||||||
removeJreEntries(dependency);
|
removeJreEntries(dependency);
|
||||||
removeBadMatches(dependency);
|
removeBadMatches(dependency);
|
||||||
|
removeBadSpringMatches(dependency);
|
||||||
removeWrongVersionMatches(dependency);
|
removeWrongVersionMatches(dependency);
|
||||||
removeSpuriousCPE(dependency);
|
removeSpuriousCPE(dependency);
|
||||||
removeDuplicativeEntriesFromJar(dependency, engine);
|
removeDuplicativeEntriesFromJar(dependency, engine);
|
||||||
addFalseNegativeCPEs(dependency);
|
addFalseNegativeCPEs(dependency);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Removes inaccurate matches on springframework CPEs.
|
||||||
|
*
|
||||||
|
* @param dependency the dependency to test for and remove known inaccurate
|
||||||
|
* CPE matches
|
||||||
|
*/
|
||||||
|
private void removeBadSpringMatches(Dependency dependency) {
|
||||||
|
String mustContain = null;
|
||||||
|
for (Identifier i : dependency.getIdentifiers()) {
|
||||||
|
if ("maven".contains(i.getType())
|
||||||
|
&& i.getValue() != null && i.getValue().startsWith("org.springframework.")) {
|
||||||
|
final int endPoint = i.getValue().indexOf(':', 19);
|
||||||
|
if (endPoint >= 0) {
|
||||||
|
mustContain = i.getValue().substring(19, endPoint).toLowerCase();
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (mustContain
|
||||||
|
!= null) {
|
||||||
|
final Iterator<Identifier> itr = dependency.getIdentifiers().iterator();
|
||||||
|
while (itr.hasNext()) {
|
||||||
|
final Identifier i = itr.next();
|
||||||
|
if ("cpe".contains(i.getType())
|
||||||
|
&& i.getValue() != null
|
||||||
|
&& i.getValue().startsWith("cpe:/a:springsource:")
|
||||||
|
&& !i.getValue().toLowerCase().contains(mustContain)) {
|
||||||
|
itr.remove();
|
||||||
|
//dependency.getIdentifiers().remove(i);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* <p>
|
* <p>
|
||||||
* Intended to remove spurious CPE entries. By spurious we mean duplicate, less specific CPE entries.</p>
|
* Intended to remove spurious CPE entries. By spurious we mean duplicate,
|
||||||
|
* less specific CPE entries.</p>
|
||||||
* <p>
|
* <p>
|
||||||
* Example:</p>
|
* Example:</p>
|
||||||
* <code>
|
* <code>
|
||||||
@@ -112,8 +173,7 @@ public class FalsePositiveAnalyzer extends AbstractAnalyzer {
|
|||||||
*/
|
*/
|
||||||
@SuppressWarnings("null")
|
@SuppressWarnings("null")
|
||||||
private void removeSpuriousCPE(Dependency dependency) {
|
private void removeSpuriousCPE(Dependency dependency) {
|
||||||
final List<Identifier> ids = new ArrayList<Identifier>();
|
final List<Identifier> ids = new ArrayList<>(dependency.getIdentifiers());
|
||||||
ids.addAll(dependency.getIdentifiers());
|
|
||||||
Collections.sort(ids);
|
Collections.sort(ids);
|
||||||
final ListIterator<Identifier> mainItr = ids.listIterator();
|
final ListIterator<Identifier> mainItr = ids.listIterator();
|
||||||
while (mainItr.hasNext()) {
|
while (mainItr.hasNext()) {
|
||||||
@@ -137,7 +197,7 @@ public class FalsePositiveAnalyzer extends AbstractAnalyzer {
|
|||||||
final String nextVersion = nextCpe.getVersion();
|
final String nextVersion = nextCpe.getVersion();
|
||||||
if (currentVersion == null && nextVersion == null) {
|
if (currentVersion == null && nextVersion == null) {
|
||||||
//how did we get here?
|
//how did we get here?
|
||||||
LOGGER.log(Level.FINE, "currentVersion and nextVersion are both null?");
|
LOGGER.debug("currentVersion and nextVersion are both null?");
|
||||||
} else if (currentVersion == null && nextVersion != null) {
|
} else if (currentVersion == null && nextVersion != null) {
|
||||||
dependency.getIdentifiers().remove(currentId);
|
dependency.getIdentifiers().remove(currentId);
|
||||||
} else if (nextVersion == null && currentVersion != null) {
|
} else if (nextVersion == null && currentVersion != null) {
|
||||||
@@ -146,10 +206,8 @@ public class FalsePositiveAnalyzer extends AbstractAnalyzer {
|
|||||||
if (nextVersion.startsWith(currentVersion) || "-".equals(currentVersion)) {
|
if (nextVersion.startsWith(currentVersion) || "-".equals(currentVersion)) {
|
||||||
dependency.getIdentifiers().remove(currentId);
|
dependency.getIdentifiers().remove(currentId);
|
||||||
}
|
}
|
||||||
} else {
|
} else if (currentVersion.startsWith(nextVersion) || "-".equals(nextVersion)) {
|
||||||
if (currentVersion.startsWith(nextVersion) || "-".equals(nextVersion)) {
|
dependency.getIdentifiers().remove(nextId);
|
||||||
dependency.getIdentifiers().remove(nextId);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -157,7 +215,8 @@ public class FalsePositiveAnalyzer extends AbstractAnalyzer {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
/**
|
/**
|
||||||
* Regex to identify core java libraries and a few other commonly misidentified ones.
|
* Regex to identify core java libraries and a few other commonly
|
||||||
|
* misidentified ones.
|
||||||
*/
|
*/
|
||||||
public static final Pattern CORE_JAVA = Pattern.compile("^cpe:/a:(sun|oracle|ibm):(j2[ems]e|"
|
public static final Pattern CORE_JAVA = Pattern.compile("^cpe:/a:(sun|oracle|ibm):(j2[ems]e|"
|
||||||
+ "java(_platform_micro_edition|_runtime_environment|_se|virtual_machine|se_development_kit|fx)?|"
|
+ "java(_platform_micro_edition|_runtime_environment|_se|virtual_machine|se_development_kit|fx)?|"
|
||||||
@@ -172,12 +231,14 @@ public class FalsePositiveAnalyzer extends AbstractAnalyzer {
|
|||||||
*/
|
*/
|
||||||
public static final Pattern CORE_FILES = Pattern.compile("(^|/)((alt[-])?rt|jsse|jfxrt|jfr|jce|javaws|deploy|charsets)\\.jar$");
|
public static final Pattern CORE_FILES = Pattern.compile("(^|/)((alt[-])?rt|jsse|jfxrt|jfr|jce|javaws|deploy|charsets)\\.jar$");
|
||||||
/**
|
/**
|
||||||
* Regex to identify core jsf java library files. This is currently incomplete.
|
* Regex to identify core jsf java library files. This is currently
|
||||||
|
* incomplete.
|
||||||
*/
|
*/
|
||||||
public static final Pattern CORE_JSF_FILES = Pattern.compile("(^|/)jsf[-][^/]*\\.jar$");
|
public static final Pattern CORE_JSF_FILES = Pattern.compile("(^|/)jsf[-][^/]*\\.jar$");
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Removes any CPE entries for the JDK/JRE unless the filename ends with rt.jar
|
* Removes any CPE entries for the JDK/JRE unless the filename ends with
|
||||||
|
* rt.jar
|
||||||
*
|
*
|
||||||
* @param dependency the dependency to remove JRE CPEs from
|
* @param dependency the dependency to remove JRE CPEs from
|
||||||
*/
|
*/
|
||||||
@@ -214,15 +275,16 @@ public class FalsePositiveAnalyzer extends AbstractAnalyzer {
|
|||||||
try {
|
try {
|
||||||
cpe.parseName(value);
|
cpe.parseName(value);
|
||||||
} catch (UnsupportedEncodingException ex) {
|
} catch (UnsupportedEncodingException ex) {
|
||||||
LOGGER.log(Level.FINEST, null, ex);
|
LOGGER.trace("", ex);
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
return cpe;
|
return cpe;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Removes bad CPE matches for a dependency. Unfortunately, right now these are hard-coded patches for specific
|
* Removes bad CPE matches for a dependency. Unfortunately, right now these
|
||||||
* problems identified when testing this on a LARGE volume of jar files.
|
* are hard-coded patches for specific problems identified when testing this
|
||||||
|
* on a LARGE volume of jar files.
|
||||||
*
|
*
|
||||||
* @param dependency the dependency to analyze
|
* @param dependency the dependency to analyze
|
||||||
*/
|
*/
|
||||||
@@ -239,7 +301,7 @@ public class FalsePositiveAnalyzer extends AbstractAnalyzer {
|
|||||||
//Set<Evidence> artifactId = dependency.getVendorEvidence().getEvidence("pom", "artifactid");
|
//Set<Evidence> artifactId = dependency.getVendorEvidence().getEvidence("pom", "artifactid");
|
||||||
while (itr.hasNext()) {
|
while (itr.hasNext()) {
|
||||||
final Identifier i = itr.next();
|
final Identifier i = itr.next();
|
||||||
//TODO move this startsWith expression to a configuration file?
|
//TODO move this startsWith expression to the base suppression file
|
||||||
if ("cpe".equals(i.getType())) {
|
if ("cpe".equals(i.getType())) {
|
||||||
if ((i.getValue().matches(".*c\\+\\+.*")
|
if ((i.getValue().matches(".*c\\+\\+.*")
|
||||||
|| i.getValue().startsWith("cpe:/a:file:file")
|
|| i.getValue().startsWith("cpe:/a:file:file")
|
||||||
@@ -254,7 +316,14 @@ public class FalsePositiveAnalyzer extends AbstractAnalyzer {
|
|||||||
|| dependency.getFileName().toLowerCase().endsWith(".dll")
|
|| dependency.getFileName().toLowerCase().endsWith(".dll")
|
||||||
|| dependency.getFileName().toLowerCase().endsWith(".exe")
|
|| dependency.getFileName().toLowerCase().endsWith(".exe")
|
||||||
|| dependency.getFileName().toLowerCase().endsWith(".nuspec")
|
|| dependency.getFileName().toLowerCase().endsWith(".nuspec")
|
||||||
|| dependency.getFileName().toLowerCase().endsWith(".nupkg"))) {
|
|| dependency.getFileName().toLowerCase().endsWith(".zip")
|
||||||
|
|| dependency.getFileName().toLowerCase().endsWith(".sar")
|
||||||
|
|| dependency.getFileName().toLowerCase().endsWith(".apk")
|
||||||
|
|| dependency.getFileName().toLowerCase().endsWith(".tar")
|
||||||
|
|| dependency.getFileName().toLowerCase().endsWith(".gz")
|
||||||
|
|| dependency.getFileName().toLowerCase().endsWith(".tgz")
|
||||||
|
|| dependency.getFileName().toLowerCase().endsWith(".ear")
|
||||||
|
|| dependency.getFileName().toLowerCase().endsWith(".war"))) {
|
||||||
itr.remove();
|
itr.remove();
|
||||||
} else if ((i.getValue().startsWith("cpe:/a:jquery:jquery")
|
} else if ((i.getValue().startsWith("cpe:/a:jquery:jquery")
|
||||||
|| i.getValue().startsWith("cpe:/a:prototypejs:prototype")
|
|| i.getValue().startsWith("cpe:/a:prototypejs:prototype")
|
||||||
@@ -268,8 +337,11 @@ public class FalsePositiveAnalyzer extends AbstractAnalyzer {
|
|||||||
|| i.getValue().startsWith("cpe:/a:microsoft:word")
|
|| i.getValue().startsWith("cpe:/a:microsoft:word")
|
||||||
|| i.getValue().startsWith("cpe:/a:microsoft:visio")
|
|| i.getValue().startsWith("cpe:/a:microsoft:visio")
|
||||||
|| i.getValue().startsWith("cpe:/a:microsoft:powerpoint")
|
|| i.getValue().startsWith("cpe:/a:microsoft:powerpoint")
|
||||||
|| i.getValue().startsWith("cpe:/a:microsoft:office"))
|
|| i.getValue().startsWith("cpe:/a:microsoft:office")
|
||||||
|
|| i.getValue().startsWith("cpe:/a:core_ftp:core_ftp"))
|
||||||
&& (dependency.getFileName().toLowerCase().endsWith(".jar")
|
&& (dependency.getFileName().toLowerCase().endsWith(".jar")
|
||||||
|
|| dependency.getFileName().toLowerCase().endsWith(".ear")
|
||||||
|
|| dependency.getFileName().toLowerCase().endsWith(".war")
|
||||||
|| dependency.getFileName().toLowerCase().endsWith("pom.xml"))) {
|
|| dependency.getFileName().toLowerCase().endsWith("pom.xml"))) {
|
||||||
itr.remove();
|
itr.remove();
|
||||||
} else if (i.getValue().startsWith("cpe:/a:apache:maven")
|
} else if (i.getValue().startsWith("cpe:/a:apache:maven")
|
||||||
@@ -287,7 +359,8 @@ public class FalsePositiveAnalyzer extends AbstractAnalyzer {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Removes CPE matches for the wrong version of a dependency. Currently, this only covers Axis 1 & 2.
|
* Removes CPE matches for the wrong version of a dependency. Currently,
|
||||||
|
* this only covers Axis 1 & 2.
|
||||||
*
|
*
|
||||||
* @param dependency the dependency to analyze
|
* @param dependency the dependency to analyze
|
||||||
*/
|
*/
|
||||||
@@ -320,26 +393,25 @@ public class FalsePositiveAnalyzer extends AbstractAnalyzer {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* There are some known CPE entries, specifically regarding sun and oracle products due to the acquisition and
|
* There are some known CPE entries, specifically regarding sun and oracle
|
||||||
* changes in product names, that based on given evidence we can add the related CPE entries to ensure a complete
|
* products due to the acquisition and changes in product names, that based
|
||||||
|
* on given evidence we can add the related CPE entries to ensure a complete
|
||||||
* list of CVE entries.
|
* list of CVE entries.
|
||||||
*
|
*
|
||||||
* @param dependency the dependency being analyzed
|
* @param dependency the dependency being analyzed
|
||||||
*/
|
*/
|
||||||
private void addFalseNegativeCPEs(Dependency dependency) {
|
private void addFalseNegativeCPEs(Dependency dependency) {
|
||||||
//TODO move this to the hint analyzer
|
//TODO move this to the hint analyzer
|
||||||
final Iterator<Identifier> itr = dependency.getIdentifiers().iterator();
|
for (final Identifier identifier : dependency.getIdentifiers()) {
|
||||||
while (itr.hasNext()) {
|
if ("cpe".equals(identifier.getType()) && identifier.getValue() != null
|
||||||
final Identifier i = itr.next();
|
&& (identifier.getValue().startsWith("cpe:/a:oracle:opensso:")
|
||||||
if ("cpe".equals(i.getType()) && i.getValue() != null
|
|| identifier.getValue().startsWith("cpe:/a:oracle:opensso_enterprise:")
|
||||||
&& (i.getValue().startsWith("cpe:/a:oracle:opensso:")
|
|| identifier.getValue().startsWith("cpe:/a:sun:opensso_enterprise:")
|
||||||
|| i.getValue().startsWith("cpe:/a:oracle:opensso_enterprise:")
|
|| identifier.getValue().startsWith("cpe:/a:sun:opensso:"))) {
|
||||||
|| i.getValue().startsWith("cpe:/a:sun:opensso_enterprise:")
|
final String newCpe = String.format("cpe:/a:sun:opensso_enterprise:%s", identifier.getValue().substring(22));
|
||||||
|| i.getValue().startsWith("cpe:/a:sun:opensso:"))) {
|
final String newCpe2 = String.format("cpe:/a:oracle:opensso_enterprise:%s", identifier.getValue().substring(22));
|
||||||
final String newCpe = String.format("cpe:/a:sun:opensso_enterprise:%s", i.getValue().substring(22));
|
final String newCpe3 = String.format("cpe:/a:sun:opensso:%s", identifier.getValue().substring(22));
|
||||||
final String newCpe2 = String.format("cpe:/a:oracle:opensso_enterprise:%s", i.getValue().substring(22));
|
final String newCpe4 = String.format("cpe:/a:oracle:opensso:%s", identifier.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));
|
|
||||||
try {
|
try {
|
||||||
dependency.addIdentifier("cpe",
|
dependency.addIdentifier("cpe",
|
||||||
newCpe,
|
newCpe,
|
||||||
@@ -354,27 +426,28 @@ public class FalsePositiveAnalyzer extends AbstractAnalyzer {
|
|||||||
newCpe4,
|
newCpe4,
|
||||||
String.format(CPEAnalyzer.NVD_SEARCH_URL, URLEncoder.encode(newCpe4, "UTF-8")));
|
String.format(CPEAnalyzer.NVD_SEARCH_URL, URLEncoder.encode(newCpe4, "UTF-8")));
|
||||||
} catch (UnsupportedEncodingException ex) {
|
} catch (UnsupportedEncodingException ex) {
|
||||||
LOGGER.log(Level.FINE, null, ex);
|
LOGGER.debug("", ex);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Removes duplicate entries identified that are contained within JAR files. These occasionally crop up due to POM
|
* Removes duplicate entries identified that are contained within JAR files.
|
||||||
* entries or other types of files (such as DLLs and EXEs) being contained within the JAR.
|
* These occasionally crop up due to POM entries or other types of files
|
||||||
|
* (such as DLLs and EXEs) being contained within the JAR.
|
||||||
*
|
*
|
||||||
* @param dependency the dependency that might be a duplicate
|
* @param dependency the dependency that might be a duplicate
|
||||||
* @param engine the engine used to scan all dependencies
|
* @param engine the engine used to scan all dependencies
|
||||||
*/
|
*/
|
||||||
private void removeDuplicativeEntriesFromJar(Dependency dependency, Engine engine) {
|
private synchronized void removeDuplicativeEntriesFromJar(Dependency dependency, Engine engine) {
|
||||||
if (dependency.getFileName().toLowerCase().endsWith("pom.xml")
|
if (dependency.getFileName().toLowerCase().endsWith("pom.xml")
|
||||||
|| "dll".equals(dependency.getFileExtension())
|
|| DLL_EXE_FILTER.accept(dependency.getActualFile())) {
|
||||||
|| "exe".equals(dependency.getFileExtension())) {
|
|
||||||
String parentPath = dependency.getFilePath().toLowerCase();
|
String parentPath = dependency.getFilePath().toLowerCase();
|
||||||
if (parentPath.contains(".jar")) {
|
if (parentPath.contains(".jar")) {
|
||||||
parentPath = parentPath.substring(0, parentPath.indexOf(".jar") + 4);
|
parentPath = parentPath.substring(0, parentPath.indexOf(".jar") + 4);
|
||||||
final Dependency parent = findDependency(parentPath, engine.getDependencies());
|
final List<Dependency> dependencies = engine.getDependencies();
|
||||||
|
final Dependency parent = findDependency(parentPath, dependencies);
|
||||||
if (parent != null) {
|
if (parent != null) {
|
||||||
boolean remove = false;
|
boolean remove = false;
|
||||||
for (Identifier i : dependency.getIdentifiers()) {
|
for (Identifier i : dependency.getIdentifiers()) {
|
||||||
@@ -391,16 +464,16 @@ public class FalsePositiveAnalyzer extends AbstractAnalyzer {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (remove) {
|
if (remove) {
|
||||||
engine.getDependencies().remove(dependency);
|
dependencies.remove(dependency);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Retrieves a given dependency, based on a given path, from a list of dependencies.
|
* Retrieves a given dependency, based on a given path, from a list of
|
||||||
|
* dependencies.
|
||||||
*
|
*
|
||||||
* @param dependencyPath the path of the dependency to return
|
* @param dependencyPath the path of the dependency to return
|
||||||
* @param dependencies the collection of dependencies to search
|
* @param dependencies the collection of dependencies to search
|
||||||
@@ -416,15 +489,16 @@ public class FalsePositiveAnalyzer extends AbstractAnalyzer {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Takes a full CPE and returns the CPE trimmed to include only vendor and product.
|
* Takes a full CPE and returns the CPE trimmed to include only vendor and
|
||||||
|
* product.
|
||||||
*
|
*
|
||||||
* @param value the CPE value to trim
|
* @param value the CPE value to trim
|
||||||
* @return a CPE value that only includes the vendor and product
|
* @return a CPE value that only includes the vendor and product
|
||||||
*/
|
*/
|
||||||
private String trimCpeToVendor(String value) {
|
private String trimCpeToVendor(String value) {
|
||||||
//cpe:/a:jruby:jruby:1.0.8
|
//cpe:/a:jruby:jruby:1.0.8
|
||||||
final int pos1 = value.indexOf(":", 7); //right of vendor
|
final int pos1 = value.indexOf(':', 7); //right of vendor
|
||||||
final int pos2 = value.indexOf(":", pos1 + 1); //right of product
|
final int pos2 = value.indexOf(':', pos1 + 1); //right of product
|
||||||
if (pos2 < 0) {
|
if (pos2 < 0) {
|
||||||
return value;
|
return value;
|
||||||
} else {
|
} else {
|
||||||
|
|||||||
@@ -18,20 +18,24 @@
|
|||||||
package org.owasp.dependencycheck.analyzer;
|
package org.owasp.dependencycheck.analyzer;
|
||||||
|
|
||||||
import java.io.File;
|
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.Engine;
|
||||||
import org.owasp.dependencycheck.analyzer.exception.AnalysisException;
|
import org.owasp.dependencycheck.analyzer.exception.AnalysisException;
|
||||||
import org.owasp.dependencycheck.dependency.Confidence;
|
import org.owasp.dependencycheck.dependency.Confidence;
|
||||||
import org.owasp.dependencycheck.dependency.Dependency;
|
import org.owasp.dependencycheck.dependency.Dependency;
|
||||||
import org.owasp.dependencycheck.utils.DependencyVersion;
|
import org.owasp.dependencycheck.utils.DependencyVersion;
|
||||||
import org.owasp.dependencycheck.utils.DependencyVersionUtil;
|
import org.owasp.dependencycheck.utils.DependencyVersionUtil;
|
||||||
|
import org.owasp.dependencycheck.utils.Settings;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
*
|
*
|
||||||
* Takes a dependency and analyzes the filename and determines the hashes.
|
* Takes a dependency and analyzes the filename and determines the hashes.
|
||||||
*
|
*
|
||||||
* @author Jeremy Long <jeremy.long@owasp.org>
|
* @author Jeremy Long
|
||||||
*/
|
*/
|
||||||
public class FileNameAnalyzer extends AbstractAnalyzer implements Analyzer {
|
public class FileNameAnalyzer extends AbstractAnalyzer {
|
||||||
|
|
||||||
//<editor-fold defaultstate="collapsed" desc="All standard implementation details of Analyzer">
|
//<editor-fold defaultstate="collapsed" desc="All standard implementation details of Analyzer">
|
||||||
/**
|
/**
|
||||||
@@ -48,6 +52,7 @@ public class FileNameAnalyzer extends AbstractAnalyzer implements Analyzer {
|
|||||||
*
|
*
|
||||||
* @return the name of the analyzer.
|
* @return the name of the analyzer.
|
||||||
*/
|
*/
|
||||||
|
@Override
|
||||||
public String getName() {
|
public String getName() {
|
||||||
return ANALYZER_NAME;
|
return ANALYZER_NAME;
|
||||||
}
|
}
|
||||||
@@ -57,59 +62,70 @@ public class FileNameAnalyzer extends AbstractAnalyzer implements Analyzer {
|
|||||||
*
|
*
|
||||||
* @return 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() {
|
public AnalysisPhase getAnalysisPhase() {
|
||||||
return ANALYSIS_PHASE;
|
return ANALYSIS_PHASE;
|
||||||
}
|
}
|
||||||
|
/**
|
||||||
|
* <p>
|
||||||
|
* Returns the setting key to determine if the analyzer is enabled.</p>
|
||||||
|
*
|
||||||
|
* @return the key for the analyzer's enabled property
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
protected String getAnalyzerEnabledSettingKey() {
|
||||||
|
return Settings.KEYS.ANALYZER_FILE_NAME_ENABLED;
|
||||||
|
}
|
||||||
//</editor-fold>
|
//</editor-fold>
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Python init files
|
||||||
|
*/
|
||||||
|
//CSOFF: WhitespaceAfter
|
||||||
|
private static final NameFileFilter IGNORED_FILES = new NameFileFilter(new String[]{
|
||||||
|
"__init__.py",
|
||||||
|
"__init__.pyc",
|
||||||
|
"__init__.pyo",});
|
||||||
|
//CSON: WhitespaceAfter
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Collects information about the file name.
|
* Collects information about the file name.
|
||||||
*
|
*
|
||||||
* @param dependency the dependency to analyze.
|
* @param dependency the dependency to analyze.
|
||||||
* @param engine the engine that is scanning the dependencies
|
* @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
|
@Override
|
||||||
public void analyze(Dependency dependency, Engine engine) throws AnalysisException {
|
protected void analyzeDependency(Dependency dependency, Engine engine) throws AnalysisException {
|
||||||
|
|
||||||
//strip any path information that may get added by ArchiveAnalyzer, etc.
|
//strip any path information that may get added by ArchiveAnalyzer, etc.
|
||||||
final File f = new File(dependency.getFileName());
|
final File f = dependency.getActualFile();
|
||||||
String fileName = f.getName();
|
final String fileName = FilenameUtils.removeExtension(f.getName());
|
||||||
|
|
||||||
//remove file extension
|
|
||||||
final int pos = fileName.lastIndexOf(".");
|
|
||||||
if (pos > 0) {
|
|
||||||
fileName = fileName.substring(0, pos);
|
|
||||||
}
|
|
||||||
|
|
||||||
//add version evidence
|
//add version evidence
|
||||||
final DependencyVersion version = DependencyVersionUtil.parseVersion(fileName);
|
final DependencyVersion version = DependencyVersionUtil.parseVersion(fileName);
|
||||||
|
final String packageName = DependencyVersionUtil.parsePreVersion(fileName);
|
||||||
if (version != null) {
|
if (version != null) {
|
||||||
// If the version number is just a number like 2 or 23, reduce the confidence
|
// If the version number is just a number like 2 or 23, reduce the confidence
|
||||||
// a shade. This should hopefully correct for cases like log4j.jar or
|
// a shade. This should hopefully correct for cases like log4j.jar or
|
||||||
// struts2-core.jar
|
// struts2-core.jar
|
||||||
if (version.getVersionParts() == null || version.getVersionParts().size() < 2) {
|
if (version.getVersionParts() == null || version.getVersionParts().size() < 2) {
|
||||||
dependency.getVersionEvidence().addEvidence("file", "name",
|
dependency.getVersionEvidence().addEvidence("file", "version",
|
||||||
version.toString(), Confidence.MEDIUM);
|
version.toString(), Confidence.MEDIUM);
|
||||||
} else {
|
} else {
|
||||||
dependency.getVersionEvidence().addEvidence("file", "name",
|
dependency.getVersionEvidence().addEvidence("file", "version",
|
||||||
version.toString(), Confidence.HIGHEST);
|
version.toString(), Confidence.HIGHEST);
|
||||||
}
|
}
|
||||||
dependency.getVersionEvidence().addEvidence("file", "name",
|
dependency.getVersionEvidence().addEvidence("file", "name",
|
||||||
fileName, Confidence.MEDIUM);
|
packageName, Confidence.MEDIUM);
|
||||||
}
|
}
|
||||||
|
|
||||||
//add as vendor and product evidence
|
if (!IGNORED_FILES.accept(f)) {
|
||||||
if (fileName.contains("-")) {
|
|
||||||
dependency.getProductEvidence().addEvidence("file", "name",
|
dependency.getProductEvidence().addEvidence("file", "name",
|
||||||
fileName, Confidence.HIGHEST);
|
packageName, Confidence.HIGH);
|
||||||
dependency.getVendorEvidence().addEvidence("file", "name",
|
dependency.getVendorEvidence().addEvidence("file", "name",
|
||||||
fileName, Confidence.HIGHEST);
|
packageName, Confidence.HIGH);
|
||||||
} else {
|
|
||||||
dependency.getProductEvidence().addEvidence("file", "name",
|
|
||||||
fileName, Confidence.HIGH);
|
|
||||||
dependency.getVendorEvidence().addEvidence("file", "name",
|
|
||||||
fileName, Confidence.HIGH);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -17,18 +17,13 @@
|
|||||||
*/
|
*/
|
||||||
package org.owasp.dependencycheck.analyzer;
|
package org.owasp.dependencycheck.analyzer;
|
||||||
|
|
||||||
|
import java.io.FileFilter;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* An Analyzer that scans specific file types.
|
* An Analyzer that scans specific file types.
|
||||||
*
|
*
|
||||||
* @author Jeremy Long <jeremy.long@owasp.org>
|
* @author Jeremy Long
|
||||||
*/
|
*/
|
||||||
public interface FileTypeAnalyzer extends Analyzer {
|
public interface FileTypeAnalyzer extends Analyzer, FileFilter {
|
||||||
|
|
||||||
/**
|
|
||||||
* Returns whether or not this analyzer can process the given extension.
|
|
||||||
*
|
|
||||||
* @param extension the file extension to test for support.
|
|
||||||
* @return whether or not the specified file extension is supported by this analyzer.
|
|
||||||
*/
|
|
||||||
boolean supportsExtension(String extension);
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -17,20 +17,54 @@
|
|||||||
*/
|
*/
|
||||||
package org.owasp.dependencycheck.analyzer;
|
package org.owasp.dependencycheck.analyzer;
|
||||||
|
|
||||||
|
import java.io.File;
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.io.InputStream;
|
||||||
|
import java.net.MalformedURLException;
|
||||||
|
import java.net.URL;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.Iterator;
|
import java.util.Iterator;
|
||||||
import java.util.Set;
|
import java.util.List;
|
||||||
|
import java.util.regex.Pattern;
|
||||||
import org.owasp.dependencycheck.Engine;
|
import org.owasp.dependencycheck.Engine;
|
||||||
import org.owasp.dependencycheck.analyzer.exception.AnalysisException;
|
import org.owasp.dependencycheck.analyzer.exception.AnalysisException;
|
||||||
import org.owasp.dependencycheck.dependency.Confidence;
|
|
||||||
import org.owasp.dependencycheck.dependency.Dependency;
|
import org.owasp.dependencycheck.dependency.Dependency;
|
||||||
import org.owasp.dependencycheck.dependency.Evidence;
|
import org.owasp.dependencycheck.dependency.Evidence;
|
||||||
|
import org.owasp.dependencycheck.exception.InitializationException;
|
||||||
|
import org.owasp.dependencycheck.xml.suppression.PropertyType;
|
||||||
|
import org.owasp.dependencycheck.utils.DownloadFailedException;
|
||||||
|
import org.owasp.dependencycheck.utils.Downloader;
|
||||||
|
import org.owasp.dependencycheck.utils.FileUtils;
|
||||||
|
import org.owasp.dependencycheck.utils.Settings;
|
||||||
|
import org.owasp.dependencycheck.xml.hints.VendorDuplicatingHintRule;
|
||||||
|
import org.owasp.dependencycheck.xml.hints.HintParseException;
|
||||||
|
import org.owasp.dependencycheck.xml.hints.HintParser;
|
||||||
|
import org.owasp.dependencycheck.xml.hints.HintRule;
|
||||||
|
import org.owasp.dependencycheck.xml.hints.Hints;
|
||||||
|
import org.slf4j.Logger;
|
||||||
|
import org.slf4j.LoggerFactory;
|
||||||
|
import org.xml.sax.SAXException;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
* This analyzer adds evidence to dependencies to enhance the accuracy of
|
||||||
|
* library identification.
|
||||||
*
|
*
|
||||||
* @author Jeremy Long <jeremy.long@owasp.org>
|
* @author Jeremy Long
|
||||||
*/
|
*/
|
||||||
public class HintAnalyzer extends AbstractAnalyzer implements Analyzer {
|
public class HintAnalyzer extends AbstractAnalyzer {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The Logger for use throughout the class
|
||||||
|
*/
|
||||||
|
private static final Logger LOGGER = LoggerFactory.getLogger(HintAnalyzer.class);
|
||||||
|
/**
|
||||||
|
* The name of the hint rule file
|
||||||
|
*/
|
||||||
|
private static final String HINT_RULE_FILE_NAME = "dependencycheck-base-hint.xml";
|
||||||
|
/**
|
||||||
|
* The collection of hints.
|
||||||
|
*/
|
||||||
|
private Hints hints;
|
||||||
|
|
||||||
//<editor-fold defaultstate="collapsed" desc="All standard implementation details of Analyzer">
|
//<editor-fold defaultstate="collapsed" desc="All standard implementation details of Analyzer">
|
||||||
/**
|
/**
|
||||||
@@ -61,60 +95,192 @@ public class HintAnalyzer extends AbstractAnalyzer implements Analyzer {
|
|||||||
public AnalysisPhase getAnalysisPhase() {
|
public AnalysisPhase getAnalysisPhase() {
|
||||||
return ANALYSIS_PHASE;
|
return ANALYSIS_PHASE;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* <p>
|
||||||
|
* Returns the setting key to determine if the analyzer is enabled.</p>
|
||||||
|
*
|
||||||
|
* @return the key for the analyzer's enabled property
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
protected String getAnalyzerEnabledSettingKey() {
|
||||||
|
return Settings.KEYS.ANALYZER_HINT_ENABLED;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The initialize method does nothing for this Analyzer.
|
||||||
|
*
|
||||||
|
* @throws InitializationException thrown if there is an exception
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
public void initializeAnalyzer() throws InitializationException {
|
||||||
|
try {
|
||||||
|
loadHintRules();
|
||||||
|
} catch (HintParseException ex) {
|
||||||
|
LOGGER.debug("Unable to parse hint file", ex);
|
||||||
|
throw new InitializationException("Unable to parse the hint file", ex);
|
||||||
|
}
|
||||||
|
}
|
||||||
//</editor-fold>
|
//</editor-fold>
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The HintAnalyzer uses knowledge about a dependency to add additional information to help in identification of
|
* The HintAnalyzer uses knowledge about a dependency to add additional
|
||||||
* identifiers or vulnerabilities.
|
* information to help in identification of identifiers or vulnerabilities.
|
||||||
*
|
*
|
||||||
* @param dependency The dependency being analyzed
|
* @param dependency The dependency being analyzed
|
||||||
* @param engine The scanning engine
|
* @param engine The scanning engine
|
||||||
* @throws AnalysisException is thrown if there is an exception analyzing the dependency.
|
* @throws AnalysisException is thrown if there is an exception analyzing
|
||||||
|
* the dependency.
|
||||||
*/
|
*/
|
||||||
@Override
|
@Override
|
||||||
public void analyze(Dependency dependency, Engine engine) throws AnalysisException {
|
protected void analyzeDependency(Dependency dependency, Engine engine) throws AnalysisException {
|
||||||
final Evidence springTest1 = new Evidence("Manifest",
|
for (HintRule hint : hints.getHintRules()) {
|
||||||
"Implementation-Title",
|
boolean matchFound = false;
|
||||||
"Spring Framework",
|
for (Evidence given : hint.getGivenVendor()) {
|
||||||
Confidence.HIGH);
|
if (dependency.getVendorEvidence().getEvidence().contains(given)) {
|
||||||
|
matchFound = true;
|
||||||
final Evidence springTest2 = new Evidence("Manifest",
|
break;
|
||||||
"Implementation-Title",
|
}
|
||||||
"org.springframework.core",
|
}
|
||||||
Confidence.HIGH);
|
if (!matchFound) {
|
||||||
|
for (Evidence given : hint.getGivenProduct()) {
|
||||||
final Evidence springTest3 = new Evidence("Manifest",
|
if (dependency.getProductEvidence().getEvidence().contains(given)) {
|
||||||
"Bundle-Vendor",
|
matchFound = true;
|
||||||
"SpringSource",
|
break;
|
||||||
Confidence.HIGH);
|
}
|
||||||
|
}
|
||||||
Set<Evidence> evidence = dependency.getProductEvidence().getEvidence();
|
}
|
||||||
if (evidence.contains(springTest1) || evidence.contains(springTest2)) {
|
if (!matchFound) {
|
||||||
dependency.getProductEvidence().addEvidence("hint analyzer", "product", "springsource_spring_framework", Confidence.HIGH);
|
for (Evidence given : hint.getGivenVersion()) {
|
||||||
dependency.getVendorEvidence().addEvidence("hint analyzer", "vendor", "SpringSource", Confidence.HIGH);
|
if (dependency.getVersionEvidence().getEvidence().contains(given)) {
|
||||||
dependency.getVendorEvidence().addEvidence("hint analyzer", "vendor", "vmware", Confidence.HIGH);
|
matchFound = true;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (!matchFound) {
|
||||||
|
for (PropertyType pt : hint.getFilenames()) {
|
||||||
|
if (pt.matches(dependency.getFileName())) {
|
||||||
|
matchFound = true;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (matchFound) {
|
||||||
|
for (Evidence e : hint.getAddVendor()) {
|
||||||
|
dependency.getVendorEvidence().addEvidence(e);
|
||||||
|
}
|
||||||
|
for (Evidence e : hint.getAddProduct()) {
|
||||||
|
dependency.getProductEvidence().addEvidence(e);
|
||||||
|
}
|
||||||
|
for (Evidence e : hint.getAddVersion()) {
|
||||||
|
dependency.getVersionEvidence().addEvidence(e);
|
||||||
|
}
|
||||||
|
for (Evidence e : hint.getRemoveVendor()) {
|
||||||
|
if (dependency.getVendorEvidence().getEvidence().contains(e)) {
|
||||||
|
dependency.getVendorEvidence().getEvidence().remove(e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
for (Evidence e : hint.getRemoveProduct()) {
|
||||||
|
if (dependency.getProductEvidence().getEvidence().contains(e)) {
|
||||||
|
dependency.getProductEvidence().getEvidence().remove(e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
for (Evidence e : hint.getRemoveVersion()) {
|
||||||
|
if (dependency.getVersionEvidence().getEvidence().contains(e)) {
|
||||||
|
dependency.getVersionEvidence().getEvidence().remove(e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
evidence = dependency.getVendorEvidence().getEvidence();
|
|
||||||
if (evidence.contains(springTest3)) {
|
|
||||||
dependency.getProductEvidence().addEvidence("hint analyzer", "product", "springsource_spring_framework", Confidence.HIGH);
|
|
||||||
dependency.getVendorEvidence().addEvidence("hint analyzer", "vendor", "vmware", Confidence.HIGH);
|
|
||||||
}
|
|
||||||
final Iterator<Evidence> itr = dependency.getVendorEvidence().iterator();
|
final Iterator<Evidence> itr = dependency.getVendorEvidence().iterator();
|
||||||
final ArrayList<Evidence> newEntries = new ArrayList<Evidence>();
|
final List<Evidence> newEntries = new ArrayList<>();
|
||||||
while (itr.hasNext()) {
|
while (itr.hasNext()) {
|
||||||
final Evidence e = itr.next();
|
final Evidence e = itr.next();
|
||||||
if ("sun".equalsIgnoreCase(e.getValue(false))) {
|
for (VendorDuplicatingHintRule dhr : hints.getVendorDuplicatingHintRules()) {
|
||||||
final Evidence newEvidence = new Evidence(e.getSource() + " (hint)", e.getName(), "oracle", e.getConfidence());
|
if (dhr.getValue().equalsIgnoreCase(e.getValue(false))) {
|
||||||
newEntries.add(newEvidence);
|
newEntries.add(new Evidence(e.getSource() + " (hint)",
|
||||||
} else if ("oracle".equalsIgnoreCase(e.getValue(false))) {
|
e.getName(), dhr.getDuplicate(), e.getConfidence()));
|
||||||
final Evidence newEvidence = new Evidence(e.getSource() + " (hint)", e.getName(), "sun", e.getConfidence());
|
}
|
||||||
newEntries.add(newEvidence);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
for (Evidence e : newEntries) {
|
for (Evidence e : newEntries) {
|
||||||
dependency.getVendorEvidence().addEvidence(e);
|
dependency.getVendorEvidence().addEvidence(e);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Loads the hint rules file.
|
||||||
|
*
|
||||||
|
* @throws HintParseException thrown if the XML cannot be parsed.
|
||||||
|
*/
|
||||||
|
private void loadHintRules() throws HintParseException {
|
||||||
|
final HintParser parser = new HintParser();
|
||||||
|
File file = null;
|
||||||
|
try {
|
||||||
|
hints = parser.parseHints(this.getClass().getClassLoader().getResourceAsStream(HINT_RULE_FILE_NAME));
|
||||||
|
} catch (HintParseException | SAXException ex) {
|
||||||
|
LOGGER.error("Unable to parse the base hint data file");
|
||||||
|
LOGGER.debug("Unable to parse the base hint data file", ex);
|
||||||
|
}
|
||||||
|
final String filePath = Settings.getString(Settings.KEYS.HINTS_FILE);
|
||||||
|
if (filePath == null) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
boolean deleteTempFile = false;
|
||||||
|
try {
|
||||||
|
final Pattern uriRx = Pattern.compile("^(https?|file)\\:.*", Pattern.CASE_INSENSITIVE);
|
||||||
|
if (uriRx.matcher(filePath).matches()) {
|
||||||
|
deleteTempFile = true;
|
||||||
|
file = FileUtils.getTempFile("hint", "xml");
|
||||||
|
final URL url = new URL(filePath);
|
||||||
|
try {
|
||||||
|
Downloader.fetchFile(url, file, false);
|
||||||
|
} catch (DownloadFailedException ex) {
|
||||||
|
Downloader.fetchFile(url, file, true);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
file = new File(filePath);
|
||||||
|
if (!file.exists()) {
|
||||||
|
try (InputStream fromClasspath = this.getClass().getClassLoader().getResourceAsStream(filePath)) {
|
||||||
|
if (fromClasspath != null) {
|
||||||
|
deleteTempFile = true;
|
||||||
|
file = FileUtils.getTempFile("hint", "xml");
|
||||||
|
try {
|
||||||
|
org.apache.commons.io.FileUtils.copyInputStreamToFile(fromClasspath, file);
|
||||||
|
} catch (IOException ex) {
|
||||||
|
throw new HintParseException("Unable to locate hints file in classpath", ex);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (file != null) {
|
||||||
|
try {
|
||||||
|
final Hints newHints = parser.parseHints(file);
|
||||||
|
hints.getHintRules().addAll(newHints.getHintRules());
|
||||||
|
hints.getVendorDuplicatingHintRules().addAll(newHints.getVendorDuplicatingHintRules());
|
||||||
|
LOGGER.debug("{} hint rules were loaded.", hints.getHintRules().size());
|
||||||
|
LOGGER.debug("{} duplicating hint rules were loaded.", hints.getVendorDuplicatingHintRules().size());
|
||||||
|
} catch (HintParseException ex) {
|
||||||
|
LOGGER.warn("Unable to parse hint rule xml file '{}'", file.getPath());
|
||||||
|
LOGGER.warn(ex.getMessage());
|
||||||
|
LOGGER.debug("", ex);
|
||||||
|
throw ex;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} catch (DownloadFailedException ex) {
|
||||||
|
throw new HintParseException("Unable to fetch the configured hint file", ex);
|
||||||
|
} catch (MalformedURLException ex) {
|
||||||
|
throw new HintParseException("Configured hint file has an invalid URL", ex);
|
||||||
|
} catch (IOException ex) {
|
||||||
|
throw new HintParseException("Unable to create temp file for hints", ex);
|
||||||
|
} finally {
|
||||||
|
if (deleteTempFile && file != null) {
|
||||||
|
FileUtils.delete(file);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
File diff suppressed because it is too large
Load Diff
@@ -1,141 +0,0 @@
|
|||||||
/*
|
|
||||||
* This file is part of dependency-check-core.
|
|
||||||
*
|
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
||||||
* you may not use this file except in compliance with the License.
|
|
||||||
* You may obtain a copy of the License at
|
|
||||||
*
|
|
||||||
* http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
*
|
|
||||||
* Unless required by applicable law or agreed to in writing, software
|
|
||||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
||||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
* See the License for the specific language governing permissions and
|
|
||||||
* limitations under the License.
|
|
||||||
*
|
|
||||||
* Copyright (c) 2014 Jeremy Long. All Rights Reserved.
|
|
||||||
*/
|
|
||||||
package org.owasp.dependencycheck.analyzer;
|
|
||||||
|
|
||||||
import java.io.BufferedReader;
|
|
||||||
import java.io.File;
|
|
||||||
import java.io.FileNotFoundException;
|
|
||||||
import java.io.FileReader;
|
|
||||||
import java.io.IOException;
|
|
||||||
import java.util.Set;
|
|
||||||
import java.util.logging.Level;
|
|
||||||
import java.util.logging.Logger;
|
|
||||||
import java.util.regex.Pattern;
|
|
||||||
import org.owasp.dependencycheck.Engine;
|
|
||||||
import org.owasp.dependencycheck.analyzer.exception.AnalysisException;
|
|
||||||
import org.owasp.dependencycheck.dependency.Dependency;
|
|
||||||
import org.owasp.dependencycheck.utils.Settings;
|
|
||||||
|
|
||||||
/**
|
|
||||||
*
|
|
||||||
* Used to analyze a JavaScript file to gather information to aid in identification of a CPE identifier.
|
|
||||||
*
|
|
||||||
* @author Jeremy Long <jeremy.long@owasp.org>
|
|
||||||
*/
|
|
||||||
public class JavaScriptAnalyzer extends AbstractFileTypeAnalyzer {
|
|
||||||
|
|
||||||
/**
|
|
||||||
* The logger.
|
|
||||||
*/
|
|
||||||
private static final Logger LOGGER = Logger.getLogger(JavaScriptAnalyzer.class.getName());
|
|
||||||
|
|
||||||
//<editor-fold defaultstate="collapsed" desc="All standard implementation details of Analyzer">
|
|
||||||
/**
|
|
||||||
* The name of the analyzer.
|
|
||||||
*/
|
|
||||||
private static final String ANALYZER_NAME = "JavaScript Analyzer";
|
|
||||||
/**
|
|
||||||
* The phase that this analyzer is intended to run in.
|
|
||||||
*/
|
|
||||||
private static final AnalysisPhase ANALYSIS_PHASE = AnalysisPhase.INFORMATION_COLLECTION;
|
|
||||||
/**
|
|
||||||
* The set of file extensions supported by this analyzer.
|
|
||||||
*/
|
|
||||||
private static final Set<String> EXTENSIONS = newHashSet("js");
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Returns a list of file EXTENSIONS supported by this analyzer.
|
|
||||||
*
|
|
||||||
* @return a list of file EXTENSIONS supported by this analyzer.
|
|
||||||
*/
|
|
||||||
@Override
|
|
||||||
public Set<String> getSupportedExtensions() {
|
|
||||||
return EXTENSIONS;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Returns the name of the analyzer.
|
|
||||||
*
|
|
||||||
* @return the name of the analyzer.
|
|
||||||
*/
|
|
||||||
@Override
|
|
||||||
public String getName() {
|
|
||||||
return ANALYZER_NAME;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Returns the phase that the analyzer is intended to run in.
|
|
||||||
*
|
|
||||||
* @return the phase that the analyzer is intended to run in.
|
|
||||||
*/
|
|
||||||
@Override
|
|
||||||
public AnalysisPhase getAnalysisPhase() {
|
|
||||||
return ANALYSIS_PHASE;
|
|
||||||
}
|
|
||||||
//</editor-fold>
|
|
||||||
/**
|
|
||||||
* Returns the key used in the properties file to reference the analyzer's enabled property.
|
|
||||||
*
|
|
||||||
* @return the analyzer's enabled property setting key
|
|
||||||
*/
|
|
||||||
@Override
|
|
||||||
protected String getAnalyzerEnabledSettingKey() {
|
|
||||||
return Settings.KEYS.ANALYZER_JAVASCRIPT_ENABLED;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Loads a specified JavaScript file and collects information from the copyright information contained within.
|
|
||||||
*
|
|
||||||
* @param dependency the dependency to analyze.
|
|
||||||
* @param engine the engine that is scanning the dependencies
|
|
||||||
* @throws AnalysisException is thrown if there is an error reading the JavaScript file.
|
|
||||||
*/
|
|
||||||
@Override
|
|
||||||
public void analyzeFileType(Dependency dependency, Engine engine) throws AnalysisException {
|
|
||||||
BufferedReader fin = null;
|
|
||||||
try {
|
|
||||||
// /\*([^\*][^/]|[\r\n\f])+?\*/
|
|
||||||
final Pattern extractComments = Pattern.compile("(/\\*([^*]|[\\r\\n]|(\\*+([^*/]|[\\r\\n])))*\\*+/)|(//.*)", Pattern.MULTILINE);
|
|
||||||
File file = dependency.getActualFile();
|
|
||||||
fin = new BufferedReader(new FileReader(file));
|
|
||||||
StringBuilder sb = new StringBuilder(2000);
|
|
||||||
String text;
|
|
||||||
while ((text = fin.readLine()) != null) {
|
|
||||||
sb.append(text);
|
|
||||||
}
|
|
||||||
} catch (FileNotFoundException ex) {
|
|
||||||
final String msg = String.format("Dependency file not found: '%s'", dependency.getActualFilePath());
|
|
||||||
throw new AnalysisException(msg, ex);
|
|
||||||
} catch (IOException ex) {
|
|
||||||
LOGGER.log(Level.SEVERE, null, ex);
|
|
||||||
} finally {
|
|
||||||
if (fin != null) {
|
|
||||||
try {
|
|
||||||
fin.close();
|
|
||||||
} catch (IOException ex) {
|
|
||||||
LOGGER.log(Level.FINEST, null, ex);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
protected void initializeFileTypeAnalyzer() throws Exception {
|
|
||||||
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -17,42 +17,60 @@
|
|||||||
*/
|
*/
|
||||||
package org.owasp.dependencycheck.analyzer;
|
package org.owasp.dependencycheck.analyzer;
|
||||||
|
|
||||||
import java.io.FileNotFoundException;
|
import org.apache.commons.io.FileUtils;
|
||||||
import java.io.IOException;
|
|
||||||
import java.net.MalformedURLException;
|
|
||||||
import java.net.URL;
|
|
||||||
import java.util.Set;
|
|
||||||
import java.util.logging.Level;
|
|
||||||
import java.util.logging.Logger;
|
|
||||||
import org.owasp.dependencycheck.Engine;
|
import org.owasp.dependencycheck.Engine;
|
||||||
import org.owasp.dependencycheck.analyzer.exception.AnalysisException;
|
import org.owasp.dependencycheck.analyzer.exception.AnalysisException;
|
||||||
import org.owasp.dependencycheck.data.nexus.MavenArtifact;
|
import org.owasp.dependencycheck.data.nexus.MavenArtifact;
|
||||||
import org.owasp.dependencycheck.data.nexus.NexusSearch;
|
import org.owasp.dependencycheck.data.nexus.NexusSearch;
|
||||||
import org.owasp.dependencycheck.dependency.Confidence;
|
import org.owasp.dependencycheck.dependency.Confidence;
|
||||||
import org.owasp.dependencycheck.dependency.Dependency;
|
import org.owasp.dependencycheck.dependency.Dependency;
|
||||||
import org.owasp.dependencycheck.dependency.Identifier;
|
import org.owasp.dependencycheck.dependency.Evidence;
|
||||||
|
import org.owasp.dependencycheck.xml.pom.PomUtils;
|
||||||
|
import org.slf4j.Logger;
|
||||||
|
import org.slf4j.LoggerFactory;
|
||||||
|
|
||||||
|
import java.io.File;
|
||||||
|
import java.io.FileFilter;
|
||||||
|
import java.io.FileNotFoundException;
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.net.MalformedURLException;
|
||||||
|
import java.net.URL;
|
||||||
|
import org.owasp.dependencycheck.exception.InitializationException;
|
||||||
|
import org.owasp.dependencycheck.utils.DownloadFailedException;
|
||||||
|
import org.owasp.dependencycheck.utils.Downloader;
|
||||||
|
import org.owasp.dependencycheck.utils.FileFilterBuilder;
|
||||||
|
import org.owasp.dependencycheck.utils.InvalidSettingException;
|
||||||
import org.owasp.dependencycheck.utils.Settings;
|
import org.owasp.dependencycheck.utils.Settings;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Analyzer which will attempt to locate a dependency on a Nexus service by SHA-1 digest of the dependency.
|
* Analyzer which will attempt to locate a dependency on a Nexus service by
|
||||||
|
* SHA-1 digest of the dependency.
|
||||||
*
|
*
|
||||||
* There are two settings which govern this behavior:
|
* There are two settings which govern this behavior:
|
||||||
*
|
*
|
||||||
* <ul>
|
* <ul>
|
||||||
* <li>{@link org.owasp.dependencycheck.utils.Settings.KEYS#ANALYZER_NEXUS_ENABLED} determines whether this analyzer is
|
* <li>{@link org.owasp.dependencycheck.utils.Settings.KEYS#ANALYZER_NEXUS_ENABLED}
|
||||||
* even enabled. This can be overridden by setting the system property.</li>
|
* determines whether this analyzer is even enabled. This can be overridden by
|
||||||
* <li>{@link org.owasp.dependencycheck.utils.Settings.KEYS#ANALYZER_NEXUS_URL} the URL to a Nexus service to search by
|
* setting the system property.</li>
|
||||||
* SHA-1. There is an expected <code>%s</code> in this where the SHA-1 will get entered.</li>
|
* <li>{@link org.owasp.dependencycheck.utils.Settings.KEYS#ANALYZER_NEXUS_URL}
|
||||||
|
* the URL to a Nexus service to search by SHA-1. There is an expected
|
||||||
|
* <code>%s</code> in this where the SHA-1 will get entered.</li>
|
||||||
* </ul>
|
* </ul>
|
||||||
*
|
*
|
||||||
* @author colezlaw
|
* @author colezlaw
|
||||||
*/
|
*/
|
||||||
public class NexusAnalyzer extends AbstractFileTypeAnalyzer {
|
public class NexusAnalyzer extends AbstractFileTypeAnalyzer {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The default URL - this will be used by the CentralAnalyzer to determine
|
||||||
|
* whether to enable this.
|
||||||
|
*/
|
||||||
|
public static final String DEFAULT_URL = "https://repository.sonatype.org/service/local/";
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The logger.
|
* The logger.
|
||||||
*/
|
*/
|
||||||
private static final Logger LOGGER = Logger.getLogger(NexusAnalyzer.class.getName());
|
private static final Logger LOGGER = LoggerFactory.getLogger(NexusAnalyzer.class);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The name of the analyzer.
|
* The name of the analyzer.
|
||||||
@@ -67,7 +85,7 @@ public class NexusAnalyzer extends AbstractFileTypeAnalyzer {
|
|||||||
/**
|
/**
|
||||||
* The types of files on which this will work.
|
* The types of files on which this will work.
|
||||||
*/
|
*/
|
||||||
private static final Set<String> SUPPORTED_EXTENSIONS = newHashSet("jar");
|
private static final String SUPPORTED_EXTENSIONS = "jar";
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The Nexus Search to be set up for this analyzer.
|
* The Nexus Search to be set up for this analyzer.
|
||||||
@@ -75,28 +93,69 @@ public class NexusAnalyzer extends AbstractFileTypeAnalyzer {
|
|||||||
private NexusSearch searcher;
|
private NexusSearch searcher;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Initializes the analyzer once before any analysis is performed.
|
* Field indicating if the analyzer is enabled.
|
||||||
|
*/
|
||||||
|
private final boolean enabled = checkEnabled();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Determines if this analyzer is enabled
|
||||||
*
|
*
|
||||||
* @throws Exception if there's an error during initialization
|
* @return <code>true</code> if the analyzer is enabled; otherwise
|
||||||
|
* <code>false</code>
|
||||||
|
*/
|
||||||
|
private boolean checkEnabled() {
|
||||||
|
/* Enable this analyzer ONLY if the Nexus URL has been set to something
|
||||||
|
other than the default one (if it's the default one, we'll use the
|
||||||
|
central one) and it's enabled by the user.
|
||||||
|
*/
|
||||||
|
boolean retval = false;
|
||||||
|
try {
|
||||||
|
if (!DEFAULT_URL.equals(Settings.getString(Settings.KEYS.ANALYZER_NEXUS_URL))
|
||||||
|
&& Settings.getBoolean(Settings.KEYS.ANALYZER_NEXUS_ENABLED)) {
|
||||||
|
LOGGER.info("Enabling Nexus analyzer");
|
||||||
|
retval = true;
|
||||||
|
} else {
|
||||||
|
LOGGER.debug("Nexus analyzer disabled, using Central instead");
|
||||||
|
}
|
||||||
|
} catch (InvalidSettingException ise) {
|
||||||
|
LOGGER.warn("Invalid setting. Disabling Nexus analyzer");
|
||||||
|
}
|
||||||
|
|
||||||
|
return retval;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Determine whether to enable this analyzer or not.
|
||||||
|
*
|
||||||
|
* @return whether the analyzer should be enabled
|
||||||
*/
|
*/
|
||||||
@Override
|
@Override
|
||||||
public void initializeFileTypeAnalyzer() throws Exception {
|
public boolean isEnabled() {
|
||||||
LOGGER.fine("Initializing Nexus Analyzer");
|
return enabled;
|
||||||
LOGGER.fine(String.format("Nexus Analyzer enabled: %s", isEnabled()));
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Initializes the analyzer once before any analysis is performed.
|
||||||
|
*
|
||||||
|
* @throws InitializationException if there's an error during initialization
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
public void initializeFileTypeAnalyzer() throws InitializationException {
|
||||||
|
LOGGER.debug("Initializing Nexus Analyzer");
|
||||||
|
LOGGER.debug("Nexus Analyzer enabled: {}", isEnabled());
|
||||||
if (isEnabled()) {
|
if (isEnabled()) {
|
||||||
|
final boolean useProxy = useProxy();
|
||||||
final String searchUrl = Settings.getString(Settings.KEYS.ANALYZER_NEXUS_URL);
|
final String searchUrl = Settings.getString(Settings.KEYS.ANALYZER_NEXUS_URL);
|
||||||
LOGGER.fine(String.format("Nexus Analyzer URL: %s", searchUrl));
|
LOGGER.debug("Nexus Analyzer URL: {}", searchUrl);
|
||||||
try {
|
try {
|
||||||
searcher = new NexusSearch(new URL(searchUrl));
|
searcher = new NexusSearch(new URL(searchUrl), useProxy);
|
||||||
if (!searcher.preflightRequest()) {
|
if (!searcher.preflightRequest()) {
|
||||||
LOGGER.warning("There was an issue getting Nexus status. Disabling analyzer.");
|
|
||||||
setEnabled(false);
|
setEnabled(false);
|
||||||
|
throw new InitializationException("There was an issue getting Nexus status. Disabling analyzer.");
|
||||||
}
|
}
|
||||||
} catch (MalformedURLException mue) {
|
} catch (MalformedURLException mue) {
|
||||||
// I know that initialize can throw an exception, but we'll
|
|
||||||
// just disable the analyzer if the URL isn't valid
|
|
||||||
LOGGER.warning(String.format("Property %s not a valid URL. Nexus Analyzer disabled", searchUrl));
|
|
||||||
setEnabled(false);
|
setEnabled(false);
|
||||||
|
throw new InitializationException("Malformed URL to Nexus: " + searchUrl, mue);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -112,7 +171,8 @@ public class NexusAnalyzer extends AbstractFileTypeAnalyzer {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 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
|
* @return the analyzer's enabled property setting key
|
||||||
*/
|
*/
|
||||||
@@ -132,13 +192,18 @@ public class NexusAnalyzer extends AbstractFileTypeAnalyzer {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns the extensions for which this Analyzer runs.
|
* The file filter used to determine which files this analyzer supports.
|
||||||
|
*/
|
||||||
|
private static final FileFilter FILTER = FileFilterBuilder.newInstance().addExtensions(SUPPORTED_EXTENSIONS).build();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the FileFilter
|
||||||
*
|
*
|
||||||
* @return the extensions for which this Analyzer runs
|
* @return the FileFilter
|
||||||
*/
|
*/
|
||||||
@Override
|
@Override
|
||||||
public Set<String> getSupportedExtensions() {
|
protected FileFilter getFileFilter() {
|
||||||
return SUPPORTED_EXTENSIONS;
|
return FILTER;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -149,42 +214,69 @@ public class NexusAnalyzer extends AbstractFileTypeAnalyzer {
|
|||||||
* @throws AnalysisException when there's an exception during analysis
|
* @throws AnalysisException when there's an exception during analysis
|
||||||
*/
|
*/
|
||||||
@Override
|
@Override
|
||||||
public void analyzeFileType(Dependency dependency, Engine engine) throws AnalysisException {
|
public void analyzeDependency(Dependency dependency, Engine engine) throws AnalysisException {
|
||||||
|
if (!isEnabled()) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
try {
|
try {
|
||||||
final MavenArtifact ma = searcher.searchSha1(dependency.getSha1sum());
|
final MavenArtifact ma = searcher.searchSha1(dependency.getSha1sum());
|
||||||
if (ma.getGroupId() != null && !"".equals(ma.getGroupId())) {
|
dependency.addAsEvidence("nexus", ma, Confidence.HIGH);
|
||||||
dependency.getVendorEvidence().addEvidence("nexus", "groupid", ma.getGroupId(), Confidence.HIGH);
|
boolean pomAnalyzed = false;
|
||||||
}
|
LOGGER.debug("POM URL {}", ma.getPomUrl());
|
||||||
if (ma.getArtifactId() != null && !"".equals(ma.getArtifactId())) {
|
for (Evidence e : dependency.getVendorEvidence()) {
|
||||||
dependency.getProductEvidence().addEvidence("nexus", "artifactid", ma.getArtifactId(), Confidence.HIGH);
|
if ("pom".equals(e.getSource())) {
|
||||||
}
|
pomAnalyzed = true;
|
||||||
if (ma.getVersion() != null && !"".equals(ma.getVersion())) {
|
break;
|
||||||
dependency.getVersionEvidence().addEvidence("nexus", "version", ma.getVersion(), Confidence.HIGH);
|
|
||||||
}
|
|
||||||
if (ma.getArtifactUrl() != null && !"".equals(ma.getArtifactUrl())) {
|
|
||||||
boolean found = false;
|
|
||||||
for (Identifier i : dependency.getIdentifiers()) {
|
|
||||||
if ("maven".equals(i.getType()) && i.getValue().equals(ma.toString())) {
|
|
||||||
found = true;
|
|
||||||
i.setConfidence(Confidence.HIGHEST);
|
|
||||||
i.setUrl(ma.getArtifactUrl());
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
if (!found) {
|
}
|
||||||
dependency.addIdentifier("maven", ma.toString(), ma.getArtifactUrl(), Confidence.HIGHEST);
|
if (!pomAnalyzed && ma.getPomUrl() != null) {
|
||||||
|
File pomFile = null;
|
||||||
|
try {
|
||||||
|
final File baseDir = Settings.getTempDirectory();
|
||||||
|
pomFile = File.createTempFile("pom", ".xml", baseDir);
|
||||||
|
if (!pomFile.delete()) {
|
||||||
|
LOGGER.warn("Unable to fetch pom.xml for {} from Nexus repository; "
|
||||||
|
+ "this could result in undetected CPE/CVEs.", dependency.getFileName());
|
||||||
|
LOGGER.debug("Unable to delete temp file");
|
||||||
|
}
|
||||||
|
LOGGER.debug("Downloading {}", ma.getPomUrl());
|
||||||
|
Downloader.fetchFile(new URL(ma.getPomUrl()), pomFile);
|
||||||
|
PomUtils.analyzePOM(dependency, pomFile);
|
||||||
|
} catch (DownloadFailedException ex) {
|
||||||
|
LOGGER.warn("Unable to download pom.xml for {} from Nexus repository; "
|
||||||
|
+ "this could result in undetected CPE/CVEs.", dependency.getFileName());
|
||||||
|
} finally {
|
||||||
|
if (pomFile != null && pomFile.exists() && !FileUtils.deleteQuietly(pomFile)) {
|
||||||
|
LOGGER.debug("Failed to delete temporary pom file {}", pomFile.toString());
|
||||||
|
pomFile.deleteOnExit();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} catch (IllegalArgumentException iae) {
|
} catch (IllegalArgumentException iae) {
|
||||||
//dependency.addAnalysisException(new AnalysisException("Invalid SHA-1"));
|
//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) {
|
} catch (FileNotFoundException fnfe) {
|
||||||
//dependency.addAnalysisException(new AnalysisException("Artifact not found on repository"));
|
//dependency.addAnalysisException(new AnalysisException("Artifact not found on repository"));
|
||||||
LOGGER.fine(String.format("Artifact not found in repository '%s'", dependency.getFileName()));
|
LOGGER.debug("Artifact not found in repository '{}'", dependency.getFileName());
|
||||||
LOGGER.log(Level.FINE, fnfe.getMessage(), fnfe);
|
LOGGER.debug(fnfe.getMessage(), fnfe);
|
||||||
} catch (IOException ioe) {
|
} catch (IOException ioe) {
|
||||||
//dependency.addAnalysisException(new AnalysisException("Could not connect to repository", ioe));
|
//dependency.addAnalysisException(new AnalysisException("Could not connect to repository", ioe));
|
||||||
LOGGER.log(Level.FINE, "Could not connect to nexus repository", ioe);
|
LOGGER.debug("Could not connect to nexus repository", ioe);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Determine if a proxy should be used.
|
||||||
|
*
|
||||||
|
* @return {@code true} if a proxy should be used
|
||||||
|
*/
|
||||||
|
public static boolean useProxy() {
|
||||||
|
try {
|
||||||
|
return Settings.getString(Settings.KEYS.PROXY_SERVER) != null
|
||||||
|
&& Settings.getBoolean(Settings.KEYS.ANALYZER_NEXUS_USES_PROXY);
|
||||||
|
} catch (InvalidSettingException ise) {
|
||||||
|
LOGGER.warn("Failed to parse proxy settings.", ise);
|
||||||
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,183 @@
|
|||||||
|
/*
|
||||||
|
* 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;
|
||||||
|
import org.owasp.dependencycheck.exception.InitializationException;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 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 InitializationException {
|
||||||
|
// 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 analyzeDependency(Dependency dependency, Engine engine) throws AnalysisException {
|
||||||
|
final File file = dependency.getActualFile();
|
||||||
|
try (JsonReader jsonReader = Json.createReader(FileUtils.openInputStream(file))) {
|
||||||
|
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);
|
||||||
|
} catch (IOException e) {
|
||||||
|
throw new AnalysisException("Problem occurred while reading dependency file.", e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Adds information to an evidence collection from the node json
|
||||||
|
* configuration.
|
||||||
|
*
|
||||||
|
* @param json information from node.js
|
||||||
|
* @param collection a set of evidence about a dependency
|
||||||
|
* @param key the key to obtain the data from the json information
|
||||||
|
*/
|
||||||
|
private void addToEvidence(JsonObject json, EvidenceCollection collection, String key) {
|
||||||
|
if (json.containsKey(key)) {
|
||||||
|
final JsonValue value = json.get(key);
|
||||||
|
if (value instanceof JsonString) {
|
||||||
|
collection.addEvidence(PACKAGE_JSON, key, ((JsonString) value).getString(), Confidence.HIGHEST);
|
||||||
|
} else if (value instanceof JsonObject) {
|
||||||
|
final JsonObject jsonObject = (JsonObject) value;
|
||||||
|
for (final Map.Entry<String, JsonValue> entry : jsonObject.entrySet()) {
|
||||||
|
final String property = entry.getKey();
|
||||||
|
final JsonValue subValue = entry.getValue();
|
||||||
|
if (subValue instanceof JsonString) {
|
||||||
|
collection.addEvidence(PACKAGE_JSON,
|
||||||
|
String.format("%s.%s", key, property),
|
||||||
|
((JsonString) subValue).getString(),
|
||||||
|
Confidence.HIGHEST);
|
||||||
|
} else {
|
||||||
|
LOGGER.warn("JSON sub-value not string as expected: {}", subValue);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
LOGGER.warn("JSON value not string or JSON object as expected: {}", value);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -17,12 +17,6 @@
|
|||||||
*/
|
*/
|
||||||
package org.owasp.dependencycheck.analyzer;
|
package org.owasp.dependencycheck.analyzer;
|
||||||
|
|
||||||
import java.io.FileInputStream;
|
|
||||||
import java.io.FileNotFoundException;
|
|
||||||
import java.io.IOException;
|
|
||||||
import java.util.Set;
|
|
||||||
import java.util.logging.Level;
|
|
||||||
import java.util.logging.Logger;
|
|
||||||
import org.owasp.dependencycheck.Engine;
|
import org.owasp.dependencycheck.Engine;
|
||||||
import org.owasp.dependencycheck.analyzer.exception.AnalysisException;
|
import org.owasp.dependencycheck.analyzer.exception.AnalysisException;
|
||||||
import org.owasp.dependencycheck.data.nuget.NugetPackage;
|
import org.owasp.dependencycheck.data.nuget.NugetPackage;
|
||||||
@@ -31,7 +25,15 @@ import org.owasp.dependencycheck.data.nuget.NuspecParser;
|
|||||||
import org.owasp.dependencycheck.data.nuget.XPathNuspecParser;
|
import org.owasp.dependencycheck.data.nuget.XPathNuspecParser;
|
||||||
import org.owasp.dependencycheck.dependency.Confidence;
|
import org.owasp.dependencycheck.dependency.Confidence;
|
||||||
import org.owasp.dependencycheck.dependency.Dependency;
|
import org.owasp.dependencycheck.dependency.Dependency;
|
||||||
|
import org.owasp.dependencycheck.utils.FileFilterBuilder;
|
||||||
import org.owasp.dependencycheck.utils.Settings;
|
import org.owasp.dependencycheck.utils.Settings;
|
||||||
|
import org.slf4j.Logger;
|
||||||
|
import org.slf4j.LoggerFactory;
|
||||||
|
|
||||||
|
import java.io.FileFilter;
|
||||||
|
import java.io.FileInputStream;
|
||||||
|
import java.io.FileNotFoundException;
|
||||||
|
import org.owasp.dependencycheck.exception.InitializationException;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Analyzer which will parse a Nuspec file to gather module information.
|
* Analyzer which will parse a Nuspec file to gather module information.
|
||||||
@@ -43,7 +45,7 @@ public class NuspecAnalyzer extends AbstractFileTypeAnalyzer {
|
|||||||
/**
|
/**
|
||||||
* The logger.
|
* The logger.
|
||||||
*/
|
*/
|
||||||
private static final Logger LOGGER = Logger.getLogger(NuspecAnalyzer.class.getName());
|
private static final Logger LOGGER = LoggerFactory.getLogger(NuspecAnalyzer.class);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The name of the analyzer.
|
* The name of the analyzer.
|
||||||
@@ -58,15 +60,15 @@ public class NuspecAnalyzer extends AbstractFileTypeAnalyzer {
|
|||||||
/**
|
/**
|
||||||
* The types of files on which this will work.
|
* The types of files on which this will work.
|
||||||
*/
|
*/
|
||||||
private static final Set<String> SUPPORTED_EXTENSIONS = newHashSet("nuspec");
|
private static final String SUPPORTED_EXTENSIONS = "nuspec";
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Initializes the analyzer once before any analysis is performed.
|
* Initializes the analyzer once before any analysis is performed.
|
||||||
*
|
*
|
||||||
* @throws Exception if there's an error during initialization
|
* @throws InitializationException if there's an error during initialization
|
||||||
*/
|
*/
|
||||||
@Override
|
@Override
|
||||||
public void initializeFileTypeAnalyzer() throws Exception {
|
public void initializeFileTypeAnalyzer() throws InitializationException {
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -80,7 +82,8 @@ public class NuspecAnalyzer extends AbstractFileTypeAnalyzer {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 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
|
* @return the analyzer's enabled property setting key
|
||||||
*/
|
*/
|
||||||
@@ -100,13 +103,19 @@ public class NuspecAnalyzer extends AbstractFileTypeAnalyzer {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns the extensions for which this Analyzer runs.
|
* The file filter used to determine which files this analyzer supports.
|
||||||
|
*/
|
||||||
|
private static final FileFilter FILTER = FileFilterBuilder.newInstance().addExtensions(
|
||||||
|
SUPPORTED_EXTENSIONS).build();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the FileFilter
|
||||||
*
|
*
|
||||||
* @return the extensions for which this Analyzer runs
|
* @return the FileFilter
|
||||||
*/
|
*/
|
||||||
@Override
|
@Override
|
||||||
public Set<String> getSupportedExtensions() {
|
protected FileFilter getFileFilter() {
|
||||||
return SUPPORTED_EXTENSIONS;
|
return FILTER;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -117,27 +126,15 @@ public class NuspecAnalyzer extends AbstractFileTypeAnalyzer {
|
|||||||
* @throws AnalysisException when there's an exception during analysis
|
* @throws AnalysisException when there's an exception during analysis
|
||||||
*/
|
*/
|
||||||
@Override
|
@Override
|
||||||
public void analyzeFileType(Dependency dependency, Engine engine) throws AnalysisException {
|
public void analyzeDependency(Dependency dependency, Engine engine) throws AnalysisException {
|
||||||
LOGGER.log(Level.FINE, "Checking Nuspec file {0}", dependency.toString());
|
LOGGER.debug("Checking Nuspec file {}", dependency);
|
||||||
try {
|
try {
|
||||||
final NuspecParser parser = new XPathNuspecParser();
|
final NuspecParser parser = new XPathNuspecParser();
|
||||||
NugetPackage np = null;
|
NugetPackage np = null;
|
||||||
FileInputStream fis = null;
|
try (FileInputStream fis = new FileInputStream(dependency.getActualFilePath())) {
|
||||||
try {
|
|
||||||
fis = new FileInputStream(dependency.getActualFilePath());
|
|
||||||
np = parser.parse(fis);
|
np = parser.parse(fis);
|
||||||
} catch (NuspecParseException ex) {
|
} catch (NuspecParseException | FileNotFoundException ex) {
|
||||||
throw new AnalysisException(ex);
|
throw new AnalysisException(ex);
|
||||||
} catch (FileNotFoundException ex) {
|
|
||||||
throw new AnalysisException(ex);
|
|
||||||
} finally {
|
|
||||||
if (fis != null) {
|
|
||||||
try {
|
|
||||||
fis.close();
|
|
||||||
} catch (IOException e) {
|
|
||||||
LOGGER.fine("Error closing input stream");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (np.getOwners() != null) {
|
if (np.getOwners() != null) {
|
||||||
|
|||||||
@@ -27,19 +27,24 @@ import org.owasp.dependencycheck.data.nvdcve.DatabaseException;
|
|||||||
import org.owasp.dependencycheck.dependency.Dependency;
|
import org.owasp.dependencycheck.dependency.Dependency;
|
||||||
import org.owasp.dependencycheck.dependency.Identifier;
|
import org.owasp.dependencycheck.dependency.Identifier;
|
||||||
import org.owasp.dependencycheck.dependency.Vulnerability;
|
import org.owasp.dependencycheck.dependency.Vulnerability;
|
||||||
|
import org.owasp.dependencycheck.exception.InitializationException;
|
||||||
|
import org.owasp.dependencycheck.utils.Settings;
|
||||||
|
import org.slf4j.LoggerFactory;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* NvdCveAnalyzer is a utility class that takes a project dependency and attempts to discern if there is an associated
|
* NvdCveAnalyzer is a utility class that takes a project dependency and
|
||||||
* CVEs. It uses the the identifiers found by other analyzers to lookup the CVE data.
|
* attempts to discern if there is an associated CVEs. It uses the the
|
||||||
|
* identifiers found by other analyzers to lookup the CVE data.
|
||||||
*
|
*
|
||||||
* @author Jeremy Long <jeremy.long@owasp.org>
|
* @author Jeremy Long
|
||||||
*/
|
*/
|
||||||
public class NvdCveAnalyzer implements Analyzer {
|
public class NvdCveAnalyzer extends AbstractAnalyzer {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The maximum number of query results to return.
|
* The Logger for use throughout the class
|
||||||
*/
|
*/
|
||||||
static final int MAX_QUERY_RESULTS = 100;
|
private static final org.slf4j.Logger LOGGER = LoggerFactory.getLogger(NvdCveAnalyzer.class);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The CVE Index.
|
* The CVE Index.
|
||||||
*/
|
*/
|
||||||
@@ -51,18 +56,18 @@ public class NvdCveAnalyzer implements Analyzer {
|
|||||||
* @throws SQLException thrown when there is a SQL Exception
|
* @throws SQLException thrown when there is a SQL Exception
|
||||||
* @throws IOException thrown when there is an IO Exception
|
* @throws IOException thrown when there is an IO Exception
|
||||||
* @throws DatabaseException thrown when there is a database exceptions
|
* @throws DatabaseException thrown when there is a database exceptions
|
||||||
* @throws ClassNotFoundException thrown if the h2 database driver cannot be loaded
|
* @throws ClassNotFoundException thrown if the h2 database driver cannot be
|
||||||
|
* loaded
|
||||||
*/
|
*/
|
||||||
public void open() throws SQLException, IOException, DatabaseException, ClassNotFoundException {
|
public void open() throws SQLException, IOException, DatabaseException, ClassNotFoundException {
|
||||||
cveDB = new CveDB();
|
cveDB = CveDB.getInstance();
|
||||||
cveDB.open();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Closes the data source.
|
* Closes the data source.
|
||||||
*/
|
*/
|
||||||
@Override
|
@Override
|
||||||
public void close() {
|
public void closeAnalyzer() {
|
||||||
cveDB.close();
|
cveDB.close();
|
||||||
cveDB = null;
|
cveDB = null;
|
||||||
}
|
}
|
||||||
@@ -73,31 +78,20 @@ public class NvdCveAnalyzer implements Analyzer {
|
|||||||
* @return true or false.
|
* @return true or false.
|
||||||
*/
|
*/
|
||||||
public boolean isOpen() {
|
public boolean isOpen() {
|
||||||
return (cveDB != null);
|
return cveDB != null;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Ensures that the CVE Database is closed.
|
* Analyzes a dependency and attempts to determine if there are any CPE
|
||||||
*
|
* identifiers for this dependency.
|
||||||
* @throws Throwable when a throwable is thrown.
|
|
||||||
*/
|
|
||||||
@Override
|
|
||||||
protected void finalize() throws Throwable {
|
|
||||||
super.finalize();
|
|
||||||
if (isOpen()) {
|
|
||||||
close();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Analyzes a dependency and attempts to determine if there are any CPE identifiers for this dependency.
|
|
||||||
*
|
*
|
||||||
* @param dependency The Dependency to analyze
|
* @param dependency The Dependency to analyze
|
||||||
* @param engine The analysis engine
|
* @param engine The analysis engine
|
||||||
* @throws AnalysisException is thrown if there is an issue analyzing the dependency
|
* @throws AnalysisException thrown if there is an issue analyzing the
|
||||||
|
* dependency
|
||||||
*/
|
*/
|
||||||
@Override
|
@Override
|
||||||
public void analyze(Dependency dependency, Engine engine) throws AnalysisException {
|
protected void analyzeDependency(Dependency dependency, Engine engine) throws AnalysisException {
|
||||||
for (Identifier id : dependency.getIdentifiers()) {
|
for (Identifier id : dependency.getIdentifiers()) {
|
||||||
if ("cpe".equals(id.getType())) {
|
if ("cpe".equals(id.getType())) {
|
||||||
try {
|
try {
|
||||||
@@ -143,12 +137,38 @@ public class NvdCveAnalyzer implements Analyzer {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Opens the database used to gather NVD CVE data.
|
* <p>
|
||||||
|
* Returns the setting key to determine if the analyzer is enabled.</p>
|
||||||
*
|
*
|
||||||
* @throws Exception is thrown if there is an issue opening the index.
|
* @return the key for the analyzer's enabled property
|
||||||
*/
|
*/
|
||||||
@Override
|
@Override
|
||||||
public void initialize() throws Exception {
|
protected String getAnalyzerEnabledSettingKey() {
|
||||||
this.open();
|
return Settings.KEYS.ANALYZER_NVD_CVE_ENABLED;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Opens the database used to gather NVD CVE data.
|
||||||
|
*
|
||||||
|
* @throws InitializationException is thrown if there is an issue opening
|
||||||
|
* the index.
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
public void initializeAnalyzer() throws InitializationException {
|
||||||
|
try {
|
||||||
|
this.open();
|
||||||
|
} catch (SQLException ex) {
|
||||||
|
LOGGER.debug("SQL Exception initializing NvdCveAnalyzer", ex);
|
||||||
|
throw new InitializationException(ex);
|
||||||
|
} catch (IOException ex) {
|
||||||
|
LOGGER.debug("IO Exception initializing NvdCveAnalyzer", ex);
|
||||||
|
throw new InitializationException(ex);
|
||||||
|
} catch (DatabaseException ex) {
|
||||||
|
LOGGER.debug("Database Exception initializing NvdCveAnalyzer", ex);
|
||||||
|
throw new InitializationException(ex);
|
||||||
|
} catch (ClassNotFoundException ex) {
|
||||||
|
LOGGER.debug("Exception initializing NvdCveAnalyzer", ex);
|
||||||
|
throw new InitializationException(ex);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,214 @@
|
|||||||
|
/*
|
||||||
|
* This file is part of dependency-check-core.
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*
|
||||||
|
* Copyright (c) 2015 Institute for Defense Analyses. All Rights Reserved.
|
||||||
|
*/
|
||||||
|
package org.owasp.dependencycheck.analyzer;
|
||||||
|
|
||||||
|
import org.apache.commons.io.FileUtils;
|
||||||
|
import org.owasp.dependencycheck.Engine;
|
||||||
|
import org.owasp.dependencycheck.analyzer.exception.AnalysisException;
|
||||||
|
import org.owasp.dependencycheck.dependency.Confidence;
|
||||||
|
import org.owasp.dependencycheck.dependency.Dependency;
|
||||||
|
import org.owasp.dependencycheck.utils.FileFilterBuilder;
|
||||||
|
import org.owasp.dependencycheck.utils.Settings;
|
||||||
|
|
||||||
|
import java.io.File;
|
||||||
|
import java.io.FileFilter;
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.nio.charset.Charset;
|
||||||
|
import java.util.regex.Matcher;
|
||||||
|
import java.util.regex.Pattern;
|
||||||
|
import org.owasp.dependencycheck.exception.InitializationException;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Used to analyze OpenSSL source code present in the file system.
|
||||||
|
*
|
||||||
|
* @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.
|
||||||
|
*/
|
||||||
|
private static final String OPENSSLV_H = "opensslv.h";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Filter that detects files named "__init__.py".
|
||||||
|
*/
|
||||||
|
private static final FileFilter OPENSSLV_FILTER = FileFilterBuilder.newInstance().addFilenames(OPENSSLV_H).build();
|
||||||
|
/**
|
||||||
|
* 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;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the open SSL version as a string.
|
||||||
|
*
|
||||||
|
* @param openSSLVersionConstant The open SSL version
|
||||||
|
* @return the version of openssl
|
||||||
|
*/
|
||||||
|
protected static String getOpenSSLVersion(long openSSLVersionConstant) {
|
||||||
|
final long major = openSSLVersionConstant >>> MAJOR_OFFSET;
|
||||||
|
final long minor = (openSSLVersionConstant & MINOR_MASK) >>> MINOR_OFFSET;
|
||||||
|
final long fix = (openSSLVersionConstant & FIX_MASK) >>> FIX_OFFSET;
|
||||||
|
final long patchLevel = (openSSLVersionConstant & PATCH_MASK) >>> PATCH_OFFSET;
|
||||||
|
final String patch = 0 == patchLevel || patchLevel > NUM_LETTERS ? "" : String.valueOf((char) (patchLevel + 'a' - 1));
|
||||||
|
final int statusCode = (int) (openSSLVersionConstant & STATUS_MASK);
|
||||||
|
final String status = 0xf == statusCode ? "" : (0 == statusCode ? "-dev" : "-beta" + statusCode);
|
||||||
|
return String.format("%d.%d.%d%s%s", major, minor, fix, patch, status);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the name of the Python Package Analyzer.
|
||||||
|
*
|
||||||
|
* @return the name of the analyzer
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
public String getName() {
|
||||||
|
return "OpenSSL Source Analyzer";
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Tell that we are used for information collection.
|
||||||
|
*
|
||||||
|
* @return INFORMATION_COLLECTION
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
public AnalysisPhase getAnalysisPhase() {
|
||||||
|
return AnalysisPhase.INFORMATION_COLLECTION;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the set of supported file extensions.
|
||||||
|
*
|
||||||
|
* @return the set of supported file extensions
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
protected FileFilter getFileFilter() {
|
||||||
|
return OPENSSLV_FILTER;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* No-op initializer implementation.
|
||||||
|
*
|
||||||
|
* @throws InitializationException never thrown
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
protected void initializeFileTypeAnalyzer() throws InitializationException {
|
||||||
|
// Nothing to do here.
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Analyzes python packages and adds evidence to the dependency.
|
||||||
|
*
|
||||||
|
* @param dependency the dependency being analyzed
|
||||||
|
* @param engine the engine being used to perform the scan
|
||||||
|
* @throws AnalysisException thrown if there is an unrecoverable error
|
||||||
|
* analyzing the dependency
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
protected void analyzeDependency(Dependency dependency, Engine engine)
|
||||||
|
throws AnalysisException {
|
||||||
|
final File file = dependency.getActualFile();
|
||||||
|
final String parentName = file.getParentFile().getName();
|
||||||
|
boolean found = false;
|
||||||
|
final String contents = getFileContents(file);
|
||||||
|
if (!contents.isEmpty()) {
|
||||||
|
final Matcher matcher = VERSION_PATTERN.matcher(contents);
|
||||||
|
if (matcher.find()) {
|
||||||
|
dependency.getVersionEvidence().addEvidence(OPENSSLV_H, "Version Constant",
|
||||||
|
getOpenSSLVersion(Long.parseLong(matcher.group(1), HEXADECIMAL)), Confidence.HIGH);
|
||||||
|
found = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (found) {
|
||||||
|
dependency.setDisplayFileName(parentName + File.separatorChar + OPENSSLV_H);
|
||||||
|
dependency.getVendorEvidence().addEvidence(OPENSSLV_H, "Vendor", "OpenSSL", Confidence.HIGHEST);
|
||||||
|
dependency.getProductEvidence().addEvidence(OPENSSLV_H, "Product", "OpenSSL", Confidence.HIGHEST);
|
||||||
|
} else {
|
||||||
|
engine.getDependencies().remove(dependency);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Retrieves the contents of a given file.
|
||||||
|
*
|
||||||
|
* @param actualFile the file to read
|
||||||
|
* @return the contents of the file
|
||||||
|
* @throws AnalysisException thrown if there is an IO Exception
|
||||||
|
*/
|
||||||
|
private String getFileContents(final File actualFile)
|
||||||
|
throws AnalysisException {
|
||||||
|
try {
|
||||||
|
return FileUtils.readFileToString(actualFile, Charset.defaultCharset()).trim();
|
||||||
|
} catch (IOException e) {
|
||||||
|
throw new AnalysisException(
|
||||||
|
"Problem occurred while reading dependency file.", e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 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;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,397 @@
|
|||||||
|
/*
|
||||||
|
* This file is part of dependency-check-core.
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*
|
||||||
|
* Copyright (c) 2015 Institute for Defense Analyses. All Rights Reserved.
|
||||||
|
*/
|
||||||
|
package org.owasp.dependencycheck.analyzer;
|
||||||
|
|
||||||
|
import java.io.BufferedInputStream;
|
||||||
|
import java.io.File;
|
||||||
|
import java.io.FileFilter;
|
||||||
|
import java.io.FileInputStream;
|
||||||
|
import java.io.FileNotFoundException;
|
||||||
|
import java.io.FilenameFilter;
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.io.InputStream;
|
||||||
|
import org.apache.commons.io.filefilter.NameFileFilter;
|
||||||
|
import org.apache.commons.io.filefilter.SuffixFileFilter;
|
||||||
|
import org.apache.commons.lang3.StringUtils;
|
||||||
|
import org.owasp.dependencycheck.Engine;
|
||||||
|
import org.owasp.dependencycheck.analyzer.exception.AnalysisException;
|
||||||
|
import org.owasp.dependencycheck.dependency.Confidence;
|
||||||
|
import org.owasp.dependencycheck.dependency.Dependency;
|
||||||
|
import org.owasp.dependencycheck.dependency.EvidenceCollection;
|
||||||
|
import org.slf4j.Logger;
|
||||||
|
import org.slf4j.LoggerFactory;
|
||||||
|
|
||||||
|
import javax.mail.MessagingException;
|
||||||
|
import javax.mail.internet.InternetHeaders;
|
||||||
|
import org.owasp.dependencycheck.exception.InitializationException;
|
||||||
|
import org.owasp.dependencycheck.utils.ExtractionException;
|
||||||
|
import org.owasp.dependencycheck.utils.ExtractionUtil;
|
||||||
|
import org.owasp.dependencycheck.utils.FileFilterBuilder;
|
||||||
|
import org.owasp.dependencycheck.utils.FileUtils;
|
||||||
|
import org.owasp.dependencycheck.utils.Settings;
|
||||||
|
import org.owasp.dependencycheck.utils.UrlStringUtils;
|
||||||
|
import java.util.concurrent.atomic.AtomicInteger;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 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
|
||||||
|
*/
|
||||||
|
@Experimental
|
||||||
|
public class PythonDistributionAnalyzer extends AbstractFileTypeAnalyzer {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Name of egg metadata files to analyze.
|
||||||
|
*/
|
||||||
|
private static final String PKG_INFO = "PKG-INFO";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Name of wheel metadata files to analyze.
|
||||||
|
*/
|
||||||
|
private static final String METADATA = "METADATA";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The logger.
|
||||||
|
*/
|
||||||
|
private static final Logger LOGGER = LoggerFactory
|
||||||
|
.getLogger(PythonDistributionAnalyzer.class);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The count of directories created during analysis. This is used for
|
||||||
|
* creating temporary directories.
|
||||||
|
*/
|
||||||
|
private static final AtomicInteger DIR_COUNT = new AtomicInteger(0);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The name of the analyzer.
|
||||||
|
*/
|
||||||
|
private static final String ANALYZER_NAME = "Python Distribution Analyzer";
|
||||||
|
/**
|
||||||
|
* The phase that this analyzer is intended to run in.
|
||||||
|
*/
|
||||||
|
private static final AnalysisPhase ANALYSIS_PHASE = AnalysisPhase.INFORMATION_COLLECTION;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The set of file extensions supported by this analyzer.
|
||||||
|
*/
|
||||||
|
private static final String[] EXTENSIONS = {"whl", "egg", "zip"};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Used to match on egg archive candidate extensions.
|
||||||
|
*/
|
||||||
|
private static final FileFilter EGG_OR_ZIP = FileFilterBuilder.newInstance().addExtensions("egg", "zip").build();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Used to detect files with a .whl extension.
|
||||||
|
*/
|
||||||
|
private static final FileFilter WHL_FILTER = FileFilterBuilder.newInstance().addExtensions("whl").build();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The parent directory for the individual directories per archive.
|
||||||
|
*/
|
||||||
|
private File tempFileLocation;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Filter that detects *.dist-info files (but doesn't verify they are
|
||||||
|
* directories.
|
||||||
|
*/
|
||||||
|
private static final FilenameFilter DIST_INFO_FILTER = new SuffixFileFilter(
|
||||||
|
".dist-info");
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Filter that detects files named "METADATA".
|
||||||
|
*/
|
||||||
|
private static final FilenameFilter EGG_INFO_FILTER = new NameFileFilter(
|
||||||
|
"EGG-INFO");
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Filter that detects files named "METADATA".
|
||||||
|
*/
|
||||||
|
private static final NameFileFilter METADATA_FILTER = new NameFileFilter(
|
||||||
|
METADATA);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Filter that detects files named "PKG-INFO".
|
||||||
|
*/
|
||||||
|
private static final NameFileFilter PKG_INFO_FILTER = new NameFileFilter(
|
||||||
|
PKG_INFO);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The file filter used to determine which files this analyzer supports.
|
||||||
|
*/
|
||||||
|
private static final FileFilter FILTER = FileFilterBuilder.newInstance().addFileFilters(
|
||||||
|
METADATA_FILTER, PKG_INFO_FILTER).addExtensions(EXTENSIONS).build();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the FileFilter
|
||||||
|
*
|
||||||
|
* @return the FileFilter
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
protected FileFilter getFileFilter() {
|
||||||
|
return FILTER;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the name of the analyzer.
|
||||||
|
*
|
||||||
|
* @return the name of the analyzer.
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
public String getName() {
|
||||||
|
return ANALYZER_NAME;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the phase that the analyzer is intended to run in.
|
||||||
|
*
|
||||||
|
* @return the phase that the analyzer is intended to run in.
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
public AnalysisPhase getAnalysisPhase() {
|
||||||
|
return ANALYSIS_PHASE;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the key used in the properties file to reference the analyzer's
|
||||||
|
* enabled property.
|
||||||
|
*
|
||||||
|
* @return the analyzer's enabled property setting key
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
protected String getAnalyzerEnabledSettingKey() {
|
||||||
|
return Settings.KEYS.ANALYZER_PYTHON_DISTRIBUTION_ENABLED;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void analyzeDependency(Dependency dependency, Engine engine)
|
||||||
|
throws AnalysisException {
|
||||||
|
final File actualFile = dependency.getActualFile();
|
||||||
|
if (WHL_FILTER.accept(actualFile)) {
|
||||||
|
collectMetadataFromArchiveFormat(dependency, DIST_INFO_FILTER,
|
||||||
|
METADATA_FILTER);
|
||||||
|
} else if (EGG_OR_ZIP.accept(actualFile)) {
|
||||||
|
collectMetadataFromArchiveFormat(dependency, EGG_INFO_FILTER,
|
||||||
|
PKG_INFO_FILTER);
|
||||||
|
} else {
|
||||||
|
final String name = actualFile.getName();
|
||||||
|
final boolean metadata = METADATA.equals(name);
|
||||||
|
if (metadata || PKG_INFO.equals(name)) {
|
||||||
|
final File parent = actualFile.getParentFile();
|
||||||
|
final String parentName = parent.getName();
|
||||||
|
dependency.setDisplayFileName(parentName + "/" + name);
|
||||||
|
if (parent.isDirectory()
|
||||||
|
&& (metadata && parentName.endsWith(".dist-info")
|
||||||
|
|| parentName.endsWith(".egg-info") || "EGG-INFO"
|
||||||
|
.equals(parentName))) {
|
||||||
|
collectWheelMetadata(dependency, actualFile);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Collects the meta data from an archive.
|
||||||
|
*
|
||||||
|
* @param dependency the archive being scanned
|
||||||
|
* @param folderFilter the filter to apply to the folder
|
||||||
|
* @param metadataFilter the filter to apply to the meta data
|
||||||
|
* @throws AnalysisException thrown when there is a problem analyzing the
|
||||||
|
* dependency
|
||||||
|
*/
|
||||||
|
private void collectMetadataFromArchiveFormat(Dependency dependency,
|
||||||
|
FilenameFilter folderFilter, FilenameFilter metadataFilter)
|
||||||
|
throws AnalysisException {
|
||||||
|
final File temp = getNextTempDirectory();
|
||||||
|
LOGGER.debug("{} exists? {}", temp, temp.exists());
|
||||||
|
try {
|
||||||
|
ExtractionUtil.extractFilesUsingFilter(
|
||||||
|
new File(dependency.getActualFilePath()), temp,
|
||||||
|
metadataFilter);
|
||||||
|
} catch (ExtractionException ex) {
|
||||||
|
throw new AnalysisException(ex);
|
||||||
|
}
|
||||||
|
|
||||||
|
File matchingFile = getMatchingFile(temp, folderFilter);
|
||||||
|
if (matchingFile != null) {
|
||||||
|
matchingFile = getMatchingFile(matchingFile, metadataFilter);
|
||||||
|
if (matchingFile != null) {
|
||||||
|
collectWheelMetadata(dependency, matchingFile);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Makes sure a usable temporary directory is available.
|
||||||
|
*
|
||||||
|
* @throws InitializationException an AnalyzeException is thrown when the
|
||||||
|
* temp directory cannot be created
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
protected void initializeFileTypeAnalyzer() throws InitializationException {
|
||||||
|
try {
|
||||||
|
final File baseDir = Settings.getTempDirectory();
|
||||||
|
tempFileLocation = File.createTempFile("check", "tmp", baseDir);
|
||||||
|
if (!tempFileLocation.delete()) {
|
||||||
|
setEnabled(false);
|
||||||
|
final String msg = String.format(
|
||||||
|
"Unable to delete temporary file '%s'.",
|
||||||
|
tempFileLocation.getAbsolutePath());
|
||||||
|
throw new InitializationException(msg);
|
||||||
|
}
|
||||||
|
if (!tempFileLocation.mkdirs()) {
|
||||||
|
setEnabled(false);
|
||||||
|
final String msg = String.format(
|
||||||
|
"Unable to create directory '%s'.",
|
||||||
|
tempFileLocation.getAbsolutePath());
|
||||||
|
throw new InitializationException(msg);
|
||||||
|
}
|
||||||
|
} catch (IOException ex) {
|
||||||
|
setEnabled(false);
|
||||||
|
throw new InitializationException("Unable to create a temporary file", ex);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Deletes any files extracted from the Wheel during analysis.
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
public void closeAnalyzer() {
|
||||||
|
if (tempFileLocation != null && tempFileLocation.exists()) {
|
||||||
|
LOGGER.debug("Attempting to delete temporary files");
|
||||||
|
final boolean success = FileUtils.delete(tempFileLocation);
|
||||||
|
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");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gathers evidence from the METADATA file.
|
||||||
|
*
|
||||||
|
* @param dependency the dependency being analyzed
|
||||||
|
* @param file a reference to the manifest/properties file
|
||||||
|
*/
|
||||||
|
private static void collectWheelMetadata(Dependency dependency, File file) {
|
||||||
|
final InternetHeaders headers = getManifestProperties(file);
|
||||||
|
addPropertyToEvidence(headers, dependency.getVersionEvidence(),
|
||||||
|
"Version", Confidence.HIGHEST);
|
||||||
|
addPropertyToEvidence(headers, dependency.getProductEvidence(), "Name",
|
||||||
|
Confidence.HIGHEST);
|
||||||
|
final String url = headers.getHeader("Home-page", null);
|
||||||
|
final EvidenceCollection vendorEvidence = dependency
|
||||||
|
.getVendorEvidence();
|
||||||
|
if (StringUtils.isNotBlank(url)) {
|
||||||
|
if (UrlStringUtils.isUrl(url)) {
|
||||||
|
vendorEvidence.addEvidence(METADATA, "vendor", url,
|
||||||
|
Confidence.MEDIUM);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
addPropertyToEvidence(headers, vendorEvidence, "Author", Confidence.LOW);
|
||||||
|
final String summary = headers.getHeader("Summary", null);
|
||||||
|
if (StringUtils.isNotBlank(summary)) {
|
||||||
|
JarAnalyzer
|
||||||
|
.addDescription(dependency, summary, METADATA, "summary");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Adds a value to the evidence collection.
|
||||||
|
*
|
||||||
|
* @param headers the properties collection
|
||||||
|
* @param evidence the evidence collection to add the value
|
||||||
|
* @param property the property name
|
||||||
|
* @param confidence the confidence of the evidence
|
||||||
|
*/
|
||||||
|
private static void addPropertyToEvidence(InternetHeaders headers,
|
||||||
|
EvidenceCollection evidence, String property, Confidence confidence) {
|
||||||
|
final String value = headers.getHeader(property, null);
|
||||||
|
LOGGER.debug("Property: {}, Value: {}", property, value);
|
||||||
|
if (StringUtils.isNotBlank(value)) {
|
||||||
|
evidence.addEvidence(METADATA, property, value, confidence);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns a list of files that match the given filter, this does not
|
||||||
|
* recursively scan the directory.
|
||||||
|
*
|
||||||
|
* @param folder the folder to filter
|
||||||
|
* @param filter the filter to apply to the files in the directory
|
||||||
|
* @return the list of Files in the directory that match the provided filter
|
||||||
|
*/
|
||||||
|
private static File getMatchingFile(File folder, FilenameFilter filter) {
|
||||||
|
File result = null;
|
||||||
|
final File[] matches = folder.listFiles(filter);
|
||||||
|
if (null != matches && 1 == matches.length) {
|
||||||
|
result = matches[0];
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Reads the manifest entries from the provided file.
|
||||||
|
*
|
||||||
|
* @param manifest the manifest
|
||||||
|
* @return the manifest entries
|
||||||
|
*/
|
||||||
|
private static InternetHeaders getManifestProperties(File manifest) {
|
||||||
|
final InternetHeaders result = new InternetHeaders();
|
||||||
|
if (null == manifest) {
|
||||||
|
LOGGER.debug("Manifest file not found.");
|
||||||
|
} else {
|
||||||
|
try (InputStream in = new BufferedInputStream(new FileInputStream(manifest))) {
|
||||||
|
result.load(in);
|
||||||
|
} catch (MessagingException | FileNotFoundException e) {
|
||||||
|
LOGGER.warn(e.getMessage(), e);
|
||||||
|
} catch (IOException ex) {
|
||||||
|
LOGGER.warn(ex.getMessage(), ex);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Retrieves the next temporary destination directory for extracting an
|
||||||
|
* archive.
|
||||||
|
*
|
||||||
|
* @return a directory
|
||||||
|
* @throws AnalysisException thrown if unable to create temporary directory
|
||||||
|
*/
|
||||||
|
private File getNextTempDirectory() throws AnalysisException {
|
||||||
|
File directory;
|
||||||
|
|
||||||
|
// getting an exception for some directories not being able to be
|
||||||
|
// created; might be because the directory already exists?
|
||||||
|
do {
|
||||||
|
final int dirCount = DIR_COUNT.incrementAndGet();
|
||||||
|
directory = new File(tempFileLocation, String.valueOf(dirCount));
|
||||||
|
} while (directory.exists());
|
||||||
|
if (!directory.mkdirs()) {
|
||||||
|
throw new AnalysisException(String.format(
|
||||||
|
"Unable to create temp directory '%s'.",
|
||||||
|
directory.getAbsolutePath()));
|
||||||
|
}
|
||||||
|
return directory;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,318 @@
|
|||||||
|
/*
|
||||||
|
* This file is part of dependency-check-core.
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*
|
||||||
|
* Copyright (c) 2015 Institute for Defense Analyses. All Rights Reserved.
|
||||||
|
*/
|
||||||
|
package org.owasp.dependencycheck.analyzer;
|
||||||
|
|
||||||
|
import org.apache.commons.io.FileUtils;
|
||||||
|
import org.apache.commons.io.filefilter.NameFileFilter;
|
||||||
|
import org.apache.commons.io.filefilter.SuffixFileFilter;
|
||||||
|
import org.owasp.dependencycheck.Engine;
|
||||||
|
import org.owasp.dependencycheck.analyzer.exception.AnalysisException;
|
||||||
|
import org.owasp.dependencycheck.dependency.Confidence;
|
||||||
|
import org.owasp.dependencycheck.dependency.Dependency;
|
||||||
|
import org.owasp.dependencycheck.dependency.EvidenceCollection;
|
||||||
|
import org.owasp.dependencycheck.utils.FileFilterBuilder;
|
||||||
|
import org.owasp.dependencycheck.utils.Settings;
|
||||||
|
import org.owasp.dependencycheck.utils.UrlStringUtils;
|
||||||
|
|
||||||
|
import java.io.File;
|
||||||
|
import java.io.FileFilter;
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.nio.charset.Charset;
|
||||||
|
import java.util.regex.Matcher;
|
||||||
|
import java.util.regex.Pattern;
|
||||||
|
import org.owasp.dependencycheck.exception.InitializationException;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Used to analyze a Python package, and collect information that can be used to
|
||||||
|
* determine the associated CPE.
|
||||||
|
*
|
||||||
|
* @author Dale Visser
|
||||||
|
*/
|
||||||
|
@Experimental
|
||||||
|
public class PythonPackageAnalyzer extends AbstractFileTypeAnalyzer {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Used when compiling file scanning regex patterns.
|
||||||
|
*/
|
||||||
|
private static final int REGEX_OPTIONS = Pattern.DOTALL
|
||||||
|
| Pattern.CASE_INSENSITIVE;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Filename extensions for files to be analyzed.
|
||||||
|
*/
|
||||||
|
private static final String EXTENSIONS = "py";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Pattern for matching the module docstring in a source file.
|
||||||
|
*/
|
||||||
|
private static final Pattern MODULE_DOCSTRING = Pattern.compile(
|
||||||
|
"^(['\\\"]{3})(.*?)\\1", REGEX_OPTIONS);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Matches assignments to version variables in Python source code.
|
||||||
|
*/
|
||||||
|
private static final Pattern VERSION_PATTERN = Pattern.compile(
|
||||||
|
"\\b(__)?version(__)? *= *(['\"]+)(\\d+\\.\\d+.*?)\\3",
|
||||||
|
REGEX_OPTIONS);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Matches assignments to title variables in Python source code.
|
||||||
|
*/
|
||||||
|
private static final Pattern TITLE_PATTERN = compileAssignPattern("title");
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Matches assignments to summary variables in Python source code.
|
||||||
|
*/
|
||||||
|
private static final Pattern SUMMARY_PATTERN = compileAssignPattern("summary");
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Matches assignments to URL/URL variables in Python source code.
|
||||||
|
*/
|
||||||
|
private static final Pattern URI_PATTERN = compileAssignPattern("ur[il]");
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Matches assignments to home page variables in Python source code.
|
||||||
|
*/
|
||||||
|
private static final Pattern HOMEPAGE_PATTERN = compileAssignPattern("home_?page");
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Matches assignments to author variables in Python source code.
|
||||||
|
*/
|
||||||
|
private static final Pattern AUTHOR_PATTERN = compileAssignPattern("author");
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Filter that detects files named "__init__.py".
|
||||||
|
*/
|
||||||
|
private static final FileFilter INIT_PY_FILTER = new NameFileFilter("__init__.py");
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The file filter for python files.
|
||||||
|
*/
|
||||||
|
private static final FileFilter PY_FILTER = new SuffixFileFilter(".py");
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the name of the Python Package Analyzer.
|
||||||
|
*
|
||||||
|
* @return the name of the analyzer
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
public String getName() {
|
||||||
|
return "Python Package Analyzer";
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Tell that we are used for information collection.
|
||||||
|
*
|
||||||
|
* @return INFORMATION_COLLECTION
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
public AnalysisPhase getAnalysisPhase() {
|
||||||
|
return AnalysisPhase.INFORMATION_COLLECTION;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The file filter used to determine which files this analyzer supports.
|
||||||
|
*/
|
||||||
|
private static final FileFilter FILTER = FileFilterBuilder.newInstance().addExtensions(EXTENSIONS).build();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the FileFilter
|
||||||
|
*
|
||||||
|
* @return the FileFilter
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
protected FileFilter getFileFilter() {
|
||||||
|
return FILTER;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* No-op initializer implementation.
|
||||||
|
*
|
||||||
|
* @throws InitializationException never thrown
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
protected void initializeFileTypeAnalyzer() throws InitializationException {
|
||||||
|
// Nothing to do here.
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Utility function to create a regex pattern matcher.
|
||||||
|
*
|
||||||
|
* @param name the value to use when constructing the assignment pattern
|
||||||
|
* @return the compiled Pattern
|
||||||
|
*/
|
||||||
|
private static Pattern compileAssignPattern(String name) {
|
||||||
|
return Pattern.compile(
|
||||||
|
String.format("\\b(__)?%s(__)?\\b *= *(['\"]+)(.*?)\\3", name),
|
||||||
|
REGEX_OPTIONS);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Analyzes python packages and adds evidence to the dependency.
|
||||||
|
*
|
||||||
|
* @param dependency the dependency being analyzed
|
||||||
|
* @param engine the engine being used to perform the scan
|
||||||
|
* @throws AnalysisException thrown if there is an unrecoverable error
|
||||||
|
* analyzing the dependency
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
protected void analyzeDependency(Dependency dependency, Engine engine)
|
||||||
|
throws AnalysisException {
|
||||||
|
final File file = dependency.getActualFile();
|
||||||
|
final File parent = file.getParentFile();
|
||||||
|
final String parentName = parent.getName();
|
||||||
|
if (INIT_PY_FILTER.accept(file)) {
|
||||||
|
//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.HIGHEST);
|
||||||
|
|
||||||
|
final File[] fileList = parent.listFiles(PY_FILTER);
|
||||||
|
if (fileList != null) {
|
||||||
|
for (final File sourceFile : fileList) {
|
||||||
|
analyzeFileContents(dependency, sourceFile);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
engine.getDependencies().remove(dependency);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This should gather information from leading docstrings, file comments,
|
||||||
|
* and assignments to __version__, __title__, __summary__, __uri__, __url__,
|
||||||
|
* __home*page__, __author__, and their all caps equivalents.
|
||||||
|
*
|
||||||
|
* @param dependency the dependency being analyzed
|
||||||
|
* @param file the file name to analyze
|
||||||
|
* @return whether evidence was found
|
||||||
|
* @throws AnalysisException thrown if there is an unrecoverable error
|
||||||
|
*/
|
||||||
|
private boolean analyzeFileContents(Dependency dependency, File file)
|
||||||
|
throws AnalysisException {
|
||||||
|
String contents;
|
||||||
|
try {
|
||||||
|
contents = FileUtils.readFileToString(file, Charset.defaultCharset()).trim();
|
||||||
|
} catch (IOException e) {
|
||||||
|
throw new AnalysisException(
|
||||||
|
"Problem occurred while reading dependency file.", e);
|
||||||
|
}
|
||||||
|
boolean found = false;
|
||||||
|
if (!contents.isEmpty()) {
|
||||||
|
final String source = file.getName();
|
||||||
|
found = gatherEvidence(VERSION_PATTERN, contents, source,
|
||||||
|
dependency.getVersionEvidence(), "SourceVersion",
|
||||||
|
Confidence.MEDIUM);
|
||||||
|
found |= addSummaryInfo(dependency, SUMMARY_PATTERN, 4, contents,
|
||||||
|
source, "summary");
|
||||||
|
if (INIT_PY_FILTER.accept(file)) {
|
||||||
|
found |= addSummaryInfo(dependency, MODULE_DOCSTRING, 2,
|
||||||
|
contents, source, "docstring");
|
||||||
|
}
|
||||||
|
found |= gatherEvidence(TITLE_PATTERN, contents, source,
|
||||||
|
dependency.getProductEvidence(), "SourceTitle",
|
||||||
|
Confidence.LOW);
|
||||||
|
final EvidenceCollection vendorEvidence = dependency
|
||||||
|
.getVendorEvidence();
|
||||||
|
found |= gatherEvidence(AUTHOR_PATTERN, contents, source,
|
||||||
|
vendorEvidence, "SourceAuthor", Confidence.MEDIUM);
|
||||||
|
found |= gatherHomePageEvidence(URI_PATTERN, vendorEvidence,
|
||||||
|
source, "URL", contents);
|
||||||
|
found |= gatherHomePageEvidence(HOMEPAGE_PATTERN,
|
||||||
|
vendorEvidence, source, "HomePage", contents);
|
||||||
|
}
|
||||||
|
return found;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Adds summary information to the dependency
|
||||||
|
*
|
||||||
|
* @param dependency the dependency being analyzed
|
||||||
|
* @param pattern the pattern used to perform analysis
|
||||||
|
* @param group the group from the pattern that indicates the data to use
|
||||||
|
* @param contents the data being analyzed
|
||||||
|
* @param source the source name to use when recording the evidence
|
||||||
|
* @param key the key name to use when recording the evidence
|
||||||
|
* @return true if evidence was collected; otherwise false
|
||||||
|
*/
|
||||||
|
private boolean addSummaryInfo(Dependency dependency, Pattern pattern,
|
||||||
|
int group, String contents, String source, String key) {
|
||||||
|
final Matcher matcher = pattern.matcher(contents);
|
||||||
|
final boolean found = matcher.find();
|
||||||
|
if (found) {
|
||||||
|
JarAnalyzer.addDescription(dependency, matcher.group(group),
|
||||||
|
source, key);
|
||||||
|
}
|
||||||
|
return found;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Collects evidence from the home page URL.
|
||||||
|
*
|
||||||
|
* @param pattern the pattern to match
|
||||||
|
* @param evidence the evidence collection to add the evidence to
|
||||||
|
* @param source the source of the evidence
|
||||||
|
* @param name the name of the evidence
|
||||||
|
* @param contents the home page URL
|
||||||
|
* @return true if evidence was collected; otherwise false
|
||||||
|
*/
|
||||||
|
private boolean gatherHomePageEvidence(Pattern pattern,
|
||||||
|
EvidenceCollection evidence, String source, String name,
|
||||||
|
String contents) {
|
||||||
|
final Matcher matcher = pattern.matcher(contents);
|
||||||
|
boolean found = false;
|
||||||
|
if (matcher.find()) {
|
||||||
|
final String url = matcher.group(4);
|
||||||
|
if (UrlStringUtils.isUrl(url)) {
|
||||||
|
found = true;
|
||||||
|
evidence.addEvidence(source, name, url, Confidence.MEDIUM);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return found;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gather evidence from a Python source file using the given string
|
||||||
|
* assignment regex pattern.
|
||||||
|
*
|
||||||
|
* @param pattern to scan contents with
|
||||||
|
* @param contents of Python source file
|
||||||
|
* @param source for storing evidence
|
||||||
|
* @param evidence to store evidence in
|
||||||
|
* @param name of evidence
|
||||||
|
* @param confidence in evidence
|
||||||
|
* @return whether evidence was found
|
||||||
|
*/
|
||||||
|
private boolean gatherEvidence(Pattern pattern, String contents,
|
||||||
|
String source, EvidenceCollection evidence, String name,
|
||||||
|
Confidence confidence) {
|
||||||
|
final Matcher matcher = pattern.matcher(contents);
|
||||||
|
final boolean found = matcher.find();
|
||||||
|
if (found) {
|
||||||
|
evidence.addEvidence(source, name, matcher.group(4), confidence);
|
||||||
|
}
|
||||||
|
return found;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected String getAnalyzerEnabledSettingKey() {
|
||||||
|
return Settings.KEYS.ANALYZER_PYTHON_PACKAGE_ENABLED;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,494 @@
|
|||||||
|
/*
|
||||||
|
* 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.io.UnsupportedEncodingException;
|
||||||
|
import java.nio.charset.Charset;
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.HashMap;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Map;
|
||||||
|
|
||||||
|
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.data.nvdcve.DatabaseException;
|
||||||
|
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.exception.InitializationException;
|
||||||
|
import org.owasp.dependencycheck.utils.FileFilterBuilder;
|
||||||
|
import org.owasp.dependencycheck.utils.Settings;
|
||||||
|
import org.slf4j.Logger;
|
||||||
|
import org.slf4j.LoggerFactory;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Used to analyze Ruby Bundler Gemspec.lock files utilizing the 3rd party
|
||||||
|
* bundle-audit tool.
|
||||||
|
*
|
||||||
|
* @author Dale Visser
|
||||||
|
*/
|
||||||
|
@Experimental
|
||||||
|
public class RubyBundleAuditAnalyzer extends AbstractFileTypeAnalyzer {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The logger.
|
||||||
|
*/
|
||||||
|
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<>();
|
||||||
|
final String bundleAuditPath = Settings.getString(Settings.KEYS.ANALYZER_BUNDLE_AUDIT_PATH);
|
||||||
|
File bundleAudit = null;
|
||||||
|
if (bundleAuditPath != null) {
|
||||||
|
bundleAudit = new File(bundleAuditPath);
|
||||||
|
if (!bundleAudit.isFile()) {
|
||||||
|
LOGGER.warn("Supplied `bundleAudit` path is incorrect: " + bundleAuditPath);
|
||||||
|
bundleAudit = null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
args.add(bundleAudit != null && bundleAudit.isFile() ? bundleAudit.getAbsolutePath() : "bundle-audit");
|
||||||
|
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 initialization failure; this error can be ignored if you are not analyzing Ruby. "
|
||||||
|
+ "Otherwise ensure that bundle-audit is installed and the path to bundle audit is correctly specified", ioe);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Initialize the analyzer. In this case, extract GrokAssembly.exe to a
|
||||||
|
* temporary location.
|
||||||
|
*
|
||||||
|
* @throws InitializationException if anything goes wrong
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
public void initializeFileTypeAnalyzer() throws InitializationException {
|
||||||
|
try {
|
||||||
|
cvedb = CveDB.getInstance();
|
||||||
|
} catch (DatabaseException ex) {
|
||||||
|
LOGGER.warn("Exception opening the database");
|
||||||
|
LOGGER.debug("error", ex);
|
||||||
|
setEnabled(false);
|
||||||
|
throw new InitializationException("Error connecting to the database", ex);
|
||||||
|
}
|
||||||
|
// Now, need to see if bundle-audit actually runs from this location.
|
||||||
|
Process process = null;
|
||||||
|
try {
|
||||||
|
process = launchBundleAudit(Settings.getTempDirectory());
|
||||||
|
} catch (AnalysisException ae) {
|
||||||
|
|
||||||
|
setEnabled(false);
|
||||||
|
final String msg = String.format("Exception from bundle-audit process: %s. Disabling %s", ae.getCause(), ANALYZER_NAME);
|
||||||
|
throw new InitializationException(msg, ae);
|
||||||
|
} catch (IOException ex) {
|
||||||
|
setEnabled(false);
|
||||||
|
throw new InitializationException("Unable to create temporary file, the Ruby Bundle Audit Analyzer will be disabled", ex);
|
||||||
|
}
|
||||||
|
|
||||||
|
final int exitValue;
|
||||||
|
try {
|
||||||
|
exitValue = process.waitFor();
|
||||||
|
} catch (InterruptedException ex) {
|
||||||
|
setEnabled(false);
|
||||||
|
final String msg = String.format("Bundle-audit process was interrupted. Disabling %s", ANALYZER_NAME);
|
||||||
|
throw new InitializationException(msg);
|
||||||
|
}
|
||||||
|
if (0 == exitValue) {
|
||||||
|
setEnabled(false);
|
||||||
|
final String msg = String.format("Unexpected exit code from bundle-audit process. Disabling %s: %s", ANALYZER_NAME, exitValue);
|
||||||
|
throw new InitializationException(msg);
|
||||||
|
} else {
|
||||||
|
try (BufferedReader 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 InitializationException("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 InitializationException("Unexpected bundle-audit output.");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} catch (UnsupportedEncodingException ex) {
|
||||||
|
setEnabled(false);
|
||||||
|
throw new InitializationException("Unexpected bundle-audit encoding.", ex);
|
||||||
|
} catch (IOException ex) {
|
||||||
|
setEnabled(false);
|
||||||
|
throw new InitializationException("Unable to read bundle-audit output.", ex);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
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.");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Closes the data source.
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
public void closeAnalyzer() {
|
||||||
|
if (cvedb != null) {
|
||||||
|
cvedb.close();
|
||||||
|
cvedb = null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 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 #analyzeDependency(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 analyzeDependency(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);
|
||||||
|
final int exitValue;
|
||||||
|
try {
|
||||||
|
exitValue = process.waitFor();
|
||||||
|
} catch (InterruptedException ie) {
|
||||||
|
throw new AnalysisException("bundle-audit process interrupted", ie);
|
||||||
|
}
|
||||||
|
if (exitValue < 0 || exitValue > 1) {
|
||||||
|
final String msg = String.format("Unexpected exit code from bundle-audit process; exit code: %s", exitValue);
|
||||||
|
throw new AnalysisException(msg);
|
||||||
|
}
|
||||||
|
try {
|
||||||
|
try (BufferedReader errReader = new BufferedReader(new InputStreamReader(process.getErrorStream(), "UTF-8"))) {
|
||||||
|
while (errReader.ready()) {
|
||||||
|
final String error = errReader.readLine();
|
||||||
|
LOGGER.warn(error);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
try (BufferedReader rdr = new BufferedReader(new InputStreamReader(process.getInputStream(), "UTF-8"))) {
|
||||||
|
processBundlerAuditOutput(dependency, engine, rdr);
|
||||||
|
}
|
||||||
|
} catch (IOException ioe) {
|
||||||
|
LOGGER.warn("bundle-audit 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<>();
|
||||||
|
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 && 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");
|
||||||
|
if (!gemFile.createNewFile()) {
|
||||||
|
throw new IOException("Unable to create temporary gem file");
|
||||||
|
}
|
||||||
|
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,141 @@
|
|||||||
|
/*
|
||||||
|
* 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 IBM Corporation. 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
|
||||||
|
* the {@link org.owasp.dependencycheck.analyzer.AnalysisPhase#PRE_FINDING_ANALYSIS}
|
||||||
|
* {@link DependencyMergingAnalyzer} 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 (https://twitter.com/biancajiang)
|
||||||
|
*/
|
||||||
|
@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 analyzeDependency(Dependency dependency, Engine engine)
|
||||||
|
throws AnalysisException {
|
||||||
|
super.analyzeDependency(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() {
|
||||||
|
@Override
|
||||||
|
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,249 @@
|
|||||||
|
/*
|
||||||
|
* 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.exception.InitializationException;
|
||||||
|
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 InitializationException {
|
||||||
|
// 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 analyzeDependency(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() {
|
||||||
|
@Override
|
||||||
|
public boolean accept(File dir, String name) {
|
||||||
|
return name.contains(VERSION_FILE_NAME);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
if (matchingFiles == null) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
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);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,192 @@
|
|||||||
|
/*
|
||||||
|
* 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 IBM Corporation. All Rights Reserved.
|
||||||
|
*/
|
||||||
|
package org.owasp.dependencycheck.analyzer;
|
||||||
|
|
||||||
|
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;
|
||||||
|
|
||||||
|
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;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This analyzer is used to analyze the SWIFT Package Manager
|
||||||
|
* (https://swift.org/package-manager/). It collects information about a package
|
||||||
|
* from Package.swift files.
|
||||||
|
*
|
||||||
|
* @author Bianca Jiang (https://twitter.com/biancajiang)
|
||||||
|
*/
|
||||||
|
@Experimental
|
||||||
|
public class SwiftPackageManagerAnalyzer extends AbstractFileTypeAnalyzer {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The name of the analyzer.
|
||||||
|
*/
|
||||||
|
private static final String ANALYZER_NAME = "SWIFT Package Manager 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 SPM_FILE_NAME = "Package.swift";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Filter that detects files named "package.json".
|
||||||
|
*/
|
||||||
|
private static final FileFilter SPM_FILE_FILTER = FileFilterBuilder.newInstance().addFilenames(SPM_FILE_NAME).build();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The capture group #1 is the block variable. e.g. "import
|
||||||
|
* PackageDescription let package = Package( name: "Gloss" )"
|
||||||
|
*/
|
||||||
|
private static final Pattern SPM_BLOCK_PATTERN = Pattern.compile("let[^=]+=\\s*Package\\s*\\(\\s*([^)]*)\\s*\\)", Pattern.DOTALL);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the FileFilter
|
||||||
|
*
|
||||||
|
* @return the FileFilter
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
protected FileFilter getFileFilter() {
|
||||||
|
return SPM_FILE_FILTER;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void initializeFileTypeAnalyzer() {
|
||||||
|
// 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_SWIFT_PACKAGE_MANAGER_ENABLED;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void analyzeDependency(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 = SPM_BLOCK_PATTERN.matcher(contents);
|
||||||
|
if (matcher.find()) {
|
||||||
|
final String packageDescription = matcher.group(1);
|
||||||
|
if (packageDescription.isEmpty()) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
final EvidenceCollection product = dependency.getProductEvidence();
|
||||||
|
final EvidenceCollection vendor = dependency.getVendorEvidence();
|
||||||
|
|
||||||
|
//SPM is currently under development for SWIFT 3. Its current metadata includes package name and dependencies.
|
||||||
|
//Future interesting metadata: version, license, homepage, author, summary, etc.
|
||||||
|
final String name = addStringEvidence(product, packageDescription, "name", "name", Confidence.HIGHEST);
|
||||||
|
if (name != null && !name.isEmpty()) {
|
||||||
|
vendor.addEvidence(SPM_FILE_NAME, "name_project", name, Confidence.HIGHEST);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
setPackagePath(dependency);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Extracts evidence from the package description and adds it to the given
|
||||||
|
* evidence collection.
|
||||||
|
*
|
||||||
|
* @param evidences the evidence collection to update
|
||||||
|
* @param packageDescription the text to extract evidence from
|
||||||
|
* @param field the name of the field being searched for
|
||||||
|
* @param fieldPattern the field pattern within the contents to search for
|
||||||
|
* @param confidence the confidence level of the evidence if found
|
||||||
|
* @return the string that was added as evidence
|
||||||
|
*/
|
||||||
|
private String addStringEvidence(EvidenceCollection evidences,
|
||||||
|
String packageDescription, String field, String fieldPattern, Confidence confidence) {
|
||||||
|
String value = "";
|
||||||
|
|
||||||
|
final Matcher matcher = Pattern.compile(
|
||||||
|
String.format("%s *:\\s*\"([^\"]*)", fieldPattern), Pattern.DOTALL).matcher(packageDescription);
|
||||||
|
if (matcher.find()) {
|
||||||
|
value = matcher.group(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (value != null) {
|
||||||
|
value = value.trim();
|
||||||
|
if (value.length() > 0) {
|
||||||
|
evidences.addEvidence(SPM_FILE_NAME, field, value, confidence);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return value;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets the package path on the given dependency.
|
||||||
|
*
|
||||||
|
* @param dep the dependency to update
|
||||||
|
*/
|
||||||
|
private void setPackagePath(Dependency dep) {
|
||||||
|
final File file = new File(dep.getFilePath());
|
||||||
|
final String parent = file.getParent();
|
||||||
|
if (parent != null) {
|
||||||
|
dep.setPackagePath(parent);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,167 @@
|
|||||||
|
/*
|
||||||
|
* 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) 2017 Jeremy Long. All Rights Reserved.
|
||||||
|
*/
|
||||||
|
package org.owasp.dependencycheck.analyzer;
|
||||||
|
|
||||||
|
import java.util.Iterator;
|
||||||
|
import java.util.Objects;
|
||||||
|
import org.owasp.dependencycheck.Engine;
|
||||||
|
import org.owasp.dependencycheck.analyzer.exception.AnalysisException;
|
||||||
|
import org.owasp.dependencycheck.dependency.Dependency;
|
||||||
|
import org.owasp.dependencycheck.dependency.Evidence;
|
||||||
|
import org.owasp.dependencycheck.dependency.EvidenceCollection;
|
||||||
|
import org.owasp.dependencycheck.utils.DependencyVersion;
|
||||||
|
import org.owasp.dependencycheck.utils.Settings;
|
||||||
|
import org.slf4j.Logger;
|
||||||
|
import org.slf4j.LoggerFactory;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This analyzer attempts to filter out erroneous version numbers collected.
|
||||||
|
* Initially, this will focus on JAR files that contain a POM version number
|
||||||
|
* that matches the file name - if identified all other version information will
|
||||||
|
* be removed.
|
||||||
|
*
|
||||||
|
* @author Jeremy Long
|
||||||
|
*/
|
||||||
|
public class VersionFilterAnalyzer extends AbstractAnalyzer {
|
||||||
|
|
||||||
|
//<editor-fold defaultstate="collapsed" desc="Constants">
|
||||||
|
/**
|
||||||
|
* Evidence source.
|
||||||
|
*/
|
||||||
|
private static final String FILE = "file";
|
||||||
|
/**
|
||||||
|
* Evidence source.
|
||||||
|
*/
|
||||||
|
private static final String POM = "pom";
|
||||||
|
/**
|
||||||
|
* Evidence source.
|
||||||
|
*/
|
||||||
|
private static final String NEXUS = "nexus";
|
||||||
|
/**
|
||||||
|
* Evidence source.
|
||||||
|
*/
|
||||||
|
private static final String CENTRAL = "central";
|
||||||
|
/**
|
||||||
|
* Evidence source.
|
||||||
|
*/
|
||||||
|
private static final String MANIFEST = "Manifest";
|
||||||
|
/**
|
||||||
|
* Evidence name.
|
||||||
|
*/
|
||||||
|
private static final String VERSION = "version";
|
||||||
|
/**
|
||||||
|
* Evidence name.
|
||||||
|
*/
|
||||||
|
private static final String IMPLEMENTATION_VERSION = "Implementation-Version";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The name of the analyzer.
|
||||||
|
*/
|
||||||
|
private static final String ANALYZER_NAME = "Version Filter Analyzer";
|
||||||
|
/**
|
||||||
|
* The phase that this analyzer is intended to run in.
|
||||||
|
*/
|
||||||
|
private static final AnalysisPhase ANALYSIS_PHASE = AnalysisPhase.POST_INFORMATION_COLLECTION;
|
||||||
|
|
||||||
|
//</editor-fold>
|
||||||
|
//<editor-fold defaultstate="collapsed" desc="Standard implementation of Analyzer">
|
||||||
|
/**
|
||||||
|
* 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 setting key to determine if the analyzer is enabled.
|
||||||
|
*
|
||||||
|
* @return the key for the analyzer's enabled property
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
protected String getAnalyzerEnabledSettingKey() {
|
||||||
|
return Settings.KEYS.ANALYZER_VERSION_FILTER_ENABLED;
|
||||||
|
}
|
||||||
|
//</editor-fold>
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The Logger for use throughout the class
|
||||||
|
*/
|
||||||
|
private static final Logger LOGGER = LoggerFactory.getLogger(VersionFilterAnalyzer.class);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The HintAnalyzer uses knowledge about a dependency to add additional
|
||||||
|
* information to help in identification of identifiers or vulnerabilities.
|
||||||
|
*
|
||||||
|
* @param dependency The dependency being analyzed
|
||||||
|
* @param engine The scanning engine
|
||||||
|
* @throws AnalysisException is thrown if there is an exception analyzing
|
||||||
|
* the dependency.
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
protected synchronized void analyzeDependency(Dependency dependency, Engine engine) throws AnalysisException {
|
||||||
|
String fileVersion = null;
|
||||||
|
String pomVersion = null;
|
||||||
|
String manifestVersion = null;
|
||||||
|
for (Evidence e : dependency.getVersionEvidence()) {
|
||||||
|
if (FILE.equals(e.getSource()) && VERSION.equals(e.getName())) {
|
||||||
|
fileVersion = e.getValue(Boolean.FALSE);
|
||||||
|
} else if ((NEXUS.equals(e.getSource()) || CENTRAL.equals(e.getSource())
|
||||||
|
|| POM.equals(e.getSource())) && VERSION.equals(e.getName())) {
|
||||||
|
pomVersion = e.getValue(Boolean.FALSE);
|
||||||
|
} else if (MANIFEST.equals(e.getSource()) && IMPLEMENTATION_VERSION.equals(e.getName())) {
|
||||||
|
manifestVersion = e.getValue(Boolean.FALSE);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
//ensure we have at least two not null
|
||||||
|
if (((fileVersion == null ? 0 : 1) + (pomVersion == null ? 0 : 1) + (manifestVersion == null ? 0 : 1)) > 1) {
|
||||||
|
final DependencyVersion dvFile = new DependencyVersion(fileVersion);
|
||||||
|
final DependencyVersion dvPom = new DependencyVersion(pomVersion);
|
||||||
|
final DependencyVersion dvManifest = new DependencyVersion(manifestVersion);
|
||||||
|
final boolean fileMatch = Objects.equals(dvFile, dvPom) || Objects.equals(dvFile, dvManifest);
|
||||||
|
final boolean manifestMatch = Objects.equals(dvManifest, dvPom) || Objects.equals(dvManifest, dvFile);
|
||||||
|
final boolean pomMatch = Objects.equals(dvPom, dvFile) || Objects.equals(dvPom, dvManifest);
|
||||||
|
if (fileMatch || manifestMatch || pomMatch) {
|
||||||
|
LOGGER.debug("filtering evidence from {}", dependency.getFileName());
|
||||||
|
final EvidenceCollection versionEvidence = dependency.getVersionEvidence();
|
||||||
|
final Iterator<Evidence> itr = versionEvidence.iterator();
|
||||||
|
while (itr.hasNext()) {
|
||||||
|
final Evidence e = itr.next();
|
||||||
|
if (!(pomMatch && VERSION.equals(e.getName())
|
||||||
|
&& (NEXUS.equals(e.getSource()) || CENTRAL.equals(e.getSource()) || POM.equals(e.getSource())))
|
||||||
|
&& !(fileMatch && VERSION.equals(e.getName()) && FILE.equals(e.getSource()))
|
||||||
|
&& !(manifestMatch && MANIFEST.equals(e.getSource()) && IMPLEMENTATION_VERSION.equals(e.getName()))) {
|
||||||
|
itr.remove();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -20,13 +20,15 @@ package org.owasp.dependencycheck.analyzer;
|
|||||||
import org.owasp.dependencycheck.analyzer.exception.AnalysisException;
|
import org.owasp.dependencycheck.analyzer.exception.AnalysisException;
|
||||||
import org.owasp.dependencycheck.Engine;
|
import org.owasp.dependencycheck.Engine;
|
||||||
import org.owasp.dependencycheck.dependency.Dependency;
|
import org.owasp.dependencycheck.dependency.Dependency;
|
||||||
import org.owasp.dependencycheck.suppression.SuppressionRule;
|
import org.owasp.dependencycheck.utils.Settings;
|
||||||
|
import org.owasp.dependencycheck.xml.suppression.SuppressionRule;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The suppression analyzer processes an externally defined XML document that complies with the suppressions.xsd schema.
|
* The suppression analyzer processes an externally defined XML document that
|
||||||
* Any identified Vulnerability entries within the dependencies that match will be removed.
|
* complies with the suppressions.xsd schema. Any identified Vulnerability
|
||||||
|
* entries within the dependencies that match will be removed.
|
||||||
*
|
*
|
||||||
* @author Jeremy Long <jeremy.long@owasp.org>
|
* @author Jeremy Long
|
||||||
*/
|
*/
|
||||||
public class VulnerabilitySuppressionAnalyzer extends AbstractSuppressionAnalyzer {
|
public class VulnerabilitySuppressionAnalyzer extends AbstractSuppressionAnalyzer {
|
||||||
|
|
||||||
@@ -59,10 +61,29 @@ public class VulnerabilitySuppressionAnalyzer extends AbstractSuppressionAnalyze
|
|||||||
public AnalysisPhase getAnalysisPhase() {
|
public AnalysisPhase getAnalysisPhase() {
|
||||||
return ANALYSIS_PHASE;
|
return ANALYSIS_PHASE;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* <p>
|
||||||
|
* Returns the setting key to determine if the analyzer is enabled.</p>
|
||||||
|
*
|
||||||
|
* @return the key for the analyzer's enabled property
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
protected String getAnalyzerEnabledSettingKey() {
|
||||||
|
return Settings.KEYS.ANALYZER_VULNERABILITY_SUPPRESSION_ENABLED;
|
||||||
|
}
|
||||||
//</editor-fold>
|
//</editor-fold>
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Analyzes a dependency's vulnerabilities against the configured CVE
|
||||||
|
* suppressions.
|
||||||
|
*
|
||||||
|
* @param dependency the dependency being analyzed
|
||||||
|
* @param engine a reference to the engine orchestrating the analysis
|
||||||
|
* @throws AnalysisException thrown if there is an error during analysis
|
||||||
|
*/
|
||||||
@Override
|
@Override
|
||||||
public void analyze(final Dependency dependency, final Engine engine) throws AnalysisException {
|
protected void analyzeDependency(Dependency dependency, Engine engine) throws AnalysisException {
|
||||||
|
|
||||||
if (getRules() == null || getRules().size() <= 0) {
|
if (getRules() == null || getRules().size() <= 0) {
|
||||||
return;
|
return;
|
||||||
|
|||||||
@@ -20,7 +20,7 @@ package org.owasp.dependencycheck.analyzer.exception;
|
|||||||
/**
|
/**
|
||||||
* An exception thrown when the analysis of a dependency fails.
|
* An exception thrown when the analysis of a dependency fails.
|
||||||
*
|
*
|
||||||
* @author Jeremy Long <jeremy.long@owasp.org>
|
* @author Jeremy Long
|
||||||
*/
|
*/
|
||||||
public class AnalysisException extends Exception {
|
public class AnalysisException extends Exception {
|
||||||
|
|
||||||
|
|||||||
@@ -20,7 +20,7 @@ package org.owasp.dependencycheck.analyzer.exception;
|
|||||||
/**
|
/**
|
||||||
* An exception thrown when files in an archive cannot be extracted.
|
* An exception thrown when files in an archive cannot be extracted.
|
||||||
*
|
*
|
||||||
* @author Jeremy Long <jeremy.long@owasp.org>
|
* @author Jeremy Long
|
||||||
*/
|
*/
|
||||||
public class ArchiveExtractionException extends Exception {
|
public class ArchiveExtractionException extends Exception {
|
||||||
|
|
||||||
|
|||||||
@@ -1,12 +1,4 @@
|
|||||||
/**
|
/**
|
||||||
* <html>
|
* A collection of exception classes used within the analyzers.
|
||||||
* <head>
|
|
||||||
* <title>org.owasp.dependencycheck.analyzer.exception</title>
|
|
||||||
* </head>
|
|
||||||
* <body>
|
|
||||||
* <p>
|
|
||||||
* A collection of exception classes used within the analyzers.</p>
|
|
||||||
* </body>
|
|
||||||
* </html>
|
|
||||||
*/
|
*/
|
||||||
package org.owasp.dependencycheck.analyzer.exception;
|
package org.owasp.dependencycheck.analyzer.exception;
|
||||||
|
|||||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user