Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions .env
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ _APP_OPTIONS_FORCE_HTTPS=disabled
_APP_OPTIONS_ROUTER_FORCE_HTTPS=disabled
_APP_OPENSSL_KEY_V1=your-secret-key
_APP_DNS=8.8.8.8
_APP_DOMAIN=traefik
_APP_DOMAIN=appwrite.test
_APP_CONSOLE_DOMAIN=localhost
_APP_DOMAIN_FUNCTIONS=functions.localhost
_APP_DOMAIN_SITES=sites.localhost
Expand Down Expand Up @@ -124,4 +124,4 @@ _APP_MESSAGE_PUSH_TEST_DSN=
_APP_WEBHOOK_MAX_FAILED_ATTEMPTS=10
_APP_PROJECT_REGIONS=default
_APP_FUNCTIONS_CREATION_ABUSE_LIMIT=5000
_APP_STATS_USAGE_DUAL_WRITING_DBS=database_db_main
_APP_STATS_USAGE_DUAL_WRITING_DBS=database_db_main
21 changes: 21 additions & 0 deletions app/config/platform.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
<?php

use Utopia\System\System;

/**
* Platform configuration
*/
return [
'domain' => System::getEnv('_APP_DOMAIN', 'localhost'),
Comment thread
loks0n marked this conversation as resolved.
'consoleDomain' => System::getEnv('_APP_CONSOLE_DOMAIN', System::getEnv('_APP_DOMAIN', 'localhost')),
Comment on lines +9 to +10
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🔴 Critical

🧩 Analysis chain

🏁 Script executed:

# First, let's examine app/config/platform.php to see the full context around line 20
cat -n app/config/platform.php | head -30

Repository: appwrite/appwrite

Length of output: 879


🏁 Script executed:

# Search for APP_DOMAIN constant definition
rg "define.*APP_DOMAIN" --type php -B 2 -A 2

Repository: appwrite/appwrite

Length of output: 43


🏁 Script executed:

# Search for how APP_DOMAIN is used in app/init.php or initialization files
fd "init.php" --type f | head -5

Repository: appwrite/appwrite

Length of output: 73


🏁 Script executed:

# Search for _APP_DOMAIN processing in the codebase
rg "_APP_DOMAIN" --type php | head -20

Repository: appwrite/appwrite

Length of output: 2512


🏁 Script executed:

# Search for APP_DOMAIN definition in app/init.php
rg "APP_DOMAIN" app/init.php -B 3 -A 3

Repository: appwrite/appwrite

Length of output: 43


🏁 Script executed:

# Also search for any processing of _APP_DOMAIN that might extract first domain
rg "explode|split|preg_split" app/init.php | grep -i domain

Repository: appwrite/appwrite

Length of output: 43


🏁 Script executed:

# Search entire PHP codebase for APP_DOMAIN definition/constant
rg "APP_DOMAIN" --type php -B 2 -A 2 | head -50

Repository: appwrite/appwrite

Length of output: 3898


🏁 Script executed:

# Check if APP_DOMAIN might be defined as a constant in multiple files
rg "define.*'APP_DOMAIN'|const.*APP_DOMAIN|APP_DOMAIN\s*=" --type php

Repository: appwrite/appwrite

Length of output: 117


🏁 Script executed:

# Check the app/init/constants.php file to see all constant definitions and context
cat -n app/init/constants.php | head -50

Repository: appwrite/appwrite

Length of output: 3015


🏁 Script executed:

# Search for documentation or comments about _APP_DOMAIN multi-domain handling
rg "_APP_DOMAIN" --type php -B 3 -A 1 app/init | head -30

Repository: appwrite/appwrite

Length of output: 429


Line 20 uses hardcoded APP_DOMAIN constant instead of respecting the _APP_DOMAIN environment variable.

Lines 9–10 correctly read from the _APP_DOMAIN environment variable (which supports comma-separated multi-domain values), but line 20 constructs websiteUrl using the hardcoded APP_DOMAIN = 'appwrite.io' constant defined in app/init/constants.php. This means websiteUrl will always be https://appwrite.io regardless of the _APP_DOMAIN setting, creating inconsistent behavior between domain, consoleDomain, and websiteUrl. Update line 20 to derive from the same _APP_DOMAIN environment variable.

🤖 Prompt for AI Agents
In app/config/platform.php around lines 9–20, websiteUrl is built from the
hardcoded APP_DOMAIN constant causing mismatch with domain/consoleDomain which
read _APP_DOMAIN; replace the hardcoded constant with the same _APP_DOMAIN
lookup (or re-use the already-resolved 'domain' value), ensuring you handle
comma-separated values by picking the primary domain (e.g., first entry) and
then prefixing it with the correct scheme (https://) to construct websiteUrl so
it reflects the _APP_DOMAIN environment variable.

'platformName' => APP_EMAIL_PLATFORM_NAME,
'logoUrl' => APP_EMAIL_LOGO_URL,
'accentColor' => APP_EMAIL_ACCENT_COLOR,
'footerImageUrl' => APP_EMAIL_FOOTER_IMAGE_URL,
'twitterUrl' => APP_SOCIAL_TWITTER,
'discordUrl' => APP_SOCIAL_DISCORD,
'githubUrl' => APP_SOCIAL_GITHUB,
'termsUrl' => APP_EMAIL_TERMS_URL,
'privacyUrl' => APP_EMAIL_PRIVACY_URL,
'websiteUrl' => 'https://' . APP_DOMAIN,
];
Comment thread
loks0n marked this conversation as resolved.
File renamed without changes.
9 changes: 3 additions & 6 deletions app/config/templates/site.php
Original file line number Diff line number Diff line change
@@ -1,18 +1,15 @@
<?php

use Utopia\Config\Config;
use Utopia\System\System;

/**
* List of Appwrite Sites templates
*/

$protocol = System::getEnv('_APP_OPTIONS_FORCE_HTTPS') === 'disabled' ? 'http' : 'https';
$hostname = System::getEnv('_APP_DOMAIN', '');

// Temporary fix until we can set _APP_DOMAIN to "localhost" instead of "traefik"
if (System::getEnv('_APP_ENV', 'development') === 'development') {
$hostname = 'localhost';
}
$platform = Config::getParam('platform', []);
$hostname = $platform['consoleDomain'] ?? '';

$url = $protocol . '://' . $hostname;

Expand Down
2 changes: 1 addition & 1 deletion app/config/variables.php
Original file line number Diff line number Diff line change
Expand Up @@ -81,7 +81,7 @@
],
[
'name' => '_APP_DOMAIN',
'description' => 'Your Appwrite domain address. When setting a public suffix domain, Appwrite will attempt to issue a valid SSL certificate automatically. When used with a dev domain, Appwrite will assign a self-signed SSL certificate. The default value is \'localhost\'.',
'description' => 'Your Appwrite domain address. When setting a public suffix domain, Appwrite will attempt to issue a valid SSL certificate automatically. When used with a dev domain, Appwrite will assign a self-signed SSL certificate. The default value is \'localhost\'. Multiple domains can be separated by commas.',
Comment thread
coderabbitai[bot] marked this conversation as resolved.
'introduction' => '',
'default' => 'localhost',
'required' => true,
Expand Down
53 changes: 24 additions & 29 deletions app/controllers/api/account.php

Large diffs are not rendered by default.

7 changes: 1 addition & 6 deletions app/controllers/api/console.php
Original file line number Diff line number Diff line change
Expand Up @@ -43,9 +43,6 @@
))
->inject('response')
->action(function (Response $response) {
$validator = new Domain(System::getEnv('_APP_DOMAIN'));
$isDomainValid = !empty(System::getEnv('_APP_DOMAIN', '')) && $validator->isKnown() && !$validator->isTest();

$validator = new Domain(System::getEnv('_APP_DOMAIN_TARGET_CNAME'));
$isCNAMEValid = !empty(System::getEnv('_APP_DOMAIN_TARGET_CNAME', '')) && $validator->isKnown() && !$validator->isTest();

Expand All @@ -55,9 +52,7 @@
$validator = new IP(IP::V6);
$isAAAAValid = !empty(System::getEnv('_APP_DOMAIN_TARGET_AAAA', '')) && $validator->isValid(System::getEnv('_APP_DOMAIN_TARGET_AAAA'));

$isDomainEnabled = $isDomainValid && (
$isAAAAValid || $isAValid || $isCNAMEValid
);
$isDomainEnabled = $isAAAAValid || $isAValid || $isCNAMEValid;

$isVcsEnabled = !empty(System::getEnv('_APP_VCS_GITHUB_APP_NAME', ''))
&& !empty(System::getEnv('_APP_VCS_GITHUB_PRIVATE_KEY', ''))
Expand Down
14 changes: 6 additions & 8 deletions app/controllers/api/messaging.php
Original file line number Diff line number Diff line change
Expand Up @@ -3495,7 +3495,8 @@
->inject('project')
->inject('queueForMessaging')
->inject('response')
->action(function (string $messageId, string $title, string $body, ?array $topics, ?array $users, ?array $targets, ?array $data, string $action, string $image, string $icon, string $sound, string $color, string $tag, int $badge, bool $draft, ?string $scheduledAt, bool $contentAvailable, bool $critical, string $priority, Event $queueForEvents, Database $dbForProject, Database $dbForPlatform, Document $project, Messaging $queueForMessaging, Response $response) {
->inject('platform')
->action(function (string $messageId, string $title, string $body, ?array $topics, ?array $users, ?array $targets, ?array $data, string $action, string $image, string $icon, string $sound, string $color, string $tag, int $badge, bool $draft, ?string $scheduledAt, bool $contentAvailable, bool $critical, string $priority, Event $queueForEvents, Database $dbForProject, Database $dbForPlatform, Document $project, Messaging $queueForMessaging, Response $response, array $platform) {
Comment thread
coderabbitai[bot] marked this conversation as resolved.
$messageId = $messageId == 'unique()'
? ID::unique()
: $messageId;
Expand Down Expand Up @@ -3551,7 +3552,6 @@
throw new Exception(Exception::STORAGE_FILE_TYPE_UNSUPPORTED);
}

$host = System::getEnv('_APP_DOMAIN', 'localhost');
$protocol = System::getEnv('_APP_OPTIONS_FORCE_HTTPS') === 'disabled' ? 'http' : 'https';

$scheduleTime = $currentScheduledAt ?? $scheduledAt;
Expand All @@ -3572,7 +3572,7 @@
$image = [
'bucketId' => $bucket->getId(),
'fileId' => $file->getId(),
'url' => "{$protocol}://{$host}/v1/storage/buckets/{$bucket->getId()}/files/{$file->getId()}/push?project={$project->getId()}&jwt={$jwt}",
'url' => "{$platform['endpoint']}/storage/buckets/{$bucket->getId()}/files/{$file->getId()}/push?project={$project->getId()}&jwt={$jwt}",
];
}

Expand Down Expand Up @@ -4378,7 +4378,8 @@
->inject('project')
->inject('queueForMessaging')
->inject('response')
->action(function (string $messageId, ?array $topics, ?array $users, ?array $targets, ?string $title, ?string $body, ?array $data, ?string $action, ?string $image, ?string $icon, ?string $sound, ?string $color, ?string $tag, ?int $badge, ?bool $draft, ?string $scheduledAt, ?bool $contentAvailable, ?bool $critical, ?string $priority, Event $queueForEvents, Database $dbForProject, Database $dbForPlatform, Document $project, Messaging $queueForMessaging, Response $response) {
->inject('platform')
->action(function (string $messageId, ?array $topics, ?array $users, ?array $targets, ?string $title, ?string $body, ?array $data, ?string $action, ?string $image, ?string $icon, ?string $sound, ?string $color, ?string $tag, ?int $badge, ?bool $draft, ?string $scheduledAt, ?bool $contentAvailable, ?bool $critical, ?string $priority, Event $queueForEvents, Database $dbForProject, Database $dbForPlatform, Document $project, Messaging $queueForMessaging, Response $response, array $platform) {
$message = $dbForProject->getDocument('messages', $messageId);

if ($message->isEmpty()) {
Expand Down Expand Up @@ -4546,9 +4547,6 @@
throw new Exception(Exception::STORAGE_FILE_TYPE_UNSUPPORTED);
}

$host = System::getEnv('_APP_DOMAIN', 'localhost');
$protocol = System::getEnv('_APP_OPTIONS_FORCE_HTTPS') === 'disabled' ? 'http' : 'https';

$scheduleTime = $currentScheduledAt ?? $scheduledAt;
if (!\is_null($scheduleTime)) {
$expiry = (new \DateTime($scheduleTime))->add(new \DateInterval('P15D'))->format('U');
Expand All @@ -4567,7 +4565,7 @@
$pushData['image'] = [
'bucketId' => $bucket->getId(),
'fileId' => $file->getId(),
'url' => "{$protocol}://{$host}/v1/storage/buckets/{$bucket->getId()}/files/{$file->getId()}/push?project={$project->getId()}&jwt={$jwt}"
'url' => "{$platform['endpoint']}/storage/buckets/{$bucket->getId()}/files/{$file->getId()}/push?project={$project->getId()}&jwt={$jwt}",
];
}

Expand Down
3 changes: 1 addition & 2 deletions app/controllers/api/teams.php
Original file line number Diff line number Diff line change
Expand Up @@ -58,7 +58,6 @@
use Utopia\Validator\Assoc;
use Utopia\Validator\Boolean;
use Utopia\Validator\Text;
use Utopia\Validator\URL;
use Utopia\Validator\WhiteList;

App::post('/v1/teams')
Expand Down Expand Up @@ -486,7 +485,7 @@
}
return new ArrayList(new Key(), APP_LIMIT_ARRAY_PARAMS_SIZE);
}, 'Array of strings. Use this param to set the user roles in the team. A role can be any string. Learn more about [roles and permissions](https://appwrite.io/docs/permissions). Maximum of ' . APP_LIMIT_ARRAY_PARAMS_SIZE . ' roles are allowed, each 32 characters long.', false, ['project'])
->param('url', '', fn ($platforms, $devKey) => $devKey->isEmpty() ? new Redirect($platforms) : new URL(), 'URL to redirect the user back to your app from the invitation email. This parameter is not required when an API key is supplied. Only URLs from hostnames in your project platform list are allowed. This requirement helps to prevent an [open redirect](https://cheatsheetseries.owasp.org/cheatsheets/Unvalidated_Redirects_and_Forwards_Cheat_Sheet.html) attack against your project API.', true, ['platforms', 'devKey']) // TODO add our own built-in confirm page
->param('url', '', fn ($redirectValidator) => $redirectValidator, 'URL to redirect the user back to your app from the invitation email. This parameter is not required when an API key is supplied. Only URLs from hostnames in your project platform list are allowed. This requirement helps to prevent an [open redirect](https://cheatsheetseries.owasp.org/cheatsheets/Unvalidated_Redirects_and_Forwards_Cheat_Sheet.html) attack against your project API.', true, ['redirectValidator']) // TODO add our own built-in confirm page
->param('name', '', new Text(128), 'Name of the new team member. Max length: 128 chars.', true)
->inject('response')
->inject('project')
Expand Down
Loading
Loading