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 | /** |
||
4 | * Moodle component manager. |
||
5 | * |
||
6 | * @author Luke Carrier <[email protected]> |
||
7 | * @copyright 2016 Luke Carrier |
||
8 | * @license GPL-3.0+ |
||
9 | */ |
||
10 | |||
11 | namespace ComponentManager\PackageSource; |
||
12 | |||
13 | use ComponentManager\Component; |
||
14 | use ComponentManager\ComponentSource\ZipComponentSource; |
||
15 | use ComponentManager\ComponentVersion; |
||
16 | use ComponentManager\Exception\InstallationFailureException; |
||
17 | use ComponentManager\ResolvedComponentVersion; |
||
18 | use GuzzleHttp\Client; |
||
19 | use GuzzleHttp\Exception\GuzzleException; |
||
20 | use Psr\Log\LoggerInterface; |
||
21 | use Symfony\Component\Filesystem\Filesystem; |
||
22 | use Symfony\Component\HttpFoundation\Request; |
||
23 | use ZipArchive; |
||
24 | |||
25 | /** |
||
26 | * Zip package source. |
||
27 | * |
||
28 | * Obtains a zip archive from the specified URL and extracts the archive to a |
||
29 | * temporary directory. |
||
30 | */ |
||
31 | class ZipPackageSource extends AbstractPackageSource |
||
32 | implements PackageSource { |
||
33 | /** |
||
34 | * Archive filename format. |
||
35 | * |
||
36 | * @var string |
||
37 | */ |
||
38 | const ARCHIVE_FILENAME_FORMAT = '%s-%s.zip'; |
||
39 | |||
40 | /** |
||
41 | * Target directory format. |
||
42 | * |
||
43 | * @var string |
||
44 | */ |
||
45 | const TARGET_DIRECTORY_FORMAT = '%s-%s'; |
||
46 | |||
47 | /** |
||
48 | * Download the specified file to the specified local filename. |
||
49 | * |
||
50 | * @param string $uri |
||
51 | * @param string $filename |
||
52 | * |
||
53 | * @return void |
||
54 | */ |
||
55 | protected function download($uri, $filename) { |
||
56 | $message = $this->httpClient->createRequest( |
||
57 | Request::METHOD_GET, $uri); |
||
58 | $response = $this->httpClient->sendRequest($message); |
||
59 | file_put_contents($filename, $response->getBody()); |
||
60 | } |
||
61 | |||
62 | /** |
||
63 | * @inheritdoc PackageSource |
||
64 | */ |
||
65 | public function getId() { |
||
66 | return 'Zip'; |
||
67 | } |
||
68 | |||
69 | /** |
||
70 | * @inheritdoc PackageSource |
||
71 | */ |
||
72 | public function getName() { |
||
73 | return 'Zip'; |
||
74 | } |
||
75 | |||
76 | /** |
||
77 | * Get archive filename. |
||
78 | * |
||
79 | * @param Component $component |
||
80 | * @param ComponentVersion $version |
||
81 | * |
||
82 | * @return string |
||
83 | */ |
||
84 | protected function getArchiveFilename(Component $component, |
||
85 | ComponentVersion $version) { |
||
86 | return sprintf(static::ARCHIVE_FILENAME_FORMAT, $component->getName(), |
||
87 | $version->getVersion()); |
||
88 | } |
||
89 | |||
90 | /** |
||
91 | * Get target directory. |
||
92 | * |
||
93 | * @param Component $component |
||
94 | * @param ComponentVersion $version |
||
95 | * |
||
96 | * @return string |
||
97 | */ |
||
98 | protected function getTargetDirectory(Component $component, |
||
99 | ComponentVersion $version) { |
||
100 | return sprintf(static::TARGET_DIRECTORY_FORMAT, $component->getName(), |
||
101 | $version->getVersion()); |
||
102 | } |
||
103 | |||
104 | /** |
||
105 | * @inheritdoc PackageSource |
||
106 | */ |
||
107 | public function obtainPackage($tempDirectory, $timeout, |
||
108 | ResolvedComponentVersion $resolvedComponentVersion, |
||
109 | Filesystem $filesystem, |
||
110 | LoggerInterface $logger) { |
||
111 | $component = $resolvedComponentVersion->getComponent(); |
||
112 | $version = $resolvedComponentVersion->getVersion(); |
||
113 | $sources = $version->getSources(); |
||
114 | |||
115 | $finalVersion = $resolvedComponentVersion->getFinalVersion(); |
||
116 | if ($finalVersion !== null) { |
||
117 | $source = new ZipComponentSource( |
||
118 | $finalVersion->archiveUri, $finalVersion->md5Checksum); |
||
119 | $logger->info('Installing pinned version', [ |
||
120 | 'archiveUri' => $finalVersion->archiveUri, |
||
121 | 'md5Checksum' => $finalVersion->md5Checksum, |
||
122 | ]); |
||
123 | |||
124 | return $this->trySource($tempDirectory, $logger, $component, $version, $source); |
||
125 | } else { |
||
126 | foreach ($sources as $source) { |
||
127 | if ($source instanceof ZipComponentSource) { |
||
128 | $moduleRootDirectory = $this->trySource( |
||
129 | $tempDirectory, $logger, $component, $version, |
||
130 | $source); |
||
131 | |||
132 | $resolvedComponentVersion->setFinalVersion((object) [ |
||
133 | 'archiveUri' => $source->getArchiveUri(), |
||
134 | 'md5Checksum' => $source->getMd5Checksum(), |
||
135 | ]); |
||
136 | |||
137 | return $moduleRootDirectory; |
||
138 | } else { |
||
139 | $logger->debug('Cannot accept component source; skipping', [ |
||
140 | 'componentSource' => $source, |
||
141 | ]); |
||
142 | } |
||
143 | } |
||
144 | } |
||
145 | |||
146 | throw new InstallationFailureException( |
||
147 | 'No zip component sources found', |
||
148 | InstallationFailureException::CODE_SOURCE_UNAVAILABLE); |
||
149 | } |
||
150 | |||
151 | /** |
||
152 | * Verify that the specified file has the specified checksum. |
||
153 | * |
||
154 | * @param string $archiveFilename |
||
155 | * @param string $checksum |
||
156 | * |
||
157 | * @return boolean |
||
158 | */ |
||
159 | protected function verifyChecksum($archiveFilename, $checksum) { |
||
160 | return strtolower(md5_file($archiveFilename)) === strtolower($checksum); |
||
161 | } |
||
162 | |||
163 | /** |
||
164 | * Try the given source. |
||
165 | * |
||
166 | * @param string $tempDirectory |
||
167 | * @param LoggerInterface $logger |
||
168 | * @param Component $component |
||
169 | * @param ComponentVersion $version |
||
170 | * @param ZipComponentSource $source |
||
171 | * |
||
172 | * @return string |
||
173 | * |
||
174 | * @throws InstallationFailureException |
||
175 | */ |
||
176 | protected function trySource($tempDirectory, LoggerInterface $logger, |
||
177 | Component $component, ComponentVersion $version, |
||
178 | ZipComponentSource $source) { |
||
179 | $archiveFilename = $this->platform->joinPaths([ |
||
180 | $tempDirectory, |
||
181 | $this->getArchiveFilename($component, $version), |
||
182 | ]); |
||
183 | $targetDirectory = $this->platform->joinPaths([ |
||
184 | $tempDirectory, |
||
185 | $this->getTargetDirectory($component, $version), |
||
186 | ]); |
||
187 | |||
188 | $logger->debug('Trying zip source', [ |
||
189 | 'archiveFilename' => $archiveFilename, |
||
190 | 'archiveUri' => $source->getArchiveUri(), |
||
191 | 'md5Checksum' => $source->getMd5Checksum(), |
||
192 | 'targetDirectory' => $targetDirectory, |
||
193 | ]); |
||
194 | |||
195 | try { |
||
196 | $this->download($source->getArchiveUri(), $archiveFilename); |
||
197 | } catch (GuzzleException $e) { |
||
198 | throw new InstallationFailureException( |
||
199 | $e->getMessage(), |
||
200 | InstallationFailureException::CODE_SOURCE_UNAVAILABLE, |
||
201 | $e); |
||
202 | } |
||
203 | |||
204 | $checksum = $source->getMd5Checksum(); |
||
205 | if (!$this->verifyChecksum($archiveFilename, $checksum)) { |
||
206 | throw new InstallationFailureException( |
||
207 | "{$archiveFilename} didn't match checksum {$checksum}", |
||
0 ignored issues
–
show
As per coding-style, please use concatenation or
sprintf for the variable $checksum instead of interpolation.
It is generally a best practice as it is often more readable to use concatenation instead of interpolation for variables inside strings. // Instead of
$x = "foo $bar $baz";
// Better use either
$x = "foo " . $bar . " " . $baz;
$x = sprintf("foo %s %s", $bar, $baz);
![]() |
|||
208 | InstallationFailureException::CODE_INVALID_SOURCE_CHECKSUM); |
||
209 | } |
||
210 | |||
211 | $archive = new ZipArchive(); |
||
212 | $archive->open($archiveFilename); |
||
213 | if (!$archive->extractTo($targetDirectory)) { |
||
214 | throw new InstallationFailureException( |
||
215 | "Unable to extract archive {$archiveFilename} to {$targetDirectory}", |
||
0 ignored issues
–
show
As per coding-style, please use concatenation or
sprintf for the variable $archiveFilename instead of interpolation.
It is generally a best practice as it is often more readable to use concatenation instead of interpolation for variables inside strings. // Instead of
$x = "foo $bar $baz";
// Better use either
$x = "foo " . $bar . " " . $baz;
$x = sprintf("foo %s %s", $bar, $baz);
![]() As per coding-style, please use concatenation or
sprintf for the variable $targetDirectory instead of interpolation.
It is generally a best practice as it is often more readable to use concatenation instead of interpolation for variables inside strings. // Instead of
$x = "foo $bar $baz";
// Better use either
$x = "foo " . $bar . " " . $baz;
$x = sprintf("foo %s %s", $bar, $baz);
![]() |
|||
216 | InstallationFailureException::CODE_EXTRACTION_FAILED); |
||
217 | } |
||
218 | |||
219 | $moduleRootDirectory = $this->platform->joinPaths([ |
||
220 | $targetDirectory, |
||
221 | $component->getPluginName(), |
||
222 | ]); |
||
223 | if (!is_dir($moduleRootDirectory)) { |
||
224 | throw new InstallationFailureException( |
||
225 | "Module directory {$moduleRootDirectory} did not exist", |
||
0 ignored issues
–
show
As per coding-style, please use concatenation or
sprintf for the variable $moduleRootDirectory instead of interpolation.
It is generally a best practice as it is often more readable to use concatenation instead of interpolation for variables inside strings. // Instead of
$x = "foo $bar $baz";
// Better use either
$x = "foo " . $bar . " " . $baz;
$x = sprintf("foo %s %s", $bar, $baz);
![]() |
|||
226 | InstallationFailureException::CODE_SOURCE_MISSING); |
||
227 | } |
||
228 | return $moduleRootDirectory; |
||
229 | } |
||
230 | } |
||
231 |
It is generally a best practice as it is often more readable to use concatenation instead of interpolation for variables inside strings.