mirror of
https://github.com/appwrite/appwrite.git
synced 2026-05-26 13:51:13 +00:00
Compare commits
8
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
74517c6fea | ||
|
|
4582994e3b | ||
|
|
d1c0af0908 | ||
|
|
b1a6dd02fb | ||
|
|
92c81ba429 | ||
|
|
abdf89ff89 | ||
|
|
5a5279a10f | ||
|
|
7f99bd2dd2 |
@@ -1379,6 +1379,17 @@ $platformCollections = [
|
||||
'array' => false,
|
||||
'filters' => [],
|
||||
],
|
||||
[
|
||||
'$id' => ID::custom('actions'),
|
||||
'type' => Database::VAR_STRING,
|
||||
'format' => '',
|
||||
'size' => 65535,
|
||||
'signed' => true,
|
||||
'required' => false,
|
||||
'default' => '',
|
||||
'array' => false,
|
||||
'filters' => ['json'],
|
||||
],
|
||||
],
|
||||
'indexes' => [
|
||||
[
|
||||
|
||||
@@ -215,9 +215,14 @@ const DELETE_TYPE_SESSION_TARGETS = 'session_targets';
|
||||
const DELETE_TYPE_CSV_EXPORTS = 'csv_exports';
|
||||
const DELETE_TYPE_MAINTENANCE = 'maintenance';
|
||||
|
||||
// Rule verification types
|
||||
const RULE_VERIFICATION_TYPE_DNS = 'dns'; // Basic verification of DNS records
|
||||
const RULE_VERIFICATION_TYPE_MANAGED_DNS = 'managed_dns'; // ACME-DNS challenge verification
|
||||
|
||||
// Rule statuses
|
||||
const RULE_STATUS_CREATED = 'created'; // This is also the status when domain DNS verification fails.
|
||||
const RULE_STATUS_CERTIFICATE_GENERATING = 'verifying';
|
||||
const RULE_STATUS_ACTION_REQUIRED = 'action_required';
|
||||
const RULE_STATUS_CERTIFICATE_GENERATION_FAILED = 'unverified';
|
||||
const RULE_STATUS_VERIFIED = 'verified';
|
||||
|
||||
|
||||
@@ -10,7 +10,7 @@ interface Adapter
|
||||
|
||||
public function isInstantGeneration(string $domain, ?string $domainType): bool;
|
||||
|
||||
public function getCertificateStatus(string $domain, ?string $domainType): string;
|
||||
public function getCertificateStatus(string $domain, ?string $domainType): array;
|
||||
|
||||
public function isRenewRequired(string $domain, ?string $domainType, Log $log): bool;
|
||||
|
||||
|
||||
@@ -90,7 +90,7 @@ class LetsEncrypt implements Adapter
|
||||
return true;
|
||||
}
|
||||
|
||||
public function getCertificateStatus(string $domain, ?string $domainType): string
|
||||
public function getCertificateStatus(string $domain, ?string $domainType): array
|
||||
{
|
||||
throw new CertificateStatusException('Certificate status retrieval is not supported for LetsEncrypt.');
|
||||
}
|
||||
|
||||
@@ -86,7 +86,7 @@ class Action extends PlatformAction
|
||||
* @param Log|null $log Log instance to add timings to
|
||||
* @return void
|
||||
*/
|
||||
protected function verifyRule(Document $rule, ?Log $log = null): void
|
||||
protected function verifyRule(Document $rule, ?Log $log = null, string $verificationType = RULE_VERIFICATION_TYPE_DNS): void
|
||||
{
|
||||
$dnsValidatorClass = $this->dnsValidatorClass;
|
||||
$dnsEnv = System::getEnv('_APP_DNS', '8.8.8.8');
|
||||
@@ -103,6 +103,25 @@ class Action extends PlatformAction
|
||||
throw new Exception(Exception::RULE_VERIFICATION_FAILED, 'DNS verification failed as domain ' . $domain->get() . ' does not resolve to a known public apex domain.');
|
||||
}
|
||||
|
||||
// Verify managed-dns challenge
|
||||
if ($verificationType === RULE_VERIFICATION_TYPE_MANAGED_DNS) {
|
||||
$managedDnsAction = current(array_filter($rule->getAttribute('actions', []), fn ($action) => $action['challengeType'] === RULE_VERIFICATION_TYPE_MANAGED_DNS));
|
||||
|
||||
if (!$managedDnsAction) {
|
||||
throw new Exception(Exception::RULE_VERIFICATION_FAILED, 'DNS verification failed as no managed-dns challenge is available in the rule.');
|
||||
}
|
||||
|
||||
$validationStart = \microtime(true);
|
||||
$validator = new $dnsValidatorClass($managedDnsAction['recordValue'], Record::typeNameToCode($managedDnsAction['recordType']), $dnsServers);
|
||||
if (!$validator->isValid($domain->get())) {
|
||||
if (!\is_null($log)) {
|
||||
$log->addExtra('dnsTimingCaa', \strval(\microtime(true) - $validationStart));
|
||||
$log->addTag('dnsDomain', $domain->get());
|
||||
}
|
||||
throw new Exception(Exception::RULE_VERIFICATION_FAILED, $validator->getDescription());
|
||||
}
|
||||
}
|
||||
|
||||
// Ensure CAA won't block certificate issuance
|
||||
$caaTarget = System::getEnv('_APP_DOMAIN_TARGET_CAA', '');
|
||||
if (!empty($caaTarget)) {
|
||||
|
||||
@@ -16,6 +16,7 @@ use Utopia\Database\Document;
|
||||
use Utopia\Database\Validator\UID;
|
||||
use Utopia\Logger\Log;
|
||||
use Utopia\Platform\Scope\HTTP;
|
||||
use Utopia\Validator\WhiteList;
|
||||
|
||||
class Update extends Action
|
||||
{
|
||||
@@ -55,6 +56,7 @@ class Update extends Action
|
||||
]
|
||||
))
|
||||
->param('ruleId', '', new UID(), 'Rule ID.')
|
||||
->param('type', '', new WhiteList([RULE_VERIFICATION_TYPE_DNS, RULE_VERIFICATION_TYPE_MANAGED_DNS]), 'Type of verification to perform.')
|
||||
->inject('response')
|
||||
->inject('queueForCertificates')
|
||||
->inject('queueForEvents')
|
||||
@@ -66,6 +68,7 @@ class Update extends Action
|
||||
|
||||
public function action(
|
||||
string $ruleId,
|
||||
string $type,
|
||||
Response $response,
|
||||
Certificate $queueForCertificates,
|
||||
Event $queueForEvents,
|
||||
@@ -87,20 +90,42 @@ class Update extends Action
|
||||
}
|
||||
|
||||
try {
|
||||
$this->verifyRule($rule, $log);
|
||||
// Reset logs and status for the rule
|
||||
$rule = $dbForPlatform->updateDocument('rules', $rule->getId(), new Document([
|
||||
'logs' => '',
|
||||
'status' => RULE_STATUS_CERTIFICATE_GENERATING,
|
||||
]));
|
||||
$this->verifyRule($rule, $log, $type);
|
||||
|
||||
$certificateId = $rule->getAttribute('certificateId', '');
|
||||
// Reset logs for the associated certificate.
|
||||
if (!empty($certificateId)) {
|
||||
$certificate = $dbForPlatform->updateDocument('certificates', $certificateId, new Document([
|
||||
'logs' => '',
|
||||
if ($type === RULE_VERIFICATION_TYPE_MANAGED_DNS) {
|
||||
// Set status to "generating" - This will ensure background sync will pick it up
|
||||
$rule = $dbForPlatform->updateDocument('rules', $rule->getId(), new Document([
|
||||
'status' => RULE_STATUS_CERTIFICATE_GENERATING,
|
||||
]));
|
||||
} else {
|
||||
// Reset logs and status for the rule
|
||||
$rule = $dbForPlatform->updateDocument('rules', $rule->getId(), new Document([
|
||||
'logs' => '',
|
||||
'status' => RULE_STATUS_CERTIFICATE_GENERATING,
|
||||
]));
|
||||
|
||||
$certificateId = $rule->getAttribute('certificateId', '');
|
||||
// Reset logs for the associated certificate.
|
||||
if (!empty($certificateId)) {
|
||||
$certificate = $dbForPlatform->updateDocument('certificates', $certificateId, new Document([
|
||||
'logs' => '',
|
||||
]));
|
||||
}
|
||||
|
||||
// Issue a TLS certificate when DNS verification is successful
|
||||
$queueForCertificates
|
||||
->setDomain(new Document([
|
||||
'domain' => $rule->getAttribute('domain'),
|
||||
'domainType' => $rule->getAttribute('deploymentResourceType', $rule->getAttribute('type')),
|
||||
]))
|
||||
->trigger();
|
||||
|
||||
if (!empty($certificate)) {
|
||||
$rule->setAttribute('renewAt', $certificate->getAttribute('renewDate', ''));
|
||||
}
|
||||
}
|
||||
|
||||
$response->dynamic($rule, Response::MODEL_PROXY_RULE);
|
||||
} catch (Exception $err) {
|
||||
$dbForPlatform->updateDocument('rules', $rule->getId(), new Document([
|
||||
'$updatedAt' => DateTime::now(),
|
||||
@@ -108,18 +133,5 @@ class Update extends Action
|
||||
throw $err;
|
||||
}
|
||||
|
||||
// Issue a TLS certificate when DNS verification is successful
|
||||
$queueForCertificates
|
||||
->setDomain(new Document([
|
||||
'domain' => $rule->getAttribute('domain'),
|
||||
'domainType' => $rule->getAttribute('deploymentResourceType', $rule->getAttribute('type')),
|
||||
]))
|
||||
->trigger();
|
||||
|
||||
if (!empty($certificate)) {
|
||||
$rule->setAttribute('renewAt', $certificate->getAttribute('renewDate', ''));
|
||||
}
|
||||
|
||||
$response->dynamic($rule, Response::MODEL_PROXY_RULE);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -76,6 +76,7 @@ class Certificates extends Action
|
||||
* @param CertificatesAdapter $certificates
|
||||
* @param array $plan
|
||||
* @param ValidatorAuthorization $authorization
|
||||
* @param array $nameservers
|
||||
* @return void
|
||||
* @throws Throwable
|
||||
* @throws \Utopia\Database\Exception
|
||||
@@ -93,6 +94,7 @@ class Certificates extends Action
|
||||
CertificatesAdapter $certificates,
|
||||
array $plan,
|
||||
ValidatorAuthorization $authorization,
|
||||
array $nameservers = [],
|
||||
): void {
|
||||
$payload = $message->getPayload() ?? [];
|
||||
|
||||
|
||||
@@ -103,6 +103,19 @@ class Rule extends Model
|
||||
'example' => APP_DATABASE_ATTRIBUTE_DATETIME,
|
||||
'array' => false,
|
||||
])
|
||||
->addRule('actions', [
|
||||
'type' => self::TYPE_ARRAY,
|
||||
'description' => 'Additional actions required from the user when rule status is "action_required"',
|
||||
'default' => [],
|
||||
'example' => [
|
||||
[
|
||||
'challengeType' => 'managed-dns',
|
||||
'recordType' => 'CNAME',
|
||||
'recordName' => '_acme-challenge',
|
||||
'recordValue' => 'test.fastly-validations.com',
|
||||
],
|
||||
],
|
||||
])
|
||||
;
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user