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 | declare (strict_types = 1); |
||
3 | /** |
||
4 | * @copyright Copyright (c) 2018 John Molakvoæ <[email protected]> |
||
5 | * |
||
6 | * @author John Molakvoæ <[email protected]> |
||
7 | * |
||
8 | * @license GNU AGPL version 3 or any later version |
||
9 | * |
||
10 | * This program is free software: you can redistribute it and/or modify |
||
11 | * it under the terms of the GNU Affero General Public License as |
||
12 | * published by the Free Software Foundation, either version 3 of the |
||
13 | * License, or (at your option) any later version. |
||
14 | * |
||
15 | * This program is distributed in the hope that it will be useful, |
||
16 | * but WITHOUT ANY WARRANTY; without even the implied warranty of |
||
17 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
||
18 | * GNU Affero General Public License for more details. |
||
19 | * |
||
20 | * You should have received a copy of the GNU Affero General Public License |
||
21 | * along with this program. If not, see <http://www.gnu.org/licenses/>. |
||
22 | * |
||
23 | */ |
||
24 | |||
25 | namespace OCA\Richdocuments; |
||
26 | |||
27 | use OCP\Files\File; |
||
28 | use OCP\Files\Folder; |
||
29 | use OCP\Files\IAppData; |
||
30 | use OCP\Files\IRootFolder; |
||
31 | use OCP\Files\Node; |
||
32 | use OCP\Files\NotFoundException; |
||
33 | use OCP\IConfig; |
||
34 | use OCP\IL10N; |
||
35 | use OCP\IPreview; |
||
36 | use OCP\IURLGenerator; |
||
37 | use OC\Files\AppData\Factory; |
||
38 | |||
39 | class TemplateManager { |
||
40 | |||
41 | /** @var string */ |
||
42 | protected $appName; |
||
43 | |||
44 | /** @var string */ |
||
45 | protected $userId; |
||
46 | |||
47 | /** @var IConfig */ |
||
48 | private $config; |
||
49 | |||
50 | /** @var IURLGenerator */ |
||
51 | private $urlGenerator; |
||
52 | |||
53 | /** @var IRootFolder */ |
||
54 | private $rootFolder; |
||
55 | |||
56 | /** @var IL10N */ |
||
57 | private $l; |
||
58 | |||
59 | /** Accepted templates mime types */ |
||
60 | const MIMES_DOCUMENTS = [ |
||
61 | 'application/vnd.oasis.opendocument.text-template', |
||
62 | 'application/vnd.openxmlformats-officedocument.wordprocessingml.template', |
||
63 | 'application/msword' |
||
64 | ]; |
||
65 | const MIMES_SHEETS = [ |
||
66 | 'application/vnd.oasis.opendocument.spreadsheet-template', |
||
67 | 'application/vnd.openxmlformats-officedocument.spreadsheetml.template', |
||
68 | 'application/vnd.ms-excel' |
||
69 | ]; |
||
70 | const MIMES_PRESENTATIONS = [ |
||
71 | 'application/vnd.oasis.opendocument.presentation-template', |
||
72 | 'application/vnd.openxmlformats-officedocument.presentationml.template', |
||
73 | 'application/vnd.ms-powerpoint' |
||
74 | ]; |
||
75 | |||
76 | /** @var array Template mime types match */ |
||
77 | static public $tplTypes = [ |
||
78 | 'document' => self::MIMES_DOCUMENTS, |
||
79 | 'spreadsheet' => self::MIMES_SHEETS, |
||
80 | 'presentation' => self::MIMES_PRESENTATIONS |
||
81 | ]; |
||
82 | |||
83 | const TYPE_EXTENTION = [ |
||
84 | 'document' => 'odt', |
||
85 | 'spreadsheet' => 'ods', |
||
86 | 'presentation' => 'odp' |
||
87 | ]; |
||
88 | |||
89 | const TYPE_EXTENSION_OOXML = [ |
||
90 | 'document' => 'docx', |
||
91 | 'spreadsheet' => 'xlsx', |
||
92 | 'presentation' => 'pptx' |
||
93 | ]; |
||
94 | |||
95 | const EMPTY_TEMPLATE_ID_TYPE = [ |
||
96 | -1 => 'document', |
||
97 | -2 => 'spreadsheet', |
||
98 | -3 => 'presentation', |
||
99 | ]; |
||
100 | const EMPTY_TEMPLATE_TYPE_ID = [ |
||
101 | 'document' => -1, |
||
102 | 'spreadsheet' => -2, |
||
103 | 'presentation' => -3, |
||
104 | ]; |
||
105 | |||
106 | |||
107 | /** |
||
108 | * Template manager |
||
109 | * |
||
110 | * @param string $appName |
||
111 | * @param string $userId |
||
112 | * @param IConfig $config |
||
113 | * @param Factory $appDataFactory |
||
0 ignored issues
–
show
|
|||
114 | * @param IURLGenerator $urlGenerator |
||
115 | * @param IRootFolder $rootFolder |
||
116 | * @param IL10N $l |
||
117 | * @throws \OCP\Files\NotPermittedException |
||
118 | */ |
||
119 | public function __construct($appName, |
||
120 | $userId, |
||
121 | IConfig $config, |
||
122 | IAppData $appData, |
||
123 | IURLGenerator $urlGenerator, |
||
124 | IRootFolder $rootFolder, |
||
125 | IL10N $l) { |
||
126 | $this->appName = $appName; |
||
127 | $this->userId = $userId; |
||
128 | $this->config = $config; |
||
129 | $this->rootFolder = $rootFolder; |
||
130 | $this->urlGenerator = $urlGenerator; |
||
131 | |||
132 | |||
133 | $this->appData = $appData; |
||
0 ignored issues
–
show
The property
appData does not exist. Did you maybe forget to declare it?
In PHP it is possible to write to properties without declaring them. For example, the following is perfectly valid PHP code: class MyClass { }
$x = new MyClass();
$x->foo = true;
Generally, it is a good practice to explictly declare properties to avoid accidental typos and provide IDE auto-completion: class MyClass {
public $foo;
}
$x = new MyClass();
$x->foo = true;
Loading history...
|
|||
134 | $this->createAppDataFolders(); |
||
135 | |||
136 | $this->l = $l; |
||
137 | } |
||
138 | |||
139 | private function createAppDataFolders() { |
||
140 | /* |
||
141 | * Init the appdata folder |
||
142 | * We need an actual folder for the fileid and previews. |
||
143 | * TODO: Fix this at some point |
||
144 | */ |
||
145 | try { |
||
146 | $this->appData->getFolder('templates'); |
||
147 | } catch (NotFoundException $e) { |
||
148 | $this->appData->newFolder('templates'); |
||
149 | } |
||
150 | try { |
||
151 | $this->appData->getFolder('empty_templates'); |
||
152 | } catch (NotFoundException $e) { |
||
153 | $this->appData->newFolder('empty_templates'); |
||
154 | } |
||
155 | } |
||
156 | |||
157 | public function setUserId($userId) { |
||
158 | $this->userId = $userId; |
||
159 | } |
||
160 | |||
161 | /** |
||
162 | * Get template ISimpleFile|Node |
||
163 | * |
||
164 | * @param int $fileId |
||
165 | * @return File |
||
166 | */ |
||
167 | public function get($fileId) { |
||
168 | // is this a global template ? |
||
169 | $files = $this->getEmptyTemplateDir()->getDirectoryListing(); |
||
170 | |||
171 | foreach ($files as $file) { |
||
172 | if ($file->getId() === $fileId) { |
||
173 | return $file; |
||
174 | } |
||
175 | } |
||
176 | |||
177 | // is this a global template ? |
||
178 | $files = $this->getSystemTemplateDir()->getDirectoryListing(); |
||
179 | |||
180 | foreach ($files as $file) { |
||
181 | if ($file->getId() === $fileId) { |
||
182 | return $file; |
||
183 | } |
||
184 | } |
||
185 | |||
186 | $templateDir = $this->getUserTemplateDir(); |
||
187 | // finally get the template file |
||
188 | $files = $templateDir->getById($fileId); |
||
189 | if ($files !== []) { |
||
190 | return $files[0]; |
||
191 | } |
||
192 | |||
193 | throw new NotFoundException(); |
||
194 | } |
||
195 | |||
196 | /** |
||
197 | * @param File[] $templates |
||
198 | * @return File[] |
||
199 | */ |
||
200 | private function filterTemplates($templates, $type = null) { |
||
201 | return array_filter($templates, function (Node $templateFile) use ($type) { |
||
202 | if (!($templateFile instanceof File)) { |
||
203 | return false; |
||
204 | } |
||
205 | |||
206 | return $this->isValidTemplateMime($templateFile->getMimeType(), $type); |
||
207 | }); |
||
208 | } |
||
209 | |||
210 | private function getEmpty($type = null) { |
||
211 | $folder = $this->getEmptyTemplateDir(); |
||
212 | |||
213 | $templateFiles = $folder->getDirectoryListing(); |
||
214 | |||
215 | if ($templateFiles === []) { |
||
216 | // Empty so lets copy over the basic templates |
||
217 | $templates = [ |
||
218 | 'document.ott', |
||
219 | 'spreadsheet.ots', |
||
220 | 'presentation.otp', |
||
221 | ]; |
||
222 | |||
223 | foreach ($templates as $template) { |
||
224 | $file = $folder->newFile($template); |
||
225 | $file->putContent(file_get_contents(__DIR__ . '/../assets/' . $template)); |
||
226 | $templateFiles[] = $file; |
||
227 | } |
||
228 | } |
||
229 | |||
230 | return $this->filterTemplates($templateFiles, $type); |
||
0 ignored issues
–
show
$templateFiles is of type array<integer,object<OCP\Files\Node>> , but the function expects a array<integer,object<OCP\Files\File>> .
It seems like the type of the argument is not accepted by the function/method which you are calling. In some cases, in particular if PHP’s automatic type-juggling kicks in this might be fine. In other cases, however this might be a bug. We suggest to add an explicit type cast like in the following example: function acceptsInteger($int) { }
$x = '123'; // string "123"
// Instead of
acceptsInteger($x);
// we recommend to use
acceptsInteger((integer) $x);
Loading history...
|
|||
231 | } |
||
232 | |||
233 | /** |
||
234 | * Remove empty_templates in appdata and recreate it from the apps templates |
||
235 | */ |
||
236 | public function updateEmptyTemplates() { |
||
237 | try { |
||
238 | $folder = $this->getEmptyTemplateDir(); |
||
239 | $folder->delete(); |
||
240 | } catch (NotFoundException $e) { |
||
0 ignored issues
–
show
Coding Style
Comprehensibility
introduced
by
|
|||
241 | } |
||
242 | $this->appData->newFolder('empty_templates'); |
||
243 | $this->getEmpty(); |
||
244 | } |
||
245 | |||
246 | /** |
||
247 | * Get all global templates |
||
248 | * |
||
249 | * @return File[] |
||
250 | */ |
||
251 | public function getSystem($type = null) { |
||
252 | $folder = $this->getSystemTemplateDir(); |
||
253 | |||
254 | $templateFiles = $folder->getDirectoryListing(); |
||
255 | return $this->filterTemplates($templateFiles, $type); |
||
0 ignored issues
–
show
$templateFiles is of type array<integer,object<OCP\Files\Node>> , but the function expects a array<integer,object<OCP\Files\File>> .
It seems like the type of the argument is not accepted by the function/method which you are calling. In some cases, in particular if PHP’s automatic type-juggling kicks in this might be fine. In other cases, however this might be a bug. We suggest to add an explicit type cast like in the following example: function acceptsInteger($int) { }
$x = '123'; // string "123"
// Instead of
acceptsInteger($x);
// we recommend to use
acceptsInteger((integer) $x);
Loading history...
|
|||
256 | } |
||
257 | |||
258 | /** |
||
259 | * @return array |
||
260 | */ |
||
261 | public function getSystemFormatted($type = null) { |
||
262 | $empty = $this->getEmpty($type); |
||
263 | $system = $this->getSystem($type); |
||
264 | |||
265 | $emptyFormatted = array_map(function(File $file) { |
||
266 | return $this->formatEmpty($file); |
||
267 | }, $empty); |
||
268 | |||
269 | $systemFormatted = array_map(function(File $file) { |
||
270 | return $this->formatNodeReturn($file); |
||
271 | }, $system); |
||
272 | |||
273 | return array_merge($emptyFormatted, $systemFormatted); |
||
274 | } |
||
275 | |||
276 | /** |
||
277 | * Get all user templates |
||
278 | * |
||
279 | * @return File[] |
||
280 | */ |
||
281 | public function getUser($type = null) { |
||
282 | try { |
||
283 | $templateDir = $this->getUserTemplateDir(); |
||
284 | $templateFiles = $templateDir->getDirectoryListing(); |
||
285 | |||
286 | return $this->filterTemplates($templateFiles, $type); |
||
0 ignored issues
–
show
$templateFiles is of type array<integer,object<OCP\Files\Node>> , but the function expects a array<integer,object<OCP\Files\File>> .
It seems like the type of the argument is not accepted by the function/method which you are calling. In some cases, in particular if PHP’s automatic type-juggling kicks in this might be fine. In other cases, however this might be a bug. We suggest to add an explicit type cast like in the following example: function acceptsInteger($int) { }
$x = '123'; // string "123"
// Instead of
acceptsInteger($x);
// we recommend to use
acceptsInteger((integer) $x);
Loading history...
|
|||
287 | } catch(NotFoundException $e) { |
||
288 | return []; |
||
289 | } |
||
290 | } |
||
291 | |||
292 | /** |
||
293 | * @return array |
||
294 | */ |
||
295 | public function getUserFormatted($type) { |
||
296 | $templates = $this->getUser($type); |
||
297 | |||
298 | return array_map(function(File $file) { |
||
299 | return $this->formatNodeReturn($file); |
||
300 | }, $templates); |
||
301 | } |
||
302 | |||
303 | /** |
||
304 | * Get all templates |
||
305 | * |
||
306 | * @return File[] |
||
307 | */ |
||
308 | public function getAll($type = 'document') { |
||
309 | $system = $this->getSystem(); |
||
310 | $user = $this->getUser(); |
||
311 | |||
312 | if (!array_key_exists($type, self::$tplTypes)) { |
||
313 | return []; |
||
314 | } |
||
315 | |||
316 | return array_values(array_filter(array_merge($user, $system), function (File $template) use ($type) { |
||
317 | foreach (self::$tplTypes[$type] as $mime) { |
||
318 | if ($template->getMimeType() === $mime) { |
||
319 | return true; |
||
320 | } |
||
321 | } |
||
322 | return false; |
||
323 | })); |
||
324 | } |
||
325 | |||
326 | public function getAllFormatted($type) { |
||
327 | if (!array_key_exists($type, self::$tplTypes)) { |
||
328 | return []; |
||
329 | } |
||
330 | |||
331 | $system = $this->getSystemFormatted($type); |
||
332 | $user = $this->getUserFormatted($type); |
||
333 | |||
334 | return array_merge($system, $user); |
||
335 | } |
||
336 | |||
337 | /** |
||
338 | * Add a template to the global template folder |
||
339 | * |
||
340 | * @param string $templateName |
||
341 | * @param string $templateFile |
||
342 | * @return array |
||
343 | */ |
||
344 | public function add($templateName, $templateFile) { |
||
345 | $folder = $this->getSystemTemplateDir(); |
||
346 | |||
347 | try { |
||
348 | $template = $folder->get($templateName); |
||
349 | } catch (NotFoundException $e) { |
||
350 | $template = $folder->newFile($templateName); |
||
351 | } |
||
352 | $template->putContent($templateFile); |
||
0 ignored issues
–
show
The method
putContent() does not seem to exist on object<OCP\Files\Node> .
This check looks for calls to methods that do not seem to exist on a given type. It looks for the method on the type itself as well as in inherited classes or implemented interfaces. This is most likely a typographical error or the method has been renamed.
Loading history...
|
|||
353 | |||
354 | return $this->formatNodeReturn($this->get($template->getId())); |
||
355 | } |
||
356 | |||
357 | /** |
||
358 | * Delete a template to the global template folder |
||
359 | * |
||
360 | * @param int $fileId |
||
361 | * @return boolean |
||
362 | * @throws NotFoundException |
||
363 | */ |
||
364 | public function delete($fileId) { |
||
365 | $files = $this->getSystemTemplateDir()->getDirectoryListing(); |
||
366 | foreach ($files as $file) { |
||
367 | if ($file->getId() === $fileId) { |
||
368 | $file->delete(); |
||
369 | return true; |
||
370 | } |
||
371 | } |
||
372 | |||
373 | throw new NotFoundException(); |
||
374 | } |
||
375 | |||
376 | /** |
||
377 | * Flip $tplTypes to retrieve types by mime |
||
378 | * |
||
379 | * @return array |
||
380 | */ |
||
381 | private function flipTypes() { |
||
382 | $result = []; |
||
383 | foreach ($this::$tplTypes as $type => $mime) { |
||
384 | $result = array_merge($result, array_fill_keys($mime, $type)); |
||
385 | } |
||
386 | |||
387 | return $result; |
||
388 | } |
||
389 | |||
390 | /** |
||
391 | * Get the user template directory |
||
392 | * |
||
393 | * @return Folder |
||
394 | * @throws NotFoundException |
||
395 | */ |
||
396 | private function getUserTemplateDir() { |
||
397 | if ($this->userId === null) { |
||
398 | throw new NotFoundException('userId not set'); |
||
399 | } |
||
400 | |||
401 | // has the user manually set a directory as the default template dir ? |
||
402 | $templateDirPath = $this->config->getUserValue($this->userId, $this->appName, 'templateFolder', false); |
||
403 | $userFolder = $this->rootFolder->getUserFolder($this->userId); |
||
404 | |||
405 | if ($templateDirPath !== false) { |
||
406 | $templateDir = $userFolder->get($templateDirPath); |
||
407 | } else { |
||
408 | // fallback to default template dir |
||
409 | try { |
||
410 | $templateDir = $userFolder->get('Templates'); |
||
411 | } catch (NotFoundException $e) { |
||
412 | throw new NotFoundException($e->getMessage()); |
||
413 | } |
||
414 | } |
||
415 | |||
416 | if (!($templateDir instanceof Folder)) { |
||
417 | throw new NotFoundException('Template dir points to a file'); |
||
418 | } |
||
419 | |||
420 | return $templateDir; |
||
421 | } |
||
422 | |||
423 | /** |
||
424 | * @return Folder |
||
425 | */ |
||
426 | private function getSystemTemplateDir() { |
||
427 | $path = 'appdata_' . $this->config->getSystemValue('instanceid', null) . '/richdocuments/templates'; |
||
428 | return $this->rootFolder->get($path); |
||
429 | } |
||
430 | |||
431 | /** |
||
432 | * @return Folder |
||
433 | */ |
||
434 | private function getEmptyTemplateDir() { |
||
435 | $path = 'appdata_' . $this->config->getSystemValue('instanceid', null) . '/richdocuments/empty_templates'; |
||
436 | return $this->rootFolder->get($path); |
||
437 | } |
||
438 | |||
439 | /** |
||
440 | * Format template file for json return object |
||
441 | * |
||
442 | * @param File $template |
||
443 | * @return array |
||
444 | */ |
||
445 | public function formatNodeReturn(File $template) { |
||
446 | $ooxml = $this->config->getAppValue($this->appName, 'doc_format', '') === 'ooxml'; |
||
447 | $documentType = $this->flipTypes()[$template->getMimeType()]; |
||
448 | return [ |
||
449 | 'id' => $template->getId(), |
||
450 | 'name' => $template->getName(), |
||
451 | 'preview' => $this->urlGenerator->linkToRouteAbsolute('richdocuments.templates.getPreview', ['fileId' => $template->getId()]), |
||
452 | 'type' => $this->flipTypes()[$template->getMimeType()], |
||
453 | 'delete' => $this->urlGenerator->linkToRouteAbsolute('richdocuments.templates.delete', ['fileId' => $template->getId()]), |
||
454 | 'extension' => $ooxml ? self::TYPE_EXTENSION_OOXML[$documentType] : self::TYPE_EXTENTION[$documentType], |
||
455 | ]; |
||
456 | } |
||
457 | |||
458 | public function isTemplate($fileId) { |
||
459 | $empty = $this->getEmpty(); |
||
460 | $system = $this->getSystem(); |
||
461 | $user = $this->getUser(); |
||
462 | /** @var File[] $all */ |
||
463 | $all = array_merge($empty, $system, $user); |
||
464 | |||
465 | foreach ($all as $template) { |
||
466 | if ($template->getId() === $fileId) { |
||
467 | return true; |
||
468 | } |
||
469 | } |
||
470 | |||
471 | return false; |
||
472 | } |
||
473 | |||
474 | public function formatEmpty(File $template) { |
||
475 | $ooxml = $this->config->getAppValue($this->appName, 'doc_format', '') === 'ooxml'; |
||
476 | $documentType = $this->flipTypes()[$template->getMimeType()]; |
||
477 | return [ |
||
478 | 'id' => $template->getId(), |
||
479 | 'name' => $this->l->t('Empty'), |
||
480 | 'type' => $this->flipTypes()[$template->getMimeType()], |
||
481 | 'extension' => $ooxml ? self::TYPE_EXTENSION_OOXML[$documentType] : self::TYPE_EXTENTION[$documentType], |
||
482 | ]; |
||
483 | } |
||
484 | |||
485 | public function isValidTemplateMime($mime, $type = null) { |
||
486 | if ($type === null) { |
||
487 | $allMimes = array_merge(self::$tplTypes['document'], self::$tplTypes['spreadsheet'], self::$tplTypes['presentation']); |
||
488 | if (!in_array($mime, $allMimes)) { |
||
489 | return false; |
||
490 | } |
||
491 | } |
||
492 | |||
493 | if ($type !== null && !in_array($mime, self::$tplTypes[$type])) { |
||
494 | return false; |
||
495 | } |
||
496 | |||
497 | return true; |
||
498 | } |
||
499 | } |
||
500 |
This check looks for PHPDoc comments describing methods or function parameters that do not exist on the corresponding method or function. It has, however, found a similar but not annotated parameter which might be a good fit.
Consider the following example. The parameter
$ireland
is not defined by the methodfinale(...)
.The most likely cause is that the parameter was changed, but the annotation was not.