mirror of
https://github.com/appwrite/appwrite.git
synced 2026-05-26 13:51:13 +00:00
Implement select query validation and dynamic subquery filtering for users
Co-authored-by: jakeb994 <jakeb994@gmail.com>
This commit is contained in:
@@ -643,6 +643,54 @@ App::get('/v1/users')
|
||||
$cursor->setValue($cursorDocument);
|
||||
}
|
||||
|
||||
// Define attributes that have subQueryX filters
|
||||
$subQueryAttributes = [
|
||||
'authenticators' => 'subQueryAuthenticators',
|
||||
'sessions' => 'subQuerySessions',
|
||||
'tokens' => 'subQueryTokens',
|
||||
'challenges' => 'subQueryChallenges',
|
||||
'memberships' => 'subQueryMemberships',
|
||||
'targets' => 'subQueryTargets'
|
||||
];
|
||||
|
||||
// Process select queries and identify subQueryX attributes
|
||||
$skipFilters = ['subQueryAuthenticators', 'subQuerySessions', 'subQueryTokens', 'subQueryChallenges', 'subQueryMemberships', 'subQueryTargets'];
|
||||
$additionalSkipFilters = [];
|
||||
|
||||
// Process queries to handle select queries with subQueryX attributes
|
||||
$processedQueries = [];
|
||||
foreach ($queries as $query) {
|
||||
if ($query->getMethod() === Query::TYPE_SELECT) {
|
||||
$selectedAttributes = $query->getValues();
|
||||
$filteredAttributes = [];
|
||||
|
||||
foreach ($selectedAttributes as $attribute) {
|
||||
if (array_key_exists($attribute, $subQueryAttributes)) {
|
||||
// Add the corresponding subQuery filter to skipFilters
|
||||
$additionalSkipFilters[] = $subQueryAttributes[$attribute];
|
||||
} else {
|
||||
// Keep this attribute in the select query
|
||||
$filteredAttributes[] = $attribute;
|
||||
}
|
||||
}
|
||||
|
||||
// Only add the select query if there are valid attributes remaining
|
||||
if (!empty($filteredAttributes)) {
|
||||
$processedQueries[] = Query::select($filteredAttributes);
|
||||
}
|
||||
} else {
|
||||
// Keep non-select queries as they are
|
||||
$processedQueries[] = $query;
|
||||
}
|
||||
}
|
||||
|
||||
// Update queries with processed queries
|
||||
$queries = $processedQueries;
|
||||
|
||||
// Add additional skip filters to the existing ones
|
||||
$skipFilters = array_merge($skipFilters, $additionalSkipFilters);
|
||||
$skipFilters = array_unique($skipFilters);
|
||||
|
||||
$users = [];
|
||||
$total = 0;
|
||||
|
||||
@@ -655,7 +703,7 @@ App::get('/v1/users')
|
||||
} catch (QueryException $e) {
|
||||
throw new Exception(Exception::GENERAL_QUERY_INVALID, $e->getMessage());
|
||||
}
|
||||
}, ['subQueryAuthenticators', 'subQuerySessions', 'subQueryTokens', 'subQueryChallenges', 'subQueryMemberships']);
|
||||
}, $skipFilters);
|
||||
|
||||
$response->dynamic(new Document([
|
||||
'users' => $users,
|
||||
|
||||
@@ -11,6 +11,7 @@ use Utopia\Database\Validator\Query\Filter;
|
||||
use Utopia\Database\Validator\Query\Limit;
|
||||
use Utopia\Database\Validator\Query\Offset;
|
||||
use Utopia\Database\Validator\Query\Order;
|
||||
use Appwrite\Utopia\Database\Validator\Query\Select;
|
||||
|
||||
class Base extends Queries
|
||||
{
|
||||
@@ -82,6 +83,7 @@ class Base extends Queries
|
||||
new Cursor(),
|
||||
new Filter($attributes, APP_DATABASE_QUERY_MAX_VALUES),
|
||||
new Order($attributes),
|
||||
new Select($attributes),
|
||||
];
|
||||
|
||||
parent::__construct($validators);
|
||||
|
||||
@@ -0,0 +1,58 @@
|
||||
<?php
|
||||
|
||||
namespace Appwrite\Utopia\Database\Validator\Query;
|
||||
|
||||
use Utopia\Database\Document;
|
||||
use Utopia\Database\Query;
|
||||
use Utopia\Database\Validator\Query;
|
||||
|
||||
class Select extends Query
|
||||
{
|
||||
protected array $schema = [];
|
||||
|
||||
/**
|
||||
* @param Document[] $attributes
|
||||
*/
|
||||
public function __construct(array $attributes)
|
||||
{
|
||||
foreach ($attributes as $attribute) {
|
||||
$this->schema[$attribute->getAttribute('key')] = $attribute->getAttribute('type');
|
||||
}
|
||||
}
|
||||
|
||||
protected function isValidAttribute(string $attribute): bool
|
||||
{
|
||||
if (str_starts_with($attribute, '$')) {
|
||||
return true; // Allow system attributes
|
||||
}
|
||||
|
||||
return array_key_exists($attribute, $this->schema);
|
||||
}
|
||||
|
||||
public function isValid(mixed $query): bool
|
||||
{
|
||||
if (!$query instanceof \Utopia\Database\Query) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if ($query->getMethod() !== Query::TYPE_SELECT) {
|
||||
return false;
|
||||
}
|
||||
|
||||
$values = $query->getValues();
|
||||
|
||||
foreach ($values as $attribute) {
|
||||
if (!$this->isValidAttribute($attribute)) {
|
||||
$this->message = 'Query select is not valid: Attribute "' . $attribute . '" not found.';
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
public function getType(): string
|
||||
{
|
||||
return Query::TYPE_SELECT;
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user