Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 6 additions & 0 deletions src/Database/Database.php
Original file line number Diff line number Diff line change
Expand Up @@ -80,6 +80,7 @@ class Database
public const MAX_DOUBLE = PHP_FLOAT_MAX;
public const MAX_VECTOR_DIMENSIONS = 16000;
public const MAX_ARRAY_INDEX_LENGTH = 255;
public const MAX_UID_DEFAULT_LENGTH = 36;

// Global SRID for geographic coordinates (WGS84)
public const DEFAULT_SRID = 4326;
Expand Down Expand Up @@ -5151,6 +5152,7 @@ public function updateDocuments(
$indexes,
$this->adapter->getIdAttributeType(),
$this->maxQueryValues,
$this->adapter->getMaxUIDLength(),
$this->adapter->getMinDateTime(),
$this->adapter->getMaxDateTime(),
$this->adapter->getSupportForAttributes()
Expand Down Expand Up @@ -6710,6 +6712,7 @@ public function deleteDocuments(
$indexes,
$this->adapter->getIdAttributeType(),
$this->maxQueryValues,
$this->adapter->getMaxUIDLength(),
$this->adapter->getMinDateTime(),
$this->adapter->getMaxDateTime(),
$this->adapter->getSupportForAttributes()
Expand Down Expand Up @@ -6908,6 +6911,7 @@ public function find(string $collection, array $queries = [], string $forPermiss
$indexes,
$this->adapter->getIdAttributeType(),
$this->maxQueryValues,
$this->adapter->getMaxUIDLength(),
$this->adapter->getMinDateTime(),
$this->adapter->getMaxDateTime(),
$this->adapter->getSupportForAttributes()
Expand Down Expand Up @@ -7139,6 +7143,7 @@ public function count(string $collection, array $queries = [], ?int $max = null)
$indexes,
$this->adapter->getIdAttributeType(),
$this->maxQueryValues,
$this->adapter->getMaxUIDLength(),
$this->adapter->getMinDateTime(),
$this->adapter->getMaxDateTime(),
$this->adapter->getSupportForAttributes()
Expand Down Expand Up @@ -7204,6 +7209,7 @@ public function sum(string $collection, string $attribute, array $queries = [],
$indexes,
$this->adapter->getIdAttributeType(),
$this->maxQueryValues,
$this->adapter->getMaxUIDLength(),
$this->adapter->getMinDateTime(),
$this->adapter->getMaxDateTime(),
$this->adapter->getSupportForAttributes()
Expand Down
24 changes: 7 additions & 17 deletions src/Database/Validator/Key.php
Original file line number Diff line number Diff line change
Expand Up @@ -2,20 +2,11 @@

namespace Utopia\Database\Validator;

use Utopia\Database\Database;
use Utopia\Validator;

class Key extends Validator
{
protected bool $allowInternal = false; // If true, you keys starting with $ are allowed

/**
* Maximum length for Key validation
*/
protected int $maxLength;

/**
* @var string
*/
protected string $message;

/**
Expand All @@ -33,10 +24,10 @@ public function getDescription(): string
/**
* Expression constructor
*/
public function __construct(bool $allowInternal = false, int $maxLength = 255)
{
$this->allowInternal = $allowInternal;
$this->maxLength = $maxLength;
public function __construct(
protected readonly bool $allowInternal = false,
protected readonly int $maxLength = Database::MAX_UID_DEFAULT_LENGTH,
) {
$this->message = 'Parameter must contain at most ' . $this->maxLength . ' chars. Valid chars are a-z, A-Z, 0-9, period, hyphen, and underscore. Can\'t start with a special char';
}

Expand All @@ -46,7 +37,6 @@ public function __construct(bool $allowInternal = false, int $maxLength = 255)
* Returns true if valid or false if not.
*
* @param $value
*
* @return bool
*/
public function isValid($value): bool
Expand All @@ -59,15 +49,14 @@ public function isValid($value): bool
return false;
}

// no leading special characters
// No leading special characters
$leading = \mb_substr($value, 0, 1);
if ($leading === '_' || $leading === '.' || $leading === '-') {
return false;
}

$isInternal = $leading === '$';


if ($isInternal && !$this->allowInternal) {
return false;
}
Expand All @@ -83,6 +72,7 @@ public function isValid($value): bool
if (\preg_match('/[^A-Za-z0-9\_\-\.]/', $value)) {
return false;
}

// At most maxLength chars
if (\mb_strlen($value) > $this->maxLength) {
return false;
Expand Down
8 changes: 6 additions & 2 deletions src/Database/Validator/Label.php
Original file line number Diff line number Diff line change
Expand Up @@ -2,10 +2,14 @@

namespace Utopia\Database\Validator;

use Utopia\Database\Database;

class Label extends Key
{
public function __construct(bool $allowInternal = false, int $maxLength = 255)
{
public function __construct(
bool $allowInternal = false,
int $maxLength = Database::MAX_UID_DEFAULT_LENGTH
) {
parent::__construct($allowInternal, $maxLength);
$this->message = 'Value must be a valid string between 1 and ' . $this->maxLength . ' chars containing only alphanumeric chars';
}
Expand Down
12 changes: 7 additions & 5 deletions src/Database/Validator/Queries/Documents.php
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,6 @@

namespace Utopia\Database\Validator\Queries;

use Exception;
use Utopia\Database\Database;
use Utopia\Database\Document;
use Utopia\Database\Validator\IndexedQueries;
Expand All @@ -16,18 +15,21 @@
class Documents extends IndexedQueries
{
/**
* Expression constructor
*
* @param array<mixed> $attributes
* @param array<mixed> $indexes
* @param string $idAttributeType
* @throws Exception
* @param int $maxValuesCount
* @param \DateTime $minAllowedDate
* @param \DateTime $maxAllowedDate
* @param bool $supportForAttributes
* @throws \Utopia\Database\Exception
*/
public function __construct(
array $attributes,
array $indexes,
string $idAttributeType,
int $maxValuesCount = 5000,
int $maxUIDLength = 36,
\DateTime $minAllowedDate = new \DateTime('0000-01-01'),
\DateTime $maxAllowedDate = new \DateTime('9999-12-31'),
bool $supportForAttributes = true
Expand Down Expand Up @@ -60,7 +62,7 @@ public function __construct(
$validators = [
new Limit(),
new Offset(),
new Cursor(),
new Cursor($maxUIDLength),
new Filter(
$attributes,
$idAttributeType,
Expand Down
7 changes: 6 additions & 1 deletion src/Database/Validator/Query/Cursor.php
Original file line number Diff line number Diff line change
Expand Up @@ -2,12 +2,17 @@

namespace Utopia\Database\Validator\Query;

use Utopia\Database\Database;
use Utopia\Database\Document;
use Utopia\Database\Query;
use Utopia\Database\Validator\UID;

class Cursor extends Base
{
public function __construct(private readonly int $maxLength = Database::MAX_UID_DEFAULT_LENGTH)
{
}

/**
* Is valid.
*
Expand All @@ -33,7 +38,7 @@ public function isValid($value): bool
$cursor = $cursor->getId();
}

$validator = new UID();
$validator = new UID($this->maxLength);
if ($validator->isValid($cursor)) {
return true;
}
Expand Down
4 changes: 3 additions & 1 deletion src/Database/Validator/UID.php
Original file line number Diff line number Diff line change
Expand Up @@ -2,12 +2,14 @@

namespace Utopia\Database\Validator;

use Utopia\Database\Database;

class UID extends Key
{
/**
* Expression constructor
*/
public function __construct(int $maxLength = 255)
public function __construct(int $maxLength = Database::MAX_UID_DEFAULT_LENGTH)
{
parent::__construct(false, $maxLength);
}
Expand Down
4 changes: 2 additions & 2 deletions tests/unit/Validator/KeyTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -66,8 +66,8 @@ public function testValues(): void
$this->assertEquals(false, $this->object->isValid('as+5dasdasdas'));
$this->assertEquals(false, $this->object->isValid('as=5dasdasdas'));

// At most 255 chars
$this->assertEquals(true, $this->object->isValid(str_repeat('a', 255)));
// At most 36 chars
$this->assertEquals(true, $this->object->isValid(str_repeat('a', 36)));
$this->assertEquals(false, $this->object->isValid(str_repeat('a', 256)));

// Internal keys
Expand Down
2 changes: 1 addition & 1 deletion tests/unit/Validator/LabelTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -59,7 +59,7 @@ public function testValues(): void
$this->assertEquals(false, $this->object->isValid('as=5dasdasdas'));

// At most 255 chars
$this->assertEquals(true, $this->object->isValid(str_repeat('a', 255)));
$this->assertEquals(true, $this->object->isValid(str_repeat('a', 36)));
$this->assertEquals(false, $this->object->isValid(str_repeat('a', 256)));
}
}
24 changes: 12 additions & 12 deletions tests/unit/Validator/PermissionsTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -248,25 +248,25 @@ public function testInvalidPermissions(): void
// team:$value, member:$value and user:$value must have valid Key for $value
// No leading special chars
$this->assertFalse($object->isValid([Permission::read(Role::user('_1234'))]));
$this->assertEquals('Role "user" identifier value is invalid: Parameter must contain at most 255 chars. Valid chars are a-z, A-Z, 0-9, period, hyphen, and underscore. Can\'t start with a special char', $object->getDescription());
$this->assertEquals('Role "user" identifier value is invalid: Parameter must contain at most 36 chars. Valid chars are a-z, A-Z, 0-9, period, hyphen, and underscore. Can\'t start with a special char', $object->getDescription());
$this->assertFalse($object->isValid([Permission::read(Role::team('-1234'))]));
$this->assertEquals('Role "team" identifier value is invalid: Parameter must contain at most 255 chars. Valid chars are a-z, A-Z, 0-9, period, hyphen, and underscore. Can\'t start with a special char', $object->getDescription());
$this->assertEquals('Role "team" identifier value is invalid: Parameter must contain at most 36 chars. Valid chars are a-z, A-Z, 0-9, period, hyphen, and underscore. Can\'t start with a special char', $object->getDescription());
$this->assertFalse($object->isValid([Permission::read(Role::member('.1234'))]));
$this->assertEquals('Role "member" identifier value is invalid: Parameter must contain at most 255 chars. Valid chars are a-z, A-Z, 0-9, period, hyphen, and underscore. Can\'t start with a special char', $object->getDescription());
$this->assertEquals('Role "member" identifier value is invalid: Parameter must contain at most 36 chars. Valid chars are a-z, A-Z, 0-9, period, hyphen, and underscore. Can\'t start with a special char', $object->getDescription());

// No unsupported special characters
$this->assertFalse($object->isValid([Permission::read(Role::user('12$4'))]));
$this->assertEquals('Role "user" identifier value is invalid: Parameter must contain at most 255 chars. Valid chars are a-z, A-Z, 0-9, period, hyphen, and underscore. Can\'t start with a special char', $object->getDescription());
$this->assertEquals('Role "user" identifier value is invalid: Parameter must contain at most 36 chars. Valid chars are a-z, A-Z, 0-9, period, hyphen, and underscore. Can\'t start with a special char', $object->getDescription());
$this->assertFalse($object->isValid([Permission::read(Role::user('12&4'))]));
$this->assertEquals('Role "user" identifier value is invalid: Parameter must contain at most 255 chars. Valid chars are a-z, A-Z, 0-9, period, hyphen, and underscore. Can\'t start with a special char', $object->getDescription());
$this->assertEquals('Role "user" identifier value is invalid: Parameter must contain at most 36 chars. Valid chars are a-z, A-Z, 0-9, period, hyphen, and underscore. Can\'t start with a special char', $object->getDescription());
$this->assertFalse($object->isValid([Permission::read(Role::user('ab(124'))]));
$this->assertEquals('Role "user" identifier value is invalid: Parameter must contain at most 255 chars. Valid chars are a-z, A-Z, 0-9, period, hyphen, and underscore. Can\'t start with a special char', $object->getDescription());
$this->assertEquals('Role "user" identifier value is invalid: Parameter must contain at most 36 chars. Valid chars are a-z, A-Z, 0-9, period, hyphen, and underscore. Can\'t start with a special char', $object->getDescription());

// Shorter than 255 chars
// Shorter than 36 chars

$this->assertTrue($object->isValid([Permission::read(Role::user(ID::custom(str_repeat('a', 255))))]));
$this->assertTrue($object->isValid([Permission::read(Role::user(ID::custom(str_repeat('a', 36))))]));
$this->assertFalse($object->isValid([Permission::read(Role::user(ID::custom(str_repeat('a', 256))))]));
$this->assertEquals('Role "user" identifier value is invalid: Parameter must contain at most 255 chars. Valid chars are a-z, A-Z, 0-9, period, hyphen, and underscore. Can\'t start with a special char', $object->getDescription());
$this->assertEquals('Role "user" identifier value is invalid: Parameter must contain at most 36 chars. Valid chars are a-z, A-Z, 0-9, period, hyphen, and underscore. Can\'t start with a special char', $object->getDescription());

// Permission role must begin with one of: member, role, team, user
$this->assertFalse($object->isValid(['update("memmber:1234")']));
Expand All @@ -278,7 +278,7 @@ public function testInvalidPermissions(): void

// Team permission
$this->assertFalse($object->isValid([Permission::read(Role::team(ID::custom('_abcd')))]));
$this->assertEquals('Role "team" identifier value is invalid: Parameter must contain at most 255 chars. Valid chars are a-z, A-Z, 0-9, period, hyphen, and underscore. Can\'t start with a special char', $object->getDescription());
$this->assertEquals('Role "team" identifier value is invalid: Parameter must contain at most 36 chars. Valid chars are a-z, A-Z, 0-9, period, hyphen, and underscore. Can\'t start with a special char', $object->getDescription());
$this->assertFalse($object->isValid([Permission::read(Role::team(ID::custom('abcd/')))]));
$this->assertEquals('Dimension must not be empty', $object->getDescription());
$this->assertFalse($object->isValid([Permission::read(Role::team(ID::custom(''), 'abcd'))]));
Expand All @@ -288,9 +288,9 @@ public function testInvalidPermissions(): void
$this->assertFalse($object->isValid([Permission::read(Role::team(ID::custom('abcd'), 'e/fgh'))]));
$this->assertEquals('Only one dimension can be provided', $object->getDescription());
$this->assertFalse($object->isValid([Permission::read(Role::team(ID::custom('ab&cd3'), 'efgh'))]));
$this->assertEquals('Role "team" identifier value is invalid: Parameter must contain at most 255 chars. Valid chars are a-z, A-Z, 0-9, period, hyphen, and underscore. Can\'t start with a special char', $object->getDescription());
$this->assertEquals('Role "team" identifier value is invalid: Parameter must contain at most 36 chars. Valid chars are a-z, A-Z, 0-9, period, hyphen, and underscore. Can\'t start with a special char', $object->getDescription());
$this->assertFalse($object->isValid([Permission::read(Role::team(ID::custom('abcd'), 'ef*gh'))]));
$this->assertEquals('Role "team" dimension value is invalid: Parameter must contain at most 255 chars. Valid chars are a-z, A-Z, 0-9, period, hyphen, and underscore. Can\'t start with a special char', $object->getDescription());
$this->assertEquals('Role "team" dimension value is invalid: Parameter must contain at most 36 chars. Valid chars are a-z, A-Z, 0-9, period, hyphen, and underscore. Can\'t start with a special char', $object->getDescription());

// Permission-list length must be valid
$object = new Permissions(100);
Expand Down