This project does not seem to handle request data directly as such no vulnerable execution paths were found.
include
, or for example
via PHP's auto-loading mechanism.
These results are based on our legacy PHP analysis, consider migrating to our new PHP analysis engine instead. Learn more
1 | <?php |
||
2 | |||
3 | namespace Kunstmaan\AdminBundle\Helper\VersionCheck; |
||
4 | |||
5 | use Doctrine\Common\Cache\Cache; |
||
6 | use Doctrine\Common\Cache\CacheProvider; |
||
7 | use Exception; |
||
8 | use GuzzleHttp\Client; |
||
9 | use Kunstmaan\AdminBundle\Helper\VersionCheck\Exception\ParseException; |
||
10 | use Symfony\Component\Cache\Adapter\AdapterInterface; |
||
11 | use Symfony\Component\Cache\Adapter\DoctrineAdapter; |
||
12 | use Symfony\Component\DependencyInjection\ContainerInterface; |
||
13 | use Symfony\Component\Translation\TranslatorInterface as LegacyTranslatorInterface; |
||
14 | use Symfony\Contracts\Translation\TranslatorInterface; |
||
15 | |||
16 | /** |
||
17 | * Version checker |
||
18 | */ |
||
19 | class VersionChecker |
||
20 | { |
||
21 | public const CACHE_KEY = 'version_check'; |
||
22 | |||
23 | /** |
||
24 | * @var ContainerInterface |
||
25 | */ |
||
26 | private $container; |
||
27 | |||
28 | /** |
||
29 | * @var AdapterInterface |
||
30 | */ |
||
31 | private $cache; |
||
32 | |||
33 | /** |
||
34 | * @var string |
||
35 | */ |
||
36 | private $webserviceUrl; |
||
37 | |||
38 | /** |
||
39 | * @var int |
||
40 | */ |
||
41 | private $cacheTimeframe; |
||
42 | |||
43 | /** |
||
44 | * @var bool |
||
45 | */ |
||
46 | private $enabled; |
||
47 | |||
48 | /** |
||
49 | * @var Client |
||
50 | */ |
||
51 | private $client; |
||
52 | |||
53 | /** |
||
54 | * @var TranslatorInterface|LegacyTranslatorInterface |
||
55 | */ |
||
56 | private $translator; |
||
57 | |||
58 | /** |
||
59 | 7 | * @param CacheProvider|AdapterInterface $cache |
|
60 | */ |
||
61 | 7 | public function __construct(ContainerInterface $container, /* AdapterInterface */$cache, $translator) |
|
62 | 7 | { |
|
63 | $this->container = $container; |
||
64 | |||
65 | 7 | if (!$cache instanceof CacheProvider && !$cache instanceof AdapterInterface) { |
|
66 | // NEXT_MAJOR Add AdapterInterface typehint for the $cache parameter |
||
67 | throw new \InvalidArgumentException(sprintf('The "$cache" parameter should extend from "%s" or implement "%s"', CacheProvider::class, AdapterInterface::class)); |
||
68 | } |
||
69 | 7 | ||
70 | $this->cache = $cache; |
||
71 | 7 | if ($cache instanceof CacheProvider) { |
|
72 | 7 | @trigger_error(sprintf('Passing an instance of "%s" as the second argument in "%s" is deprecated since KunstmaanAdminBundle 5.7 and an instance of "%s" will be required in KunstmaanAdminBundle 6.0.', CacheProvider::class, __METHOD__, AdapterInterface::class), E_USER_DEPRECATED); |
|
0 ignored issues
–
show
|
|||
73 | 7 | ||
74 | 7 | $this->cache = new DoctrineAdapter($cache); |
|
75 | } |
||
76 | |||
77 | // NEXT_MAJOR Add "Symfony\Contracts\Translation\TranslatorInterface" typehint when sf <4.4 support is removed. |
||
78 | if (!$translator instanceof TranslatorInterface && !$translator instanceof LegacyTranslatorInterface) { |
||
79 | throw new \InvalidArgumentException(sprintf('The "$translator" parameter should be instance of "%s" or "%s"', TranslatorInterface::class, LegacyTranslatorInterface::class)); |
||
80 | } |
||
81 | 7 | ||
82 | $this->translator = $translator; |
||
83 | 7 | ||
84 | $this->webserviceUrl = $this->container->getParameter('version_checker.url'); |
||
85 | $this->cacheTimeframe = $this->container->getParameter('version_checker.timeframe'); |
||
86 | $this->enabled = $this->container->getParameter('version_checker.enabled'); |
||
87 | } |
||
88 | |||
89 | /** |
||
90 | * Check that the version check is enabled. |
||
91 | 1 | * |
|
92 | * @return bool |
||
93 | 1 | */ |
|
94 | public function isEnabled() |
||
95 | { |
||
96 | return $this->enabled; |
||
97 | 1 | } |
|
98 | 1 | ||
99 | /** |
||
100 | * Check if we recently did a version check, if not do one now. |
||
101 | 1 | * |
|
102 | * @throws ParseException |
||
103 | */ |
||
104 | public function periodicallyCheck() |
||
105 | { |
||
106 | if (!$this->isEnabled()) { |
||
107 | return; |
||
108 | } |
||
109 | |||
110 | 5 | $cacheItem = $this->cache->getItem(self::CACHE_KEY); |
|
111 | if (!$cacheItem->isHit() || !\is_array($cacheItem->get())) { |
||
112 | 5 | $this->check(); |
|
113 | } |
||
114 | } |
||
115 | |||
116 | 5 | /** |
|
117 | 5 | * Get the version details via webservice. |
|
118 | 5 | * |
|
119 | 5 | * @return mixed a list of bundles if available |
|
120 | 2 | * |
|
121 | * @throws ParseException |
||
122 | 2 | */ |
|
123 | 2 | public function check() |
|
124 | 2 | { |
|
125 | 2 | if (!$this->isEnabled()) { |
|
126 | 2 | return; |
|
127 | } |
||
128 | |||
129 | $host = $this->container->get('request_stack')->getCurrentRequest()->getHttpHost(); |
||
130 | 2 | $console = realpath($this->container->get('kernel')->getProjectDir().'/bin/console'); |
|
131 | 2 | $installed = filectime($console); |
|
132 | 1 | $bundles = $this->parseComposer(); |
|
133 | 1 | $title = $this->container->getParameter('kunstmaan_admin.website_title'); |
|
134 | |||
135 | 1 | $jsonData = json_encode(array( |
|
136 | 'host' => $host, |
||
137 | 'installed' => $installed, |
||
138 | 'bundles' => $bundles, |
||
139 | 'project' => $this->translator->trans($title), |
||
140 | 1 | )); |
|
141 | |||
142 | 1 | try { |
|
143 | 1 | $client = $this->getClient(); |
|
144 | $response = $client->post($this->webserviceUrl, ['body' => $jsonData]); |
||
145 | 1 | $contents = $response->getBody()->getContents(); |
|
146 | $data = json_decode($contents); |
||
147 | |||
148 | if (null === $data) { |
||
149 | return false; |
||
150 | } |
||
151 | |||
152 | 1 | // Save the result in the cache to make sure we don't do the check too often |
|
153 | $cacheItem = $this->cache->getItem(self::CACHE_KEY); |
||
154 | 1 | $cacheItem->expiresAfter($this->cacheTimeframe); |
|
155 | 1 | $cacheItem->set($data); |
|
156 | |||
157 | $this->cache->save($cacheItem); |
||
158 | 1 | ||
159 | return $data; |
||
160 | } catch (Exception $e) { |
||
161 | // We did not receive valid json |
||
162 | return false; |
||
163 | } |
||
164 | } |
||
165 | |||
166 | /** |
||
167 | * @return Client |
||
168 | */ |
||
169 | public function getClient() |
||
170 | { |
||
171 | if (!$this->client) { |
||
172 | $this->client = new Client(array('connect_timeout' => 3, 'timeout' => 1)); |
||
173 | } |
||
174 | |||
175 | return $this->client; |
||
176 | } |
||
177 | |||
178 | /** |
||
179 | * @param Client $client |
||
180 | */ |
||
181 | public function setClient($client) |
||
182 | { |
||
183 | $this->client = $client; |
||
184 | } |
||
185 | |||
186 | /** |
||
187 | * Returns the absolute path to the composer.lock file. |
||
188 | * |
||
189 | 4 | * @return string |
|
190 | */ |
||
191 | 4 | protected function getLockPath() |
|
192 | 4 | { |
|
193 | $kernel = $this->container->get('kernel'); |
||
194 | 4 | $rootPath = $kernel->getProjectDir(); |
|
195 | 4 | ||
196 | 1 | return $rootPath.'/composer.lock'; |
|
197 | } |
||
198 | |||
199 | 3 | /** |
|
200 | 3 | * Returns a list of composer packages. |
|
201 | * |
||
202 | 3 | * @return array |
|
203 | 1 | * |
|
204 | * @throws ParseException |
||
205 | */ |
||
206 | 2 | protected function getPackages() |
|
207 | 1 | { |
|
208 | $translator = $this->container->get('translator'); |
||
209 | $errorMessage = $translator->trans('settings.version.error_parsing_composer'); |
||
210 | |||
211 | 1 | $composerPath = $this->getLockPath(); |
|
212 | if (!file_exists($composerPath)) { |
||
213 | throw new ParseException($translator->trans('settings.version.composer_lock_not_found')); |
||
214 | } |
||
215 | |||
216 | $json = file_get_contents($composerPath); |
||
217 | $result = json_decode($json, true); |
||
218 | |||
219 | if (json_last_error() !== JSON_ERROR_NONE) { |
||
220 | throw new ParseException($errorMessage.' (#'.json_last_error().')'); |
||
221 | 4 | } |
|
222 | |||
223 | 4 | if (\array_key_exists('packages', $result) && \is_array($result['packages'])) { |
|
224 | 4 | return $result['packages']; |
|
225 | 1 | } |
|
226 | 1 | ||
227 | 1 | // No package list in JSON structure |
|
228 | 1 | throw new ParseException($errorMessage); |
|
229 | 1 | } |
|
230 | |||
231 | /** |
||
232 | * Parse the composer.lock file to get the currently used versions of the kunstmaan bundles. |
||
233 | * |
||
234 | 1 | * @return array |
|
235 | * |
||
236 | * @throws ParseException |
||
237 | */ |
||
238 | protected function parseComposer() |
||
239 | { |
||
240 | $bundles = array(); |
||
241 | foreach ($this->getPackages() as $package) { |
||
242 | if (!strncmp($package['name'], 'kunstmaan/', \strlen('kunstmaan/'))) { |
||
243 | $bundles[] = array( |
||
244 | 'name' => $package['name'], |
||
245 | 'version' => $package['version'], |
||
246 | 'reference' => $package['source']['reference'], |
||
247 | ); |
||
248 | } |
||
249 | } |
||
250 | |||
251 | return $bundles; |
||
252 | } |
||
253 | } |
||
254 |
If you suppress an error, we recommend checking for the error condition explicitly: