mirror of
https://github.com/appwrite/appwrite.git
synced 2026-05-26 13:51:13 +00:00
handling bucket enforced permissions
This commit is contained in:
+162
-12
@@ -30,6 +30,8 @@ use Utopia\Validator\Integer;
|
||||
use Utopia\Database\Query;
|
||||
use Utopia\Database\Validator\Permissions;
|
||||
use Utopia\Storage\Validator\FileExt;
|
||||
use Utopia\Database\Exception\Duplicate as DuplicateException;
|
||||
use Utopia\Database\Exception\Structure as StructureException;
|
||||
|
||||
App::post('/v1/storage/buckets')
|
||||
->desc('Create storage bucket')
|
||||
@@ -522,6 +524,14 @@ App::post('/v1/storage/buckets/:bucketId/files')
|
||||
throw new Exception('Bucket not found', 404);
|
||||
}
|
||||
|
||||
// Check bucket permissions when enforced
|
||||
if ($bucket->getAttribute('permission') === 'bucket') {
|
||||
$validator = new Authorization('write');
|
||||
if (!$validator->isValid($bucket->getWrite())) {
|
||||
throw new Exception('Unauthorized permissions', 401);
|
||||
}
|
||||
}
|
||||
|
||||
$file = $request->getFiles('file');
|
||||
|
||||
/*
|
||||
@@ -626,7 +636,23 @@ App::post('/v1/storage/buckets/:bucketId/files')
|
||||
$data['openSSLIV'] = \bin2hex($iv);
|
||||
}
|
||||
|
||||
$file = $dbForInternal->createDocument('bucket_' . $bucket->getId(), new Document($data));
|
||||
try {
|
||||
if($bucket->getAttribute('permission') === 'bucket') {
|
||||
$file = Authorization::skip(function() use ($dbForInternal, $bucket, $data) {
|
||||
return $dbForInternal->createDocument('bucket_' . $bucket->getId(), new Document($data));
|
||||
});
|
||||
} else {
|
||||
$file = $dbForInternal->createDocument('bucket_' . $bucket->getId(), new Document($data));
|
||||
}
|
||||
|
||||
}
|
||||
catch (StructureException $exception) {
|
||||
throw new Exception($exception->getMessage(), 400);
|
||||
}
|
||||
catch (DuplicateException $exception) {
|
||||
throw new Exception('Document already exists', 409);
|
||||
}
|
||||
|
||||
|
||||
$audits
|
||||
->setParam('event', 'storage.files.create')
|
||||
@@ -677,6 +703,14 @@ App::get('/v1/storage/buckets/:bucketId/files')
|
||||
throw new Exception('Bucket not found', 404);
|
||||
}
|
||||
|
||||
// Check bucket permissions when enforced
|
||||
if ($bucket->getAttribute('permission') === 'bucket') {
|
||||
$validator = new Authorization('read');
|
||||
if (!$validator->isValid($bucket->getRead())) {
|
||||
throw new Exception('Unauthorized permissions', 401);
|
||||
}
|
||||
}
|
||||
|
||||
$queries = [new Query('bucketId', Query::TYPE_EQUAL, [$bucketId])];
|
||||
|
||||
if($search) {
|
||||
@@ -684,7 +718,13 @@ App::get('/v1/storage/buckets/:bucketId/files')
|
||||
}
|
||||
|
||||
if (!empty($cursor)) {
|
||||
$cursorFile = $dbForInternal->getDocument('bucket_' . $bucketId, $cursor);
|
||||
if($bucket->getAttribute('permission') ==='bucket') {
|
||||
$cursorFile = Authorization::skip(function() use ($dbForInternal, $bucket, $cursor) {
|
||||
return $dbForInternal->getDocument('bucket_' . $bucket->getId(), $cursor);
|
||||
});
|
||||
} else {
|
||||
$cursorFile = $dbForInternal->getDocument('bucket_' . $bucket->getId(), $cursor);
|
||||
}
|
||||
|
||||
if ($cursorFile->isEmpty()) {
|
||||
throw new Exception("File '{$cursor}' for the 'cursor' value not found.", 400);
|
||||
@@ -697,13 +737,21 @@ App::get('/v1/storage/buckets/:bucketId/files')
|
||||
$queries[] = new Query('search', Query::TYPE_SEARCH, [$search]);
|
||||
}
|
||||
|
||||
if($bucket->getAttribute('permission') === 'bucket') {
|
||||
$files = Authorization::skip(function() use ($dbForInternal, $bucketId, $queries, $limit, $offset, $cursor, $cursorDirection, $orderType) {
|
||||
return $dbForInternal->find('bucket_' . $bucketId, $queries, $limit, $offset, [], [$orderType], $cursorFile ?? null, $cursorDirection);
|
||||
});
|
||||
} else {
|
||||
$files = $dbForInternal->find('bucket_' . $bucketId, $queries, $limit, $offset, [], [$orderType], $cursorFile ?? null, $cursorDirection);
|
||||
}
|
||||
|
||||
$usage
|
||||
->setParam('storage.files.read', 1)
|
||||
->setParam('bucketId', $bucketId)
|
||||
;
|
||||
|
||||
$response->dynamic(new Document([
|
||||
'files' => $dbForInternal->find('bucket_' . $bucketId, $queries, $limit, $offset, [], [$orderType], $cursorFile ?? null, $cursorDirection),
|
||||
'files' => $files,
|
||||
'sum' => $dbForInternal->count('bucket_' . $bucketId, $queries, APP_LIMIT_COUNT),
|
||||
]), Response::MODEL_FILE_LIST);
|
||||
});
|
||||
@@ -736,7 +784,21 @@ App::get('/v1/storage/buckets/:bucketId/files/:fileId')
|
||||
throw new Exception('Bucket not found', 404);
|
||||
}
|
||||
|
||||
$file = $dbForInternal->getDocument('bucket_' . $bucketId, $fileId);
|
||||
// Check bucket permissions when enforced
|
||||
if ($bucket->getAttribute('permission') === 'bucket') {
|
||||
$validator = new Authorization('read');
|
||||
if (!$validator->isValid($bucket->getRead())) {
|
||||
throw new Exception('Unauthorized permissions', 401);
|
||||
}
|
||||
}
|
||||
|
||||
if($bucket->getAttribute('permission') === 'bucket') {
|
||||
$file = Authorization::skip(function() use ($dbForInternal, $bucketId, $fileId) {
|
||||
return $dbForInternal->getDocument('bucket_' . $bucketId, $fileId);
|
||||
});
|
||||
} else {
|
||||
$file = $dbForInternal->getDocument('bucket_' . $bucketId, $fileId);
|
||||
}
|
||||
|
||||
if ($file->isEmpty() || $file->getAttribute('bucketId') !== $bucketId) {
|
||||
throw new Exception('File not found', 404);
|
||||
@@ -800,6 +862,14 @@ App::get('/v1/storage/buckets/:bucketId/files/:fileId/preview')
|
||||
throw new Exception('Bucket not found', 404);
|
||||
}
|
||||
|
||||
// Check bucket permissions when enforced
|
||||
if ($bucket->getAttribute('permission') === 'bucket') {
|
||||
$validator = new Authorization('read');
|
||||
if (!$validator->isValid($bucket->getRead())) {
|
||||
throw new Exception('Unauthorized permissions', 401);
|
||||
}
|
||||
}
|
||||
|
||||
if ((\strpos($request->getAccept(), 'image/webp') === false) && ('webp' === $output)) { // Fallback webp to jpeg when no browser support
|
||||
$output = 'jpg';
|
||||
}
|
||||
@@ -811,7 +881,14 @@ App::get('/v1/storage/buckets/:bucketId/files/:fileId/preview')
|
||||
$date = \date('D, d M Y H:i:s', \time() + (60 * 60 * 24 * 45)).' GMT'; // 45 days cache
|
||||
$key = \md5($fileId.$width.$height.$gravity.$quality.$borderWidth.$borderColor.$borderRadius.$opacity.$rotation.$background.$storage.$output);
|
||||
|
||||
$file = $dbForInternal->getDocument('bucket_' . $bucketId, $fileId);
|
||||
if($bucket->getAttribute('permission')==='bucket') {
|
||||
// skip authorization
|
||||
$file = Authorization::skip(function () use ($dbForInternal, $bucketId, $fileId) {
|
||||
return $dbForInternal->getDocument('bucket_' . $bucketId, $fileId);
|
||||
});
|
||||
} else {
|
||||
$file = $dbForInternal->getDocument('bucket_' . $bucketId, $fileId);
|
||||
}
|
||||
|
||||
if ($file->isEmpty() || $file->getAttribute('bucketId') !== $bucketId) {
|
||||
throw new Exception('File not found', 404);
|
||||
@@ -943,7 +1020,21 @@ App::get('/v1/storage/buckets/:bucketId/files/:fileId/download')
|
||||
throw new Exception('Bucket not found', 404);
|
||||
}
|
||||
|
||||
$file = $dbForInternal->getDocument('bucket_' . $bucketId, $fileId);
|
||||
// Check bucket permissions when enforced
|
||||
if ($bucket->getAttribute('permission') === 'bucket') {
|
||||
$validator = new Authorization('read');
|
||||
if (!$validator->isValid($bucket->getRead())) {
|
||||
throw new Exception('Unauthorized permissions', 401);
|
||||
}
|
||||
}
|
||||
|
||||
if($bucket->getAttribute('permission') === 'bucket') {
|
||||
$file = Authorization::skip(function() use ($dbForInternal, $fileId, $bucketId) {
|
||||
return $dbForInternal->getDocument('bucket_' . $bucketId, $fileId);
|
||||
});
|
||||
} else {
|
||||
$file = $dbForInternal->getDocument('bucket_' . $bucketId, $fileId);
|
||||
}
|
||||
|
||||
if ($file->isEmpty() || $file->getAttribute('bucketId') !== $bucketId) {
|
||||
throw new Exception('File not found', 404);
|
||||
@@ -1016,7 +1107,22 @@ App::get('/v1/storage/buckets/:bucketId/files/:fileId/view')
|
||||
throw new Exception('Bucket not found', 404);
|
||||
}
|
||||
|
||||
$file = $dbForInternal->getDocument('bucket_' . $bucketId, $fileId);
|
||||
// Check bucket permissions when enforced
|
||||
if ($bucket->getAttribute('permission') === 'bucket') {
|
||||
$validator = new Authorization('read');
|
||||
if (!$validator->isValid($bucket->getRead())) {
|
||||
throw new Exception('Unauthorized permissions', 401);
|
||||
}
|
||||
}
|
||||
|
||||
if($bucket->getAttribute('permission') === 'bucket') {
|
||||
$file = Authorization::skip(function() use ($dbForInternal, $fileId, $bucketId) {
|
||||
return $dbForInternal->getDocument('bucket_' . $bucketId, $fileId);
|
||||
});
|
||||
} else {
|
||||
$file = $dbForInternal->getDocument('bucket_' . $bucketId, $fileId);
|
||||
}
|
||||
|
||||
$mimes = Config::getParam('storage-mimes');
|
||||
|
||||
if ($file->isEmpty() || $file->getAttribute('bucketId') !== $bucketId) {
|
||||
@@ -1103,16 +1209,39 @@ App::put('/v1/storage/buckets/:bucketId/files/:fileId')
|
||||
throw new Exception('Bucket not found', 404);
|
||||
}
|
||||
|
||||
$file = $dbForInternal->getDocument('bucket_' . $bucketId, $fileId);
|
||||
// Check bucket permissions when enforced
|
||||
if ($bucket->getAttribute('permission') === 'bucket') {
|
||||
$validator = new Authorization('write');
|
||||
if (!$validator->isValid($bucket->getWrite())) {
|
||||
throw new Exception('Unauthorized permissions', 401);
|
||||
}
|
||||
}
|
||||
|
||||
if($bucket->getAttribute('permission') === 'bucket') {
|
||||
$file = Authorization::skip(function() use ($dbForInternal, $fileId, $bucketId) {
|
||||
return $dbForInternal->getDocument('bucket_' . $bucketId, $fileId);
|
||||
});
|
||||
} else {
|
||||
$file = $dbForInternal->getDocument('bucket_' . $bucketId, $fileId);
|
||||
}
|
||||
|
||||
if ($file->isEmpty() || $file->getAttribute('bucketId') !== $bucketId) {
|
||||
throw new Exception('File not found', 404);
|
||||
}
|
||||
|
||||
$file = $dbForInternal->updateDocument('bucket_' . $bucketId, $fileId, $file
|
||||
if($bucket->getAttribute('permission') === 'bucket') {
|
||||
$file = Authorization::skip(function() use ($dbForInternal, $fileId, $bucketId, $file, $read, $write) {
|
||||
return $dbForInternal->updateDocument('bucket_' . $bucketId, $fileId, $file
|
||||
->setAttribute('$read', $read)
|
||||
->setAttribute('$write', $write)
|
||||
);
|
||||
});
|
||||
} else {
|
||||
$file = $dbForInternal->updateDocument('bucket_' . $bucketId, $fileId, $file
|
||||
->setAttribute('$read', $read)
|
||||
->setAttribute('$write', $write)
|
||||
);
|
||||
);
|
||||
}
|
||||
|
||||
$audits
|
||||
->setParam('event', 'storage.files.update')
|
||||
@@ -1159,7 +1288,21 @@ App::delete('/v1/storage/buckets/:bucketId/files/:fileId')
|
||||
throw new Exception('Bucket not found', 404);
|
||||
}
|
||||
|
||||
$file = $dbForInternal->getDocument('bucket_' . $bucketId, $fileId);
|
||||
// Check bucket permissions when enforced
|
||||
if ($bucket->getAttribute('permission') === 'bucket') {
|
||||
$validator = new Authorization('write');
|
||||
if (!$validator->isValid($bucket->getWrite())) {
|
||||
throw new Exception('Unauthorized permissions', 401);
|
||||
}
|
||||
}
|
||||
|
||||
if($bucket->getAttribute('permission') === 'bucket') {
|
||||
$file = Authorization::skip(function() use ($dbForInternal, $fileId, $bucketId) {
|
||||
return $dbForInternal->getDocument('bucket_' . $bucketId, $fileId);
|
||||
});
|
||||
} else {
|
||||
$file = $dbForInternal->getDocument('bucket_' . $bucketId, $fileId);
|
||||
}
|
||||
|
||||
if ($file->isEmpty() || $file->getAttribute('bucketId') !== $bucketId) {
|
||||
throw new Exception('File not found', 404);
|
||||
@@ -1168,7 +1311,14 @@ App::delete('/v1/storage/buckets/:bucketId/files/:fileId')
|
||||
$device = Storage::getDevice('files');
|
||||
|
||||
if ($device->delete($file->getAttribute('path', ''))) {
|
||||
if (!$dbForInternal->deleteDocument('bucket_' . $bucketId, $fileId)) {
|
||||
if($bucket->getAttribute('permission') === 'bucket') {
|
||||
$deleted = Authorization::skip(function() use ($dbForInternal, $fileId, $bucketId) {
|
||||
return $dbForInternal->deleteDocument('bucket_' . $bucketId, $fileId);
|
||||
});
|
||||
} else {
|
||||
$deleted = $dbForInternal->deleteDocument('bucket_' . $bucketId, $fileId);
|
||||
}
|
||||
if (!$deleted) {
|
||||
throw new Exception('Failed to remove file from DB', 500);
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user