fix: create a validator isntead of redundant code

This commit is contained in:
Harsh Mahajan
2025-07-25 17:50:45 +05:30
parent e6cb252763
commit fef2d50159
9 changed files with 172 additions and 53 deletions
+1 -1
View File
@@ -1033,7 +1033,7 @@ services:
volumes:
- appwrite-mariadb:/var/lib/mysql:rw
ports:
- "3306:3306"
- "3307:3306"
environment:
- MYSQL_ROOT_PASSWORD=${_APP_DB_ROOT_PASS}
- MYSQL_DATABASE=${_APP_DB_SCHEMA}
@@ -0,0 +1,44 @@
<?php
namespace Appwrite\Network\Validator;
use Utopia\Validator;
class AppwriteNetworkDomain extends Validator
{
public function getDescription(): string
{
return 'Sub-subdomains are not allowed for appwrite.network. Only one level of subdomain is permitted.';
}
public function isValid($value): bool
{
if (!is_string($value) || empty($value)) {
return true;
}
if (\str_starts_with($value, '.')) {
return false;
}
if (\str_ends_with($value, '.appwrite.network.')) {
return false;
}
if (!\str_ends_with(\strtolower($value), '.appwrite.network')) {
return true;
}
$subdomain = substr(strtolower($value), 0, -strlen('.appwrite.network'));
if (\str_contains($subdomain, '.')) {
return false;
}
return true;
}
public function isArray(): bool
{
return false;
}
public function getType(): string
{
return self::TYPE_STRING;
}
}
@@ -3,6 +3,7 @@
namespace Appwrite\Platform\Modules\Console\Http\Resources;
use Appwrite\Extend\Exception;
use Appwrite\Network\Validator\AppwriteNetworkDomain;
use Appwrite\SDK\AuthType;
use Appwrite\SDK\ContentType;
use Appwrite\SDK\Method;
@@ -68,11 +69,10 @@ class Get extends Action
) {
if ($type === 'rules') {
$validator = new Domain($value);
if (\str_ends_with(\strtolower($value), '.appwrite.network')) {
$subdomain = \str_replace('.appwrite.network', '', strtolower($value));
if (\str_contains($subdomain, '.')) {
throw new Exception(Exception::GENERAL_ARGUMENT_INVALID, 'Sub-subdomains are not allowed for appwrite.network. Only one level of subdomain is permitted.');
}
$appwriteNetworkValidator = new AppwriteNetworkDomain();
if (!$appwriteNetworkValidator->isValid($value)) {
throw new Exception(Exception::GENERAL_ARGUMENT_INVALID, $appwriteNetworkValidator->getDescription());
}
if (!$validator->isValid($value)) {
@@ -5,6 +5,7 @@ namespace Appwrite\Platform\Modules\Proxy\Http\Rules\API;
use Appwrite\Event\Certificate;
use Appwrite\Event\Event;
use Appwrite\Extend\Exception;
use Appwrite\Network\Validator\AppwriteNetworkDomain;
use Appwrite\Network\Validator\DNS;
use Appwrite\SDK\AuthType;
use Appwrite\SDK\Method;
@@ -106,11 +107,10 @@ class Create extends Action
throw new Exception(Exception::GENERAL_ARGUMENT_INVALID, 'This domain name is not allowed. Please use a different domain.');
}
if (\str_ends_with(\strtolower($domain), '.appwrite.network')) {
$subdomain = \str_replace('.appwrite.network', '', \strtolower($domain));
if (empty($subdomain) || \str_contains($subdomain, '.')) {
throw new Exception(Exception::GENERAL_ARGUMENT_INVALID, 'Sub-subdomains are not allowed for appwrite.network. Only one level of subdomain is permitted.');
}
$appwriteNetworkValidator = new AppwriteNetworkDomain();
if (!$appwriteNetworkValidator->isValid($domain)) {
throw new Exception(Exception::GENERAL_ARGUMENT_INVALID, $appwriteNetworkValidator->getDescription());
}
try {
@@ -5,6 +5,7 @@ namespace Appwrite\Platform\Modules\Proxy\Http\Rules\Function;
use Appwrite\Event\Certificate;
use Appwrite\Event\Event;
use Appwrite\Extend\Exception;
use Appwrite\Network\Validator\AppwriteNetworkDomain;
use Appwrite\Network\Validator\DNS;
use Appwrite\SDK\AuthType;
use Appwrite\SDK\Method;
@@ -111,11 +112,10 @@ class Create extends Action
throw new Exception(Exception::GENERAL_ARGUMENT_INVALID, 'This domain name is not allowed. Please use a different domain.');
}
if (\str_ends_with(\strtolower($domain), '.appwrite.network')) {
$subdomain = \str_replace('.appwrite.network', '', strtolower($domain));
if (\str_contains($subdomain, '.')) {
throw new Exception(Exception::GENERAL_ARGUMENT_INVALID, 'Sub-subdomains are not allowed for appwrite.network. Only one level of subdomain is permitted.');
}
$appwriteNetworkValidator = new AppwriteNetworkDomain();
if (!$appwriteNetworkValidator->isValid($domain)) {
throw new Exception(Exception::GENERAL_ARGUMENT_INVALID, $appwriteNetworkValidator->getDescription());
}
try {
@@ -5,6 +5,7 @@ namespace Appwrite\Platform\Modules\Proxy\Http\Rules\Redirect;
use Appwrite\Event\Certificate;
use Appwrite\Event\Event;
use Appwrite\Extend\Exception;
use Appwrite\Network\Validator\AppwriteNetworkDomain;
use Appwrite\Network\Validator\DNS;
use Appwrite\SDK\AuthType;
use Appwrite\SDK\Method;
@@ -114,11 +115,10 @@ class Create extends Action
throw new Exception(Exception::GENERAL_ARGUMENT_INVALID, 'This domain name is not allowed. Please use a different domain.');
}
if (\str_ends_with(\strtolower($domain), '.appwrite.network')) {
$subdomain = \str_replace('.appwrite.network', '', strtolower($domain));
if (\str_contains($subdomain, '.')) {
throw new Exception(Exception::GENERAL_ARGUMENT_INVALID, 'Sub-subdomains are not allowed for appwrite.network. Only one level of subdomain is permitted.');
}
$appwriteNetworkValidator = new AppwriteNetworkDomain();
if (!$appwriteNetworkValidator->isValid($domain)) {
throw new Exception(Exception::GENERAL_ARGUMENT_INVALID, $appwriteNetworkValidator->getDescription());
}
try {
@@ -5,6 +5,7 @@ namespace Appwrite\Platform\Modules\Proxy\Http\Rules\Site;
use Appwrite\Event\Certificate;
use Appwrite\Event\Event;
use Appwrite\Extend\Exception;
use Appwrite\Network\Validator\AppwriteNetworkDomain;
use Appwrite\Network\Validator\DNS;
use Appwrite\SDK\AuthType;
use Appwrite\SDK\Method;
@@ -111,11 +112,10 @@ class Create extends Action
throw new Exception(Exception::GENERAL_ARGUMENT_INVALID, 'This domain name is not allowed. Please use a different domain.');
}
if (\str_ends_with(\strtolower($domain), '.appwrite.network')) {
$subdomain = \str_replace('.appwrite.network', '', strtolower($domain));
if (\str_contains($subdomain, '.')) {
throw new Exception(Exception::GENERAL_ARGUMENT_INVALID, 'Sub-subdomains are not allowed for appwrite.network. Only one level of subdomain is permitted.');
}
$appwriteNetworkValidator = new AppwriteNetworkDomain();
if (!$appwriteNetworkValidator->isValid($domain)) {
throw new Exception(Exception::GENERAL_ARGUMENT_INVALID, $appwriteNetworkValidator->getDescription());
}
try {
@@ -81,33 +81,6 @@ class ProxyCustomServerTest extends Scope
$this->cleanupRule($rule['body']['$id']);
}
public function testCreateAPIRuleAppwriteNetworkValidation(): void
{
// Test vallid single subdomain for appwrite.network
$validDomain = \uniqid() . '.appwrite.network';
$rule = $this->createAPIRule($validDomain);
$this->assertEquals(201, $rule['headers']['status-code']);
$this->cleanupRule($rule['body']['$id']);
// Test invalid sub-subdomain for appwrite.network
$invalidDomain = 'api.staging.appwrite.network';
$rule = $this->createAPIRule($invalidDomain);
$this->assertEquals(400, $rule['headers']['status-code']);
$this->assertStringContainsString('Sub-subdomains are not allowed for appwrite.network', $rule['body']['message']);
// Test another invalid sub-subdomain with multiple dots
$invalidDomain2 = 'asadsdsa.sddsa.appwrite.network';
$rule = $this->createAPIRule($invalidDomain2);
$this->assertEquals(400, $rule['headers']['status-code']);
$this->assertStringContainsString('Sub-subdomains are not allowed for appwrite.network', $rule['body']['message']);
// Test valid domain that doesn't end with appwrite.network (should pass)
$otherDomain = \uniqid() . '.example.com';
$rule = $this->createAPIRule($otherDomain);
$this->assertEquals(201, $rule['headers']['status-code']);
$this->cleanupRule($rule['body']['$id']);
}
public function testCreateAPIRule(): void
{
$domain = \uniqid() . '-api.custom.localhost';
@@ -0,0 +1,102 @@
<?php
namespace Tests\Unit\Network\Validators;
use Appwrite\Network\Validator\AppwriteNetworkDomain;
use PHPUnit\Framework\TestCase;
class AppwriteNetworkDomainTest extends TestCase
{
protected ?AppwriteNetworkDomain $validator = null;
public function setUp(): void
{
$this->validator = new AppwriteNetworkDomain();
}
public function tearDown(): void
{
$this->validator = null;
}
public function testValidSingleSubdomains(): void
{
// Valid single-level subdomains for appwrite.network
$this->assertEquals(true, $this->validator->isValid('api.appwrite.network'));
$this->assertEquals(true, $this->validator->isValid('app.appwrite.network'));
$this->assertEquals(true, $this->validator->isValid('test.appwrite.network'));
$this->assertEquals(true, $this->validator->isValid('myapp.appwrite.network'));
$this->assertEquals(true, $this->validator->isValid('123.appwrite.network'));
$this->assertEquals(true, $this->validator->isValid('my-app.appwrite.network'));
$this->assertEquals(true, $this->validator->isValid('a.appwrite.network'));
// Test case insensitivity
$this->assertEquals(true, $this->validator->isValid('API.APPWRITE.NETWORK'));
$this->assertEquals(true, $this->validator->isValid('Api.Appwrite.Network'));
}
public function testInvalidSubSubdomains(): void
{
// Invalid sub-subdomains for appwrite.network
$this->assertEquals(false, $this->validator->isValid('api.staging.appwrite.network'));
$this->assertEquals(false, $this->validator->isValid('app.dev.appwrite.network'));
$this->assertEquals(false, $this->validator->isValid('test.beta.appwrite.network'));
$this->assertEquals(false, $this->validator->isValid('foo.bar.appwrite.network'));
$this->assertEquals(false, $this->validator->isValid('a.b.appwrite.network'));
$this->assertEquals(false, $this->validator->isValid('very.long.subdomain.appwrite.network'));
$this->assertEquals(false, $this->validator->isValid('multi.level.deep.appwrite.network'));
// Test case insensitivity
$this->assertEquals(false, $this->validator->isValid('API.STAGING.APPWRITE.NETWORK'));
$this->assertEquals(false, $this->validator->isValid('Api.Dev.Appwrite.Network'));
}
public function testNonAppwriteNetworkDomains(): void
{
// Non-appwrite.network domains should pass validation (not our concern)
$this->assertEquals(true, $this->validator->isValid('example.com'));
$this->assertEquals(true, $this->validator->isValid('api.example.com'));
$this->assertEquals(true, $this->validator->isValid('deep.nested.example.com'));
$this->assertEquals(true, $this->validator->isValid('google.com'));
$this->assertEquals(true, $this->validator->isValid('sub.domain.test.io'));
$this->assertEquals(true, $this->validator->isValid('localhost'));
$this->assertEquals(true, $this->validator->isValid('127.0.0.1'));
// Similar but different domains
$this->assertEquals(true, $this->validator->isValid('appwrite.com'));
$this->assertEquals(true, $this->validator->isValid('api.appwrite.com'));
$this->assertEquals(true, $this->validator->isValid('test.appwrite.org'));
$this->assertEquals(true, $this->validator->isValid('notappwrite.network'));
}
public function testDoubleSubdomainCustomDomain(): void
{
// Double subdomain for a custom domain should be allowed
$this->assertEquals(true, $this->validator->isValid('stage.dashboard.example.com'));
$this->assertEquals(true, $this->validator->isValid('foo.bar.baz.example.com'));
}
public function testEdgeCases(): void
{
// Empty and invalid values should pass (let other validators handle them)
$this->assertEquals(true, $this->validator->isValid(''));
$this->assertEquals(true, $this->validator->isValid(null));
$this->assertEquals(true, $this->validator->isValid(false));
$this->assertEquals(true, $this->validator->isValid(123));
$this->assertEquals(true, $this->validator->isValid([]));
// Just the root domain (unlikely but should be valid)
$this->assertEquals(true, $this->validator->isValid('appwrite.network'));
// Domain with trailing/leading dots
$this->assertEquals(false, $this->validator->isValid('api.test.appwrite.network.'));
$this->assertEquals(false, $this->validator->isValid('.api.test.appwrite.network'));
}
public function testValidatorProperties(): void
{
$this->assertEquals('Sub-subdomains are not allowed for appwrite.network. Only one level of subdomain is permitted.', $this->validator->getDescription());
$this->assertEquals(false, $this->validator->isArray());
$this->assertEquals('string', $this->validator->getType());
}
}