1
0
Fork 0
mirror of synced 2024-06-02 19:04:49 +12:00

File upload route (POST /v1/storage/files) now accept a single file per request

This commit is contained in:
Eldad Fux 2020-01-19 10:05:31 +02:00
parent 9be443c9dd
commit 7799ef47ec
3 changed files with 101 additions and 109 deletions

View file

@ -15,6 +15,7 @@
* Added a new Spotify OAuth adapter
* Upgraded MariaDB image to version 1.0.2
* Upgraded SMTP image to version 1.0.1
* File upload route (POST /v1/storage/files) now accept a single file per request
## Bug Fixes

View file

@ -406,13 +406,13 @@ $utopia->post('/v1/storage/files')
->label('sdk.method', 'createFile')
->label('sdk.description', '/docs/references/storage/create-file.md')
->label('sdk.consumes', 'multipart/form-data')
->param('files', [], function () { return new File(); }, 'Binary Files.', false)
->param('file', [], function () { return new File(); }, 'Binary Files.', false)
->param('read', [], function () { return new ArrayList(new Text(64)); }, 'An array of strings with read permissions. By default no user is granted with any read permissions. [learn more about permissions](/docs/permissions) and get a full list of available permissions.')
->param('write', [], function () { return new ArrayList(new Text(64)); }, 'An array of strings with write permissions. By default no user is granted with any write permissions. [learn more about permissions](/docs/permissions) and get a full list of available permissions.')
// ->param('folderId', '', function () { return new UID(); }, 'Folder to associate files with.', true)
->action(
function ($files, $read, $write, $folderId = '') use ($request, $response, $user, $projectDB, $webhook, $audit, $usage) {
$files = $request->getFiles('files');
function ($file, $read, $write, $folderId = '') use ($request, $response, $user, $projectDB, $webhook, $audit, $usage) {
$file = $request->getFiles('file');
$read = (empty($read)) ? ['user:'.$user->getUid()] : $read;
$write = (empty($write)) ? ['user:'.$user->getUid()] : $write;
@ -423,27 +423,23 @@ $utopia->post('/v1/storage/files')
$fileSize = new FileSize(2097152 * 2); // 4MB
$upload = new Upload();
if (empty($files)) {
throw new Exception('No files sent', 400);
if (empty($file)) {
throw new Exception('No file sent', 400);
}
// Make sure we handle single file and multiple files the same way
$files['name'] = (is_array($files['name'])) ? $files['name'] : [$files['name']];
$files['tmp_name'] = (is_array($files['tmp_name'])) ? $files['tmp_name'] : [$files['tmp_name']];
$files['size'] = (is_array($files['size'])) ? $files['size'] : [$files['size']];
// Make sure we handle a single file and multiple files the same way
$file['name'] = (is_array($file['name']) && isset($file['name'][0])) ? $file['name'][0] : $file['name'];
$file['tmp_name'] = (is_array($file['tmp_name']) && isset($file['tmp_name'][0])) ? $file['tmp_name'][0] : $file['tmp_name'];
$file['size'] = (is_array($file['size']) && isset($file['size'][0])) ? $file['size'][0] : $file['size'];
// Check if file type is allowed
//foreach ($files['tmp_name'] as $tmpName) {
//if (!$fileType->isValid($tmpName)) {
// Check if file type is allowed (feature for project settings?)
//if (!$fileType->isValid($file['tmp_name'])) {
//throw new Exception('File type not allowed', 400);
//}
//}
// Check if file size is exceeding allowed limit
foreach ($files['size'] as $tmpSize) {
if (!$fileSize->isValid($tmpSize)) {
throw new Exception('File size not allowed', 400);
}
if (!$fileSize->isValid($file['size'])) {
throw new Exception('File size not allowed', 400);
}
$antiVirus = new Network('clamav', 3310);
@ -454,88 +450,83 @@ $utopia->post('/v1/storage/files')
$list = [];
$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->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)) {
$device->delete($path);
throw new Exception('Invalid file', 403);
}
// Compression
$compressor = new GZIP();
$data = $device->read($path);
$data = $compressor->compress($data);
$key = $request->getServer('_APP_OPENSSL_KEY_V1');
$iv = OpenSSL::randomPseudoBytes(OpenSSL::cipherIVLength(OpenSSL::CIPHER_AES_128_GCM));
$data = OpenSSL::encrypt($data, OpenSSL::CIPHER_AES_128_GCM, $key, 0, $iv, $tag);
if(!$device->write($path, $data)) {
throw new Exception('Failed to save file', 500);
}
$sizeActual = $device->getFileSize($path);
$file = $projectDB->createDocument([
'$collection' => Database::SYSTEM_COLLECTION_FILES,
'$permissions' => [
'read' => $read,
'write' => $write,
],
'dateCreated' => time(),
'folderId' => $folderId,
'name' => $name,
'path' => $path,
'signature' => $device->getFileHash($path),
'mimeType' => $mimeType,
'sizeOriginal' => $size,
'sizeActual' => $sizeActual,
'algorithm' => $compressor->getName(),
'token' => bin2hex(random_bytes(64)),
'comment' => '',
'fileOpenSSLVersion' => '1',
'fileOpenSSLCipher' => OpenSSL::CIPHER_AES_128_GCM,
'fileOpenSSLTag' => bin2hex($tag),
'fileOpenSSLIV' => bin2hex($iv),
]);
if (false === $file) {
throw new Exception('Failed saving file to DB', 500);
}
$webhook
->setParam('payload', $file->getArrayCopy())
;
$audit
->setParam('event', 'storage.files.create')
->setParam('resource', 'storage/files/'.$file->getUid())
;
$usage
->setParam('storage', $sizeActual)
;
$list[] = $file->getArrayCopy();
if (!$upload->isValid($file['tmp_name'])) {
throw new Exception('Invalid file', 403);
}
// Save to storage
$size = $device->getFileSize($file['tmp_name']);
$path = $device->getPath(uniqid().'.'.pathinfo($file['name'], PATHINFO_EXTENSION));
if (!$device->upload($file['tmp_name'], $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)) {
$device->delete($path);
throw new Exception('Invalid file', 403);
}
// Compression
$compressor = new GZIP();
$data = $device->read($path);
$data = $compressor->compress($data);
$key = $request->getServer('_APP_OPENSSL_KEY_V1');
$iv = OpenSSL::randomPseudoBytes(OpenSSL::cipherIVLength(OpenSSL::CIPHER_AES_128_GCM));
$data = OpenSSL::encrypt($data, OpenSSL::CIPHER_AES_128_GCM, $key, 0, $iv, $tag);
if(!$device->write($path, $data)) {
throw new Exception('Failed to save file', 500);
}
$sizeActual = $device->getFileSize($path);
$file = $projectDB->createDocument([
'$collection' => Database::SYSTEM_COLLECTION_FILES,
'$permissions' => [
'read' => $read,
'write' => $write,
],
'dateCreated' => time(),
'folderId' => $folderId,
'name' => $file['name'],
'path' => $path,
'signature' => $device->getFileHash($path),
'mimeType' => $mimeType,
'sizeOriginal' => $size,
'sizeActual' => $sizeActual,
'algorithm' => $compressor->getName(),
'token' => bin2hex(random_bytes(64)),
'comment' => '',
'fileOpenSSLVersion' => '1',
'fileOpenSSLCipher' => OpenSSL::CIPHER_AES_128_GCM,
'fileOpenSSLTag' => bin2hex($tag),
'fileOpenSSLIV' => bin2hex($iv),
]);
if (false === $file) {
throw new Exception('Failed saving file to DB', 500);
}
$webhook
->setParam('payload', $file->getArrayCopy())
;
$audit
->setParam('event', 'storage.files.create')
->setParam('resource', 'storage/files/'.$file->getUid())
;
$usage
->setParam('storage', $sizeActual)
;
$response
->setStatusCode(Response::STATUS_CODE_CREATED)
->json($list)
->json($file->getArrayCopy())
;
}
);

View file

@ -16,30 +16,30 @@ trait StorageBase
'content-type' => 'multipart/form-data',
'x-appwrite-project' => $this->getProject()['$uid'],
], $this->getHeaders()), [
'files' => new CURLFile(realpath(__DIR__ . '/../../../resources/logo.png'), 'image/png', 'logo.png'),
'file' => new CURLFile(realpath(__DIR__ . '/../../../resources/logo.png'), 'image/png', 'logo.png'),
'read' => ['*'],
'write' => ['*'],
'folderId' => 'xyz',
]);
$this->assertEquals($file['headers']['status-code'], 201);
$this->assertNotEmpty($file['body'][0]['$uid']);
$this->assertEquals('files', $file['body'][0]['$collection']);
$this->assertIsInt($file['body'][0]['dateCreated']);
$this->assertEquals('logo.png', $file['body'][0]['name']);
$this->assertEquals('image/png', $file['body'][0]['mimeType']);
$this->assertEquals(47218, $file['body'][0]['sizeOriginal']);
$this->assertEquals(54944, $file['body'][0]['sizeActual']);
$this->assertEquals('gzip', $file['body'][0]['algorithm']);
$this->assertEquals('1', $file['body'][0]['fileOpenSSLVersion']);
$this->assertEquals('aes-128-gcm', $file['body'][0]['fileOpenSSLCipher']);
$this->assertNotEmpty($file['body'][0]['fileOpenSSLTag']);
$this->assertNotEmpty($file['body'][0]['fileOpenSSLIV']);
$this->assertNotEmpty($file['body']['$uid']);
$this->assertEquals('files', $file['body']['$collection']);
$this->assertIsInt($file['body']['dateCreated']);
$this->assertEquals('logo.png', $file['body']['name']);
$this->assertEquals('image/png', $file['body']['mimeType']);
$this->assertEquals(47218, $file['body']['sizeOriginal']);
$this->assertEquals(54944, $file['body']['sizeActual']);
$this->assertEquals('gzip', $file['body']['algorithm']);
$this->assertEquals('1', $file['body']['fileOpenSSLVersion']);
$this->assertEquals('aes-128-gcm', $file['body']['fileOpenSSLCipher']);
$this->assertNotEmpty($file['body']['fileOpenSSLTag']);
$this->assertNotEmpty($file['body']['fileOpenSSLIV']);
/**
* Test for FAILURE
*/
return ['fileId' => $file['body'][0]['$uid']];
return ['fileId' => $file['body']['$uid']];
}
/**