mirror of
https://github.com/appwrite/appwrite.git
synced 2026-05-26 13:51:13 +00:00
Compare commits
17
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
85c48fc5d1 | ||
|
|
68ae8ce348 | ||
|
|
87b0bfcdfe | ||
|
|
d37bab37e6 | ||
|
|
7810d54238 | ||
|
|
b3f9404b93 | ||
|
|
d4b5d7df73 | ||
|
|
e93f479157 | ||
|
|
a1b1f97162 | ||
|
|
4ce2426c3d | ||
|
|
25b3680b1d | ||
|
|
c442dd3ef1 | ||
|
|
bf5aa7b86c | ||
|
|
b42cc11eba | ||
|
|
cc6f5fea6d | ||
|
|
12e3af6ad7 | ||
|
|
f0b6eeb303 |
@@ -300,7 +300,7 @@ return [
|
||||
[
|
||||
'key' => 'python',
|
||||
'name' => 'Python',
|
||||
'version' => '13.6.0',
|
||||
'version' => '13.6.1',
|
||||
'url' => 'https://github.com/appwrite/sdk-for-python',
|
||||
'package' => 'https://pypi.org/project/appwrite/',
|
||||
'enabled' => true,
|
||||
|
||||
@@ -31203,7 +31203,7 @@
|
||||
"tags": [
|
||||
"sites"
|
||||
],
|
||||
"description": "Create a new site code deployment. Use this endpoint to upload a new version of your site code. To activate your newly uploaded code, you'll need to update the function's deployment to use your new deployment ID.",
|
||||
"description": "Create a new site code deployment. Use this endpoint to upload a new version of your site code. To activate your newly uploaded code, you'll need to update the site's deployment to use your new deployment ID.",
|
||||
"responses": {
|
||||
"202": {
|
||||
"description": "Deployment",
|
||||
@@ -31224,7 +31224,7 @@
|
||||
"cookies": false,
|
||||
"type": "upload",
|
||||
"demo": "sites\/create-deployment.md",
|
||||
"edit": "https:\/\/github.com\/appwrite\/appwrite\/edit\/masterCreate a new site code deployment. Use this endpoint to upload a new version of your site code. To activate your newly uploaded code, you'll need to update the function's deployment to use your new deployment ID.",
|
||||
"edit": "https:\/\/github.com\/appwrite\/appwrite\/edit\/masterCreate a new site code deployment. Use this endpoint to upload a new version of your site code. To activate your newly uploaded code, you'll need to update the site's deployment to use your new deployment ID.",
|
||||
"rate-limit": 0,
|
||||
"rate-time": 3600,
|
||||
"rate-key": "url:{url},ip:{ip}",
|
||||
|
||||
@@ -21725,7 +21725,7 @@
|
||||
"tags": [
|
||||
"sites"
|
||||
],
|
||||
"description": "Create a new site code deployment. Use this endpoint to upload a new version of your site code. To activate your newly uploaded code, you'll need to update the function's deployment to use your new deployment ID.",
|
||||
"description": "Create a new site code deployment. Use this endpoint to upload a new version of your site code. To activate your newly uploaded code, you'll need to update the site's deployment to use your new deployment ID.",
|
||||
"responses": {
|
||||
"202": {
|
||||
"description": "Deployment",
|
||||
@@ -21746,7 +21746,7 @@
|
||||
"cookies": false,
|
||||
"type": "upload",
|
||||
"demo": "sites\/create-deployment.md",
|
||||
"edit": "https:\/\/github.com\/appwrite\/appwrite\/edit\/masterCreate a new site code deployment. Use this endpoint to upload a new version of your site code. To activate your newly uploaded code, you'll need to update the function's deployment to use your new deployment ID.",
|
||||
"edit": "https:\/\/github.com\/appwrite\/appwrite\/edit\/masterCreate a new site code deployment. Use this endpoint to upload a new version of your site code. To activate your newly uploaded code, you'll need to update the site's deployment to use your new deployment ID.",
|
||||
"rate-limit": 0,
|
||||
"rate-time": 3600,
|
||||
"rate-key": "url:{url},ip:{ip}",
|
||||
|
||||
@@ -31203,7 +31203,7 @@
|
||||
"tags": [
|
||||
"sites"
|
||||
],
|
||||
"description": "Create a new site code deployment. Use this endpoint to upload a new version of your site code. To activate your newly uploaded code, you'll need to update the function's deployment to use your new deployment ID.",
|
||||
"description": "Create a new site code deployment. Use this endpoint to upload a new version of your site code. To activate your newly uploaded code, you'll need to update the site's deployment to use your new deployment ID.",
|
||||
"responses": {
|
||||
"202": {
|
||||
"description": "Deployment",
|
||||
@@ -31224,7 +31224,7 @@
|
||||
"cookies": false,
|
||||
"type": "upload",
|
||||
"demo": "sites\/create-deployment.md",
|
||||
"edit": "https:\/\/github.com\/appwrite\/appwrite\/edit\/masterCreate a new site code deployment. Use this endpoint to upload a new version of your site code. To activate your newly uploaded code, you'll need to update the function's deployment to use your new deployment ID.",
|
||||
"edit": "https:\/\/github.com\/appwrite\/appwrite\/edit\/masterCreate a new site code deployment. Use this endpoint to upload a new version of your site code. To activate your newly uploaded code, you'll need to update the site's deployment to use your new deployment ID.",
|
||||
"rate-limit": 0,
|
||||
"rate-time": 3600,
|
||||
"rate-key": "url:{url},ip:{ip}",
|
||||
|
||||
@@ -21725,7 +21725,7 @@
|
||||
"tags": [
|
||||
"sites"
|
||||
],
|
||||
"description": "Create a new site code deployment. Use this endpoint to upload a new version of your site code. To activate your newly uploaded code, you'll need to update the function's deployment to use your new deployment ID.",
|
||||
"description": "Create a new site code deployment. Use this endpoint to upload a new version of your site code. To activate your newly uploaded code, you'll need to update the site's deployment to use your new deployment ID.",
|
||||
"responses": {
|
||||
"202": {
|
||||
"description": "Deployment",
|
||||
@@ -21746,7 +21746,7 @@
|
||||
"cookies": false,
|
||||
"type": "upload",
|
||||
"demo": "sites\/create-deployment.md",
|
||||
"edit": "https:\/\/github.com\/appwrite\/appwrite\/edit\/masterCreate a new site code deployment. Use this endpoint to upload a new version of your site code. To activate your newly uploaded code, you'll need to update the function's deployment to use your new deployment ID.",
|
||||
"edit": "https:\/\/github.com\/appwrite\/appwrite\/edit\/masterCreate a new site code deployment. Use this endpoint to upload a new version of your site code. To activate your newly uploaded code, you'll need to update the site's deployment to use your new deployment ID.",
|
||||
"rate-limit": 0,
|
||||
"rate-time": 3600,
|
||||
"rate-key": "url:{url},ip:{ip}",
|
||||
|
||||
@@ -31350,7 +31350,7 @@
|
||||
"tags": [
|
||||
"sites"
|
||||
],
|
||||
"description": "Create a new site code deployment. Use this endpoint to upload a new version of your site code. To activate your newly uploaded code, you'll need to update the function's deployment to use your new deployment ID.",
|
||||
"description": "Create a new site code deployment. Use this endpoint to upload a new version of your site code. To activate your newly uploaded code, you'll need to update the site's deployment to use your new deployment ID.",
|
||||
"responses": {
|
||||
"202": {
|
||||
"description": "Deployment",
|
||||
@@ -31367,7 +31367,7 @@
|
||||
"cookies": false,
|
||||
"type": "upload",
|
||||
"demo": "sites\/create-deployment.md",
|
||||
"edit": "https:\/\/github.com\/appwrite\/appwrite\/edit\/masterCreate a new site code deployment. Use this endpoint to upload a new version of your site code. To activate your newly uploaded code, you'll need to update the function's deployment to use your new deployment ID.",
|
||||
"edit": "https:\/\/github.com\/appwrite\/appwrite\/edit\/masterCreate a new site code deployment. Use this endpoint to upload a new version of your site code. To activate your newly uploaded code, you'll need to update the site's deployment to use your new deployment ID.",
|
||||
"rate-limit": 0,
|
||||
"rate-time": 3600,
|
||||
"rate-key": "url:{url},ip:{ip}",
|
||||
|
||||
@@ -21920,7 +21920,7 @@
|
||||
"tags": [
|
||||
"sites"
|
||||
],
|
||||
"description": "Create a new site code deployment. Use this endpoint to upload a new version of your site code. To activate your newly uploaded code, you'll need to update the function's deployment to use your new deployment ID.",
|
||||
"description": "Create a new site code deployment. Use this endpoint to upload a new version of your site code. To activate your newly uploaded code, you'll need to update the site's deployment to use your new deployment ID.",
|
||||
"responses": {
|
||||
"202": {
|
||||
"description": "Deployment",
|
||||
@@ -21937,7 +21937,7 @@
|
||||
"cookies": false,
|
||||
"type": "upload",
|
||||
"demo": "sites\/create-deployment.md",
|
||||
"edit": "https:\/\/github.com\/appwrite\/appwrite\/edit\/masterCreate a new site code deployment. Use this endpoint to upload a new version of your site code. To activate your newly uploaded code, you'll need to update the function's deployment to use your new deployment ID.",
|
||||
"edit": "https:\/\/github.com\/appwrite\/appwrite\/edit\/masterCreate a new site code deployment. Use this endpoint to upload a new version of your site code. To activate your newly uploaded code, you'll need to update the site's deployment to use your new deployment ID.",
|
||||
"rate-limit": 0,
|
||||
"rate-time": 3600,
|
||||
"rate-key": "url:{url},ip:{ip}",
|
||||
|
||||
@@ -31350,7 +31350,7 @@
|
||||
"tags": [
|
||||
"sites"
|
||||
],
|
||||
"description": "Create a new site code deployment. Use this endpoint to upload a new version of your site code. To activate your newly uploaded code, you'll need to update the function's deployment to use your new deployment ID.",
|
||||
"description": "Create a new site code deployment. Use this endpoint to upload a new version of your site code. To activate your newly uploaded code, you'll need to update the site's deployment to use your new deployment ID.",
|
||||
"responses": {
|
||||
"202": {
|
||||
"description": "Deployment",
|
||||
@@ -31367,7 +31367,7 @@
|
||||
"cookies": false,
|
||||
"type": "upload",
|
||||
"demo": "sites\/create-deployment.md",
|
||||
"edit": "https:\/\/github.com\/appwrite\/appwrite\/edit\/masterCreate a new site code deployment. Use this endpoint to upload a new version of your site code. To activate your newly uploaded code, you'll need to update the function's deployment to use your new deployment ID.",
|
||||
"edit": "https:\/\/github.com\/appwrite\/appwrite\/edit\/masterCreate a new site code deployment. Use this endpoint to upload a new version of your site code. To activate your newly uploaded code, you'll need to update the site's deployment to use your new deployment ID.",
|
||||
"rate-limit": 0,
|
||||
"rate-time": 3600,
|
||||
"rate-key": "url:{url},ip:{ip}",
|
||||
|
||||
@@ -21920,7 +21920,7 @@
|
||||
"tags": [
|
||||
"sites"
|
||||
],
|
||||
"description": "Create a new site code deployment. Use this endpoint to upload a new version of your site code. To activate your newly uploaded code, you'll need to update the function's deployment to use your new deployment ID.",
|
||||
"description": "Create a new site code deployment. Use this endpoint to upload a new version of your site code. To activate your newly uploaded code, you'll need to update the site's deployment to use your new deployment ID.",
|
||||
"responses": {
|
||||
"202": {
|
||||
"description": "Deployment",
|
||||
@@ -21937,7 +21937,7 @@
|
||||
"cookies": false,
|
||||
"type": "upload",
|
||||
"demo": "sites\/create-deployment.md",
|
||||
"edit": "https:\/\/github.com\/appwrite\/appwrite\/edit\/masterCreate a new site code deployment. Use this endpoint to upload a new version of your site code. To activate your newly uploaded code, you'll need to update the function's deployment to use your new deployment ID.",
|
||||
"edit": "https:\/\/github.com\/appwrite\/appwrite\/edit\/masterCreate a new site code deployment. Use this endpoint to upload a new version of your site code. To activate your newly uploaded code, you'll need to update the site's deployment to use your new deployment ID.",
|
||||
"rate-limit": 0,
|
||||
"rate-time": 3600,
|
||||
"rate-key": "url:{url},ip:{ip}",
|
||||
|
||||
+2
-2
@@ -55,9 +55,9 @@
|
||||
"utopia-php/detector": "0.2.*",
|
||||
"utopia-php/domains": "0.9.*",
|
||||
"utopia-php/emails": "0.6.*",
|
||||
"utopia-php/dns": "0.3.*",
|
||||
"utopia-php/dns": "1.1.*",
|
||||
"utopia-php/dsn": "0.2.1",
|
||||
"utopia-php/framework": "0.33.*",
|
||||
"utopia-php/framework": "dev-fix-nullable-check as 0.33.28",
|
||||
"utopia-php/fetch": "0.4.*",
|
||||
"utopia-php/image": "0.8.*",
|
||||
"utopia-php/locale": "0.8.*",
|
||||
|
||||
Generated
+20
-21
@@ -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": "66e5a72649d7f816ba8ec979faca4cd8",
|
||||
"content-hash": "ad28b7155175986191bd19bbcd13d623",
|
||||
"packages": [
|
||||
{
|
||||
"name": "adhocore/jwt",
|
||||
@@ -3840,16 +3840,16 @@
|
||||
},
|
||||
{
|
||||
"name": "utopia-php/database",
|
||||
"version": "3.1.3",
|
||||
"version": "3.1.5",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/utopia-php/database.git",
|
||||
"reference": "b38cc9887a8fefedcb9a962168dd6f28b7082fc1"
|
||||
"reference": "76568b81f25d89fc1e0c53f0370f139130eeb939"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/utopia-php/database/zipball/b38cc9887a8fefedcb9a962168dd6f28b7082fc1",
|
||||
"reference": "b38cc9887a8fefedcb9a962168dd6f28b7082fc1",
|
||||
"url": "https://api.github.com/repos/utopia-php/database/zipball/76568b81f25d89fc1e0c53f0370f139130eeb939",
|
||||
"reference": "76568b81f25d89fc1e0c53f0370f139130eeb939",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
@@ -3892,9 +3892,9 @@
|
||||
],
|
||||
"support": {
|
||||
"issues": "https://github.com/utopia-php/database/issues",
|
||||
"source": "https://github.com/utopia-php/database/tree/3.1.3"
|
||||
"source": "https://github.com/utopia-php/database/tree/3.1.5"
|
||||
},
|
||||
"time": "2025-11-04T11:41:54+00:00"
|
||||
"time": "2025-11-05T10:17:55+00:00"
|
||||
},
|
||||
{
|
||||
"name": "utopia-php/detector",
|
||||
@@ -3943,29 +3943,28 @@
|
||||
},
|
||||
{
|
||||
"name": "utopia-php/dns",
|
||||
"version": "0.3.0",
|
||||
"version": "1.1.0",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/utopia-php/dns.git",
|
||||
"reference": "8fd4161bc3a8021a670c1101b40f6b09a97f1a54"
|
||||
"reference": "d6eca184883262bdcb4261e57491c91b16079b9a"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/utopia-php/dns/zipball/8fd4161bc3a8021a670c1101b40f6b09a97f1a54",
|
||||
"reference": "8fd4161bc3a8021a670c1101b40f6b09a97f1a54",
|
||||
"url": "https://api.github.com/repos/utopia-php/dns/zipball/d6eca184883262bdcb4261e57491c91b16079b9a",
|
||||
"reference": "d6eca184883262bdcb4261e57491c91b16079b9a",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
"php": ">=8.0",
|
||||
"utopia-php/cli": "0.15.*",
|
||||
"utopia-php/telemetry": "^0.1.1"
|
||||
"php": ">=8.3",
|
||||
"utopia-php/console": "0.0.*",
|
||||
"utopia-php/telemetry": "0.1.*"
|
||||
},
|
||||
"require-dev": {
|
||||
"laravel/pint": "1.2.*",
|
||||
"phpstan/phpstan": "1.8.*",
|
||||
"phpunit/phpunit": "^9.3",
|
||||
"rregeer/phpunit-coverage-check": "^0.3.1",
|
||||
"swoole/ide-helper": "4.6.6"
|
||||
"laravel/pint": "1.25.*",
|
||||
"phpstan/phpstan": "2.0.*",
|
||||
"phpunit/phpunit": "12.4.*",
|
||||
"swoole/ide-helper": "5.1.8"
|
||||
},
|
||||
"type": "library",
|
||||
"autoload": {
|
||||
@@ -3993,9 +3992,9 @@
|
||||
],
|
||||
"support": {
|
||||
"issues": "https://github.com/utopia-php/dns/issues",
|
||||
"source": "https://github.com/utopia-php/dns/tree/0.3.0"
|
||||
"source": "https://github.com/utopia-php/dns/tree/1.1.0"
|
||||
},
|
||||
"time": "2025-08-04T11:05:53+00:00"
|
||||
"time": "2025-11-03T22:49:02+00:00"
|
||||
},
|
||||
{
|
||||
"name": "utopia-php/domains",
|
||||
|
||||
@@ -1,5 +1,9 @@
|
||||
# Change Log
|
||||
|
||||
## 13.6.1
|
||||
|
||||
* Fix passing of `None` to nullable parameters
|
||||
|
||||
## 13.6.0
|
||||
|
||||
* Add `total` parameter to list queries allowing skipping counting rows in a table for improved performance
|
||||
|
||||
@@ -3,118 +3,65 @@
|
||||
namespace Appwrite\Network\Validator;
|
||||
|
||||
use Utopia\DNS\Client;
|
||||
use Utopia\DNS\Message;
|
||||
use Utopia\DNS\Message\Question;
|
||||
use Utopia\DNS\Message\Record;
|
||||
use Utopia\Domains\Domain;
|
||||
use Utopia\System\System;
|
||||
use Utopia\Validator;
|
||||
|
||||
class DNS extends Validator
|
||||
{
|
||||
public const RECORD_A = 'A';
|
||||
public const RECORD_AAAA = 'AAAA';
|
||||
public const RECORD_CNAME = 'CNAME';
|
||||
public const RECORD_CAA = 'CAA'; // You can provide domain only (as $target) for CAA validation
|
||||
|
||||
/**
|
||||
* @var mixed
|
||||
*/
|
||||
protected mixed $logs;
|
||||
|
||||
/**
|
||||
* @var string
|
||||
*/
|
||||
protected string $dnsServer;
|
||||
|
||||
/**
|
||||
* @param string $target
|
||||
*/
|
||||
public function __construct(protected string $target, protected string $type = self::RECORD_CNAME, string $dnsServer = '')
|
||||
{
|
||||
if (empty($dnsServer)) {
|
||||
$dnsServer = System::getEnv('_APP_DNS', '8.8.8.8');
|
||||
}
|
||||
|
||||
$this->dnsServer = $dnsServer;
|
||||
public function __construct(
|
||||
protected string $target,
|
||||
protected int $type = Record::TYPE_CNAME,
|
||||
protected string $server = ''
|
||||
) {
|
||||
$this->server = $server ?: System::getEnv('_APP_DNS', '8.8.8.8');
|
||||
}
|
||||
|
||||
/**
|
||||
* @return string
|
||||
*/
|
||||
public function getDescription(): string
|
||||
{
|
||||
return 'Invalid DNS record';
|
||||
return 'Invalid DNS record.';
|
||||
}
|
||||
|
||||
/**
|
||||
* @return mixed
|
||||
*/
|
||||
public function getLogs(): mixed
|
||||
{
|
||||
return $this->logs;
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if DNS record value matches specific value
|
||||
*
|
||||
* @param mixed $domain
|
||||
* @return bool
|
||||
*/
|
||||
public function isValid($value): bool
|
||||
{
|
||||
if (!is_string($value)) {
|
||||
if (!is_string($value) || trim($value) === '') {
|
||||
return false;
|
||||
}
|
||||
|
||||
$dns = new Client($this->dnsServer);
|
||||
|
||||
$client = new Client($this->server);
|
||||
try {
|
||||
$rawQuery = $dns->query($value, $this->type);
|
||||
|
||||
// Some DNS servers return all records, not only type that's asked for
|
||||
// Likely occurs when no records of specific type are found
|
||||
$query = array_filter($rawQuery, function ($record) {
|
||||
return $record->getTypeName() === $this->type;
|
||||
});
|
||||
|
||||
$this->logs = $query;
|
||||
} catch (\Exception $e) {
|
||||
$this->logs = ['error' => $e->getMessage()];
|
||||
$response = $client->query(Message::query(
|
||||
new Question($value, $this->type)
|
||||
));
|
||||
} catch (\Throwable) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (empty($query)) {
|
||||
// CAA records inherit from parent (custom CAA behaviour)
|
||||
if ($this->type === self::RECORD_CAA) {
|
||||
$domain = new Domain($value);
|
||||
if ($domain->get() === $domain->getApex()) {
|
||||
return true; // No CAA on apex domain means anyone can issue certificate
|
||||
}
|
||||
$typeMatches = array_filter(
|
||||
$response->answers,
|
||||
fn (Record $record) => $record->type === $this->type
|
||||
);
|
||||
|
||||
// Recursive validation by parent domain
|
||||
$parts = \explode('.', $value);
|
||||
\array_shift($parts);
|
||||
$parentDomain = \implode('.', $parts);
|
||||
$validator = new DNS($this->target, DNS::RECORD_CAA, $this->dnsServer);
|
||||
return $validator->isValid($parentDomain);
|
||||
if (empty($typeMatches)) {
|
||||
if ($this->type === Record::TYPE_CAA) {
|
||||
return $this->validateParentCAA($value);
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
foreach ($query as $record) {
|
||||
// CAA validation only needs to ensure domain
|
||||
if ($this->type === self::RECORD_CAA) {
|
||||
// Extract domain; comments showcase extraction steps in most complex scenario
|
||||
$rdata = $record->getRdata(); // 255 issuewild "certainly.com;validationmethods=tls-alpn-01;retrytimeout=3600"
|
||||
$rdata = \explode(' ', $rdata, 3)[2] ?? ''; // "certainly.com;validationmethods=tls-alpn-01;retrytimeout=3600"
|
||||
$rdata = \trim($rdata, '"'); // certainly.com;validationmethods=tls-alpn-01;retrytimeout=3600
|
||||
$rdata = \explode(';', $rdata, 2)[0] ?? ''; // certainly.com
|
||||
|
||||
if ($rdata === $this->target) {
|
||||
foreach ($typeMatches as $record) {
|
||||
if ($this->type === Record::TYPE_CAA) {
|
||||
$valuePart = $this->extractCAAValue($record->rdata);
|
||||
if ($valuePart !== '' && $valuePart === $this->target) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
if ($record->getRdata() === $this->target) {
|
||||
if ($record->rdata === $this->target) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
@@ -122,25 +69,46 @@ class DNS extends Validator
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Is array
|
||||
*
|
||||
* Function will return true if object is array.
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
private function validateParentCAA(string $domain): bool
|
||||
{
|
||||
try {
|
||||
$domainInfo = new Domain($domain);
|
||||
} catch (\Throwable) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if ($domainInfo->get() === $domainInfo->getApex()) {
|
||||
return true;
|
||||
}
|
||||
|
||||
$parts = explode('.', $domainInfo->get());
|
||||
array_shift($parts);
|
||||
$parent = implode('.', $parts);
|
||||
|
||||
if ($parent === '') {
|
||||
return false;
|
||||
}
|
||||
|
||||
$validator = new self($this->target, Record::TYPE_CAA, $this->server);
|
||||
return $validator->isValid($parent);
|
||||
}
|
||||
|
||||
private function extractCAAValue(string $rdata): string
|
||||
{
|
||||
$parts = explode(' ', $rdata, 3);
|
||||
if (count($parts) < 3) {
|
||||
return '';
|
||||
}
|
||||
|
||||
$value = trim($parts[2], '"');
|
||||
return explode(';', $value)[0] ?? '';
|
||||
}
|
||||
|
||||
public function isArray(): bool
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get Type
|
||||
*
|
||||
* Returns validator type.
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function getType(): string
|
||||
{
|
||||
return self::TYPE_STRING;
|
||||
|
||||
@@ -589,7 +589,10 @@ class Builds extends Action
|
||||
// Some runtimes/frameworks can't compile with less memory than this
|
||||
$minMemory = $resource->getCollection() === 'sites' ? 2048 : 1024;
|
||||
|
||||
if ($resource->getAttribute('framework', '') === 'analog') {
|
||||
if (
|
||||
$resource->getAttribute('framework', '') === 'analog' ||
|
||||
$resource->getAttribute('framework', '') === 'tanstack-start'
|
||||
) {
|
||||
$minMemory = 4096;
|
||||
}
|
||||
|
||||
|
||||
@@ -14,6 +14,7 @@ use Utopia\Database\Database;
|
||||
use Utopia\Database\Document;
|
||||
use Utopia\Database\Exception\Duplicate;
|
||||
use Utopia\Database\Helpers\ID;
|
||||
use Utopia\DNS\Message\Record;
|
||||
use Utopia\Domains\Domain;
|
||||
use Utopia\Platform\Action;
|
||||
use Utopia\Platform\Scope\HTTP;
|
||||
@@ -135,13 +136,13 @@ class Create extends Action
|
||||
$validators = [];
|
||||
$targetCNAME = new Domain(System::getEnv('_APP_DOMAIN_TARGET_CNAME', ''));
|
||||
if ($targetCNAME->isKnown() && !$targetCNAME->isTest()) {
|
||||
$validators[] = new DNS($targetCNAME->get(), DNS::RECORD_CNAME);
|
||||
$validators[] = new DNS($targetCNAME->get(), Record::TYPE_CNAME);
|
||||
}
|
||||
if ((new IP(IP::V4))->isValid(System::getEnv('_APP_DOMAIN_TARGET_A', ''))) {
|
||||
$validators[] = new DNS(System::getEnv('_APP_DOMAIN_TARGET_A', ''), DNS::RECORD_A);
|
||||
$validators[] = new DNS(System::getEnv('_APP_DOMAIN_TARGET_A', ''), Record::TYPE_A);
|
||||
}
|
||||
if ((new IP(IP::V6))->isValid(System::getEnv('_APP_DOMAIN_TARGET_AAAA', ''))) {
|
||||
$validators[] = new DNS(System::getEnv('_APP_DOMAIN_TARGET_AAAA', ''), DNS::RECORD_AAAA);
|
||||
$validators[] = new DNS(System::getEnv('_APP_DOMAIN_TARGET_AAAA', ''), Record::TYPE_AAAA);
|
||||
}
|
||||
|
||||
if (empty($validators)) {
|
||||
|
||||
@@ -15,6 +15,7 @@ use Utopia\Database\Document;
|
||||
use Utopia\Database\Exception\Duplicate;
|
||||
use Utopia\Database\Helpers\ID;
|
||||
use Utopia\Database\Validator\UID;
|
||||
use Utopia\DNS\Message\Record;
|
||||
use Utopia\Domains\Domain;
|
||||
use Utopia\Platform\Action;
|
||||
use Utopia\Platform\Scope\HTTP;
|
||||
@@ -147,13 +148,13 @@ class Create extends Action
|
||||
$validators = [];
|
||||
$targetCNAME = new Domain(System::getEnv('_APP_DOMAIN_TARGET_CNAME', ''));
|
||||
if ($targetCNAME->isKnown() && !$targetCNAME->isTest()) {
|
||||
$validators[] = new DNS($targetCNAME->get(), DNS::RECORD_CNAME);
|
||||
$validators[] = new DNS($targetCNAME->get(), Record::TYPE_CNAME);
|
||||
}
|
||||
if ((new IP(IP::V4))->isValid(System::getEnv('_APP_DOMAIN_TARGET_A', ''))) {
|
||||
$validators[] = new DNS(System::getEnv('_APP_DOMAIN_TARGET_A', ''), DNS::RECORD_A);
|
||||
$validators[] = new DNS(System::getEnv('_APP_DOMAIN_TARGET_A', ''), Record::TYPE_A);
|
||||
}
|
||||
if ((new IP(IP::V6))->isValid(System::getEnv('_APP_DOMAIN_TARGET_AAAA', ''))) {
|
||||
$validators[] = new DNS(System::getEnv('_APP_DOMAIN_TARGET_AAAA', ''), DNS::RECORD_AAAA);
|
||||
$validators[] = new DNS(System::getEnv('_APP_DOMAIN_TARGET_AAAA', ''), Record::TYPE_AAAA);
|
||||
}
|
||||
|
||||
if (empty($validators)) {
|
||||
|
||||
@@ -15,6 +15,7 @@ use Utopia\Database\Document;
|
||||
use Utopia\Database\Exception\Duplicate;
|
||||
use Utopia\Database\Helpers\ID;
|
||||
use Utopia\Database\Validator\UID;
|
||||
use Utopia\DNS\Message\Record;
|
||||
use Utopia\Domains\Domain;
|
||||
use Utopia\Platform\Action;
|
||||
use Utopia\Platform\Scope\HTTP;
|
||||
@@ -152,13 +153,13 @@ class Create extends Action
|
||||
$validators = [];
|
||||
$targetCNAME = new Domain(System::getEnv('_APP_DOMAIN_TARGET_CNAME', ''));
|
||||
if ($targetCNAME->isKnown() && !$targetCNAME->isTest()) {
|
||||
$validators[] = new DNS($targetCNAME->get(), DNS::RECORD_CNAME);
|
||||
$validators[] = new DNS($targetCNAME->get(), Record::TYPE_CNAME);
|
||||
}
|
||||
if ((new IP(IP::V4))->isValid(System::getEnv('_APP_DOMAIN_TARGET_A', ''))) {
|
||||
$validators[] = new DNS(System::getEnv('_APP_DOMAIN_TARGET_A', ''), DNS::RECORD_A);
|
||||
$validators[] = new DNS(System::getEnv('_APP_DOMAIN_TARGET_A', ''), Record::TYPE_A);
|
||||
}
|
||||
if ((new IP(IP::V6))->isValid(System::getEnv('_APP_DOMAIN_TARGET_AAAA', ''))) {
|
||||
$validators[] = new DNS(System::getEnv('_APP_DOMAIN_TARGET_AAAA', ''), DNS::RECORD_AAAA);
|
||||
$validators[] = new DNS(System::getEnv('_APP_DOMAIN_TARGET_AAAA', ''), Record::TYPE_AAAA);
|
||||
}
|
||||
|
||||
if (empty($validators)) {
|
||||
|
||||
@@ -15,6 +15,7 @@ use Utopia\Database\Document;
|
||||
use Utopia\Database\Exception\Duplicate;
|
||||
use Utopia\Database\Helpers\ID;
|
||||
use Utopia\Database\Validator\UID;
|
||||
use Utopia\DNS\Message\Record;
|
||||
use Utopia\Domains\Domain;
|
||||
use Utopia\Platform\Action;
|
||||
use Utopia\Platform\Scope\HTTP;
|
||||
@@ -147,13 +148,13 @@ class Create extends Action
|
||||
$validators = [];
|
||||
$targetCNAME = new Domain(System::getEnv('_APP_DOMAIN_TARGET_CNAME', ''));
|
||||
if ($targetCNAME->isKnown() && !$targetCNAME->isTest()) {
|
||||
$validators[] = new DNS($targetCNAME->get(), DNS::RECORD_CNAME);
|
||||
$validators[] = new DNS($targetCNAME->get(), Record::TYPE_CNAME);
|
||||
}
|
||||
if ((new IP(IP::V4))->isValid(System::getEnv('_APP_DOMAIN_TARGET_A', ''))) {
|
||||
$validators[] = new DNS(System::getEnv('_APP_DOMAIN_TARGET_A', ''), DNS::RECORD_A);
|
||||
$validators[] = new DNS(System::getEnv('_APP_DOMAIN_TARGET_A', ''), Record::TYPE_A);
|
||||
}
|
||||
if ((new IP(IP::V6))->isValid(System::getEnv('_APP_DOMAIN_TARGET_AAAA', ''))) {
|
||||
$validators[] = new DNS(System::getEnv('_APP_DOMAIN_TARGET_AAAA', ''), DNS::RECORD_AAAA);
|
||||
$validators[] = new DNS(System::getEnv('_APP_DOMAIN_TARGET_AAAA', ''), Record::TYPE_AAAA);
|
||||
}
|
||||
|
||||
if (empty($validators)) {
|
||||
|
||||
@@ -13,6 +13,7 @@ use Appwrite\Utopia\Response;
|
||||
use Utopia\Database\Database;
|
||||
use Utopia\Database\Document;
|
||||
use Utopia\Database\Validator\UID;
|
||||
use Utopia\DNS\Message\Record;
|
||||
use Utopia\Domains\Domain;
|
||||
use Utopia\Logger\Log;
|
||||
use Utopia\Platform\Action;
|
||||
@@ -113,15 +114,15 @@ class Update extends Action
|
||||
|
||||
if (!is_null($targetCNAME)) {
|
||||
if ($targetCNAME->isKnown() && !$targetCNAME->isTest()) {
|
||||
$validators[] = new DNS($targetCNAME->get(), DNS::RECORD_CNAME);
|
||||
$validators[] = new DNS($targetCNAME->get(), Record::TYPE_CNAME);
|
||||
}
|
||||
}
|
||||
|
||||
if ((new IP(IP::V4))->isValid(System::getEnv('_APP_DOMAIN_TARGET_A', ''))) {
|
||||
$validators[] = new DNS(System::getEnv('_APP_DOMAIN_TARGET_A', ''), DNS::RECORD_A);
|
||||
$validators[] = new DNS(System::getEnv('_APP_DOMAIN_TARGET_A', ''), Record::TYPE_A);
|
||||
}
|
||||
if ((new IP(IP::V6))->isValid(System::getEnv('_APP_DOMAIN_TARGET_AAAA', ''))) {
|
||||
$validators[] = new DNS(System::getEnv('_APP_DOMAIN_TARGET_AAAA', ''), DNS::RECORD_AAAA);
|
||||
$validators[] = new DNS(System::getEnv('_APP_DOMAIN_TARGET_AAAA', ''), Record::TYPE_AAAA);
|
||||
}
|
||||
|
||||
if (empty($validators)) {
|
||||
@@ -139,24 +140,13 @@ class Update extends Action
|
||||
if (!$validator->isValid($domain->get())) {
|
||||
$log->addExtra('dnsTiming', \strval(\microtime(true) - $validationStart));
|
||||
$log->addTag('dnsDomain', $domain->get());
|
||||
|
||||
$errors = [];
|
||||
foreach ($validators as $validator) {
|
||||
if (!empty($validator->getLogs())) {
|
||||
$errors[] = $validator->getLogs();
|
||||
}
|
||||
}
|
||||
|
||||
$error = \implode("\n", $errors);
|
||||
$log->addExtra('dnsResponse', \is_array($error) ? \json_encode($error) : \strval($error));
|
||||
|
||||
throw new Exception(Exception::RULE_VERIFICATION_FAILED);
|
||||
}
|
||||
|
||||
// Ensure CAA won't block certificate issuance
|
||||
if (!empty(System::getEnv('_APP_DOMAIN_TARGET_CAA', ''))) {
|
||||
$validationStart = \microtime(true);
|
||||
$validator = new DNS(System::getEnv('_APP_DOMAIN_TARGET_CAA', ''), DNS::RECORD_CAA);
|
||||
$validator = new DNS(System::getEnv('_APP_DOMAIN_TARGET_CAA', ''), Record::TYPE_CAA);
|
||||
if (!$validator->isValid($domain->get())) {
|
||||
$log->addExtra('dnsTimingCaa', \strval(\microtime(true) - $validationStart));
|
||||
$log->addTag('dnsDomain', $domain->get());
|
||||
|
||||
@@ -57,7 +57,7 @@ class Create extends Action
|
||||
group: 'deployments',
|
||||
name: 'createDeployment',
|
||||
description: <<<EOT
|
||||
Create a new site code deployment. Use this endpoint to upload a new version of your site code. To activate your newly uploaded code, you'll need to update the function's deployment to use your new deployment ID.
|
||||
Create a new site code deployment. Use this endpoint to upload a new version of your site code. To activate your newly uploaded code, you'll need to update the site's deployment to use your new deployment ID.
|
||||
EOT,
|
||||
auth: [AuthType::KEY],
|
||||
responses: [
|
||||
|
||||
@@ -22,6 +22,7 @@ use Utopia\Database\Exception\Conflict;
|
||||
use Utopia\Database\Exception\Structure;
|
||||
use Utopia\Database\Helpers\ID;
|
||||
use Utopia\Database\Query;
|
||||
use Utopia\DNS\Message\Record;
|
||||
use Utopia\Domains\Domain;
|
||||
use Utopia\Locale\Locale;
|
||||
use Utopia\Logger\Log;
|
||||
@@ -313,13 +314,13 @@ class Certificates extends Action
|
||||
$validators = [];
|
||||
$targetCNAME = new Domain(System::getEnv('_APP_DOMAIN_TARGET_CNAME', ''));
|
||||
if ($targetCNAME->isKnown() && !$targetCNAME->isTest()) {
|
||||
$validators[] = new DNS($targetCNAME->get(), DNS::RECORD_CNAME);
|
||||
$validators[] = new DNS($targetCNAME->get(), Record::TYPE_CNAME);
|
||||
}
|
||||
if ((new IP(IP::V4))->isValid(System::getEnv('_APP_DOMAIN_TARGET_A', ''))) {
|
||||
$validators[] = new DNS(System::getEnv('_APP_DOMAIN_TARGET_A', ''), DNS::RECORD_A);
|
||||
$validators[] = new DNS(System::getEnv('_APP_DOMAIN_TARGET_A', ''), Record::TYPE_A);
|
||||
}
|
||||
if ((new IP(IP::V6))->isValid(System::getEnv('_APP_DOMAIN_TARGET_AAAA', ''))) {
|
||||
$validators[] = new DNS(System::getEnv('_APP_DOMAIN_TARGET_AAAA', ''), DNS::RECORD_AAAA);
|
||||
$validators[] = new DNS(System::getEnv('_APP_DOMAIN_TARGET_AAAA', ''), Record::TYPE_AAAA);
|
||||
}
|
||||
|
||||
// Validate if domain target is properly configured
|
||||
@@ -332,24 +333,13 @@ class Certificates extends Action
|
||||
if (!$validator->isValid($domain->get())) {
|
||||
$log->addExtra('dnsTiming', \strval(\microtime(true) - $validationStart));
|
||||
$log->addTag('dnsDomain', $domain->get());
|
||||
|
||||
$errors = [];
|
||||
foreach ($validators as $validator) {
|
||||
if (!empty($validator->getLogs())) {
|
||||
$errors[] = $validator->getLogs();
|
||||
}
|
||||
}
|
||||
|
||||
$error = \implode("\n", $errors);
|
||||
$log->addExtra('dnsResponse', \is_array($error) ? \json_encode($error) : \strval($error));
|
||||
|
||||
throw new Exception('Failed to verify domain DNS records.');
|
||||
}
|
||||
|
||||
// Ensure CAA won't block certificate issuance
|
||||
if (!empty(System::getEnv('_APP_DOMAIN_TARGET_CAA', ''))) {
|
||||
$validationStart = \microtime(true);
|
||||
$validator = new DNS(System::getEnv('_APP_DOMAIN_TARGET_CAA', ''), DNS::RECORD_CAA);
|
||||
$validator = new DNS(System::getEnv('_APP_DOMAIN_TARGET_CAA', ''), Record::TYPE_CAA);
|
||||
if (!$validator->isValid($domain->get())) {
|
||||
$log->addExtra('dnsTimingCaa', \strval(\microtime(true) - $validationStart));
|
||||
$log->addTag('dnsDomain', $domain->get());
|
||||
|
||||
@@ -138,6 +138,7 @@ class StatsUsage extends Action
|
||||
$this->getLogsDB = $getLogsDB;
|
||||
$this->register = $register;
|
||||
$payload = $message->getPayload() ?? [];
|
||||
Console::log('Payload: ' . json_encode($payload));
|
||||
if (empty($payload)) {
|
||||
throw new Exception('Missing payload');
|
||||
}
|
||||
|
||||
@@ -5,30 +5,20 @@ namespace Tests\Unit\Network\Validators;
|
||||
use Appwrite\Network\Validator\DNS;
|
||||
use Appwrite\Tests\Retry;
|
||||
use PHPUnit\Framework\TestCase;
|
||||
use Utopia\DNS\Message\Record;
|
||||
|
||||
/*
|
||||
DNS Setup (on Appwrite Labs digital ocean team, network tab):
|
||||
|
||||
certainly.caa.appwrite.org: CAA 0 issue "certainly.com"
|
||||
certainly-full.caa.appwrite.org: CAA 128 issuewild "certainly.com;account=123456;validationmethods=dns-01"
|
||||
letsencrypt.certainly.caa.appwrite.org: CAA 0 issue "letsencrypt.org"
|
||||
|
||||
*/
|
||||
|
||||
/**
|
||||
* DNS Setup (on Appwrite Labs digital ocean team, network tab):
|
||||
*
|
||||
* certainly.caa.appwrite.org: CAA 0 issue "certainly.com"
|
||||
* certainly-full.caa.appwrite.org: CAA 128 issuewild "certainly.com;account=123456;validationmethods=dns-01"
|
||||
* letsencrypt.certainly.caa.appwrite.org: CAA 0 issue "letsencrypt.org"
|
||||
*/
|
||||
class DNSTest extends TestCase
|
||||
{
|
||||
public function setUp(): void
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
public function tearDown(): void
|
||||
{
|
||||
}
|
||||
|
||||
public function testCNAME(): void
|
||||
{
|
||||
$validator = new DNS('appwrite.io', DNS::RECORD_CNAME);
|
||||
$validator = new DNS('appwrite.io', Record::TYPE_CNAME);
|
||||
$this->assertEquals($validator->isValid(''), false);
|
||||
$this->assertEquals($validator->isValid(null), false);
|
||||
$this->assertEquals($validator->isValid(false), false);
|
||||
@@ -39,7 +29,7 @@ class DNSTest extends TestCase
|
||||
public function testA(): void
|
||||
{
|
||||
// IPv4 for documentation purposes
|
||||
$validator = new DNS('203.0.113.1', DNS::RECORD_A);
|
||||
$validator = new DNS('203.0.113.1', Record::TYPE_A);
|
||||
$this->assertEquals($validator->isValid(''), false);
|
||||
$this->assertEquals($validator->isValid(null), false);
|
||||
$this->assertEquals($validator->isValid(false), false);
|
||||
@@ -50,7 +40,7 @@ class DNSTest extends TestCase
|
||||
public function testAAAA(): void
|
||||
{
|
||||
// IPv6 for documentation purposes
|
||||
$validator = new DNS('2001:db8::1', DNS::RECORD_AAAA);
|
||||
$validator = new DNS('2001:db8::1', Record::TYPE_AAAA);
|
||||
$this->assertEquals($validator->isValid(''), false);
|
||||
$this->assertEquals($validator->isValid(null), false);
|
||||
$this->assertEquals($validator->isValid(false), false);
|
||||
@@ -61,8 +51,8 @@ class DNSTest extends TestCase
|
||||
#[Retry(count: 5)]
|
||||
public function testCAA(): void
|
||||
{
|
||||
$certainly = new DNS('certainly.com', DNS::RECORD_CAA, 'ns1.digitalocean.com');
|
||||
$letsencrypt = new DNS('letsencrypt.org', DNS::RECORD_CAA, 'ns1.digitalocean.com');
|
||||
$certainly = new DNS('certainly.com', Record::TYPE_CAA, 'ns1.digitalocean.com');
|
||||
$letsencrypt = new DNS('letsencrypt.org', Record::TYPE_CAA, 'ns1.digitalocean.com');
|
||||
|
||||
// No CAA record succeeds on main domain & subdomains for any issuer
|
||||
$this->assertEquals($certainly->isValid('caa.appwrite.org'), true);
|
||||
@@ -78,11 +68,11 @@ class DNSTest extends TestCase
|
||||
$this->assertEquals($letsencrypt->isValid('certainly-full.caa.appwrite.org'), false);
|
||||
|
||||
// Custom flags&tag are not allowed if validator includes specific flags&tag
|
||||
$certainlyFull = new DNS('0 issue "certainly.com"', DNS::RECORD_CAA);
|
||||
$certainlyFull = new DNS('0 issue "certainly.com"', Record::TYPE_CAA);
|
||||
$this->assertEquals($certainlyFull->isValid('certainly-full.caa.appwrite.org'), false);
|
||||
|
||||
// Custom flags&tag still allows if they match exactly
|
||||
$certainlyFull = new DNS('128 issuewild "certainly.com;account=123456;validationmethods=dns-01"', DNS::RECORD_CAA);
|
||||
$certainlyFull = new DNS('128 issuewild "certainly.com;account=123456;validationmethods=dns-01"', Record::TYPE_CAA);
|
||||
$this->assertEquals($certainlyFull->isValid('certainly-full.caa.appwrite.org'), true);
|
||||
|
||||
// Certainly CAA allows Certainly, but not LetsEncrypt; Same for subdomains
|
||||
|
||||
Reference in New Issue
Block a user