diff --git a/src/Database/Helpers/Role.php b/src/Database/Helpers/Role.php index 5553ba878..aaf755038 100644 --- a/src/Database/Helpers/Role.php +++ b/src/Database/Helpers/Role.php @@ -140,6 +140,17 @@ public static function team(string $identifier, string $dimension = ''): self return new self('team', $identifier, $dimension); } + /** + * Create a label role from the given ID + * + * @param string $identifier + * @return Role + */ + public static function label(string $identifier): self + { + return new self('label', $identifier, ''); + } + /** * Create an any satisfy role * diff --git a/src/Database/Validator/Label.php b/src/Database/Validator/Label.php new file mode 100644 index 000000000..6cc4f031f --- /dev/null +++ b/src/Database/Validator/Label.php @@ -0,0 +1,31 @@ + false, ], ], + self::ROLE_LABEL => [ + 'identifier' => [ + 'allowed' => true, + 'required' => true, + ], + 'dimension' =>[ + 'allowed' => false, + 'required' => false, + ], + ], ]; // Dimensions @@ -226,6 +238,7 @@ protected function isValidRole( string $dimension ): bool { $key = new Key(); + $label = new Label(); $config = self::CONFIG[$role] ?? null; @@ -251,11 +264,14 @@ protected function isValidRole( } // Allowed and has an invalid identifier - if ($allowed - && !empty($identifier) - && !$key->isValid($identifier)) { - $this->message = 'Role "' . $role . '"' . ' identifier value is invalid: ' . $key->getDescription(); - return false; + if ($allowed && !empty($identifier)) { + if ($role === self::ROLE_LABEL && !$label->isValid($identifier)) { + $this->message = 'Role "' . $role . '"' . ' identifier value is invalid: ' . $label->getDescription(); + return false; + } elseif ($role !== self::ROLE_LABEL && !$key->isValid($identifier)) { + $this->message = 'Role "' . $role . '"' . ' identifier value is invalid: ' . $key->getDescription(); + return false; + } } // Process dimension configuration diff --git a/tests/Database/Base.php b/tests/Database/Base.php index 17a2bbc05..4ba150db5 100644 --- a/tests/Database/Base.php +++ b/tests/Database/Base.php @@ -10987,6 +10987,32 @@ public function testCollectionPermissionsRelationshipsDeleteWorks(array $data): )); } + public function testLabels(): void + { + $this->assertInstanceOf('Utopia\Database\Document', static::getDatabase()->createCollection( + 'labels_test', + )); + static::getDatabase()->createAttribute('labels_test', 'attr1', Database::VAR_STRING, 10, false); + + static::getDatabase()->createDocument('labels_test', new Document([ + '$id' => 'doc1', + 'attr1' => 'value1', + '$permissions' => [ + Permission::read(Role::label('reader')), + ], + ])); + + $documents = static::getDatabase()->find('labels_test'); + + $this->assertEmpty($documents); + + Authorization::setRole(Role::label('reader')->toString()); + + $documents = static::getDatabase()->find('labels_test'); + + $this->assertCount(1, $documents); + } + public function testEvents(): void { Authorization::skip(function () { diff --git a/tests/Database/PermissionTest.php b/tests/Database/PermissionTest.php index 531002bed..c672b66d5 100644 --- a/tests/Database/PermissionTest.php +++ b/tests/Database/PermissionTest.php @@ -271,6 +271,9 @@ public function testInvalidFormats(): void $this->expectException(\Exception::class); Permission::parse('read("users/")'); + + $this->expectException(\Exception::class); + Permission::parse('read("label:alphanumeric-only")'); } /** diff --git a/tests/Database/RoleTest.php b/tests/Database/RoleTest.php index f551e89e2..b5baa1169 100644 --- a/tests/Database/RoleTest.php +++ b/tests/Database/RoleTest.php @@ -49,6 +49,11 @@ public function testOutputFromString(): void $this->assertEquals('users', $role->getRole()); $this->assertEmpty($role->getIdentifier()); $this->assertEquals('verified', $role->getDimension()); + + $role = Role::parse('label:vip'); + $this->assertEquals('label', $role->getRole()); + $this->assertEquals('vip', $role->getIdentifier()); + $this->assertEmpty($role->getDimension()); } public function testInputFromParameters(): void @@ -70,6 +75,9 @@ public function testInputFromParameters(): void $role = new Role('team', '123', '456'); $this->assertEquals('team:123/456', $role->toString()); + + $role = new Role('label', 'vip'); + $this->assertEquals('label:vip', $role->toString()); } public function testInputFromRoles(): void @@ -91,6 +99,9 @@ public function testInputFromRoles(): void $role = Role::team(ID::custom('123'), '456'); $this->assertEquals('team:123/456', $role->toString()); + + $role = Role::label('vip'); + $this->assertEquals('label:vip', $role->toString()); } public function testInputFromID(): void diff --git a/tests/Database/Validator/LabelTest.php b/tests/Database/Validator/LabelTest.php new file mode 100644 index 000000000..b02b44eb8 --- /dev/null +++ b/tests/Database/Validator/LabelTest.php @@ -0,0 +1,67 @@ +object = new Label(); + } + + public function tearDown(): void + { + } + + public function testValues(): void + { + // Must be strings + $this->assertEquals(false, $this->object->isValid(false)); + $this->assertEquals(false, $this->object->isValid(null)); + $this->assertEquals(false, $this->object->isValid(['value'])); + $this->assertEquals(false, $this->object->isValid(0)); + $this->assertEquals(false, $this->object->isValid(1.5)); + $this->assertEquals(true, $this->object->isValid('asdas7as9as')); + $this->assertEquals(true, $this->object->isValid('5f058a8925807')); + + // No special chars + $this->assertEquals(false, $this->object->isValid('_asdasdasdas')); + $this->assertEquals(false, $this->object->isValid('.as5dasdasdas')); + $this->assertEquals(false, $this->object->isValid('-as5dasdasdas')); + $this->assertEquals(false, $this->object->isValid('as5dadasdas_')); + $this->assertEquals(false, $this->object->isValid('as_5dasdasdas')); + $this->assertEquals(false, $this->object->isValid('as5dasdasdas.')); + $this->assertEquals(false, $this->object->isValid('as.5dasdasdas')); + $this->assertEquals(false, $this->object->isValid('as5dasdasdas-')); + $this->assertEquals(false, $this->object->isValid('as-5dasdasdas')); + $this->assertEquals(false, $this->object->isValid('dasda asdasd')); + $this->assertEquals(false, $this->object->isValid('asd"asd6sdas')); + $this->assertEquals(false, $this->object->isValid('asd\'as0asdas')); + $this->assertEquals(false, $this->object->isValid('as!5dasdasdas')); + $this->assertEquals(false, $this->object->isValid('as@5dasdasdas')); + $this->assertEquals(false, $this->object->isValid('as#5dasdasdas')); + $this->assertEquals(false, $this->object->isValid('as$5dasdasdas')); + $this->assertEquals(false, $this->object->isValid('as%5dasdasdas')); + $this->assertEquals(false, $this->object->isValid('as^5dasdasdas')); + $this->assertEquals(false, $this->object->isValid('as&5dasdasdas')); + $this->assertEquals(false, $this->object->isValid('as*5dasdasdas')); + $this->assertEquals(false, $this->object->isValid('as(5dasdasdas')); + $this->assertEquals(false, $this->object->isValid('as)5dasdasdas')); + $this->assertEquals(false, $this->object->isValid('as+5dasdasdas')); + $this->assertEquals(false, $this->object->isValid('as=5dasdasdas')); + + // At most 36 chars + $this->assertEquals(true, $this->object->isValid('socialAccountForYoutubeSubscribersss')); + $this->assertEquals(false, $this->object->isValid('socialAccountForYoutubeSubscriberssss')); + $this->assertEquals(true, $this->object->isValid('5f058a89258075f058a89258075f058t9214')); + $this->assertEquals(false, $this->object->isValid('5f058a89258075f058a89258075f058tx9214')); + } +} diff --git a/tests/Database/Validator/PermissionsTest.php b/tests/Database/Validator/PermissionsTest.php index a42b10910..d4a5c7d86 100644 --- a/tests/Database/Validator/PermissionsTest.php +++ b/tests/Database/Validator/PermissionsTest.php @@ -91,6 +91,8 @@ public function testSingleMethodSingleValue(): void $this->assertTrue($object->isValid($document->getPermissions())); $document['$permissions'] = [Permission::delete(Role::users('verified'))]; $this->assertTrue($object->isValid($document->getPermissions())); + $document['$permissions'] = [Permission::delete(Role::label('vip'))]; + $this->assertTrue($object->isValid($document->getPermissions())); } public function testMultipleMethodSingleValue(): void diff --git a/tests/Database/Validator/RolesTest.php b/tests/Database/Validator/RolesTest.php index d88ce4369..0f61e752c 100644 --- a/tests/Database/Validator/RolesTest.php +++ b/tests/Database/Validator/RolesTest.php @@ -73,4 +73,11 @@ public function testDisallowedRoles(): void $this->assertFalse($object->isValid([Role::any()->toString()])); $this->assertEquals('Role "any" is not allowed. Must be one of: users.', $object->getDescription()); } + + public function testLabels(): void + { + $object = new Roles(); + $this->assertTrue($object->isValid(['label:123'])); + $this->assertFalse($object->isValid(['label:not-alphanumeric'])); + } }