File upload route (POST /v1/storage/files) now accept a single file per request
This commit is contained in:
parent
9be443c9dd
commit
7799ef47ec
|
@ -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
|
||||
|
||||
|
|
|
@ -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())
|
||||
;
|
||||
}
|
||||
);
|
||||
|
|
|
@ -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']];
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
Loading…
Reference in a new issue