Merge pull request #9359 from appwrite/fix-site-cors

Fix: Site CORS
This commit is contained in:
Matej Bačo 2025-02-14 12:40:37 +01:00 committed by GitHub
commit 9222fec7f8
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
2 changed files with 73 additions and 12 deletions

View file

@ -125,7 +125,7 @@ function router(App $utopia, Database $dbForPlatform, callable $getProjectDB, Sw
$type = $rule->getAttribute('resourceType');
if ($type === 'function' || $type === 'site' || $type === 'deployment') {
$resourceCollection = match($type) {
$resourceCollection = match ($type) {
'function' => 'functions',
'site' => 'sites',
'deployment' => 'deployments',
@ -200,7 +200,7 @@ function router(App $utopia, Database $dbForPlatform, callable $getProjectDB, Sw
throw new AppwriteException(AppwriteException::GENERAL_RESOURCE_BLOCKED);
}
$version = match($type) {
$version = match ($type) {
'function' => $resource->getAttribute('version', 'v2'),
'site' => 'v4',
'deployment' => 'v4'
@ -209,7 +209,7 @@ function router(App $utopia, Database $dbForPlatform, callable $getProjectDB, Sw
$runtimes = Config::getParam($version === 'v2' ? 'runtimes-v2' : 'runtimes', []);
$spec = Config::getParam('runtime-specifications')[$resource->getAttribute('specification', APP_COMPUTE_SPECIFICATION_DEFAULT)];
$runtime = match($type) {
$runtime = match ($type) {
'function' => $runtimes[$resource->getAttribute('runtime')] ?? null,
'site' => $runtimes[$resource->getAttribute('buildRuntime')] ?? null,
'deployment' => $runtimes[$resource->getAttribute('buildRuntime')] ?? null,
@ -224,7 +224,7 @@ function router(App $utopia, Database $dbForPlatform, callable $getProjectDB, Sw
throw new AppwriteException(AppwriteException::FUNCTION_RUNTIME_UNSUPPORTED, 'Runtime "' . $resource->getAttribute('runtime', '') . '" is not supported');
}
$deploymentId = match($type) {
$deploymentId = match ($type) {
'function' => $resource->getAttribute('deployment', ''),
'site' => $resource->getAttribute('deploymentId', ''),
'deployment' => $subResource->getId()
@ -390,12 +390,12 @@ function router(App $utopia, Database $dbForPlatform, callable $getProjectDB, Sw
/** Execute function */
$executor = new Executor(System::getEnv('_APP_EXECUTOR_HOST'));
try {
$version = match($type) {
$version = match ($type) {
'function' => $resource->getAttribute('version', 'v2'),
'site' => 'v4',
'deployment' => 'v4'
};
$entrypoint = match($type) {
$entrypoint = match ($type) {
'function' => $deployment->getAttribute('entrypoint', ''),
'site' => '',
'deployment' => ''
@ -422,7 +422,7 @@ function router(App $utopia, Database $dbForPlatform, callable $getProjectDB, Sw
$runtimeEntrypoint = 'cp /tmp/code.tar.gz /mnt/code/code.tar.gz && nohup helpers/start.sh "' . $startCommand . '"';
}
$entrypoint = match($type) {
$entrypoint = match ($type) {
'function' => $deployment->getAttribute('entrypoint', ''),
'site' => '',
'deployment' => ''
@ -490,8 +490,8 @@ function router(App $utopia, Database $dbForPlatform, callable $getProjectDB, Sw
if ($type === 'function') {
$execution
->setAttribute('status', 'failed')
->setAttribute('errors', $th->getMessage() . '\nError Code: ' . $th->getCode());
->setAttribute('status', 'failed')
->setAttribute('errors', $th->getMessage() . '\nError Code: ' . $th->getCode());
}
Console::error($th->getMessage());
@ -558,8 +558,7 @@ function router(App $utopia, Database $dbForPlatform, callable $getProjectDB, Sw
->addMetric(METRIC_EXECUTIONS_MB_SECONDS, (int)(($spec['memory'] ?? APP_COMPUTE_MEMORY_DEFAULT) * $execution->getAttribute('duration', 0) * ($spec['cpus'] ?? APP_COMPUTE_CPUS_DEFAULT)))
->addMetric(str_replace('{functionInternalId}', $resource->getInternalId(), METRIC_FUNCTION_ID_EXECUTIONS_MB_SECONDS), (int)(($spec['memory'] ?? APP_COMPUTE_MEMORY_DEFAULT) * $execution->getAttribute('duration', 0) * ($spec['cpus'] ?? APP_COMPUTE_CPUS_DEFAULT)))
->setProject($project)
->trigger()
;
->trigger();
return true;
} elseif ($type === 'api') {
@ -738,6 +737,12 @@ App::init()
$validator = new Hostname($clients);
if ($validator->isValid($origin)) {
$refDomainOrigin = $origin;
} else {
// Auto-allow domains with linked rule
$rule = Authorization::skip(fn () => $dbForPlatform->getDocument('rules', md5($origin)));
if (!$rule->isEmpty() && $rule->getAttribute('projectInternalId') === $project->getInternalId()) {
$refDomainOrigin = $origin;
}
}
$refDomain = (!empty($protocol) ? $protocol : $request->getProtocol()) . '://' . $refDomainOrigin . (!empty($port) ? ':' . $port : '');
@ -787,7 +792,7 @@ App::init()
$response->addFilter(new ResponseV18());
}
if (version_compare($responseFormat, APP_VERSION_STABLE, '>')) {
$response->addHeader('X-Appwrite-Warning', "The current SDK is built for Appwrite " . $responseFormat . ". However, the current Appwrite server version is ". APP_VERSION_STABLE . ". Please downgrade your SDK to match the Appwrite version: https://appwrite.io/docs/sdks");
$response->addHeader('X-Appwrite-Warning', "The current SDK is built for Appwrite " . $responseFormat . ". However, the current Appwrite server version is " . APP_VERSION_STABLE . ". Please downgrade your SDK to match the Appwrite version: https://appwrite.io/docs/sdks");
}
}

View file

@ -1405,5 +1405,61 @@ class SitesCustomServerTest extends Scope
$this->cleanupSite($siteId);
}
public function testSiteCors(): void
{
// Create rule together with site
$subdomain = 'startup' . \uniqid();
$siteId = $this->setupSite([
'siteId' => ID::unique(),
'name' => 'Startup site',
'framework' => 'other',
'adapter' => 'static',
'buildRuntime' => 'static-1',
'outputDirectory' => './',
'buildCommand' => '',
'installCommand' => '',
'fallbackFile' => '',
'subdomain' => $subdomain
]);
$this->assertNotEmpty($siteId);
$domain = $this->getSiteDomain($siteId);
$this->assertNotEmpty($domain);
$url = 'http://' . $domain;
$response = $this->client->call(Client::METHOD_GET, '/account', array_merge([
'content-type' => 'application/json',
'x-appwrite-project' => $this->getProject()['$id'],
'referer' => $url,
'origin' => $url
]));
$this->assertEquals($url, $response['headers']['access-control-allow-origin']);
$response = $this->client->call(Client::METHOD_GET, '/account', array_merge([
'content-type' => 'application/json',
'x-appwrite-project' => 'unknown',
'referer' => $url,
'origin' => $url
]));
$this->assertNotEquals($url, $response['headers']['access-control-allow-origin']);
$this->assertEquals('http://localhost', $response['headers']['access-control-allow-origin']);
$response = $this->client->call(Client::METHOD_GET, '/account', array_merge([
'content-type' => 'application/json',
'x-appwrite-project' => $this->getProject()['$id'],
'referer' => 'http://unknown.com',
'origin' => 'http://unknown.com'
]));
$this->assertNotEquals($url, $response['headers']['access-control-allow-origin']);
$this->assertEquals('http://localhost', $response['headers']['access-control-allow-origin']);
}
// TODO: Add tests for deletion of resources when site is deleted
}