Apply improved domain validator

This commit is contained in:
Matej Bačo 2025-08-26 11:48:54 +02:00
parent 5436c16f85
commit 6ee95186ce
7 changed files with 144 additions and 38 deletions

View file

@ -57,7 +57,7 @@
"utopia-php/domains": "0.8.*",
"utopia-php/dns": "0.3.*",
"utopia-php/dsn": "0.2.1",
"utopia-php/framework": "0.33.*",
"utopia-php/framework": "dev-feat-domain-restrictions as 0.33.88",
"utopia-php/fetch": "0.4.*",
"utopia-php/image": "0.8.*",
"utopia-php/locale": "0.8.*",

29
composer.lock generated
View file

@ -4,7 +4,7 @@
"Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies",
"This file is @generated automatically"
],
"content-hash": "73ce235556fcb80b52ba92b0670b66e8",
"content-hash": "13f580eba5642949316d81d524996ba8",
"packages": [
{
"name": "adhocore/jwt",
@ -3856,16 +3856,16 @@
},
{
"name": "utopia-php/framework",
"version": "0.33.21",
"version": "dev-feat-domain-restrictions",
"source": {
"type": "git",
"url": "https://github.com/utopia-php/http.git",
"reference": "eb0e82e90b8fa493f99b8d131bdd25173422c493"
"reference": "4a029c13b374c6daa13cd1cbc043ccd713fc6d79"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/utopia-php/http/zipball/eb0e82e90b8fa493f99b8d131bdd25173422c493",
"reference": "eb0e82e90b8fa493f99b8d131bdd25173422c493",
"url": "https://api.github.com/repos/utopia-php/http/zipball/4a029c13b374c6daa13cd1cbc043ccd713fc6d79",
"reference": "4a029c13b374c6daa13cd1cbc043ccd713fc6d79",
"shasum": ""
},
"require": {
@ -3897,9 +3897,9 @@
],
"support": {
"issues": "https://github.com/utopia-php/http/issues",
"source": "https://github.com/utopia-php/http/tree/0.33.21"
"source": "https://github.com/utopia-php/http/tree/feat-domain-restrictions"
},
"time": "2025-08-19T10:52:15+00:00"
"time": "2025-08-26T09:28:47+00:00"
},
{
"name": "utopia-php/image",
@ -8420,9 +8420,18 @@
"time": "2024-03-07T20:33:40+00:00"
}
],
"aliases": [],
"aliases": [
{
"package": "utopia-php/framework",
"version": "dev-feat-domain-restrictions",
"alias": "0.33.88",
"alias_normalized": "0.33.88.0"
}
],
"minimum-stability": "stable",
"stability-flags": [],
"stability-flags": {
"utopia-php/framework": 20
},
"prefer-stable": false,
"prefer-lowest": false,
"platform": {
@ -8446,5 +8455,5 @@
"platform-overrides": {
"php": "8.3"
},
"plugin-api-version": "2.6.0"
"plugin-api-version": "2.3.0"
}

View file

@ -11,9 +11,11 @@ use Appwrite\Utopia\Response;
use Utopia\Database\Database;
use Utopia\Database\Query;
use Utopia\Database\Validator\Authorization;
use Utopia\Domains\Domain as Domain;
use Utopia\Platform\Action;
use Utopia\Platform\Scope\HTTP;
use Utopia\Validator\Domain;
use Utopia\System\System;
use Utopia\Validator\Domain as DomainValidator;
use Utopia\Validator\Text;
use Utopia\Validator\WhiteList;
@ -67,10 +69,57 @@ class Get extends Action
Database $dbForPlatform
) {
if ($type === 'rules') {
$validator = new Domain($value);
$sitesDomain = System::getEnv('_APP_DOMAIN_SITES', '');
$functionsDomain = System::getEnv('_APP_DOMAIN_FUNCTIONS', '');
$restrictions = [];
if (!empty($sitesDomain)) {
$domainLevel = \count(\explode('.', $sitesDomain));
$restrictions[] = DomainValidator::createRestriction($sitesDomain, $domainLevel + 1, ['commit-', 'branch-']);
}
if (!empty($functionsDomain)) {
$domainLevel = \count(\explode('.', $functionsDomain));
$restrictions[] = DomainValidator::createRestriction($functionsDomain, $domainLevel + 1);
}
$validator = new DomainValidator($restrictions);
if (!$validator->isValid($value)) {
throw new Exception(Exception::GENERAL_ARGUMENT_INVALID, $validator->getDescription());
throw new Exception(Exception::GENERAL_ARGUMENT_INVALID, 'This domain name is not allowed. Please use a different domain.');
}
$deniedDomains = [
'localhost',
APP_HOSTNAME_INTERNAL
];
$mainDomain = System::getEnv('_APP_DOMAIN', '');
$deniedDomains[] = $mainDomain;
if (!empty($sitesDomain)) {
$deniedDomains[] = $sitesDomain;
}
if (!empty($functionsDomain)) {
$deniedDomains[] = $functionsDomain;
}
$denyListDomains = System::getEnv('_APP_CUSTOM_DOMAIN_DENY_LIST', '');
$denyListDomains = \array_map('trim', explode(',', $denyListDomains));
foreach ($denyListDomains as $denyListDomain) {
if (empty($denyListDomain)) {
continue;
}
$deniedDomains[] = $denyListDomain;
}
if (\in_array($value, $deniedDomains)) {
throw new Exception(Exception::GENERAL_ARGUMENT_INVALID, 'This domain name is not allowed. Please use a different domain.');
}
try {
$domain = new Domain($value);
} catch (\Throwable) {
throw new Exception(Exception::GENERAL_ARGUMENT_INVALID, 'Domain may not start with http:// or https://.');
}
$document = Authorization::skip(fn () => $dbForPlatform->findOne('rules', [

View file

@ -71,6 +71,24 @@ class Create extends Action
public function action(string $domain, Response $response, Document $project, Certificate $queueForCertificates, Event $queueForEvents, Database $dbForPlatform)
{
$sitesDomain = System::getEnv('_APP_DOMAIN_SITES', '');
$functionsDomain = System::getEnv('_APP_DOMAIN_FUNCTIONS', '');
$restrictions = [];
if (!empty($sitesDomain)) {
$domainLevel = \count(\explode('.', $sitesDomain));
$restrictions[] = ValidatorDomain::createRestriction($sitesDomain, $domainLevel + 1, ['commit-', 'branch-']);
}
if (!empty($functionsDomain)) {
$domainLevel = \count(\explode('.', $functionsDomain));
$restrictions[] = ValidatorDomain::createRestriction($functionsDomain, $domainLevel + 1);
}
$validator = new ValidatorDomain($restrictions);
if (!$validator->isValid($domain)) {
throw new Exception(Exception::GENERAL_ARGUMENT_INVALID, 'This domain name is not allowed. Please use a different domain.');
}
$deniedDomains = [
'localhost',
APP_HOSTNAME_INTERNAL
@ -79,12 +97,10 @@ class Create extends Action
$mainDomain = System::getEnv('_APP_DOMAIN', '');
$deniedDomains[] = $mainDomain;
$sitesDomain = System::getEnv('_APP_DOMAIN_SITES', '');
if (!empty($sitesDomain)) {
$deniedDomains[] = $sitesDomain;
}
$functionsDomain = System::getEnv('_APP_DOMAIN_FUNCTIONS', '');
if (!empty($functionsDomain)) {
$deniedDomains[] = $functionsDomain;
}
@ -102,10 +118,6 @@ class Create extends Action
throw new Exception(Exception::GENERAL_ARGUMENT_INVALID, 'This domain name is not allowed. Please use a different domain.');
}
if (\str_starts_with($domain, 'commit-') || \str_starts_with($domain, 'branch-')) {
throw new Exception(Exception::GENERAL_ARGUMENT_INVALID, 'This domain name is not allowed. Please use a different domain.');
}
try {
$domain = new Domain($domain);
} catch (\Throwable) {

View file

@ -76,6 +76,24 @@ class Create extends Action
public function action(string $domain, string $functionId, string $branch, Response $response, Document $project, Certificate $queueForCertificates, Event $queueForEvents, Database $dbForPlatform, Database $dbForProject)
{
$sitesDomain = System::getEnv('_APP_DOMAIN_SITES', '');
$functionsDomain = System::getEnv('_APP_DOMAIN_FUNCTIONS', '');
$restrictions = [];
if (!empty($sitesDomain)) {
$domainLevel = \count(\explode('.', $sitesDomain));
$restrictions[] = ValidatorDomain::createRestriction($sitesDomain, $domainLevel + 1, ['commit-', 'branch-']);
}
if (!empty($functionsDomain)) {
$domainLevel = \count(\explode('.', $functionsDomain));
$restrictions[] = ValidatorDomain::createRestriction($functionsDomain, $domainLevel + 1);
}
$validator = new ValidatorDomain($restrictions);
if (!$validator->isValid($domain)) {
throw new Exception(Exception::GENERAL_ARGUMENT_INVALID, 'This domain name is not allowed. Please use a different domain.');
}
$deniedDomains = [
'localhost',
APP_HOSTNAME_INTERNAL
@ -84,12 +102,10 @@ class Create extends Action
$mainDomain = System::getEnv('_APP_DOMAIN', '');
$deniedDomains[] = $mainDomain;
$sitesDomain = System::getEnv('_APP_DOMAIN_SITES', '');
if (!empty($sitesDomain)) {
$deniedDomains[] = $sitesDomain;
}
$functionsDomain = System::getEnv('_APP_DOMAIN_FUNCTIONS', '');
if (!empty($functionsDomain)) {
$deniedDomains[] = $functionsDomain;
}
@ -107,10 +123,6 @@ class Create extends Action
throw new Exception(Exception::GENERAL_ARGUMENT_INVALID, 'This domain name is not allowed. Please use a different domain.');
}
if (\str_starts_with($domain, 'commit-') || \str_starts_with($domain, 'branch-')) {
throw new Exception(Exception::GENERAL_ARGUMENT_INVALID, 'This domain name is not allowed. Please use a different domain.');
}
try {
$domain = new Domain($domain);
} catch (\Throwable) {

View file

@ -79,6 +79,24 @@ class Create extends Action
public function action(string $domain, string $url, int $statusCode, string $resourceId, string $resourceType, Response $response, Document $project, Certificate $queueForCertificates, Event $queueForEvents, Database $dbForPlatform, Database $dbForProject)
{
$sitesDomain = System::getEnv('_APP_DOMAIN_SITES', '');
$functionsDomain = System::getEnv('_APP_DOMAIN_FUNCTIONS', '');
$restrictions = [];
if (!empty($sitesDomain)) {
$domainLevel = \count(\explode('.', $sitesDomain));
$restrictions[] = ValidatorDomain::createRestriction($sitesDomain, $domainLevel + 1, ['commit-', 'branch-']);
}
if (!empty($functionsDomain)) {
$domainLevel = \count(\explode('.', $functionsDomain));
$restrictions[] = ValidatorDomain::createRestriction($functionsDomain, $domainLevel + 1);
}
$validator = new ValidatorDomain($restrictions);
if (!$validator->isValid($domain)) {
throw new Exception(Exception::GENERAL_ARGUMENT_INVALID, 'This domain name is not allowed. Please use a different domain.');
}
$deniedDomains = [
'localhost',
APP_HOSTNAME_INTERNAL
@ -87,12 +105,10 @@ class Create extends Action
$mainDomain = System::getEnv('_APP_DOMAIN', '');
$deniedDomains[] = $mainDomain;
$sitesDomain = System::getEnv('_APP_DOMAIN_SITES', '');
if (!empty($sitesDomain)) {
$deniedDomains[] = $sitesDomain;
}
$functionsDomain = System::getEnv('_APP_DOMAIN_FUNCTIONS', '');
if (!empty($functionsDomain)) {
$deniedDomains[] = $functionsDomain;
}
@ -110,10 +126,6 @@ class Create extends Action
throw new Exception(Exception::GENERAL_ARGUMENT_INVALID, 'This domain name is not allowed. Please use a different domain.');
}
if (\str_starts_with($domain, 'commit-') || \str_starts_with($domain, 'branch-')) {
throw new Exception(Exception::GENERAL_ARGUMENT_INVALID, 'This domain name is not allowed. Please use a different domain.');
}
try {
$domain = new Domain($domain);
} catch (\Throwable) {

View file

@ -76,6 +76,24 @@ class Create extends Action
public function action(string $domain, string $siteId, string $branch, Response $response, Document $project, Certificate $queueForCertificates, Event $queueForEvents, Database $dbForPlatform, Database $dbForProject)
{
$sitesDomain = System::getEnv('_APP_DOMAIN_SITES', '');
$functionsDomain = System::getEnv('_APP_DOMAIN_FUNCTIONS', '');
$restrictions = [];
if (!empty($sitesDomain)) {
$domainLevel = \count(\explode('.', $sitesDomain));
$restrictions[] = ValidatorDomain::createRestriction($sitesDomain, $domainLevel + 1, ['commit-', 'branch-']);
}
if (!empty($functionsDomain)) {
$domainLevel = \count(\explode('.', $functionsDomain));
$restrictions[] = ValidatorDomain::createRestriction($functionsDomain, $domainLevel + 1);
}
$validator = new ValidatorDomain($restrictions);
if (!$validator->isValid($domain)) {
throw new Exception(Exception::GENERAL_ARGUMENT_INVALID, 'This domain name is not allowed. Please use a different domain.');
}
$deniedDomains = [
'localhost',
APP_HOSTNAME_INTERNAL
@ -84,12 +102,10 @@ class Create extends Action
$mainDomain = System::getEnv('_APP_DOMAIN', '');
$deniedDomains[] = $mainDomain;
$sitesDomain = System::getEnv('_APP_DOMAIN_SITES', '');
if (!empty($sitesDomain)) {
$deniedDomains[] = $sitesDomain;
}
$functionsDomain = System::getEnv('_APP_DOMAIN_FUNCTIONS', '');
if (!empty($functionsDomain)) {
$deniedDomains[] = $functionsDomain;
}
@ -107,10 +123,6 @@ class Create extends Action
throw new Exception(Exception::GENERAL_ARGUMENT_INVALID, 'This domain name is not allowed. Please use a different domain.');
}
if (\str_starts_with($domain, 'commit-') || \str_starts_with($domain, 'branch-')) {
throw new Exception(Exception::GENERAL_ARGUMENT_INVALID, 'This domain name is not allowed. Please use a different domain.');
}
try {
$domain = new Domain($domain);
} catch (\Throwable) {