diff --git a/app/config/locale/templates/email-base-styled.tpl b/app/config/locale/templates/email-base-styled.tpl index 1979d560b5..81964b968f 100644 --- a/app/config/locale/templates/email-base-styled.tpl +++ b/app/config/locale/templates/email-base-styled.tpl @@ -187,7 +187,7 @@ Appwrite logo @@ -225,7 +225,7 @@ @@ -234,7 +234,7 @@ @@ -242,7 +242,7 @@ @@ -252,15 +252,15 @@ - + - +
TermsTerms
|
PrivacyPrivacy

- © {{year}} Appwrite | 251 Little Falls Drive, Wilmington 19808, + © {{year}} {{platform}} | 251 Little Falls Drive, Wilmington 19808, Delaware, United States

diff --git a/app/config/platform.php b/app/config/platform.php index b9d9dccbef..e44eaefa89 100644 --- a/app/config/platform.php +++ b/app/config/platform.php @@ -22,4 +22,5 @@ return [ 'termsUrl' => APP_EMAIL_TERMS_URL, 'privacyUrl' => APP_EMAIL_PRIVACY_URL, 'websiteUrl' => 'https://' . APP_DOMAIN, + 'emailSenderName' => APP_EMAIL_PLATFORM_NAME, ]; diff --git a/app/controllers/api/account.php b/app/controllers/api/account.php index f18cb27834..7ff3a981d2 100644 --- a/app/controllers/api/account.php +++ b/app/controllers/api/account.php @@ -74,7 +74,7 @@ use Utopia\Validator\WhiteList; $oauthDefaultSuccess = '/console/auth/oauth2/success'; $oauthDefaultFailure = '/console/auth/oauth2/failure'; -function sendSessionAlert(Locale $locale, Document $user, Document $project, Document $session, Mail $queueForMails) +function sendSessionAlert(Locale $locale, Document $user, Document $project, array $platform, Document $session, Mail $queueForMails) { $subject = $locale->getText("emails.sessionAlert.subject"); $preview = $locale->getText("emails.sessionAlert.preview"); @@ -157,13 +157,18 @@ function sendSessionAlert(Locale $locale, Document $user, Document $project, Doc $session->setAttribute('clientName', $clientName); } + $projectName = $project->getAttribute('name'); + if ($project->getId() === 'console') { + $projectName = $platform['platformName']; + } + $emailVariables = [ 'direction' => $locale->getText('settings.direction'), 'date' => (new \DateTime())->format('F j'), 'year' => (new \DateTime())->format('YYYY'), 'time' => (new \DateTime())->format('H:i:s'), 'user' => $user->getAttribute('name'), - 'project' => $project->getAttribute('name'), + 'project' => $projectName, 'device' => $session->getAttribute('clientName'), 'ipAddress' => $session->getAttribute('ip'), 'country' => $locale->getText('countries.' . $session->getAttribute('countryCode'), $locale->getText('locale.country.unknown')), @@ -171,13 +176,14 @@ function sendSessionAlert(Locale $locale, Document $user, Document $project, Doc if ($smtpBaseTemplate === APP_BRANDED_EMAIL_BASE_TEMPLATE) { $emailVariables = array_merge($emailVariables, [ - 'accentColor' => APP_EMAIL_ACCENT_COLOR, - 'logoUrl' => APP_EMAIL_LOGO_URL, - 'twitterUrl' => APP_SOCIAL_TWITTER, - 'discordUrl' => APP_SOCIAL_DISCORD, - 'githubUrl' => APP_SOCIAL_GITHUB_APPWRITE, - 'termsUrl' => APP_EMAIL_TERMS_URL, - 'privacyUrl' => APP_EMAIL_PRIVACY_URL, + 'accentColor' => $platform['accentColor'], + 'logoUrl' => $platform['logoUrl'], + 'twitter' => $platform['twitterUrl'], + 'discord' => $platform['discordUrl'], + 'github' => $platform['githubUrl'], + 'terms' => $platform['termsUrl'], + 'privacy' => $platform['privacyUrl'], + 'platform' => $platform['platformName'], ]); } @@ -189,12 +195,18 @@ function sendSessionAlert(Locale $locale, Document $user, Document $project, Doc ->setBody($body) ->setBodyTemplate($bodyTemplate) ->setVariables($emailVariables) - ->setRecipient($email) - ->trigger(); -} -; + ->setRecipient($email); -$createSession = function (string $userId, string $secret, Request $request, Response $response, User $user, Database $dbForProject, Document $project, Locale $locale, Reader $geodb, Event $queueForEvents, Mail $queueForMails, Store $store, ProofsToken $proofForToken, ProofsCode $proofForCode) { + // since this is console project, set email sender name! + if ($smtpBaseTemplate === APP_BRANDED_EMAIL_BASE_TEMPLATE) { + $queueForMails->setSenderName($platform['emailSenderName']); + } + + $queueForMails->trigger(); +} + + +$createSession = function (string $userId, string $secret, Request $request, Response $response, User $user, Database $dbForProject, Document $project, array $platform, Locale $locale, Reader $geodb, Event $queueForEvents, Mail $queueForMails, Store $store, ProofsToken $proofForToken, ProofsCode $proofForCode) { /** @var Appwrite\Utopia\Database\Documents\User $userFromRequest */ $userFromRequest = Authorization::skip(fn () => $dbForProject->getDocument('users', $userId)); @@ -295,7 +307,7 @@ $createSession = function (string $userId, string $secret, Request $request, Res ]) !== 1; if ($isAllowedTokenType && $hasUserEmail && $isSessionAlertsEnabled && $isNotFirstSession) { - sendSessionAlert($locale, $user, $project, $session, $queueForMails); + sendSessionAlert($locale, $user, $project, $platform, $session, $queueForMails); } $queueForEvents @@ -953,6 +965,7 @@ App::post('/v1/account/sessions/email') ->inject('user') ->inject('dbForProject') ->inject('project') + ->inject('platform') ->inject('locale') ->inject('geodb') ->inject('queueForEvents') @@ -961,7 +974,7 @@ App::post('/v1/account/sessions/email') ->inject('store') ->inject('proofForPassword') ->inject('proofForToken') - ->action(function (string $email, string $password, Request $request, Response $response, User $user, Database $dbForProject, Document $project, Locale $locale, Reader $geodb, Event $queueForEvents, Mail $queueForMails, Hooks $hooks, Store $store, ProofsPassword $proofForPassword, ProofsToken $proofForToken) { + ->action(function (string $email, string $password, Request $request, Response $response, User $user, Database $dbForProject, Document $project, array $platform, Locale $locale, Reader $geodb, Event $queueForEvents, Mail $queueForMails, Hooks $hooks, Store $store, ProofsPassword $proofForPassword, ProofsToken $proofForToken) { $email = \strtolower($email); $protocol = $request->getProtocol(); @@ -1062,7 +1075,7 @@ App::post('/v1/account/sessions/email') Query::equal('userId', [$user->getId()]), ]) !== 1 ) { - sendSessionAlert($locale, $user, $project, $session, $queueForMails); + sendSessionAlert($locale, $user, $project, $platform, $session, $queueForMails); } } @@ -1250,6 +1263,7 @@ App::post('/v1/account/sessions/token') ->inject('user') ->inject('dbForProject') ->inject('project') + ->inject('platform') ->inject('locale') ->inject('geodb') ->inject('queueForEvents') @@ -2251,11 +2265,16 @@ App::post('/v1/account/tokens/magic-url') ->setSmtpSenderName($senderName); } + $projectName = $project->getAttribute('name'); + if ($project->getId() === 'console') { + $projectName = $platform['platformName']; + } + $emailVariables = [ 'direction' => $locale->getText('settings.direction'), // {{user}}, {{redirect}} and {{project}} are required in default and custom templates 'user' => $user->getAttribute('name'), - 'project' => $project->getAttribute('name'), + 'project' => $projectName, 'redirect' => $url, 'agentDevice' => $agentDevice['deviceBrand'] ?? $agentDevice['deviceBrand'] ?? 'UNKNOWN', 'agentClient' => $agentClient['clientName'] ?? 'UNKNOWN', @@ -2270,8 +2289,13 @@ App::post('/v1/account/tokens/magic-url') ->setPreview($preview) ->setBody($body) ->setVariables($emailVariables) - ->setRecipient($email) - ->trigger(); + ->setRecipient($email); + + if ($project->getId() === 'console') { + $queueForMails->setSenderName($platform['emailSenderName']); + } + + $queueForMails->trigger(); $token->setAttribute('secret', $tokenSecret); @@ -2318,13 +2342,14 @@ App::post('/v1/account/tokens/email') ->inject('response') ->inject('user') ->inject('project') + ->inject('platform') ->inject('dbForProject') ->inject('locale') ->inject('queueForEvents') ->inject('queueForMails') ->inject('proofForPassword') ->inject('proofForCode') - ->action(function (string $userId, string $email, bool $phrase, Request $request, Response $response, User $user, Document $project, Database $dbForProject, Locale $locale, Event $queueForEvents, Mail $queueForMails, ProofsPassword $proofForPassword, ProofsCode $proofForCode) { + ->action(function (string $userId, string $email, bool $phrase, Request $request, Response $response, User $user, Document $project, array $platform, Database $dbForProject, Locale $locale, Event $queueForEvents, Mail $queueForMails, ProofsPassword $proofForPassword, ProofsCode $proofForCode) { if (empty(System::getEnv('_APP_SMTP_HOST'))) { throw new Exception(Exception::GENERAL_SMTP_DISABLED, 'SMTP disabled'); } @@ -2525,12 +2550,17 @@ App::post('/v1/account/tokens/email') ->setSmtpSenderName($senderName); } + $projectName = $project->getAttribute('name'); + if ($project->getId() === 'console') { + $projectName = $platform['platformName']; + } + $emailVariables = [ 'heading' => $heading, 'direction' => $locale->getText('settings.direction'), // {{user}}, {{project}} and {{otp}} are required in the templates 'user' => $user->getAttribute('name'), - 'project' => $project->getAttribute('name'), + 'project' => $projectName, 'otp' => $tokenSecret, 'agentDevice' => $agentDevice['deviceBrand'] ?? $agentDevice['deviceBrand'] ?? 'UNKNOWN', 'agentClient' => $agentClient['clientName'] ?? 'UNKNOWN', @@ -2542,13 +2572,14 @@ App::post('/v1/account/tokens/email') if ($smtpBaseTemplate === APP_BRANDED_EMAIL_BASE_TEMPLATE) { $emailVariables = array_merge($emailVariables, [ - 'accentColor' => APP_EMAIL_ACCENT_COLOR, - 'logoUrl' => APP_EMAIL_LOGO_URL, - 'twitterUrl' => APP_SOCIAL_TWITTER, - 'discordUrl' => APP_SOCIAL_DISCORD, - 'githubUrl' => APP_SOCIAL_GITHUB_APPWRITE, - 'termsUrl' => APP_EMAIL_TERMS_URL, - 'privacyUrl' => APP_EMAIL_PRIVACY_URL, + 'accentColor' => $platform['accentColor'], + 'logoUrl' => $platform['logoUrl'], + 'twitter' => $platform['twitterUrl'], + 'discord' => $platform['discordUrl'], + 'github' => $platform['githubUrl'], + 'terms' => $platform['termsUrl'], + 'privacy' => $platform['privacyUrl'], + 'platform' => $platform['platformName'], ]); } @@ -2558,8 +2589,14 @@ App::post('/v1/account/tokens/email') ->setBody($body) ->setBodyTemplate($bodyTemplate) ->setVariables($emailVariables) - ->setRecipient($email) - ->trigger(); + ->setRecipient($email); + + // since this is console project, set email sender name! + if ($smtpBaseTemplate === APP_BRANDED_EMAIL_BASE_TEMPLATE) { + $queueForMails->setSenderName($platform['emailSenderName']); + } + + $queueForMails->trigger(); $token->setAttribute('secret', $tokenSecret); @@ -2610,16 +2647,17 @@ App::put('/v1/account/sessions/magic-url') ->inject('user') ->inject('dbForProject') ->inject('project') + ->inject('platform') ->inject('locale') ->inject('geodb') ->inject('queueForEvents') ->inject('queueForMails') ->inject('store') ->inject('proofForCode') - ->action(function ($userId, $secret, $request, $response, $user, $dbForProject, $project, $locale, $geodb, $queueForEvents, $queueForMails, $store, $proofForCode) use ($createSession) { + ->action(function ($userId, $secret, $request, $response, $user, $dbForProject, $project, $platform, $locale, $geodb, $queueForEvents, $queueForMails, $store, $proofForCode) use ($createSession) { $proofForToken = new ProofsToken(TOKEN_LENGTH_MAGIC_URL); $proofForToken->setHash(new Sha()); - $createSession($userId, $secret, $request, $response, $user, $dbForProject, $project, $locale, $geodb, $queueForEvents, $queueForMails, $store, $proofForToken, $proofForCode); + $createSession($userId, $secret, $request, $response, $user, $dbForProject, $project, $platform, $locale, $geodb, $queueForEvents, $queueForMails, $store, $proofForToken, $proofForCode); }); App::put('/v1/account/sessions/phone') @@ -2657,6 +2695,7 @@ App::put('/v1/account/sessions/phone') ->inject('user') ->inject('dbForProject') ->inject('project') + ->inject('platform') ->inject('locale') ->inject('geodb') ->inject('queueForEvents') @@ -2697,6 +2736,7 @@ App::post('/v1/account/tokens/phone') ->inject('response') ->inject('user') ->inject('project') + ->inject('platform') ->inject('dbForProject') ->inject('queueForEvents') ->inject('queueForMessaging') @@ -2706,7 +2746,7 @@ App::post('/v1/account/tokens/phone') ->inject('plan') ->inject('store') ->inject('proofForCode') - ->action(function (string $userId, string $phone, Request $request, Response $response, User $user, Document $project, Database $dbForProject, Event $queueForEvents, Messaging $queueForMessaging, Locale $locale, callable $timelimit, StatsUsage $queueForStatsUsage, array $plan, Store $store, ProofsCode $proofForCode) { + ->action(function (string $userId, string $phone, Request $request, Response $response, User $user, Document $project, array $platform, Database $dbForProject, Event $queueForEvents, Messaging $queueForMessaging, Locale $locale, callable $timelimit, StatsUsage $queueForStatsUsage, array $plan, Store $store, ProofsCode $proofForCode) { if (empty(System::getEnv('_APP_SMS_PROVIDER'))) { throw new Exception(Exception::GENERAL_PHONE_DISABLED, 'Phone provider not configured'); } @@ -2823,9 +2863,14 @@ App::post('/v1/account/tokens/phone') $message = $customTemplate['message'] ?? $message; } + $projectName = $project->getAttribute('name'); + if ($project->getId() === 'console') { + $projectName = $platform['platformName']; + } + $messageContent = Template::fromString($locale->getText("sms.verification.body")); $messageContent - ->setParam('{{project}}', $project->getAttribute('name')) + ->setParam('{{project}}', $projectName) ->setParam('{{secret}}', $secret); $messageContent = \strip_tags($messageContent->render()); $message = $message->setParam('{{token}}', $messageContent); @@ -3473,15 +3518,16 @@ App::post('/v1/account/recovery') ->inject('user') ->inject('dbForProject') ->inject('project') + ->inject('platform') ->inject('locale') ->inject('queueForMails') ->inject('queueForEvents') ->inject('proofForToken') - ->action(function (string $email, string $url, Request $request, Response $response, User $user, Database $dbForProject, Document $project, Locale $locale, Mail $queueForMails, Event $queueForEvents, ProofsToken $proofForToken) { - + ->action(function (string $email, string $url, Request $request, Response $response, User $user, Database $dbForProject, Document $project, array $platform, Locale $locale, Mail $queueForMails, Event $queueForEvents, ProofsToken $proofForToken) { if (empty(System::getEnv('_APP_SMTP_HOST'))) { throw new Exception(Exception::GENERAL_SMTP_DISABLED, 'SMTP Disabled'); } + $url = htmlentities($url); $email = \strtolower($email); @@ -3528,7 +3574,14 @@ App::post('/v1/account/recovery') $url['query'] = Template::mergeQuery(((isset($url['query'])) ? $url['query'] : ''), ['userId' => $profile->getId(), 'secret' => $secret, 'expire' => $expire]); $url = Template::unParseURL($url); - $projectName = $project->isEmpty() ? 'Console' : $project->getAttribute('name', '[APP-NAME]'); + $projectName = $project->isEmpty() + ? 'Console' + : $project->getAttribute('name', '[APP-NAME]'); + + if ($project->getId() === 'console') { + $projectName = $platform['platformName']; + } + $body = $locale->getText("emails.recovery.body"); $subject = $locale->getText("emails.recovery.subject"); $preview = $locale->getText("emails.recovery.preview"); @@ -3606,8 +3659,13 @@ App::post('/v1/account/recovery') ->setBody($body) ->setVariables($emailVariables) ->setSubject($subject) - ->setPreview($preview) - ->trigger(); + ->setPreview($preview); + + if ($project->getId() === 'console') { + $queueForMails->setSenderName($platform['emailSenderName']); + } + + $queueForMails->trigger(); $recovery->setAttribute('secret', $secret); @@ -3767,13 +3825,14 @@ App::post('/v1/account/verifications/email') ->inject('request') ->inject('response') ->inject('project') + ->inject('platform') ->inject('user') ->inject('dbForProject') ->inject('locale') ->inject('queueForEvents') ->inject('queueForMails') ->inject('proofForToken') - ->action(function (string $url, Request $request, Response $response, Document $project, User $user, Database $dbForProject, Locale $locale, Event $queueForEvents, Mail $queueForMails, ProofsToken $proofForToken) { + ->action(function (string $url, Request $request, Response $response, Document $project, array $platform, User $user, Database $dbForProject, Locale $locale, Event $queueForEvents, Mail $queueForMails, ProofsToken $proofForToken) { if (empty(System::getEnv('_APP_SMTP_HOST'))) { throw new Exception(Exception::GENERAL_SMTP_DISABLED, 'SMTP Disabled'); @@ -3817,7 +3876,15 @@ App::post('/v1/account/verifications/email') $url['query'] = Template::mergeQuery(((isset($url['query'])) ? $url['query'] : ''), ['userId' => $user->getId(), 'secret' => $verificationSecret, 'expire' => $expire]); $url = Template::unParseURL($url); - $projectName = $project->isEmpty() ? 'Console' : $project->getAttribute('name', '[APP-NAME]'); + $projectName = $project->isEmpty() + ? 'Console' + : $project->getAttribute('name', '[APP-NAME]'); + + if ($project->getId() === 'console') { + $projectName = $platform['platformName']; + } + + $body = $locale->getText("emails.verification.body"); $preview = $locale->getText("emails.verification.preview"); $subject = $locale->getText("emails.verification.subject"); @@ -3903,13 +3970,14 @@ App::post('/v1/account/verifications/email') if ($smtpBaseTemplate === APP_BRANDED_EMAIL_BASE_TEMPLATE) { $emailVariables = array_merge($emailVariables, [ - 'accentColor' => APP_EMAIL_ACCENT_COLOR, - 'logoUrl' => APP_EMAIL_LOGO_URL, - 'twitterUrl' => APP_SOCIAL_TWITTER, - 'discordUrl' => APP_SOCIAL_DISCORD, - 'githubUrl' => APP_SOCIAL_GITHUB_APPWRITE, - 'termsUrl' => APP_EMAIL_TERMS_URL, - 'privacyUrl' => APP_EMAIL_PRIVACY_URL, + 'accentColor' => $platform['accentColor'], + 'logoUrl' => $platform['logoUrl'], + 'twitter' => $platform['twitterUrl'], + 'discord' => $platform['discordUrl'], + 'github' => $platform['githubUrl'], + 'terms' => $platform['termsUrl'], + 'privacy' => $platform['privacyUrl'], + 'platform' => $platform['platformName'], ]); } @@ -3920,8 +3988,13 @@ App::post('/v1/account/verifications/email') ->setBodyTemplate($bodyTemplate) ->setVariables($emailVariables) ->setRecipient($user->getAttribute('email')) - ->setName($user->getAttribute('name') ?? '') - ->trigger(); + ->setName($user->getAttribute('name') ?? ''); + + if ($project->getId() === 'console') { + $queueForMails->setSenderName($platform['emailSenderName']); + } + + $queueForMails->trigger(); $verification->setAttribute('secret', $verificationSecret); diff --git a/app/init/resources.php b/app/init/resources.php index 99476c695f..672fcd8b4e 100644 --- a/app/init/resources.php +++ b/app/init/resources.php @@ -281,6 +281,7 @@ App::setResource('cors', fn (array $allowedHostnames) => new Cors( 'X-SDK-Language', 'X-SDK-Platform', 'X-SDK-GraphQL', + 'X-SDK-Profile', // Caching 'Range', 'Cache-Control', diff --git a/src/Appwrite/Platform/Modules/Account/Http/Account/MFA/Challenges/Create.php b/src/Appwrite/Platform/Modules/Account/Http/Account/MFA/Challenges/Create.php index 196c83999d..4dc50a8ec7 100644 --- a/src/Appwrite/Platform/Modules/Account/Http/Account/MFA/Challenges/Create.php +++ b/src/Appwrite/Platform/Modules/Account/Http/Account/MFA/Challenges/Create.php @@ -98,6 +98,7 @@ class Create extends Action ->inject('user') ->inject('locale') ->inject('project') + ->inject('platform') ->inject('request') ->inject('queueForEvents') ->inject('queueForMessaging') @@ -117,6 +118,7 @@ class Create extends Action Document $user, Locale $locale, Document $project, + array $platform, Request $request, Event $queueForEvents, Messaging $queueForMessaging, @@ -146,6 +148,11 @@ class Create extends Action $challenge = $dbForProject->createDocument('challenges', $challenge); + $projectName = $project->getAttribute('name'); + if ($project->getId() === 'console') { + $projectName = $platform['platformName']; + } + // 9 levels up to project root $templatesPath = \dirname(__DIR__, 9) . '/app/config/locale/templates'; @@ -170,7 +177,7 @@ class Create extends Action $messageContent = Template::fromString($locale->getText("sms.verification.body")); $messageContent - ->setParam('{{project}}', $project->getAttribute('name')) + ->setParam('{{project}}', $projectName) ->setParam('{{secret}}', $code); $messageContent = \strip_tags($messageContent->render()); $message = $message->setParam('{{token}}', $messageContent); @@ -300,7 +307,7 @@ class Create extends Action 'heading' => $heading, 'direction' => $locale->getText('settings.direction'), 'user' => $user->getAttribute('name'), - 'project' => $project->getAttribute('name'), + 'project' => $projectName, 'otp' => $code, 'agentDevice' => $agentDevice['deviceBrand'] ?? 'UNKNOWN', 'agentClient' => $agentClient['clientName'] ?? 'UNKNOWN', @@ -309,13 +316,14 @@ class Create extends Action if ($smtpBaseTemplate === APP_BRANDED_EMAIL_BASE_TEMPLATE) { $emailVariables = array_merge($emailVariables, [ - 'accentColor' => APP_EMAIL_ACCENT_COLOR, - 'logoUrl' => APP_EMAIL_LOGO_URL, - 'twitterUrl' => APP_SOCIAL_TWITTER, - 'discordUrl' => APP_SOCIAL_DISCORD, - 'githubUrl' => APP_SOCIAL_GITHUB_APPWRITE, - 'termsUrl' => APP_EMAIL_TERMS_URL, - 'privacyUrl' => APP_EMAIL_PRIVACY_URL, + 'accentColor' => $platform['accentColor'], + 'logoUrl' => $platform['logoUrl'], + 'twitter' => $platform['twitterUrl'], + 'discord' => $platform['discordUrl'], + 'github' => $platform['githubUrl'], + 'terms' => $platform['termsUrl'], + 'privacy' => $platform['privacyUrl'], + 'platform' => $platform['platformName'], ]); } @@ -325,8 +333,14 @@ class Create extends Action ->setBody($body) ->setBodyTemplate($bodyTemplate) ->setVariables($emailVariables) - ->setRecipient($user->getAttribute('email')) - ->trigger(); + ->setRecipient($user->getAttribute('email')); + + // since this is console project, set email sender name! + if ($smtpBaseTemplate === APP_BRANDED_EMAIL_BASE_TEMPLATE) { + $queueForMails->setSenderName($platform['emailSenderName']); + } + + $queueForMails->trigger(); break; } diff --git a/tests/e2e/General/HTTPTest.php b/tests/e2e/General/HTTPTest.php index b8ccde202e..6323500136 100644 --- a/tests/e2e/General/HTTPTest.php +++ b/tests/e2e/General/HTTPTest.php @@ -31,7 +31,7 @@ class HTTPTest extends Scope $this->assertEquals(204, $response['headers']['status-code']); $this->assertEquals('Appwrite', $response['headers']['server']); $this->assertEquals('GET, POST, PUT, PATCH, DELETE', $response['headers']['access-control-allow-methods']); - $this->assertEquals('Accept, Origin, Cookie, Set-Cookie, Content-Type, Content-Range, X-Appwrite-Project, X-Appwrite-Key, X-Appwrite-Dev-Key, X-Appwrite-Locale, X-Appwrite-Mode, X-Appwrite-JWT, X-Appwrite-Response-Format, X-Appwrite-Timeout, X-Appwrite-ID, X-Appwrite-Timestamp, X-Appwrite-Session, X-SDK-Version, X-SDK-Name, X-SDK-Language, X-SDK-Platform, X-SDK-GraphQL, Range, Cache-Control, Expires, Pragma, X-Fallback-Cookies, X-Requested-With, X-Forwarded-For, X-Forwarded-User-Agent', $response['headers']['access-control-allow-headers']); + $this->assertEquals('Accept, Origin, Cookie, Set-Cookie, Content-Type, Content-Range, X-Appwrite-Project, X-Appwrite-Key, X-Appwrite-Dev-Key, X-Appwrite-Locale, X-Appwrite-Mode, X-Appwrite-JWT, X-Appwrite-Response-Format, X-Appwrite-Timeout, X-Appwrite-ID, X-Appwrite-Timestamp, X-Appwrite-Session, X-SDK-Version, X-SDK-Name, X-SDK-Language, X-SDK-Platform, X-SDK-GraphQL, X-SDK-Profile, Range, Cache-Control, Expires, Pragma, X-Fallback-Cookies, X-Requested-With, X-Forwarded-For, X-Forwarded-User-Agent', $response['headers']['access-control-allow-headers']); $this->assertEquals('X-Appwrite-Session, X-Fallback-Cookies', $response['headers']['access-control-expose-headers']); $this->assertEquals('http://localhost', $response['headers']['access-control-allow-origin']); $this->assertEquals('true', $response['headers']['access-control-allow-credentials']);