diff --git a/app/controllers/storage.php b/app/controllers/storage.php index a585411ad3..a8c342354f 100644 --- a/app/controllers/storage.php +++ b/app/controllers/storage.php @@ -18,6 +18,7 @@ use Storage\Storage; use Storage\Devices\Local; use Storage\Validators\File; use Storage\Validators\FileSize; +use Storage\Validators\Upload; use Storage\Compression\Algorithms\GZIP; use Resize\Resize; use OpenSSL\OpenSSL; @@ -189,7 +190,7 @@ $utopia->get('/v1/storage/files/:fileId/preview') } if (!Storage::exists($storage)) { - throw new Exception('No such storage device'); + throw new Exception('No such storage device', 400); } if ((strpos($request->getServer('HTTP_ACCEPT'), 'image/webp') === false) && ('webp' == $output)) { // Fallback webp to jpeg when no browser support @@ -209,7 +210,6 @@ $utopia->get('/v1/storage/files/:fileId/preview') $algorithm = $file->getAttribute('algorithm'); $type = strtolower(pathinfo($path, PATHINFO_EXTENSION)); $cipher = $file->getAttribute('fileOpenSSLCipher'); - //$mimeType = $file->getAttribute('mimeType', 'unknown'); $compressor = new GZIP(); $device = Storage::getDevice('local'); @@ -413,10 +413,11 @@ $utopia->post('/v1/storage/files') $write = (empty($write)) ? ['user:'.$user->getUid()] : $write; /* - * Validation + * Validators */ - //$fileType = new FileType(array(FileType::FILE_TYPE_PNG, FileType::FILE_TYPE_GIF, FileType::FILE_TYPE_JPEG)); + //$fileType = new FileType(array(FileType::FILE_TYPE_PNG, FileType::FILE_TYPE_GIF, FileType::FILE_TYPE_JPEG)); $fileSize = new FileSize(2097152 * 2); // 4MB + $upload = new Upload(); if (empty($files)) { throw new Exception('No files sent', 400); @@ -450,11 +451,20 @@ $utopia->post('/v1/storage/files') $device = Storage::getDevice('local'); foreach ($files['tmp_name'] as $i => $tmpName) { + if (!$upload->isValid($tmpName)) { + throw new Exception('Invalid file', 403); + } + // Save to storage $name = $files['name'][$i]; $size = $device->getFileSize($tmpName); - $path = $device->upload($tmpName, $files['name'][$i]); - $mimeType = $device->getFileMimeType($path); + $path = $device->getPath(uniqid().'.'.pathinfo($name, PATHINFO_EXTENSION)); + + if (!$device->upload($tmpName, $path)) { // TODO deprecate 'upload' and replace with 'move' + throw new Exception('Failed moving file', 500); + } + + $mimeType = $device->getFileMimeType($path); // Get mime-type before compression and encryption // Check if file size is exceeding allowed limit if (!$antiVirus->fileScan($path)) { diff --git a/src/Storage/Device.php b/src/Storage/Device.php index 1e841c2d81..facfcdd40a 100644 --- a/src/Storage/Device.php +++ b/src/Storage/Device.php @@ -47,16 +47,16 @@ abstract class Device /** * Upload. * - * Upload a file to desired destination in the selected disk. + * Upload a file to desired destination in the selected disk, return true on success and false on failure. * - * @param string $target - * @param string $filename + * @param string $source + * @param string $path * * @throws \Exception * - * @return string|bool saved destination on success or false on failures + * @return bool */ - abstract public function upload($target, $filename = ''); + abstract public function upload($source, $path):bool; /** * Read file by given path. @@ -78,7 +78,7 @@ abstract class Device abstract public function write(string $path, string $data):bool; /** - * Move file from given source to given path, Return true on success and false on failure. + * Move file from given source to given path, return true on success and false on failure. * * @see http://php.net/manual/en/function.filesize.php * @@ -90,7 +90,7 @@ abstract class Device abstract public function move(string $source, string $target):bool; /** - * Delete file in given path, Return true on success and false on failure. + * Delete file in given path return true on success and false on failure. * * @see http://php.net/manual/en/function.filesize.php * diff --git a/src/Storage/Devices/Local.php b/src/Storage/Devices/Local.php index 27be34f3fa..c3180d2130 100644 --- a/src/Storage/Devices/Local.php +++ b/src/Storage/Devices/Local.php @@ -73,28 +73,19 @@ class Local extends Device * * @return string|bool saved destination on success or false on failures */ - public function upload($target, $filename = '') + public function upload($source, $path):bool { - $filename = (empty($filename)) ? $target : $filename; - $filename = uniqid().'.'.pathinfo($filename, PATHINFO_EXTENSION); - - $path = $this->getPath($filename); - - if (!is_uploaded_file($target)) { - throw new Exception('File is not a valid uploaded file'); - } - if (!file_exists(dirname($path))) { // Checks if directory path to file exists if (!@mkdir(dirname($path), 0755, true)) { - throw new Exception('Can\'t create directory '.dirname($path)); + throw new Exception('Can\'t create directory: '.dirname($path)); } } - if (move_uploaded_file($target, $path)) { - return $path; + if (move_uploaded_file($source, $path)) { + return true; } - throw new Exception('Upload failed'); + return false; } /** diff --git a/src/Storage/Validators/Upload.php b/src/Storage/Validators/Upload.php new file mode 100644 index 0000000000..89cd0cbea3 --- /dev/null +++ b/src/Storage/Validators/Upload.php @@ -0,0 +1,29 @@ +object = new Upload(); + } + + public function tearDown() + { + } + + public function testValues() + { + $this->assertEquals($this->object->isValid(__DIR__ . '/../../../resources/disk-a/kitten-1.jpg'), false); + $this->assertEquals($this->object->isValid(__DIR__ . '/../../../resources/disk-a/kitten-2.jpg'), false); + $this->assertEquals($this->object->isValid(__DIR__ . '/../../../resources/disk-b/kitten-1.png'), false); + $this->assertEquals($this->object->isValid(__DIR__ . '/../../../resources/disk-b/kitten-2.png'), false); + $this->assertEquals($this->object->isValid(__FILE__), false); + } +} \ No newline at end of file