1
1
<?php
2
2
3
+ use Doctrine \Common \Cache \FilesystemCache ;
4
+ use DrupalComposer \DrupalSecurityAdvisories \Projects ;
5
+ use DrupalComposer \DrupalSecurityAdvisories \UrlHelper ;
6
+ use DrupalComposer \DrupalSecurityAdvisories \VersionParser ;
3
7
use GuzzleHttp \Client ;
4
8
use GuzzleHttp \HandlerStack ;
5
9
use Kevinrob \GuzzleCache \CacheMiddleware ;
6
- use Doctrine \Common \Cache \FilesystemCache ;
7
- use Kevinrob \GuzzleCache \Strategy \PrivateCacheStrategy ;
8
10
use Kevinrob \GuzzleCache \Storage \DoctrineCacheStorage ;
11
+ use Kevinrob \GuzzleCache \Strategy \GreedyCacheStrategy ;
9
12
10
13
require __DIR__ . '/vendor/autoload.php ' ;
11
14
16
19
$ stack = HandlerStack::create ();
17
20
$ stack ->push (
18
21
new CacheMiddleware (
19
- new PrivateCacheStrategy (
22
+ new GreedyCacheStrategy (
20
23
new DoctrineCacheStorage (
21
24
new FilesystemCache (__DIR__ . '/cache ' )
22
- )
25
+ ),
26
+ 3600
23
27
)
24
28
),
25
29
'cache '
26
30
);
27
31
$ client = new Client (['handler ' => $ stack ]);
28
-
29
- $ data = json_decode ($ client ->get ('https://www.drupal.org/api-d7/node.json?type=project_release&taxonomy_vocabulary_7=100&field_release_build_type=static ' )->getBody ());
30
-
31
- $ projects = [];
32
+ $ projects = new Projects ($ client );
32
33
$ conflict = [];
33
34
34
- class UrlHelper {
35
-
36
- public static function prepareUrl ($ url ) {
37
- return str_replace ('https://www.drupal.org/api-d7/node ' , 'https://www.drupal.org/api-d7/node.json ' , $ url );
35
+ /**
36
+ * @param $url
37
+ * @param \GuzzleHttp\Client $client
38
+ *
39
+ * @return array
40
+ */
41
+ function fetchAllData ($ url , Client $ client ) {
42
+ $ results = [];
43
+ $ data = json_decode ($ client ->get ($ url )->getBody ());
44
+ while (isset ($ data ) && isset ($ data ->list )) {
45
+ $ results = array_merge ($ results , $ data ->list );
46
+
47
+ if (isset ($ data ->next )) {
48
+ $ data = json_decode ($ client ->get (UrlHelper::prepareUrl ($ data ->next ))->getBody ());
49
+ }
50
+ else {
51
+ $ data = NULL ;
52
+ }
38
53
}
39
-
54
+ return $ results ;
40
55
}
41
56
42
- class VersionParser {
43
-
44
- public static function getSemVer ($ version , $ isCore ) {
45
- $ version = $ isCore ? static ::handleCore ($ version ) : static ::handleContrib ($ version );
46
- return static ::isValid ($ version ) ? $ version : FALSE ;
47
- }
57
+ // Security releases
58
+ $ results = fetchAllData ('https://www.drupal.org/api-d7/node.json?type=project_release&taxonomy_vocabulary_7=100&field_release_build_type=static ' , $ client );
59
+ foreach ($ results as $ result ) {
60
+ $ nid = $ result ->field_release_project ->id ;
61
+ $ core = (int ) substr ($ result ->field_release_version , 0 , 1 );
48
62
49
- public static function handleCore ($ version ) {
50
- return $ version ;
63
+ // Skip D6 and older.
64
+ if ($ core < 7 ) {
65
+ continue ;
51
66
}
52
67
53
- public static function handleContrib ($ version ) {
54
- list ($ core , $ version ) = explode ('- ' , $ version , 2 );
55
- return $ version ;
56
- }
68
+ $ project = $ projects ->getFromNid ($ nid );
57
69
58
- public static function isValid ($ version ) {
59
- return (strpos ($ version , 'unstable ' ) === FALSE );
70
+ if (!$ project ) {
71
+ // @todo: log error
72
+ continue ;
60
73
}
61
74
62
- }
63
-
64
- while ( isset ( $ data ) && isset ( $ data -> list )) {
65
- $ results = array_merge ( $ results , $ data -> list );
66
-
67
- if ( isset ( $ data -> next )) {
68
- $ data = json_decode ( $ client -> get (UrlHelper:: prepareUrl ( $ data -> next ))-> getBody ()) ;
69
- }
70
- else {
71
- $ data = NULL ;
75
+ try {
76
+ $ is_core = ( $ project -> field_project_machine_name == ' drupal ' ) ? TRUE : FALSE ;
77
+ $ constraint = VersionParser:: generateRangeConstraint ( $ result -> field_release_version , $ is_core );
78
+ if (! $ constraint ) {
79
+ throw new InvalidArgumentException ( ' Invalid version number. ' );
80
+ }
81
+ $ conflict [ $ core ][ ' drupal/ ' . $ project -> field_project_machine_name ][] = $ constraint ;
82
+ } catch ( \ Exception $ e ) {
83
+ // @todo: log exception
84
+ continue ;
72
85
}
73
86
}
74
87
88
+ // Insecure releases
89
+ $ results = fetchAllData ('https://www.drupal.org/api-d7/node.json?type=project_release&taxonomy_vocabulary_7=188131&field_release_build_type=static ' , $ client );
75
90
foreach ($ results as $ result ) {
76
91
$ nid = $ result ->field_release_project ->id ;
77
92
$ core = (int ) substr ($ result ->field_release_version , 0 , 1 );
@@ -81,24 +96,20 @@ public static function isValid($version) {
81
96
continue ;
82
97
}
83
98
84
- try {
85
- if (!isset ($ projects [$ nid ])) {
86
- $ project = json_decode ($ client ->get ('https://www.drupal.org/api-d7/node.json?nid= ' . $ nid )->getBody ());
87
- $ projects [$ nid ] = $ project ->list [0 ];
88
- }
89
- } catch (\GuzzleHttp \Exception \ServerException $ e ) {
90
- // @todo: log exception
99
+ $ project = $ projects ->getFromNid ($ nid );
100
+
101
+ if (!$ project ) {
102
+ // @todo: log error
91
103
continue ;
92
104
}
93
105
94
106
try {
95
- $ project = $ projects [$ nid ];
96
107
$ is_core = ($ project ->field_project_machine_name == 'drupal ' ) ? TRUE : FALSE ;
97
- $ version = VersionParser::getSemVer ($ result ->field_release_version , $ is_core );
98
- if (!$ version ) {
108
+ $ constraint = VersionParser::generateExplicitConstraint ($ result ->field_release_version , $ is_core );
109
+ if (!$ constraint ) {
99
110
throw new InvalidArgumentException ('Invalid version number. ' );
100
111
}
101
- $ conflict [$ core ]['drupal/ ' . $ project ->field_project_machine_name ][] = ' < ' . $ version ;
112
+ $ conflict [$ core ]['drupal/ ' . $ project ->field_project_machine_name ][] = $ constraint ;
102
113
} catch (\Exception $ e ) {
103
114
// @todo: log exception
104
115
continue ;
@@ -121,7 +132,7 @@ public static function isValid($version) {
121
132
122
133
foreach ($ packages as $ package => $ constraints ) {
123
134
natsort ($ constraints );
124
- $ composer ['conflict ' ][$ package ] = implode (', ' , $ constraints );
135
+ $ composer ['conflict ' ][$ package ] = implode ('| ' , $ constraints );
125
136
}
126
137
127
138
// drupal/core is a subtree split for drupal/drupal and has no own SAs.
0 commit comments