1<?php 2/** 3 * @author Piotr Mrowczynski piotr@owncloud.com 4 * 5 * @copyright Copyright (c) 2019, ownCloud GmbH 6 * @license AGPL-3.0 7 * 8 * This code is free software: you can redistribute it and/or modify 9 * it under the terms of the GNU Affero General Public License, version 3, 10 * as published by the Free Software Foundation. 11 * 12 * This program is distributed in the hope that it will be useful, 13 * but WITHOUT ANY WARRANTY; without even the implied warranty of 14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 15 * GNU Affero General Public License for more details. 16 * 17 * You should have received a copy of the GNU Affero General Public License, version 3, 18 * along with this program. If not, see <http://www.gnu.org/licenses/> 19 * 20 */ 21 22namespace OCA\Files_Sharing; 23 24use OCP\Files\File; 25use OCP\Files\Folder; 26use OCP\Files\Node; 27use OCP\Files\NotFoundException; 28 29/** 30 * Handles restricting for download of files 31 */ 32class ViewOnly { 33 34 /** @var Folder */ 35 private $userFolder; 36 37 public function __construct(Folder $userFolder) { 38 $this->userFolder = $userFolder; 39 } 40 41 /** 42 * @param string[] $pathsToCheck 43 * @return bool 44 */ 45 public function check($pathsToCheck) { 46 // If any of elements cannot be downloaded, prevent whole download 47 foreach ($pathsToCheck as $file) { 48 try { 49 $info = $this->userFolder->get($file); 50 if ($info instanceof File) { 51 // access to filecache is expensive in the loop 52 if (!$this->checkFileInfo($info)) { 53 return false; 54 } 55 } elseif ($info instanceof Folder) { 56 // get directory content is rather cheap query 57 if (!$this->dirRecursiveCheck($info)) { 58 return false; 59 } 60 } 61 } catch (NotFoundException $e) { 62 continue; 63 } 64 } 65 return true; 66 } 67 68 /** 69 * @param Folder $dirInfo 70 * @return bool 71 * @throws NotFoundException 72 */ 73 private function dirRecursiveCheck(Folder $dirInfo) { 74 if (!$this->checkFileInfo($dirInfo)) { 75 return false; 76 } 77 // If any of elements cannot be downloaded, prevent whole download 78 $files = $dirInfo->getDirectoryListing(); 79 foreach ($files as $file) { 80 if ($file instanceof File) { 81 if (!$this->checkFileInfo($file)) { 82 return false; 83 } 84 } elseif ($file instanceof Folder) { 85 return $this->dirRecursiveCheck($file); 86 } 87 } 88 89 return true; 90 } 91 92 /** 93 * @param Node $fileInfo 94 * @return bool 95 * @throws NotFoundException 96 */ 97 private function checkFileInfo(Node $fileInfo) { 98 // Restrict view-only to nodes which are shared 99 $storage = $fileInfo->getStorage(); 100 if (!$storage->instanceOfStorage(SharedStorage::class)) { 101 return true; 102 } 103 104 // Extract extra permissions 105 /** @var \OCA\Files_Sharing\SharedStorage $storage */ 106 '@phan-var \OCA\Files_Sharing\SharedStorage $storage'; 107 $share = $storage->getShare(); 108 109 // Check if read-only and on whether permission can download is both set and disabled. 110 111 $canDownload = $share->getAttributes()->getAttribute('permissions', 'download'); 112 if ($canDownload !== null && !$canDownload) { 113 return false; 114 } 115 return true; 116 } 117} 118